-
Notifications
You must be signed in to change notification settings - Fork 235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tests fail with Python 3.9 #160
Comments
Both tests seem to relate to what has been a long standing bug in Python that I reported many many years ago related to the |
I guess that's you ;-). |
First reported in 2013. Patch was even provided. But as a non Python core contributor who knew nothing about what was required to submit patches to core, the response I got was very off putting. Never wanted to get involved with Python core work after that. |
Yeah, from what I've seen a lot of very old patches have suddenly made it to 3.9, when their authors haven't looked at them in years (and might have not agreed with the final solution after all). |
Does this mean that the test failure is safe to ignore? |
I don't know. It was late at night when you reported it. I need to make time to look properly at it. |
Well, the way I read https://wrapt.readthedocs.io/en/latest/decorators.html#decorating-class-methods it says that it might be fixed one day and that users shouldn't do this. I'm going to make a PR with the assumption that Py3.9 behavior is correct. |
Sorry, clicked the wrong button. |
@GrahamDumpleton @mgorny Bumping this to inject when the issue was marked resolved: python/cpython#8405 |
These tests are fixed up with version 1.13.0 of wrapt. |
Fixes GrahamDumpleton#259 The failures were: =================================== FAILURES =================================== _____________ TestCallingOuterClassMethod.test_class_call_function _____________ self = <test_outer_classmethod.TestCallingOuterClassMethod testMethod=test_class_call_function> def test_class_call_function(self): # Test calling classmethod. Prior to Python 3.9, the instance # and class passed to the wrapper will both be None because our # decorator is surrounded by the classmethod decorator. The # classmethod decorator doesn't bind the method and treats it # like a normal function, explicitly passing the class as the # first argument with the actual arguments following that. This # was only finally fixed in Python 3.9. For more details see: # https://bugs.python.org/issue19072 _args = (1, 2) _kwargs = {'one': 1, 'two': 2} @wrapt.decorator def _decorator(wrapped, instance, args, kwargs): if PYXY < (3, 9): self.assertEqual(instance, None) self.assertEqual(args, (Class,)+_args) else: self.assertEqual(instance, Class) self.assertEqual(args, _args) self.assertEqual(kwargs, _kwargs) self.assertEqual(wrapped.__module__, _function.__module__) self.assertEqual(wrapped.__name__, _function.__name__) return wrapped(*args, **kwargs) @_decorator def _function(*args, **kwargs): return args, kwargs class Class(object): @classmethod @_decorator def _function(cls, *args, **kwargs): return (args, kwargs) > result = Class._function(*_args, **_kwargs) tests/test_outer_classmethod.py:160: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tests/test_outer_classmethod.py:141: in _decorator self.assertEqual(instance, Class) E AssertionError: None != <class 'test_outer_classmethod.TestCallin[54 chars]ass'> ___________ TestCallingOuterClassMethod.test_instance_call_function ____________ self = <test_outer_classmethod.TestCallingOuterClassMethod testMethod=test_instance_call_function> def test_instance_call_function(self): # Test calling classmethod via class instance. Prior to Python # 3.9, the instance and class passed to the wrapper will both be # None because our decorator is surrounded by the classmethod # decorator. The classmethod decorator doesn't bind the method # and treats it like a normal function, explicitly passing the # class as the first argument with the actual arguments # following that. This was only finally fixed in Python 3.9. For # more details see: https://bugs.python.org/issue19072 _args = (1, 2) _kwargs = {'one': 1, 'two': 2} @wrapt.decorator def _decorator(wrapped, instance, args, kwargs): if PYXY < (3, 9): self.assertEqual(instance, None) self.assertEqual(args, (Class,)+_args) else: self.assertEqual(instance, Class) self.assertEqual(args, _args) self.assertEqual(kwargs, _kwargs) self.assertEqual(wrapped.__module__, _function.__module__) self.assertEqual(wrapped.__name__, _function.__name__) return wrapped(*args, **kwargs) @_decorator def _function(*args, **kwargs): return args, kwargs class Class(object): @classmethod @_decorator def _function(cls, *args, **kwargs): return (args, kwargs) > result = Class()._function(*_args, **_kwargs) tests/test_outer_classmethod.py:202: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tests/test_outer_classmethod.py:183: in _decorator self.assertEqual(instance, Class) E AssertionError: None != <class 'test_outer_classmethod.TestCallin[57 chars]ass'> _____________ TestSynchronized.test_synchronized_outer_classmethod _____________ self = <test_synchronized_lock.TestSynchronized testMethod=test_synchronized_outer_classmethod> def test_synchronized_outer_classmethod(self): # Prior to Python 3.9 this isn't detected as a class method # call, as the classmethod decorator doesn't bind the wrapped # function to the class before calling and just calls it direct, # explicitly passing the class as first argument. For more # details see: https://bugs.python.org/issue19072 if PYXY < (3, 9): _lock0 = getattr(C4.function2, '_synchronized_lock', None) else: _lock0 = getattr(C4, '_synchronized_lock', None) self.assertEqual(_lock0, None) c4.function2() if PYXY < (3, 9): _lock1 = getattr(C4.function2, '_synchronized_lock', None) else: _lock1 = getattr(C4, '_synchronized_lock', None) > self.assertNotEqual(_lock1, None) E AssertionError: None == None tests/test_synchronized_lock.py:181: AssertionError ----------------------------- Captured stdout call ----------------------------- function2 =========================== short test summary info ============================ FAILED tests/test_outer_classmethod.py::TestCallingOuterClassMethod::test_class_call_function FAILED tests/test_outer_classmethod.py::TestCallingOuterClassMethod::test_instance_call_function FAILED tests/test_synchronized_lock.py::TestSynchronized::test_synchronized_outer_classmethod ======================== 3 failed, 435 passed in 0.83s ========================= To fix the same failures on Python 3.9, they were adjusted in the past. For details see GrahamDumpleton#160 However, Python 3.13 reverted the change from 3.9, so this adds an upper bound for the conditionals. To make the conditionals easier to read, the if-else branches were switched.
Fixes GrahamDumpleton#259 The failures were: =================================== FAILURES =================================== _____________ TestCallingOuterClassMethod.test_class_call_function _____________ self = <test_outer_classmethod.TestCallingOuterClassMethod testMethod=test_class_call_function> def test_class_call_function(self): # Test calling classmethod. Prior to Python 3.9, the instance # and class passed to the wrapper will both be None because our # decorator is surrounded by the classmethod decorator. The # classmethod decorator doesn't bind the method and treats it # like a normal function, explicitly passing the class as the # first argument with the actual arguments following that. This # was only finally fixed in Python 3.9. For more details see: # https://bugs.python.org/issue19072 _args = (1, 2) _kwargs = {'one': 1, 'two': 2} @wrapt.decorator def _decorator(wrapped, instance, args, kwargs): if PYXY < (3, 9): self.assertEqual(instance, None) self.assertEqual(args, (Class,)+_args) else: self.assertEqual(instance, Class) self.assertEqual(args, _args) self.assertEqual(kwargs, _kwargs) self.assertEqual(wrapped.__module__, _function.__module__) self.assertEqual(wrapped.__name__, _function.__name__) return wrapped(*args, **kwargs) @_decorator def _function(*args, **kwargs): return args, kwargs class Class(object): @classmethod @_decorator def _function(cls, *args, **kwargs): return (args, kwargs) > result = Class._function(*_args, **_kwargs) tests/test_outer_classmethod.py:160: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tests/test_outer_classmethod.py:141: in _decorator self.assertEqual(instance, Class) E AssertionError: None != <class 'test_outer_classmethod.TestCallin[54 chars]ass'> ___________ TestCallingOuterClassMethod.test_instance_call_function ____________ self = <test_outer_classmethod.TestCallingOuterClassMethod testMethod=test_instance_call_function> def test_instance_call_function(self): # Test calling classmethod via class instance. Prior to Python # 3.9, the instance and class passed to the wrapper will both be # None because our decorator is surrounded by the classmethod # decorator. The classmethod decorator doesn't bind the method # and treats it like a normal function, explicitly passing the # class as the first argument with the actual arguments # following that. This was only finally fixed in Python 3.9. For # more details see: https://bugs.python.org/issue19072 _args = (1, 2) _kwargs = {'one': 1, 'two': 2} @wrapt.decorator def _decorator(wrapped, instance, args, kwargs): if PYXY < (3, 9): self.assertEqual(instance, None) self.assertEqual(args, (Class,)+_args) else: self.assertEqual(instance, Class) self.assertEqual(args, _args) self.assertEqual(kwargs, _kwargs) self.assertEqual(wrapped.__module__, _function.__module__) self.assertEqual(wrapped.__name__, _function.__name__) return wrapped(*args, **kwargs) @_decorator def _function(*args, **kwargs): return args, kwargs class Class(object): @classmethod @_decorator def _function(cls, *args, **kwargs): return (args, kwargs) > result = Class()._function(*_args, **_kwargs) tests/test_outer_classmethod.py:202: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tests/test_outer_classmethod.py:183: in _decorator self.assertEqual(instance, Class) E AssertionError: None != <class 'test_outer_classmethod.TestCallin[57 chars]ass'> _____________ TestSynchronized.test_synchronized_outer_classmethod _____________ self = <test_synchronized_lock.TestSynchronized testMethod=test_synchronized_outer_classmethod> def test_synchronized_outer_classmethod(self): # Prior to Python 3.9 this isn't detected as a class method # call, as the classmethod decorator doesn't bind the wrapped # function to the class before calling and just calls it direct, # explicitly passing the class as first argument. For more # details see: https://bugs.python.org/issue19072 if PYXY < (3, 9): _lock0 = getattr(C4.function2, '_synchronized_lock', None) else: _lock0 = getattr(C4, '_synchronized_lock', None) self.assertEqual(_lock0, None) c4.function2() if PYXY < (3, 9): _lock1 = getattr(C4.function2, '_synchronized_lock', None) else: _lock1 = getattr(C4, '_synchronized_lock', None) > self.assertNotEqual(_lock1, None) E AssertionError: None == None tests/test_synchronized_lock.py:181: AssertionError ----------------------------- Captured stdout call ----------------------------- function2 =========================== short test summary info ============================ FAILED tests/test_outer_classmethod.py::TestCallingOuterClassMethod::test_class_call_function FAILED tests/test_outer_classmethod.py::TestCallingOuterClassMethod::test_instance_call_function FAILED tests/test_synchronized_lock.py::TestSynchronized::test_synchronized_outer_classmethod ======================== 3 failed, 435 passed in 0.83s ========================= To fix the same failures on Python 3.9, they were adjusted in the past. For details see GrahamDumpleton#160 However, Python 3.13 reverted the change from 3.9, so this adds an upper bound for the conditionals. To make the conditionals easier to read, the if-else branches were switched. Signed-off-by: Filipe Laíns <[email protected]>
This is via running
tox -e py39
on git master, with Python 3.9.0b1.Full log: py39.log
The text was updated successfully, but these errors were encountered: