| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -292,6 +292,12 @@ Porting to Python 3.14 | |||
| 292 | 292 | This section lists previously described changes and other bugfixes | |
| 293 | 293 | that may require changes to your code. | |
| 294 | 294 | ||
| 295 | + Changes in the Python API | ||
| 296 | + ------------------------- | ||
| 297 | + | ||
| 298 | + * :class:`functools.partial` is now a method descriptor. | ||
| 299 | + Wrap it in :func:`staticmethod` if you want to preserve the old behavior. | ||
| 300 | + (Contributed by Serhiy Storchaka and D. Grigonis in :gh:`121027`.) | ||
| 295 | 301 | ||
| 296 | 302 | Build Changes | |
| 297 | 303 | ============= | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,6 +18,7 @@ | |||
| 18 | 18 | from collections import namedtuple | |
| 19 | 19 | # import types, weakref # Deferred to single_dispatch() | |
| 20 | 20 | from reprlib import recursive_repr | |
| 21 | + from types import MethodType | ||
| 21 | 22 | from _thread import RLock | |
| 22 | 23 | ||
| 23 | 24 | # Avoid importing types, so we can speedup import time | |
@@ -314,12 +315,7 @@ def __repr__(self): | |||
| 314 | 315 | def __get__(self, obj, objtype=None): | |
| 315 | 316 | if obj is None: | |
| 316 | 317 | return self | |
| 317 | - import warnings | ||
| 318 | - warnings.warn('functools.partial will be a method descriptor in ' | ||
| 319 | - 'future Python versions; wrap it in staticmethod() ' | ||
| 320 | - 'if you want to preserve the old behavior', | ||
| 321 | - FutureWarning, 2) | ||
| 322 | - return self | ||
| 318 | + return MethodType(self, obj) | ||
| 323 | 319 | ||
| 324 | 320 | def __reduce__(self): | |
| 325 | 321 | return type(self), (self.func,), (self.func, self.args, | |
@@ -402,7 +398,7 @@ def _method(cls_or_self, /, *args, **keywords): | |||
| 402 | 398 | def __get__(self, obj, cls=None): | |
| 403 | 399 | get = getattr(self.func, "__get__", None) | |
| 404 | 400 | result = None | |
| 405 | - if get is not None and not isinstance(self.func, partial): | ||
| 401 | + if get is not None: | ||
| 406 | 402 | new_func = get(obj, cls) | |
| 407 | 403 | if new_func is not self.func: | |
| 408 | 404 | # Assume __get__ returning something new indicates the | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -405,9 +405,7 @@ class A: | |||
| 405 | 405 | self.assertEqual(A.meth(3, b=4), ((1, 3), {'a': 2, 'b': 4})) | |
| 406 | 406 | self.assertEqual(A.cmeth(3, b=4), ((1, A, 3), {'a': 2, 'b': 4})) | |
| 407 | 407 | self.assertEqual(A.smeth(3, b=4), ((1, 3), {'a': 2, 'b': 4})) | |
| 408 | - with self.assertWarns(FutureWarning) as w: | ||
| 409 | - self.assertEqual(a.meth(3, b=4), ((1, 3), {'a': 2, 'b': 4})) | ||
| 410 | - self.assertEqual(w.filename, __file__) | ||
| 408 | + self.assertEqual(a.meth(3, b=4), ((1, a, 3), {'a': 2, 'b': 4})) | ||
| 411 | 409 | self.assertEqual(a.cmeth(3, b=4), ((1, A, 3), {'a': 2, 'b': 4})) | |
| 412 | 410 | self.assertEqual(a.smeth(3, b=4), ((1, 3), {'a': 2, 'b': 4})) | |
| 413 | 411 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3868,17 +3868,15 @@ def __init__(self, b): | |||
| 3868 | 3868 | ||
| 3869 | 3869 | with self.subTest('partial'): | |
| 3870 | 3870 | class CM(type): | |
| 3871 | - __call__ = functools.partial(lambda x, a: (x, a), 2) | ||
| 3871 | + __call__ = functools.partial(lambda x, a, b: (x, a, b), 2) | ||
| 3872 | 3872 | class C(metaclass=CM): | |
| 3873 | - def __init__(self, b): | ||
| 3873 | + def __init__(self, c): | ||
| 3874 | 3874 | pass | |
| 3875 | 3875 | ||
| 3876 | - with self.assertWarns(FutureWarning): | ||
| 3877 | - self.assertEqual(C(1), (2, 1)) | ||
| 3878 | - with self.assertWarns(FutureWarning): | ||
| 3879 | - self.assertEqual(self.signature(C), | ||
| 3880 | - ((('a', ..., ..., "positional_or_keyword"),), | ||
| 3881 | - ...)) | ||
| 3876 | + self.assertEqual(C(1), (2, C, 1)) | ||
| 3877 | + self.assertEqual(self.signature(C), | ||
| 3878 | + ((('b', ..., ..., "positional_or_keyword"),), | ||
| 3879 | + ...)) | ||
| 3882 | 3880 | ||
| 3883 | 3881 | with self.subTest('partialmethod'): | |
| 3884 | 3882 | class CM(type): | |
@@ -4024,14 +4022,12 @@ class C: | |||
| 4024 | 4022 | ||
| 4025 | 4023 | with self.subTest('partial'): | |
| 4026 | 4024 | class C: | |
| 4027 | - __init__ = functools.partial(lambda x, a: None, 2) | ||
| 4025 | + __init__ = functools.partial(lambda x, a, b: None, 2) | ||
| 4028 | 4026 | ||
| 4029 | - with self.assertWarns(FutureWarning): | ||
| 4030 | - C(1) # does not raise | ||
| 4031 | - with self.assertWarns(FutureWarning): | ||
| 4032 | - self.assertEqual(self.signature(C), | ||
| 4033 | - ((('a', ..., ..., "positional_or_keyword"),), | ||
| 4034 | - ...)) | ||
| 4027 | + C(1) # does not raise | ||
| 4028 | + self.assertEqual(self.signature(C), | ||
| 4029 | + ((('b', ..., ..., "positional_or_keyword"),), | ||
| 4030 | + ...)) | ||
| 4035 | 4031 | ||
| 4036 | 4032 | with self.subTest('partialmethod'): | |
| 4037 | 4033 | class C: | |
@@ -4284,15 +4280,13 @@ class C: | |||
| 4284 | 4280 | ||
| 4285 | 4281 | with self.subTest('partial'): | |
| 4286 | 4282 | class C: | |
| 4287 | - __call__ = functools.partial(lambda x, a: (x, a), 2) | ||
| 4283 | + __call__ = functools.partial(lambda x, a, b: (x, a, b), 2) | ||
| 4288 | 4284 | ||
| 4289 | 4285 | c = C() | |
| 4290 | - with self.assertWarns(FutureWarning): | ||
| 4291 | - self.assertEqual(c(1), (2, 1)) | ||
| 4292 | - with self.assertWarns(FutureWarning): | ||
| 4293 | - self.assertEqual(self.signature(c), | ||
| 4294 | - ((('a', ..., ..., "positional_or_keyword"),), | ||
| 4295 | - ...)) | ||
| 4286 | + self.assertEqual(c(1), (2, c, 1)) | ||
| 4287 | + self.assertEqual(self.signature(C()), | ||
| 4288 | + ((('b', ..., ..., "positional_or_keyword"),), | ||
| 4289 | + ...)) | ||
| 4296 | 4290 | ||
| 4297 | 4291 | with self.subTest('partialmethod'): | |
| 4298 | 4292 | class C: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1 @@ | |||
| 1 | + Make the :class:`functools.partial` object a method descriptor. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -203,14 +203,7 @@ partial_descr_get(PyObject *self, PyObject *obj, PyObject *type) | |||
| 203 | 203 | if (obj == Py_None || obj == NULL) { | |
| 204 | 204 | return Py_NewRef(self); | |
| 205 | 205 | } | |
| 206 | - if (PyErr_WarnEx(PyExc_FutureWarning, | ||
| 207 | - "functools.partial will be a method descriptor in " | ||
| 208 | - "future Python versions; wrap it in staticmethod() " | ||
| 209 | - "if you want to preserve the old behavior", 1) < 0) | ||
| 210 | - { | ||
| 211 | - return NULL; | ||
| 212 | - } | ||
| 213 | - return Py_NewRef(self); | ||
| 206 | + return PyMethod_New(self, obj); | ||
| 214 | 207 | } | |
| 215 | 208 | ||
| 216 | 209 | /* Merging keyword arguments using the vectorcall convention is messy, so | |
| Back | FazBrowse Home | New Git URL |
0 commit comments