From c99de515a023d186f152833197eb4ccfe43017e3 Mon Sep 17 00:00:00 2001 From: FBruzzesi Date: Sat, 14 Sep 2024 23:16:26 +0200 Subject: [PATCH 1/4] WIP --- dirty_equals/_sequence.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/dirty_equals/_sequence.py b/dirty_equals/_sequence.py index 9b8ba2b..300a403 100644 --- a/dirty_equals/_sequence.py +++ b/dirty_equals/_sequence.py @@ -153,6 +153,15 @@ def __init__( 8. If you don't care about the first few values of a list or tuple, you can use [`AnyThing`][dirty_equals.AnyThing] in your arguments. """ + if not (items or positions or length): + allowed_type_names = ' or '.join(t.__name__ for t in self.allowed_type) + msg = ( + f'Instantiating `{self.__class__.__name__}` without any argument is ambiguous.\n' + f'- For an empty {allowed_type_names}, please specify {self.__class__.__name__}(length=0)\n' + f'- For a {allowed_type_names} of any given length, please specify {self.__class__.__name__}(length=...)' + ) + raise AssertionError(msg) + if positions is not None: self.positions: Optional[Dict[int, Any]] = positions if items: @@ -226,7 +235,7 @@ class IsList(IsListOrTuple[List[Any]]): ``` """ - allowed_type = list + allowed_type = (list, ) class IsTuple(IsListOrTuple[Tuple[Any, ...]]): @@ -247,7 +256,7 @@ class IsTuple(IsListOrTuple[Tuple[Any, ...]]): ``` """ - allowed_type = tuple + allowed_type = (tuple, ) def _length_repr(length: 'LengthType') -> Any: From 3445ebcaada119cb62850ca9ca9f1e907392aae0 Mon Sep 17 00:00:00 2001 From: FBruzzesi Date: Sun, 15 Sep 2024 11:13:19 +0200 Subject: [PATCH 2/4] tests --- dirty_equals/_sequence.py | 4 ++-- tests/test_list_tuple.py | 35 ++++++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/dirty_equals/_sequence.py b/dirty_equals/_sequence.py index 300a403..4338fde 100644 --- a/dirty_equals/_sequence.py +++ b/dirty_equals/_sequence.py @@ -153,14 +153,14 @@ def __init__( 8. If you don't care about the first few values of a list or tuple, you can use [`AnyThing`][dirty_equals.AnyThing] in your arguments. """ - if not (items or positions or length): + if not (items or positions or length is not None): allowed_type_names = ' or '.join(t.__name__ for t in self.allowed_type) msg = ( f'Instantiating `{self.__class__.__name__}` without any argument is ambiguous.\n' f'- For an empty {allowed_type_names}, please specify {self.__class__.__name__}(length=0)\n' f'- For a {allowed_type_names} of any given length, please specify {self.__class__.__name__}(length=...)' ) - raise AssertionError(msg) + raise TypeError(msg) if positions is not None: self.positions: Optional[Dict[int, Any]] = positions diff --git a/tests/test_list_tuple.py b/tests/test_list_tuple.py index 40c596e..24d30e4 100644 --- a/tests/test_list_tuple.py +++ b/tests/test_list_tuple.py @@ -1,3 +1,5 @@ +import re + import pytest from dirty_equals import AnyThing, Contains, HasLen, IsInt, IsList, IsListOrTuple, IsNegative, IsTuple @@ -6,11 +8,9 @@ @pytest.mark.parametrize( 'other,dirty', [ - ([], IsList), - ((), IsTuple), - ([], IsList()), + ([], IsList(length=0)), + ((), IsTuple(length=0)), ([1], IsList(length=1)), - ((), IsTuple()), ([1, 2, 3], IsList(1, 2, 3)), ((1, 2, 3), IsTuple(1, 2, 3)), ((1, 2, 3), IsListOrTuple(1, 2, 3)), @@ -51,9 +51,9 @@ def test_dirty_equals(other, dirty): @pytest.mark.parametrize( 'other,dirty', [ - ([], IsTuple), - ((), IsList), - ([1], IsList), + ([], IsTuple(length=0)), + ((), IsList(length=0)), + ([1], IsList(length=0)), ([1, 2, 3], IsTuple(1, 2, 3)), ((1, 2, 3), IsList(1, 2, 3)), ([1, 2, 3, 4], IsList(1, 2, 3)), @@ -99,6 +99,27 @@ def test_wrong_length_length(): with pytest.raises(TypeError, match='length must be a tuple of length 2, not 3'): IsList(1, 2, length=(1, 2, 3)) +@pytest.mark.parametrize( + 'dirty,allowed_type_names', [ + (IsList, 'list'), + (IsTuple, 'tuple'), + (IsListOrTuple, 'list or tuple'), + ] +) +def test_no_args(dirty: type, allowed_type_names: str): + + err_msg = re.escape( + rf'Instantiating `{dirty.__name__}` without any argument is ambiguous.' + '\n' + rf'- For an empty {allowed_type_names}, please specify {dirty.__name__}(length=0)' + '\n' + rf'- For a {allowed_type_names} of any given length, please specify {dirty.__name__}(length=...)' + ) + with pytest.raises( + TypeError, + match=err_msg + ): + dirty() + + @pytest.mark.parametrize( 'dirty,repr_str', From b476f44a7c07ec4a5ed4c474ca68d18889aec45a Mon Sep 17 00:00:00 2001 From: FBruzzesi Date: Sun, 15 Sep 2024 11:13:59 +0200 Subject: [PATCH 3/4] trigger pre commit From ec547ffa94e1b308a9417b58955103fa8208f855 Mon Sep 17 00:00:00 2001 From: FBruzzesi Date: Sun, 15 Sep 2024 11:24:47 +0200 Subject: [PATCH 4/4] guess it did not trigger --- dirty_equals/_sequence.py | 10 ++++++---- tests/test_list_tuple.py | 19 ++++++++----------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/dirty_equals/_sequence.py b/dirty_equals/_sequence.py index 4338fde..e2b1e96 100644 --- a/dirty_equals/_sequence.py +++ b/dirty_equals/_sequence.py @@ -87,7 +87,9 @@ class IsListOrTuple(DirtyEquals[T]): Check that some object is a list or tuple and optionally its values match some constraints. """ - allowed_type: Union[Type[T], Tuple[Type[List[Any]], Type[Tuple[Any, ...]]]] = (list, tuple) + allowed_type: Union[ + Tuple[Type[List[Any]]], Tuple[Type[Tuple[Any, ...]]], Tuple[Type[List[Any]], Type[Tuple[Any, ...]]] + ] = (list, tuple) @overload def __init__(self, *items: Any, check_order: bool = True, length: 'LengthType' = None): ... @@ -159,7 +161,7 @@ def __init__( f'Instantiating `{self.__class__.__name__}` without any argument is ambiguous.\n' f'- For an empty {allowed_type_names}, please specify {self.__class__.__name__}(length=0)\n' f'- For a {allowed_type_names} of any given length, please specify {self.__class__.__name__}(length=...)' - ) + ) raise TypeError(msg) if positions is not None: @@ -235,7 +237,7 @@ class IsList(IsListOrTuple[List[Any]]): ``` """ - allowed_type = (list, ) + allowed_type = (list,) class IsTuple(IsListOrTuple[Tuple[Any, ...]]): @@ -256,7 +258,7 @@ class IsTuple(IsListOrTuple[Tuple[Any, ...]]): ``` """ - allowed_type = (tuple, ) + allowed_type = (tuple,) def _length_repr(length: 'LengthType') -> Any: diff --git a/tests/test_list_tuple.py b/tests/test_list_tuple.py index 24d30e4..26b3b31 100644 --- a/tests/test_list_tuple.py +++ b/tests/test_list_tuple.py @@ -99,28 +99,25 @@ def test_wrong_length_length(): with pytest.raises(TypeError, match='length must be a tuple of length 2, not 3'): IsList(1, 2, length=(1, 2, 3)) + @pytest.mark.parametrize( - 'dirty,allowed_type_names', [ - (IsList, 'list'), - (IsTuple, 'tuple'), - (IsListOrTuple, 'list or tuple'), - ] + 'dirty,allowed_type_names', + [ + (IsList, 'list'), + (IsTuple, 'tuple'), + (IsListOrTuple, 'list or tuple'), + ], ) def test_no_args(dirty: type, allowed_type_names: str): - err_msg = re.escape( rf'Instantiating `{dirty.__name__}` without any argument is ambiguous.' + '\n' rf'- For an empty {allowed_type_names}, please specify {dirty.__name__}(length=0)' + '\n' rf'- For a {allowed_type_names} of any given length, please specify {dirty.__name__}(length=...)' ) - with pytest.raises( - TypeError, - match=err_msg - ): + with pytest.raises(TypeError, match=err_msg): dirty() - @pytest.mark.parametrize( 'dirty,repr_str', [