diff --git a/1.15.0.tar.gz b/1.15.0.tar.gz deleted file mode 100644 index 426171b..0000000 --- a/1.15.0.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:09491f2d38754d96544c77ecf7ce205f0986dd61398642c24810302f341fd485 -size 137402 diff --git a/1.16.0.tar.gz b/1.16.0.tar.gz new file mode 100644 index 0000000..d0bbf80 --- /dev/null +++ b/1.16.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:107dc12b9d60100b7219169dad7687986407dc7bade3ef965b20fe82e1c3a6dc +size 138520 diff --git a/py313-classmethods.patch b/py313-classmethods.patch new file mode 100644 index 0000000..741db65 --- /dev/null +++ b/py313-classmethods.patch @@ -0,0 +1,262 @@ +From 9a38c9f45a2e9d2a306deedce2e243b5e7a83ab2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= +Date: Fri, 8 Mar 2024 00:40:11 +0100 +Subject: [PATCH] Fix classmethod tests with Python 3.13+ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes https://github.com/GrahamDumpleton/wrapt/issues/259 + +The failures were: + + =================================== FAILURES =================================== + _____________ TestCallingOuterClassMethod.test_class_call_function _____________ + + self = + + 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 != + ___________ TestCallingOuterClassMethod.test_instance_call_function ____________ + + self = + + 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 != + _____________ TestSynchronized.test_synchronized_outer_classmethod _____________ + + self = + + 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 +https://github.com/GrahamDumpleton/wrapt/issues/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 +--- + tests/test_outer_classmethod.py | 18 ++++++++++-------- + tests/test_synchronized_lock.py | 26 ++++++++++++++------------ + 2 files changed, 24 insertions(+), 20 deletions(-) + +diff --git a/tests/test_outer_classmethod.py b/tests/test_outer_classmethod.py +index ab807646..c08d34a5 100644 +--- a/tests/test_outer_classmethod.py ++++ b/tests/test_outer_classmethod.py +@@ -128,18 +128,20 @@ def test_class_call_function(self): + # 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 ++ # Starting with Python 3.13 the old behavior is back. ++ # For more details see https://github.com/python/cpython/issues/89519 + + _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: ++ if (3, 9) <= PYXY < (3, 13): + self.assertEqual(instance, Class) + self.assertEqual(args, _args) ++ else: ++ self.assertEqual(instance, None) ++ self.assertEqual(args, (Class,)+_args) + + self.assertEqual(kwargs, _kwargs) + self.assertEqual(wrapped.__module__, _function.__module__) +@@ -176,12 +178,12 @@ def test_instance_call_function(self): + + @wrapt.decorator + def _decorator(wrapped, instance, args, kwargs): +- if PYXY < (3, 9): +- self.assertEqual(instance, None) +- self.assertEqual(args, (Class,)+_args) +- else: ++ if (3, 9) <= PYXY < (3, 13): + self.assertEqual(instance, Class) + self.assertEqual(args, _args) ++ else: ++ self.assertEqual(instance, None) ++ self.assertEqual(args, (Class,)+_args) + + self.assertEqual(kwargs, _kwargs) + self.assertEqual(wrapped.__module__, _function.__module__) +diff --git a/tests/test_synchronized_lock.py b/tests/test_synchronized_lock.py +index 0e43f7af..7c41aa5a 100644 +--- a/tests/test_synchronized_lock.py ++++ b/tests/test_synchronized_lock.py +@@ -165,36 +165,38 @@ def test_synchronized_outer_classmethod(self): + # 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 ++ # Starting with Python 3.13 the old behavior is back. ++ # For more details see https://github.com/python/cpython/issues/89519 + +- if PYXY < (3, 9): +- _lock0 = getattr(C4.function2, '_synchronized_lock', None) +- else: ++ if (3, 9) <= PYXY < (3, 13): + _lock0 = getattr(C4, '_synchronized_lock', None) ++ else: ++ _lock0 = getattr(C4.function2, '_synchronized_lock', None) + self.assertEqual(_lock0, None) + + c4.function2() + +- if PYXY < (3, 9): +- _lock1 = getattr(C4.function2, '_synchronized_lock', None) +- else: ++ if (3, 9) <= PYXY < (3, 13): + _lock1 = getattr(C4, '_synchronized_lock', None) ++ else: ++ _lock1 = getattr(C4.function2, '_synchronized_lock', None) + self.assertNotEqual(_lock1, None) + + C4.function2() + +- if PYXY < (3, 9): +- _lock2 = getattr(C4.function2, '_synchronized_lock', None) +- else: ++ if (3, 9) <= PYXY < (3, 13): + _lock2 = getattr(C4, '_synchronized_lock', None) ++ else: ++ _lock2 = getattr(C4.function2, '_synchronized_lock', None) + self.assertNotEqual(_lock2, None) + self.assertEqual(_lock2, _lock1) + + C4.function2() + +- if PYXY < (3, 9): +- _lock3 = getattr(C4.function2, '_synchronized_lock', None) +- else: ++ if (3, 9) <= PYXY < (3, 13): + _lock3 = getattr(C4, '_synchronized_lock', None) ++ else: ++ _lock3 = getattr(C4.function2, '_synchronized_lock', None) + self.assertNotEqual(_lock3, None) + self.assertEqual(_lock3, _lock2) + diff --git a/python-wrapt.changes b/python-wrapt.changes index 41bbbcc..5547bfd 100644 --- a/python-wrapt.changes +++ b/python-wrapt.changes @@ -1,3 +1,36 @@ +------------------------------------------------------------------- +Mon Oct 28 11:56:13 UTC 2024 - Dirk Müller + +- add py313-classmethods.patch to fix test failures with py313 + +------------------------------------------------------------------- +Mon Nov 27 20:31:38 UTC 2023 - Dirk Müller + +- update to 1.16.0: + * Note that version 1.16.0 drops support for Python 2.7 and + 3.5. Python version 3.6 or later is required. + * The ``patch_function_wrapper()`` decorator now accepts an + ``enabled`` argument, which can be a literal boolean value, + object that evaluates as boolean, or a callable object which + returns a boolean. In the case of a callable, determination + of whether the wrapper is invoked will be left until + the point of the call. In the other cases, the wrapper will + not be applied if the value evaluates false at the point of + applying the wrapper. + * The import hook loader and finder objects are now implemented + as transparent object proxies so they properly proxy pass + access to attributes/functions of the wrapped loader or finder. + * Code files in the implementation have been reorganized such + that the pure Python version of the ``ObjectProxy`` class + is directly available even if the C extension variant is + being used. This is to allow the pure Python variant to + be used in exceptional cases where the C extension variant is + not fully compatible with the pure Python implementation and the + behaviour of the pure Python variant is what is required. + * It was not possible to update the ``__class__`` attribute + through the transparent object proxy when relying on the C + implementation. + ------------------------------------------------------------------- Thu May 4 20:43:27 UTC 2023 - Dirk Müller @@ -61,7 +94,7 @@ Sat Nov 6 18:18:03 UTC 2021 - Dirk Müller - update to 1.13.3: * Adds wheels for Python 3.10 on PyPi and where possible also now - generating binary wheels for ``musllinux``. + generating binary wheels for ``musllinux``. ------------------------------------------------------------------- Tue Oct 26 21:13:04 UTC 2021 - Dirk Müller @@ -139,7 +172,7 @@ Mon Mar 9 16:25:43 UTC 2020 - Dirk Mueller class, if the class declared special methods to override the result for when the class instance was tested as a boolean so that it returned ``False`` all the time, the synchronized method would fail when called. - * When using an adapter function to change the signature of the decorated + * When using an adapter function to change the signature of the decorated function, ``inspect.signature()`` was returning the wrong signature when an instance method was inspected by accessing the method via the class type. @@ -164,7 +197,7 @@ Sun Jul 9 10:26:29 UTC 2017 - adrian@suse.de - update to version 1.10.10: * Added back missing description and categorisations when releasing to PyPi. - * Code for inspect.getargspec() when using Python 2.6 was missing + * Code for inspect.getargspec() when using Python 2.6 was missing import of sys module. ------------------------------------------------------------------- diff --git a/python-wrapt.spec b/python-wrapt.spec index 380ddb7..06bffee 100644 --- a/python-wrapt.spec +++ b/python-wrapt.spec @@ -1,7 +1,7 @@ # # spec file for package python-wrapt # -# Copyright (c) 2023 SUSE LLC +# Copyright (c) 2024 SUSE LLC # Copyright (c) 2015 LISA GmbH, Bingen, Germany. # # All modifications and additions to the file contributed by third parties @@ -17,16 +17,16 @@ # -%{?!python_module:%define python_module() python-%{**} python3-%{**}} %{?sle15_python_module_pythons} Name: python-wrapt -Version: 1.15.0 +Version: 1.16.0 Release: 0 Summary: A Python module for decorators, wrappers and monkey patching License: BSD-2-Clause Group: Development/Languages/Python URL: https://github.com/GrahamDumpleton/wrapt Source: https://github.com/GrahamDumpleton/wrapt/archive/%{version}.tar.gz +Patch1: https://github.com/GrahamDumpleton/wrapt/commit/9a38c9f45a2e9d2a306deedce2e243b5e7a83ab2.patch#/py313-classmethods.patch BuildRequires: %{python_module devel} BuildRequires: %{python_module pytest} BuildRequires: %{python_module setuptools}