Skip to content

Commit 01ecf18

Browse files
authored
Merge branch 'main' into current-executor
2 parents 46ef280 + 4912b29 commit 01ecf18

File tree

16 files changed

+1287
-761
lines changed

16 files changed

+1287
-761
lines changed

Doc/deprecations/index.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ Deprecations
55

66
.. include:: pending-removal-in-3.16.rst
77

8+
.. include:: pending-removal-in-3.17.rst
9+
810
.. include:: pending-removal-in-future.rst
911

1012
C API deprecations
1113
------------------
1214

1315
.. include:: c-api-pending-removal-in-3.15.rst
1416

17+
.. include:: c-api-pending-removal-in-3.18.rst
18+
1519
.. include:: c-api-pending-removal-in-future.rst

Doc/deprecations/pending-removal-in-3.16.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ Pending removal in Python 3.16
6161
* Calling the Python implementation of :func:`functools.reduce` with *function*
6262
or *sequence* as keyword arguments has been deprecated since Python 3.14.
6363

64+
* :mod:`logging`:
65+
66+
Support for custom logging handlers with the *strm* argument is deprecated
67+
and scheduled for removal in Python 3.16. Define handlers with the *stream*
68+
argument instead. (Contributed by Mariusz Felisiak in :gh:`115032`.)
69+
6470
* :mod:`mimetypes`:
6571

6672
* Valid extensions start with a '.' or are empty for
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Pending removal in Python 3.17
2+
------------------------------
3+
4+
* :mod:`typing`:
5+
6+
- Before Python 3.14, old-style unions were implemented using the private class
7+
``typing._UnionGenericAlias``. This class is no longer needed for the implementation,
8+
but it has been retained for backward compatibility, with removal scheduled for Python
9+
3.17. Users should use documented introspection helpers like :func:`typing.get_origin`
10+
and :func:`typing.get_args` instead of relying on private implementation details.

Doc/whatsnew/3.12.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,8 @@ Deprecated
13471347

13481348
.. include:: ../deprecations/pending-removal-in-3.16.rst
13491349

1350+
.. include:: ../deprecations/pending-removal-in-3.17.rst
1351+
13501352
.. include:: ../deprecations/pending-removal-in-future.rst
13511353

13521354
.. _whatsnew312-removed:

Doc/whatsnew/3.13.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,6 +2009,8 @@ New Deprecations
20092009

20102010
.. include:: ../deprecations/pending-removal-in-3.16.rst
20112011

2012+
.. include:: ../deprecations/pending-removal-in-3.17.rst
2013+
20122014
.. include:: ../deprecations/pending-removal-in-future.rst
20132015

20142016
CPython Bytecode Changes
@@ -2529,6 +2531,8 @@ Deprecated C APIs
25292531

25302532
.. include:: ../deprecations/c-api-pending-removal-in-3.15.rst
25312533

2534+
.. include:: ../deprecations/c-api-pending-removal-in-3.18.rst
2535+
25322536
.. include:: ../deprecations/c-api-pending-removal-in-future.rst
25332537

25342538
.. _pythoncapi-compat project: https://github.com/python/pythoncapi-compat/

Doc/whatsnew/3.14.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,6 +1737,8 @@ Deprecated
17371737

17381738
.. include:: ../deprecations/pending-removal-in-3.16.rst
17391739

1740+
.. include:: ../deprecations/pending-removal-in-3.17.rst
1741+
17401742
.. include:: ../deprecations/pending-removal-in-future.rst
17411743

17421744
Removed

Grammar/python.gram

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,15 +233,17 @@ import_from_targets[asdl_alias_seq*]:
233233
import_from_as_names[asdl_alias_seq*]:
234234
| a[asdl_alias_seq*]=','.import_from_as_name+ { a }
235235
import_from_as_name[alias_ty]:
236-
| a=NAME b=['as' z=NAME { z }] { _PyAST_alias(a->v.Name.id,
237-
(b) ? ((expr_ty) b)->v.Name.id : NULL,
238-
EXTRA) }
236+
| invalid_import_from_as_name
237+
| a=NAME b=['as' z=NAME { z }] { _PyAST_alias(
238+
a->v.Name.id, (b) ? ((expr_ty) b)->v.Name.id : NULL, EXTRA) }
239+
239240
dotted_as_names[asdl_alias_seq*]:
240241
| a[asdl_alias_seq*]=','.dotted_as_name+ { a }
241242
dotted_as_name[alias_ty]:
242-
| a=dotted_name b=['as' z=NAME { z }] { _PyAST_alias(a->v.Name.id,
243-
(b) ? ((expr_ty) b)->v.Name.id : NULL,
244-
EXTRA) }
243+
| invalid_dotted_as_name
244+
| a=dotted_name b=['as' z=NAME { z }] { _PyAST_alias(
245+
a->v.Name.id, (b) ? ((expr_ty) b)->v.Name.id : NULL, EXTRA) }
246+
245247
dotted_name[expr_ty]:
246248
| a=dotted_name '.' b=NAME { _PyPegen_join_names_with_dot(p, a, b) }
247249
| NAME
@@ -1375,6 +1377,14 @@ invalid_import:
13751377
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "Did you mean to use 'from ... import ...' instead?") }
13761378
| 'import' token=NEWLINE {
13771379
RAISE_SYNTAX_ERROR_STARTING_FROM(token, "Expected one or more names after 'import'") }
1380+
invalid_dotted_as_name:
1381+
| dotted_name 'as' !(NAME (',' | ')' | NEWLINE)) a=expression {
1382+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a,
1383+
"cannot use %s as import target", _PyPegen_get_expr_name(a)) }
1384+
invalid_import_from_as_name:
1385+
| NAME 'as' !(NAME (',' | ')' | NEWLINE)) a=expression {
1386+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a,
1387+
"cannot use %s as import target", _PyPegen_get_expr_name(a)) }
13781388

13791389
invalid_import_from_targets:
13801390
| import_from_as_names ',' NEWLINE {

Lib/inspect.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,7 +1901,7 @@ def getasyncgenlocals(agen):
19011901
types.BuiltinFunctionType)
19021902

19031903

1904-
def _signature_get_user_defined_method(cls, method_name):
1904+
def _signature_get_user_defined_method(cls, method_name, *, follow_wrapper_chains=True):
19051905
"""Private helper. Checks if ``cls`` has an attribute
19061906
named ``method_name`` and returns it only if it is a
19071907
pure python function.
@@ -1910,12 +1910,20 @@ def _signature_get_user_defined_method(cls, method_name):
19101910
meth = getattr(cls, method_name, None)
19111911
else:
19121912
meth = getattr_static(cls, method_name, None)
1913-
if meth is None or isinstance(meth, _NonUserDefinedCallables):
1913+
if meth is None:
1914+
return None
1915+
1916+
if follow_wrapper_chains:
1917+
meth = unwrap(meth, stop=(lambda m: hasattr(m, "__signature__")
1918+
or _signature_is_builtin(m)))
1919+
if isinstance(meth, _NonUserDefinedCallables):
19141920
# Once '__signature__' will be added to 'C'-level
19151921
# callables, this check won't be necessary
19161922
return None
19171923
if method_name != '__new__':
19181924
meth = _descriptor_get(meth, cls)
1925+
if follow_wrapper_chains:
1926+
meth = unwrap(meth, stop=lambda m: hasattr(m, "__signature__"))
19191927
return meth
19201928

19211929

@@ -2507,12 +2515,26 @@ def _signature_from_callable(obj, *,
25072515

25082516
# First, let's see if it has an overloaded __call__ defined
25092517
# in its metaclass
2510-
call = _signature_get_user_defined_method(type(obj), '__call__')
2518+
call = _signature_get_user_defined_method(
2519+
type(obj),
2520+
'__call__',
2521+
follow_wrapper_chains=follow_wrapper_chains,
2522+
)
25112523
if call is not None:
25122524
return _get_signature_of(call)
25132525

2514-
new = _signature_get_user_defined_method(obj, '__new__')
2515-
init = _signature_get_user_defined_method(obj, '__init__')
2526+
# NOTE: The user-defined method can be a function with a thin wrapper
2527+
# around object.__new__ (e.g., generated by `@warnings.deprecated`)
2528+
new = _signature_get_user_defined_method(
2529+
obj,
2530+
'__new__',
2531+
follow_wrapper_chains=follow_wrapper_chains,
2532+
)
2533+
init = _signature_get_user_defined_method(
2534+
obj,
2535+
'__init__',
2536+
follow_wrapper_chains=follow_wrapper_chains,
2537+
)
25162538

25172539
# Go through the MRO and see if any class has user-defined
25182540
# pure Python __new__ or __init__ method
@@ -2552,10 +2574,14 @@ def _signature_from_callable(obj, *,
25522574
# Last option is to check if its '__init__' is
25532575
# object.__init__ or type.__init__.
25542576
if type not in obj.__mro__:
2577+
obj_init = obj.__init__
2578+
obj_new = obj.__new__
2579+
if follow_wrapper_chains:
2580+
obj_init = unwrap(obj_init)
2581+
obj_new = unwrap(obj_new)
25552582
# We have a class (not metaclass), but no user-defined
25562583
# __init__ or __new__ for it
2557-
if (obj.__init__ is object.__init__ and
2558-
obj.__new__ is object.__new__):
2584+
if obj_init is object.__init__ and obj_new is object.__new__:
25592585
# Return a signature of 'object' builtin.
25602586
return sigcls.from_callable(object)
25612587
else:

Lib/test/test_inspect/test_inspect.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3847,7 +3847,6 @@ def wrapped_foo_call():
38473847
('b', ..., ..., "positional_or_keyword")),
38483848
...))
38493849

3850-
38513850
def test_signature_on_class(self):
38523851
class C:
38533852
def __init__(self, a):
@@ -4022,6 +4021,45 @@ def __init__(self, b):
40224021
('bar', 2, ..., "keyword_only")),
40234022
...))
40244023

4024+
def test_signature_on_class_with_decorated_new(self):
4025+
def identity(func):
4026+
@functools.wraps(func)
4027+
def wrapped(*args, **kwargs):
4028+
return func(*args, **kwargs)
4029+
return wrapped
4030+
4031+
class Foo:
4032+
@identity
4033+
def __new__(cls, a, b):
4034+
pass
4035+
4036+
self.assertEqual(self.signature(Foo),
4037+
((('a', ..., ..., "positional_or_keyword"),
4038+
('b', ..., ..., "positional_or_keyword")),
4039+
...))
4040+
4041+
self.assertEqual(self.signature(Foo.__new__),
4042+
((('cls', ..., ..., "positional_or_keyword"),
4043+
('a', ..., ..., "positional_or_keyword"),
4044+
('b', ..., ..., "positional_or_keyword")),
4045+
...))
4046+
4047+
class Bar:
4048+
__new__ = identity(object.__new__)
4049+
4050+
varargs_signature = (
4051+
(('args', ..., ..., 'var_positional'),
4052+
('kwargs', ..., ..., 'var_keyword')),
4053+
...,
4054+
)
4055+
4056+
self.assertEqual(self.signature(Bar), ((), ...))
4057+
self.assertEqual(self.signature(Bar.__new__), varargs_signature)
4058+
self.assertEqual(self.signature(Bar, follow_wrapped=False),
4059+
varargs_signature)
4060+
self.assertEqual(self.signature(Bar.__new__, follow_wrapped=False),
4061+
varargs_signature)
4062+
40254063
def test_signature_on_class_with_init(self):
40264064
class C:
40274065
def __init__(self, b):

Lib/test/test_pydoc/test_pydoc.py

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,18 +1927,28 @@ def test_text_doc_routines_in_class(self, cls=pydocfodder.B):
19271927
self.assertIn(' | global_func(x, y) from test.test_pydoc.pydocfodder', lines)
19281928
self.assertIn(' | global_func_alias = global_func(x, y)', lines)
19291929
self.assertIn(' | global_func2_alias = global_func2(x, y) from test.test_pydoc.pydocfodder', lines)
1930-
self.assertIn(' | count(self, value, /) from builtins.list', lines)
1931-
self.assertIn(' | list_count = count(self, value, /)', lines)
1932-
self.assertIn(' | __repr__(self, /) from builtins.object', lines)
1933-
self.assertIn(' | object_repr = __repr__(self, /)', lines)
1930+
if not support.MISSING_C_DOCSTRINGS:
1931+
self.assertIn(' | count(self, value, /) from builtins.list', lines)
1932+
self.assertIn(' | list_count = count(self, value, /)', lines)
1933+
self.assertIn(' | __repr__(self, /) from builtins.object', lines)
1934+
self.assertIn(' | object_repr = __repr__(self, /)', lines)
1935+
else:
1936+
self.assertIn(' | count(self, object, /) from builtins.list', lines)
1937+
self.assertIn(' | list_count = count(self, object, /)', lines)
1938+
self.assertIn(' | __repr__(...) from builtins.object', lines)
1939+
self.assertIn(' | object_repr = __repr__(...)', lines)
19341940

19351941
lines = self.getsection(result, f' | Static methods {where}:', ' | ' + '-'*70)
19361942
self.assertIn(' | A_classmethod_ref = A_classmethod(x) class method of test.test_pydoc.pydocfodder.A', lines)
19371943
note = '' if cls is pydocfodder.B else ' class method of test.test_pydoc.pydocfodder.B'
19381944
self.assertIn(' | B_classmethod_ref = B_classmethod(x)' + note, lines)
19391945
self.assertIn(' | A_method_ref = A_method() method of test.test_pydoc.pydocfodder.A instance', lines)
1940-
self.assertIn(' | get(key, default=None, /) method of builtins.dict instance', lines)
1941-
self.assertIn(' | dict_get = get(key, default=None, /) method of builtins.dict instance', lines)
1946+
if not support.MISSING_C_DOCSTRINGS:
1947+
self.assertIn(' | get(key, default=None, /) method of builtins.dict instance', lines)
1948+
self.assertIn(' | dict_get = get(key, default=None, /) method of builtins.dict instance', lines)
1949+
else:
1950+
self.assertIn(' | get(...) method of builtins.dict instance', lines)
1951+
self.assertIn(' | dict_get = get(...) method of builtins.dict instance', lines)
19421952

19431953
lines = self.getsection(result, f' | Class methods {where}:', ' | ' + '-'*70)
19441954
self.assertIn(' | B_classmethod(x)', lines)
@@ -1957,10 +1967,16 @@ def test_html_doc_routines_in_class(self, cls=pydocfodder.B):
19571967
self.assertIn('global_func(x, y) from test.test_pydoc.pydocfodder', lines)
19581968
self.assertIn('global_func_alias = global_func(x, y)', lines)
19591969
self.assertIn('global_func2_alias = global_func2(x, y) from test.test_pydoc.pydocfodder', lines)
1960-
self.assertIn('count(self, value, /) from builtins.list', lines)
1961-
self.assertIn('list_count = count(self, value, /)', lines)
1962-
self.assertIn('__repr__(self, /) from builtins.object', lines)
1963-
self.assertIn('object_repr = __repr__(self, /)', lines)
1970+
if not support.MISSING_C_DOCSTRINGS:
1971+
self.assertIn('count(self, value, /) from builtins.list', lines)
1972+
self.assertIn('list_count = count(self, value, /)', lines)
1973+
self.assertIn('__repr__(self, /) from builtins.object', lines)
1974+
self.assertIn('object_repr = __repr__(self, /)', lines)
1975+
else:
1976+
self.assertIn('count(self, object, /) from builtins.list', lines)
1977+
self.assertIn('list_count = count(self, object, /)', lines)
1978+
self.assertIn('__repr__(...) from builtins.object', lines)
1979+
self.assertIn('object_repr = __repr__(...)', lines)
19641980

19651981
lines = self.getsection(result, f'Static methods {where}:', '-'*70)
19661982
self.assertIn('A_classmethod_ref = A_classmethod(x) class method of test.test_pydoc.pydocfodder.A', lines)
@@ -1997,15 +2013,27 @@ def test_text_doc_routines_in_module(self):
19972013
self.assertIn(' A_method3 = A_method() method of B instance', lines)
19982014
self.assertIn(' A_staticmethod_ref = A_staticmethod(x, y)', lines)
19992015
self.assertIn(' A_staticmethod_ref2 = A_staticmethod(y) method of B instance', lines)
2000-
self.assertIn(' get(key, default=None, /) method of builtins.dict instance', lines)
2001-
self.assertIn(' dict_get = get(key, default=None, /) method of builtins.dict instance', lines)
2016+
if not support.MISSING_C_DOCSTRINGS:
2017+
self.assertIn(' get(key, default=None, /) method of builtins.dict instance', lines)
2018+
self.assertIn(' dict_get = get(key, default=None, /) method of builtins.dict instance', lines)
2019+
else:
2020+
self.assertIn(' get(...) method of builtins.dict instance', lines)
2021+
self.assertIn(' dict_get = get(...) method of builtins.dict instance', lines)
2022+
20022023
# unbound methods
20032024
self.assertIn(' B_method(self)', lines)
20042025
self.assertIn(' B_method2 = B_method(self)', lines)
2005-
self.assertIn(' count(self, value, /) unbound builtins.list method', lines)
2006-
self.assertIn(' list_count = count(self, value, /) unbound builtins.list method', lines)
2007-
self.assertIn(' __repr__(self, /) unbound builtins.object method', lines)
2008-
self.assertIn(' object_repr = __repr__(self, /) unbound builtins.object method', lines)
2026+
if not support.MISSING_C_DOCSTRINGS:
2027+
self.assertIn(' count(self, value, /) unbound builtins.list method', lines)
2028+
self.assertIn(' list_count = count(self, value, /) unbound builtins.list method', lines)
2029+
self.assertIn(' __repr__(self, /) unbound builtins.object method', lines)
2030+
self.assertIn(' object_repr = __repr__(self, /) unbound builtins.object method', lines)
2031+
else:
2032+
self.assertIn(' count(self, object, /) unbound builtins.list method', lines)
2033+
self.assertIn(' list_count = count(self, object, /) unbound builtins.list method', lines)
2034+
self.assertIn(' __repr__(...) unbound builtins.object method', lines)
2035+
self.assertIn(' object_repr = __repr__(...) unbound builtins.object method', lines)
2036+
20092037

20102038
def test_html_doc_routines_in_module(self):
20112039
doc = pydoc.HTMLDoc()
@@ -2026,15 +2054,25 @@ def test_html_doc_routines_in_module(self):
20262054
self.assertIn(' A_method3 = A_method() method of B instance', lines)
20272055
self.assertIn(' A_staticmethod_ref = A_staticmethod(x, y)', lines)
20282056
self.assertIn(' A_staticmethod_ref2 = A_staticmethod(y) method of B instance', lines)
2029-
self.assertIn(' get(key, default=None, /) method of builtins.dict instance', lines)
2030-
self.assertIn(' dict_get = get(key, default=None, /) method of builtins.dict instance', lines)
2057+
if not support.MISSING_C_DOCSTRINGS:
2058+
self.assertIn(' get(key, default=None, /) method of builtins.dict instance', lines)
2059+
self.assertIn(' dict_get = get(key, default=None, /) method of builtins.dict instance', lines)
2060+
else:
2061+
self.assertIn(' get(...) method of builtins.dict instance', lines)
2062+
self.assertIn(' dict_get = get(...) method of builtins.dict instance', lines)
20312063
# unbound methods
20322064
self.assertIn(' B_method(self)', lines)
20332065
self.assertIn(' B_method2 = B_method(self)', lines)
2034-
self.assertIn(' count(self, value, /) unbound builtins.list method', lines)
2035-
self.assertIn(' list_count = count(self, value, /) unbound builtins.list method', lines)
2036-
self.assertIn(' __repr__(self, /) unbound builtins.object method', lines)
2037-
self.assertIn(' object_repr = __repr__(self, /) unbound builtins.object method', lines)
2066+
if not support.MISSING_C_DOCSTRINGS:
2067+
self.assertIn(' count(self, value, /) unbound builtins.list method', lines)
2068+
self.assertIn(' list_count = count(self, value, /) unbound builtins.list method', lines)
2069+
self.assertIn(' __repr__(self, /) unbound builtins.object method', lines)
2070+
self.assertIn(' object_repr = __repr__(self, /) unbound builtins.object method', lines)
2071+
else:
2072+
self.assertIn(' count(self, object, /) unbound builtins.list method', lines)
2073+
self.assertIn(' list_count = count(self, object, /) unbound builtins.list method', lines)
2074+
self.assertIn(' __repr__(...) unbound builtins.object method', lines)
2075+
self.assertIn(' object_repr = __repr__(...) unbound builtins.object method', lines)
20382076

20392077

20402078
@unittest.skipIf(

0 commit comments

Comments
 (0)