1 |
commit: 40dcb32287d8bdaca28bd0597e2a66d85e3d3ac1 |
2 |
Author: Michał Górny <mgorny <AT> gentoo <DOT> org> |
3 |
AuthorDate: Fri May 29 14:09:26 2020 +0000 |
4 |
Commit: Michał Górny <mgorny <AT> gentoo <DOT> org> |
5 |
CommitDate: Sat May 30 07:40:17 2020 +0000 |
6 |
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=40dcb322 |
7 |
|
8 |
dev-python/wrapt: Port to py39 |
9 |
|
10 |
Signed-off-by: Michał Górny <mgorny <AT> gentoo.org> |
11 |
|
12 |
dev-python/wrapt/files/wrapt-1.12.1-py39.patch | 182 +++++++++++++++++++++++++ |
13 |
dev-python/wrapt/wrapt-1.12.1.ebuild | 6 +- |
14 |
2 files changed, 187 insertions(+), 1 deletion(-) |
15 |
|
16 |
diff --git a/dev-python/wrapt/files/wrapt-1.12.1-py39.patch b/dev-python/wrapt/files/wrapt-1.12.1-py39.patch |
17 |
new file mode 100644 |
18 |
index 00000000000..c3e85e09b66 |
19 |
--- /dev/null |
20 |
+++ b/dev-python/wrapt/files/wrapt-1.12.1-py39.patch |
21 |
@@ -0,0 +1,182 @@ |
22 |
+From 33708e76578c173333d1879a4a21baddf8fcdb6a Mon Sep 17 00:00:00 2001 |
23 |
+From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= <mgorny@g.o> |
24 |
+Date: Fri, 29 May 2020 16:06:07 +0200 |
25 |
+Subject: [PATCH] Update for fixed outer @classmethod behavior in Python 3.9 |
26 |
+ |
27 |
+Fixes #160 |
28 |
+--- |
29 |
+ docs/decorators.rst | 18 ++++++------- |
30 |
+ tests/test_outer_classmethod.py | 45 +++++++++++++++++++++------------ |
31 |
+ tests/test_synchronized_lock.py | 22 ++++++++-------- |
32 |
+ 3 files changed, 49 insertions(+), 36 deletions(-) |
33 |
+ |
34 |
+diff --git a/docs/decorators.rst b/docs/decorators.rst |
35 |
+index b8200d6..94201de 100644 |
36 |
+--- a/docs/decorators.rst |
37 |
++++ b/docs/decorators.rst |
38 |
+@@ -641,15 +641,15 @@ When calling the wrapped function in the decorator wrapper function, the |
39 |
+ instance is already bound to ``wrapped`` and will be passed automatically |
40 |
+ as the first argument to the original wrapped function. |
41 |
+ |
42 |
+-Note that due to a bug in Python ``classmethod.__get__()``, whereby it does |
43 |
+-not apply the descriptor protocol to the function wrapped by ``@classmethod``, |
44 |
+-the above only applies where the decorator wraps the ``@classmethod`` |
45 |
+-decorator. If the decorator is placed inside of the ``@classmethod`` |
46 |
+-decorator, then ``instance`` will be ``None`` and the decorator wrapper |
47 |
+-function will see the call as being the same as a normal function. As a |
48 |
+-result, always place any decorator outside of the ``@classmethod`` |
49 |
+-decorator. Hopefully this issue in Python can be addressed in a future |
50 |
+-Python version. |
51 |
++Note that due to a bug in Python prior to 3.9 ``classmethod.__get__()``, |
52 |
++whereby it does not apply the descriptor protocol to the function |
53 |
++wrapped by ``@classmethod``, the above only applies where the decorator |
54 |
++wraps the ``@classmethod`` decorator. If the decorator is placed inside |
55 |
++of the ``@classmethod`` decorator, then ``instance`` will be ``None`` |
56 |
++and the decorator wrapper function will see the call as being the same |
57 |
++as a normal function. As a result, always place any decorator outside of |
58 |
++the ``@classmethod`` decorator if you need to support earlier Python |
59 |
++versions. |
60 |
+ |
61 |
+ Decorating Static Methods |
62 |
+ ------------------------- |
63 |
+diff --git a/tests/test_outer_classmethod.py b/tests/test_outer_classmethod.py |
64 |
+index 6b4af4f..9c2fcb8 100644 |
65 |
+--- a/tests/test_outer_classmethod.py |
66 |
++++ b/tests/test_outer_classmethod.py |
67 |
+@@ -3,6 +3,7 @@ from __future__ import print_function |
68 |
+ import unittest |
69 |
+ import inspect |
70 |
+ import imp |
71 |
++import sys |
72 |
+ |
73 |
+ import wrapt |
74 |
+ |
75 |
+@@ -121,20 +122,26 @@ class TestNamingOuterClassMethod(unittest.TestCase): |
76 |
+ class TestCallingOuterClassMethod(unittest.TestCase): |
77 |
+ |
78 |
+ def test_class_call_function(self): |
79 |
+- # Test calling classmethod. The instance and class passed to the |
80 |
+- # wrapper will both be None because our decorator is surrounded |
81 |
+- # by the classmethod decorator. The classmethod decorator |
82 |
+- # doesn't bind the method and treats it like a normal function, |
83 |
+- # explicitly passing the class as the first argument with the |
84 |
+- # actual arguments following that. |
85 |
++ # Test calling classmethod. In Python 3.9, the class will be |
86 |
++ # passed as instance. In older versions of Python, the instance |
87 |
++ # and class passed to the wrapper will both be None because our |
88 |
++ # decorator is surrounded by the classmethod decorator. |
89 |
++ # The classmethod decorator doesn't bind the method and treats |
90 |
++ # it like a normal function, explicitly passing the class |
91 |
++ # as the first argument with the actual arguments following |
92 |
++ # that. |
93 |
+ |
94 |
+ _args = (1, 2) |
95 |
+ _kwargs = {'one': 1, 'two': 2} |
96 |
+ |
97 |
+ @wrapt.decorator |
98 |
+ def _decorator(wrapped, instance, args, kwargs): |
99 |
+- self.assertEqual(instance, None) |
100 |
+- self.assertEqual(args, (Class,)+_args) |
101 |
++ if sys.hexversion >= 0x03090000: |
102 |
++ self.assertEqual(instance, Class) |
103 |
++ self.assertEqual(args, _args) |
104 |
++ else: |
105 |
++ self.assertEqual(instance, None) |
106 |
++ self.assertEqual(args, (Class,)+_args) |
107 |
+ self.assertEqual(kwargs, _kwargs) |
108 |
+ self.assertEqual(wrapped.__module__, _function.__module__) |
109 |
+ self.assertEqual(wrapped.__name__, _function.__name__) |
110 |
+@@ -155,20 +162,26 @@ class TestCallingOuterClassMethod(unittest.TestCase): |
111 |
+ self.assertEqual(result, (_args, _kwargs)) |
112 |
+ |
113 |
+ def test_instance_call_function(self): |
114 |
+- # Test calling classmethod via class instance. The instance |
115 |
+- # and class passed to the wrapper will both be None because our |
116 |
+- # decorator is surrounded by the classmethod decorator. The |
117 |
+- # classmethod decorator doesn't bind the method and treats it |
118 |
+- # like a normal function, explicitly passing the class as the |
119 |
+- # first argument with the actual arguments following that. |
120 |
++ # Test calling classmethod via class instance. In Python 3.9, |
121 |
++ # the class will be passed as instance. In older versions |
122 |
++ # of Python, the instance and class passed to the wrapper will |
123 |
++ # both be None because our decorator is surrounded |
124 |
++ # by the classmethod decorator. The classmethod decorator |
125 |
++ # doesn't bind the method and treats it like a normal function, |
126 |
++ # explicitly passing the class as the first argument with |
127 |
++ # the actual arguments following that. |
128 |
+ |
129 |
+ _args = (1, 2) |
130 |
+ _kwargs = {'one': 1, 'two': 2} |
131 |
+ |
132 |
+ @wrapt.decorator |
133 |
+ def _decorator(wrapped, instance, args, kwargs): |
134 |
+- self.assertEqual(instance, None) |
135 |
+- self.assertEqual(args, (Class,)+_args) |
136 |
++ if sys.hexversion >= 0x03090000: |
137 |
++ self.assertEqual(instance, Class) |
138 |
++ self.assertEqual(args, _args) |
139 |
++ else: |
140 |
++ self.assertEqual(instance, None) |
141 |
++ self.assertEqual(args, (Class,)+_args) |
142 |
+ self.assertEqual(kwargs, _kwargs) |
143 |
+ self.assertEqual(wrapped.__module__, _function.__module__) |
144 |
+ self.assertEqual(wrapped.__name__, _function.__name__) |
145 |
+diff --git a/tests/test_synchronized_lock.py b/tests/test_synchronized_lock.py |
146 |
+index 6e7eb12..b8f60f3 100644 |
147 |
+--- a/tests/test_synchronized_lock.py |
148 |
++++ b/tests/test_synchronized_lock.py |
149 |
+@@ -1,5 +1,6 @@ |
150 |
+ from __future__ import print_function |
151 |
+ |
152 |
++import sys |
153 |
+ import unittest |
154 |
+ |
155 |
+ import wrapt |
156 |
+@@ -157,34 +158,33 @@ class TestSynchronized(unittest.TestCase): |
157 |
+ self.assertEqual(_lock3, _lock2) |
158 |
+ |
159 |
+ def test_synchronized_outer_classmethod(self): |
160 |
+- # XXX If all was good, this would be detected as a class |
161 |
++ # Bug in Python < 3.9: |
162 |
++ # If all was good, this would be detected as a class |
163 |
+ # method call, but the classmethod decorator doesn't bind |
164 |
+ # the wrapped function to the class before calling and |
165 |
+ # just calls it direct, explicitly passing the class as |
166 |
+- # first argument. This screws things up. Would be nice if |
167 |
+- # Python were fixed, but that isn't likely to happen. |
168 |
++ # first argument. This screws things up. |
169 |
+ |
170 |
+- #_lock0 = getattr(C4, '_synchronized_lock', None) |
171 |
+- _lock0 = getattr(C4.function2, '_synchronized_lock', None) |
172 |
++ lock_target = (C4 if sys.hexversion >= 0x03090000 |
173 |
++ else C4.function2) |
174 |
++ |
175 |
++ _lock0 = getattr(lock_target, '_synchronized_lock', None) |
176 |
+ self.assertEqual(_lock0, None) |
177 |
+ |
178 |
+ c4.function2() |
179 |
+ |
180 |
+- #_lock1 = getattr(C4, '_synchronized_lock', None) |
181 |
+- _lock1 = getattr(C4.function2, '_synchronized_lock', None) |
182 |
++ _lock1 = getattr(lock_target, '_synchronized_lock', None) |
183 |
+ self.assertNotEqual(_lock1, None) |
184 |
+ |
185 |
+ C4.function2() |
186 |
+ |
187 |
+- #_lock2 = getattr(C4, '_synchronized_lock', None) |
188 |
+- _lock2 = getattr(C4.function2, '_synchronized_lock', None) |
189 |
++ _lock2 = getattr(lock_target, '_synchronized_lock', None) |
190 |
+ self.assertNotEqual(_lock2, None) |
191 |
+ self.assertEqual(_lock2, _lock1) |
192 |
+ |
193 |
+ C4.function2() |
194 |
+ |
195 |
+- #_lock3 = getattr(C4, '_synchronized_lock', None) |
196 |
+- _lock3 = getattr(C4.function2, '_synchronized_lock', None) |
197 |
++ _lock3 = getattr(lock_target, '_synchronized_lock', None) |
198 |
+ self.assertNotEqual(_lock3, None) |
199 |
+ self.assertEqual(_lock3, _lock2) |
200 |
+ |
201 |
+-- |
202 |
+2.26.2 |
203 |
+ |
204 |
|
205 |
diff --git a/dev-python/wrapt/wrapt-1.12.1.ebuild b/dev-python/wrapt/wrapt-1.12.1.ebuild |
206 |
index 6634d9007d7..24fccc88aaf 100644 |
207 |
--- a/dev-python/wrapt/wrapt-1.12.1.ebuild |
208 |
+++ b/dev-python/wrapt/wrapt-1.12.1.ebuild |
209 |
@@ -4,7 +4,7 @@ |
210 |
EAPI=7 |
211 |
|
212 |
DISTUTILS_USE_SETUPTOOLS=no |
213 |
-PYTHON_COMPAT=( python3_{6,7,8} pypy3 ) |
214 |
+PYTHON_COMPAT=( python3_{6,7,8,9} pypy3 ) |
215 |
|
216 |
inherit distutils-r1 |
217 |
|
218 |
@@ -19,6 +19,10 @@ KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~ia64 ~ppc ~ppc64 ~s390 ~sparc ~x86 ~amd64-l |
219 |
distutils_enable_tests pytest |
220 |
distutils_enable_sphinx docs dev-python/sphinx_rtd_theme |
221 |
|
222 |
+PATCHES=( |
223 |
+ "${FILESDIR}"/${P}-py39.patch |
224 |
+) |
225 |
+ |
226 |
python_compile() { |
227 |
local WRAPT_EXTENSIONS=true |