diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ad95b67e75018ec40f4cc1793c783e3b3447838..4804b24e8f036a25790775dcfebe87b82cce6504 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,3 +2,4 @@ * fixed `AlreadySeen` to support non-hashable objects * improved `ComparableIntEnum` +* fixed a bug in `get_argument` while comparing uncomparable items diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000000000000000000000000000000000000..20341273762b5f2015703410eaebe5ff4007e8d7 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +log_cli = true + diff --git a/satella/__init__.py b/satella/__init__.py index 041b19ad9bb130f42313c4f85bbb79738f0b5d96..90cfa8cccde4089e7d5d10426d35be03cb0b4101 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1 +1 @@ -__version__ = '2.14.36a3' +__version__ = '2.14.36' diff --git a/satella/coding/decorators/arguments.py b/satella/coding/decorators/arguments.py index 04fe264fcfa097896208b32b2dbd5610d6b054e1..dfda9fdf128a29b99cbde470a7bb2dd76825f755 100644 --- a/satella/coding/decorators/arguments.py +++ b/satella/coding/decorators/arguments.py @@ -326,8 +326,18 @@ def for_argument(*t_ops: ForArgumentArg, **t_kwops: ForArgumentArg): t_kwops[key] = source_to_function(value) def outer(fun): - if any(param.default != Parameter.empty for param in - inspect.signature(fun).parameters.values()): + comparison = False + # Check whether this function has any default arguments + for param in inspect.signature(fun).parameters.values(): + try: + if Parameter.empty != param.default: + comparison = True + break + except (AttributeError, TypeError): + comparison = True + break + + if comparison: @wraps(fun) def inner(*args, **kwargs): dict_operations = _get_arguments(fun, True, *t_ops, **t_kwops) diff --git a/satella/coding/misc.py b/satella/coding/misc.py index d6d65d0543604b40fbe7b6b1bf66642e49301e43..5cfcd394f23a975b5413a68ba84f9ac7bfb939f2 100644 --- a/satella/coding/misc.py +++ b/satella/coding/misc.py @@ -267,9 +267,12 @@ def _get_arguments(function: tp.Callable, special_behaviour: bool, *args, **kwar v = args.pop() arguments_left.remove(arg_name) except IndexError: - if arg.default == Parameter.empty: - break - else: + try: + if arg.default != Parameter.empty: + raise AttributeError() + else: + break + except (AttributeError, TypeError): v = arg.default local_vars[arg_name] = v @@ -286,13 +289,16 @@ def _get_arguments(function: tp.Callable, special_behaviour: bool, *args, **kwar try: v = kwargs.pop(keyword_name) except KeyError: - if keyword.default == Parameter.empty: - if special_behaviour: - v = None + try: + if Parameter.empty == keyword.default: + if special_behaviour: + v = None + else: + raise TypeError('Not enough keyword arguments') else: - raise TypeError('Not enough keyword arguments') - else: - v = keyword.default + v = keyword.default + except (AttributeError, TypeError): + continue # comparison was impossible local_vars[keyword_name] = v diff --git a/tests/test_coding/test_misc.py b/tests/test_coding/test_misc.py index a44ec1318d720fd211c9daa59d6e4b72f610e787..19f53ce79c49aa8a27e30c6f748c93f917d8047e 100644 --- a/tests/test_coding/test_misc.py +++ b/tests/test_coding/test_misc.py @@ -1,16 +1,33 @@ +import logging import enum import gc import unittest from satella.coding import update_key_if_not_none, overload, class_or_instancemethod, \ update_key_if_true, get_arguments, call_with_arguments, chain_callables, Closeable, \ - contains, enum_value + contains, enum_value, for_argument from satella.coding.structures import HashableMixin, ComparableEnum from satella.coding.transforms import jsonify, intify +logger = logging.getLogger(__name__) class TestCase(unittest.TestCase): + def test_cant_compare_me(self): + class Uncomparable: + def __eq__(self, other): + raise TypeError() + + def __str__(self): + return 'test' + + @for_argument(y=str) + def test(y = Uncomparable()): + return y + + b = test() + self.assertEqual(b, 'test') + def test_contains(self): class CEnum(ComparableEnum): A = 1