Skip to content

Commit 36ff421

Browse files
Merge branch 'python:main' into fix-docs-115986
2 parents c4d976c + ed4dfd8 commit 36ff421

17 files changed

+4749
-72
lines changed

Doc/library/ast.rst

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,20 +103,15 @@ Node classes
103103
For example, to create and populate an :class:`ast.UnaryOp` node, you could
104104
use ::
105105

106-
node = ast.UnaryOp()
107-
node.op = ast.USub()
108-
node.operand = ast.Constant()
109-
node.operand.value = 5
110-
node.operand.lineno = 0
111-
node.operand.col_offset = 0
112-
node.lineno = 0
113-
node.col_offset = 0
114-
115-
or the more compact ::
116-
117106
node = ast.UnaryOp(ast.USub(), ast.Constant(5, lineno=0, col_offset=0),
118107
lineno=0, col_offset=0)
119108

109+
If a field that is optional in the grammar is omitted from the constructor,
110+
it defaults to ``None``. If a list field is omitted, it defaults to the empty
111+
list. If any other field is omitted, a :exc:`DeprecationWarning` is raised
112+
and the AST node will not have this field. In Python 3.15, this condition will
113+
raise an error.
114+
120115
.. versionchanged:: 3.8
121116

122117
Class :class:`ast.Constant` is now used for all constants.
@@ -140,6 +135,14 @@ Node classes
140135
In the meantime, instantiating them will return an instance of
141136
a different class.
142137

138+
.. deprecated-removed:: 3.13 3.15
139+
140+
Previous versions of Python allowed the creation of AST nodes that were missing
141+
required fields. Similarly, AST node constructors allowed arbitrary keyword
142+
arguments that were set as attributes of the AST node, even if they did not
143+
match any of the fields of the AST node. This behavior is deprecated and will
144+
be removed in Python 3.15.
145+
143146
.. note::
144147
The descriptions of the specific node classes displayed here
145148
were initially adapted from the fantastic `Green Tree

Doc/whatsnew/3.13.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,21 @@ array
206206
ast
207207
---
208208

209+
* The constructors of node types in the :mod:`ast` module are now stricter
210+
in the arguments they accept, and have more intuitive behaviour when
211+
arguments are omitted.
212+
213+
If an optional field on an AST node is not included as an argument when
214+
constructing an instance, the field will now be set to ``None``. Similarly,
215+
if a list field is omitted, that field will now be set to an empty list.
216+
(Previously, in both cases, the attribute would be missing on the newly
217+
constructed AST node instance.)
218+
219+
If other arguments are omitted, a :exc:`DeprecationWarning` is emitted.
220+
This will cause an exception in Python 3.15. Similarly, passing a keyword
221+
argument that does not map to a field on the AST node is now deprecated,
222+
and will raise an exception in Python 3.15.
223+
209224
* :func:`ast.parse` now accepts an optional argument ``optimize``
210225
which is passed on to the :func:`compile` built-in. This makes it
211226
possible to obtain an optimized ``AST``.

Include/internal/pycore_global_objects_fini_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_global_strings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ struct _Py_global_strings {
242242
STRUCT_FOR_ID(_check_retval_)
243243
STRUCT_FOR_ID(_dealloc_warn)
244244
STRUCT_FOR_ID(_feature_version)
245+
STRUCT_FOR_ID(_field_types)
245246
STRUCT_FOR_ID(_fields_)
246247
STRUCT_FOR_ID(_finalizing)
247248
STRUCT_FOR_ID(_find_and_load)

Include/internal/pycore_runtime_init_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_unicodeobject_generated.h

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/asyncio/events.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ def _repr_info(self):
5454
info.append('cancelled')
5555
if self._callback is not None:
5656
info.append(format_helpers._format_callback_source(
57-
self._callback, self._args))
57+
self._callback, self._args,
58+
debug=self._loop.get_debug()))
5859
if self._source_traceback:
5960
frame = self._source_traceback[-1]
6061
info.append(f'created at {frame[0]}:{frame[1]}')
@@ -90,7 +91,8 @@ def _run(self):
9091
raise
9192
except BaseException as exc:
9293
cb = format_helpers._format_callback_source(
93-
self._callback, self._args)
94+
self._callback, self._args,
95+
debug=self._loop.get_debug())
9496
msg = f'Exception in callback {cb}'
9597
context = {
9698
'message': msg,

Lib/asyncio/format_helpers.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,26 @@ def _get_function_source(func):
1919
return None
2020

2121

22-
def _format_callback_source(func, args):
23-
func_repr = _format_callback(func, args, None)
22+
def _format_callback_source(func, args, *, debug=False):
23+
func_repr = _format_callback(func, args, None, debug=debug)
2424
source = _get_function_source(func)
2525
if source:
2626
func_repr += f' at {source[0]}:{source[1]}'
2727
return func_repr
2828

2929

30-
def _format_args_and_kwargs(args, kwargs):
30+
def _format_args_and_kwargs(args, kwargs, *, debug=False):
3131
"""Format function arguments and keyword arguments.
3232
3333
Special case for a single parameter: ('hello',) is formatted as ('hello').
34+
35+
Note that this function only returns argument details when
36+
debug=True is specified, as arguments may contain sensitive
37+
information.
3438
"""
39+
if not debug:
40+
return '()'
41+
3542
# use reprlib to limit the length of the output
3643
items = []
3744
if args:
@@ -41,10 +48,11 @@ def _format_args_and_kwargs(args, kwargs):
4148
return '({})'.format(', '.join(items))
4249

4350

44-
def _format_callback(func, args, kwargs, suffix=''):
51+
def _format_callback(func, args, kwargs, *, debug=False, suffix=''):
4552
if isinstance(func, functools.partial):
46-
suffix = _format_args_and_kwargs(args, kwargs) + suffix
47-
return _format_callback(func.func, func.args, func.keywords, suffix)
53+
suffix = _format_args_and_kwargs(args, kwargs, debug=debug) + suffix
54+
return _format_callback(func.func, func.args, func.keywords,
55+
debug=debug, suffix=suffix)
4856

4957
if hasattr(func, '__qualname__') and func.__qualname__:
5058
func_repr = func.__qualname__
@@ -53,7 +61,7 @@ def _format_callback(func, args, kwargs, suffix=''):
5361
else:
5462
func_repr = repr(func)
5563

56-
func_repr += _format_args_and_kwargs(args, kwargs)
64+
func_repr += _format_args_and_kwargs(args, kwargs, debug=debug)
5765
if suffix:
5866
func_repr += suffix
5967
return func_repr

Lib/asyncio/streams.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@ def __init__(self, stream_reader, client_connected_cb=None, loop=None):
201201
# is established.
202202
self._strong_reader = stream_reader
203203
self._reject_connection = False
204-
self._stream_writer = None
205204
self._task = None
206205
self._transport = None
207206
self._client_connected_cb = client_connected_cb
@@ -214,10 +213,8 @@ def _stream_reader(self):
214213
return None
215214
return self._stream_reader_wr()
216215

217-
def _replace_writer(self, writer):
216+
def _replace_transport(self, transport):
218217
loop = self._loop
219-
transport = writer.transport
220-
self._stream_writer = writer
221218
self._transport = transport
222219
self._over_ssl = transport.get_extra_info('sslcontext') is not None
223220

@@ -239,11 +236,8 @@ def connection_made(self, transport):
239236
reader.set_transport(transport)
240237
self._over_ssl = transport.get_extra_info('sslcontext') is not None
241238
if self._client_connected_cb is not None:
242-
self._stream_writer = StreamWriter(transport, self,
243-
reader,
244-
self._loop)
245-
res = self._client_connected_cb(reader,
246-
self._stream_writer)
239+
writer = StreamWriter(transport, self, reader, self._loop)
240+
res = self._client_connected_cb(reader, writer)
247241
if coroutines.iscoroutine(res):
248242
def callback(task):
249243
if task.cancelled():
@@ -405,7 +399,7 @@ async def start_tls(self, sslcontext, *,
405399
ssl_handshake_timeout=ssl_handshake_timeout,
406400
ssl_shutdown_timeout=ssl_shutdown_timeout)
407401
self._transport = new_transport
408-
protocol._replace_writer(self)
402+
protocol._replace_transport(new_transport)
409403

410404
def __del__(self, warnings=warnings):
411405
if not self._transport.is_closing():

0 commit comments

Comments
 (0)