Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 056efee

Browse filesBrowse files
committed
Merge remote-tracking branch 'upstream/main' into pep688fix
2 parents 3b50138 + 7a7eaff commit 056efee
Copy full SHA for 056efee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner

41 files changed

+972
-452
lines changed

‎Doc/library/asyncio-task.rst

Copy file name to clipboardExpand all lines: Doc/library/asyncio-task.rst
+8-4Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ Introspection
10141014
Task Object
10151015
===========
10161016

1017-
.. class:: Task(coro, *, loop=None, name=None)
1017+
.. class:: Task(coro, *, loop=None, name=None, context=None)
10181018

10191019
A :class:`Future-like <Future>` object that runs a Python
10201020
:ref:`coroutine <coroutine>`. Not thread-safe.
@@ -1049,9 +1049,10 @@ Task Object
10491049
APIs except :meth:`Future.set_result` and
10501050
:meth:`Future.set_exception`.
10511051

1052-
Tasks support the :mod:`contextvars` module. When a Task
1053-
is created it copies the current context and later runs its
1054-
coroutine in the copied context.
1052+
An optional keyword-only *context* argument allows specifying a
1053+
custom :class:`contextvars.Context` for the *coro* to run in.
1054+
If no *context* is provided, the Task copies the current context
1055+
and later runs its coroutine in the copied context.
10551056

10561057
.. versionchanged:: 3.7
10571058
Added support for the :mod:`contextvars` module.
@@ -1063,6 +1064,9 @@ Task Object
10631064
Deprecation warning is emitted if *loop* is not specified
10641065
and there is no running event loop.
10651066

1067+
.. versionchanged:: 3.11
1068+
Added the *context* parameter.
1069+
10661070
.. method:: done()
10671071

10681072
Return ``True`` if the Task is *done*.

‎Doc/whatsnew/3.12.rst

Copy file name to clipboardExpand all lines: Doc/whatsnew/3.12.rst
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,19 @@ Pending Removal in Python 3.14
844844
use :func:`importlib.util.find_spec` instead.
845845
(Contributed by Nikita Sobolev in :gh:`97850`.)
846846

847+
* The following :mod:`ast` features have been deprecated in documentation since
848+
Python 3.8, now cause a :exc:`DeprecationWarning` to be emitted at runtime
849+
when they are accessed or used, and will be removed in Python 3.14:
850+
851+
* :class:`!ast.Num`
852+
* :class:`!ast.Str`
853+
* :class:`!ast.Bytes`
854+
* :class:`!ast.NameConstant`
855+
* :class:`!ast.Ellipsis`
856+
857+
Use :class:`ast.Constant` instead.
858+
(Contributed by Serhiy Storchaka in :gh:`90953`.)
859+
847860
Pending Removal in Future Versions
848861
----------------------------------
849862

‎Include/internal/pycore_ceval.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_ceval.h
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ extern int _PyEval_ThreadsInitialized(void);
100100
extern PyStatus _PyEval_InitGIL(PyThreadState *tstate, int own_gil);
101101
extern void _PyEval_FiniGIL(PyInterpreterState *interp);
102102

103+
extern void _PyEval_AcquireLock(PyThreadState *tstate);
103104
extern void _PyEval_ReleaseLock(PyThreadState *tstate);
105+
extern PyThreadState * _PyThreadState_SwapNoGIL(PyThreadState *);
104106

105107
extern void _PyEval_DeactivateOpCache(void);
106108

‎Include/internal/pycore_format.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_format.h
-2Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,12 @@ extern "C" {
1414
* F_BLANK ' '
1515
* F_ALT '#'
1616
* F_ZERO '0'
17-
* F_NO_NEG_0 'z'
1817
*/
1918
#define F_LJUST (1<<0)
2019
#define F_SIGN (1<<1)
2120
#define F_BLANK (1<<2)
2221
#define F_ALT (1<<3)
2322
#define F_ZERO (1<<4)
24-
#define F_NO_NEG_0 (1<<5)
2523

2624
#ifdef __cplusplus
2725
}

‎Lib/argparse.py

Copy file name to clipboardExpand all lines: Lib/argparse.py
+5-3Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,9 +2605,11 @@ def print_help(self, file=None):
26052605

26062606
def _print_message(self, message, file=None):
26072607
if message:
2608-
if file is None:
2609-
file = _sys.stderr
2610-
file.write(message)
2608+
file = file or _sys.stderr
2609+
try:
2610+
file.write(message)
2611+
except (AttributeError, OSError):
2612+
pass
26112613

26122614
# ===============
26132615
# Exiting methods

‎Lib/ast.py

Copy file name to clipboardExpand all lines: Lib/ast.py
+74-8Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,7 @@ def get_docstring(node, clean=True):
294294
if not(node.body and isinstance(node.body[0], Expr)):
295295
return None
296296
node = node.body[0].value
297-
if isinstance(node, Str):
298-
text = node.s
299-
elif isinstance(node, Constant) and isinstance(node.value, str):
297+
if isinstance(node, Constant) and isinstance(node.value, str):
300298
text = node.value
301299
else:
302300
return None
@@ -499,27 +497,66 @@ def generic_visit(self, node):
499497
return node
500498

501499

500+
_DEPRECATED_VALUE_ALIAS_MESSAGE = (
501+
"{name} is deprecated and will be removed in Python {remove}; use value instead"
502+
)
503+
_DEPRECATED_CLASS_MESSAGE = (
504+
"{name} is deprecated and will be removed in Python {remove}; "
505+
"use ast.Constant instead"
506+
)
507+
508+
502509
# If the ast module is loaded more than once, only add deprecated methods once
503510
if not hasattr(Constant, 'n'):
504511
# The following code is for backward compatibility.
505512
# It will be removed in future.
506513

507-
def _getter(self):
514+
def _n_getter(self):
515+
"""Deprecated. Use value instead."""
516+
import warnings
517+
warnings._deprecated(
518+
"Attribute n", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 14)
519+
)
520+
return self.value
521+
522+
def _n_setter(self, value):
523+
import warnings
524+
warnings._deprecated(
525+
"Attribute n", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 14)
526+
)
527+
self.value = value
528+
529+
def _s_getter(self):
508530
"""Deprecated. Use value instead."""
531+
import warnings
532+
warnings._deprecated(
533+
"Attribute s", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 14)
534+
)
509535
return self.value
510536

511-
def _setter(self, value):
537+
def _s_setter(self, value):
538+
import warnings
539+
warnings._deprecated(
540+
"Attribute s", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 14)
541+
)
512542
self.value = value
513543

514-
Constant.n = property(_getter, _setter)
515-
Constant.s = property(_getter, _setter)
544+
Constant.n = property(_n_getter, _n_setter)
545+
Constant.s = property(_s_getter, _s_setter)
516546

517547
class _ABC(type):
518548

519549
def __init__(cls, *args):
520550
cls.__doc__ = """Deprecated AST node class. Use ast.Constant instead"""
521551

522552
def __instancecheck__(cls, inst):
553+
if cls in _const_types:
554+
import warnings
555+
warnings._deprecated(
556+
f"ast.{cls.__qualname__}",
557+
message=_DEPRECATED_CLASS_MESSAGE,
558+
remove=(3, 14)
559+
)
523560
if not isinstance(inst, Constant):
524561
return False
525562
if cls in _const_types:
@@ -543,6 +580,10 @@ def _new(cls, *args, **kwargs):
543580
if pos < len(args):
544581
raise TypeError(f"{cls.__name__} got multiple values for argument {key!r}")
545582
if cls in _const_types:
583+
import warnings
584+
warnings._deprecated(
585+
f"ast.{cls.__qualname__}", message=_DEPRECATED_CLASS_MESSAGE, remove=(3, 14)
586+
)
546587
return Constant(*args, **kwargs)
547588
return Constant.__new__(cls, *args, **kwargs)
548589

@@ -565,10 +606,19 @@ class Ellipsis(Constant, metaclass=_ABC):
565606
_fields = ()
566607

567608
def __new__(cls, *args, **kwargs):
568-
if cls is Ellipsis:
609+
if cls is _ast_Ellipsis:
610+
import warnings
611+
warnings._deprecated(
612+
"ast.Ellipsis", message=_DEPRECATED_CLASS_MESSAGE, remove=(3, 14)
613+
)
569614
return Constant(..., *args, **kwargs)
570615
return Constant.__new__(cls, *args, **kwargs)
571616

617+
# Keep another reference to Ellipsis in the global namespace
618+
# so it can be referenced in Ellipsis.__new__
619+
# (The original "Ellipsis" name is removed from the global namespace later on)
620+
_ast_Ellipsis = Ellipsis
621+
572622
_const_types = {
573623
Num: (int, float, complex),
574624
Str: (str,),
@@ -1699,6 +1749,22 @@ def unparse(ast_obj):
16991749
return unparser.visit(ast_obj)
17001750

17011751

1752+
_deprecated_globals = {
1753+
name: globals().pop(name)
1754+
for name in ('Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis')
1755+
}
1756+
1757+
def __getattr__(name):
1758+
if name in _deprecated_globals:
1759+
globals()[name] = value = _deprecated_globals[name]
1760+
import warnings
1761+
warnings._deprecated(
1762+
f"ast.{name}", message=_DEPRECATED_CLASS_MESSAGE, remove=(3, 14)
1763+
)
1764+
return value
1765+
raise AttributeError(f"module 'ast' has no attribute '{name}'")
1766+
1767+
17021768
def main():
17031769
import argparse
17041770

‎Lib/asyncio/tasks.py

Copy file name to clipboardExpand all lines: Lib/asyncio/tasks.py
+12-1Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,7 @@ def _done_callback(fut):
813813
children = []
814814
nfuts = 0
815815
nfinished = 0
816+
done_futs = []
816817
loop = None
817818
outer = None # bpo-46672
818819
for arg in coros_or_futures:
@@ -829,7 +830,10 @@ def _done_callback(fut):
829830

830831
nfuts += 1
831832
arg_to_fut[arg] = fut
832-
fut.add_done_callback(_done_callback)
833+
if fut.done():
834+
done_futs.append(fut)
835+
else:
836+
fut.add_done_callback(_done_callback)
833837

834838
else:
835839
# There's a duplicate Future object in coros_or_futures.
@@ -838,6 +842,13 @@ def _done_callback(fut):
838842
children.append(fut)
839843

840844
outer = _GatheringFuture(children, loop=loop)
845+
# Run done callbacks after GatheringFuture created so any post-processing
846+
# can be performed at this point
847+
# optimization: in the special case that *all* futures finished eagerly,
848+
# this will effectively complete the gather eagerly, with the last
849+
# callback setting the result (or exception) on outer before returning it
850+
for fut in done_futs:
851+
_done_callback(fut)
841852
return outer
842853

843854

‎Lib/pathlib.py

Copy file name to clipboardExpand all lines: Lib/pathlib.py
+10-1Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ def is_absolute(self):
664664
# ntpath.isabs() is defective - see GH-44626 .
665665
if self._flavour is ntpath:
666666
return bool(self.drive and self.root)
667-
return self._flavour.isabs(self)
667+
return self._flavour.isabs(self._raw_path)
668668

669669
def is_reserved(self):
670670
"""Return True if the path contains one of the special names reserved
@@ -873,6 +873,15 @@ def absolute(self):
873873
cwd = self._flavour.abspath(self.drive)
874874
else:
875875
cwd = os.getcwd()
876+
# Fast path for "empty" paths, e.g. Path("."), Path("") or Path().
877+
# We pass only one argument to with_segments() to avoid the cost
878+
# of joining, and we exploit the fact that getcwd() returns a
879+
# fully-normalized string by storing it in _str. This is used to
880+
# implement Path.cwd().
881+
if not self.root and not self._tail:
882+
result = self.with_segments(cwd)
883+
result._str = cwd
884+
return result
876885
return self.with_segments(cwd, self)
877886

878887
def resolve(self, strict=False):

‎Lib/test/test_argparse.py

Copy file name to clipboardExpand all lines: Lib/test/test_argparse.py
+31Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Author: Steven J. Bethard <steven.bethard@gmail.com>.
22

3+
import contextlib
4+
import functools
35
import inspect
46
import io
57
import operator
@@ -35,6 +37,35 @@ def getvalue(self):
3537
return self.buffer.raw.getvalue().decode('utf-8')
3638

3739

40+
class StdStreamTest(unittest.TestCase):
41+
42+
def test_skip_invalid_stderr(self):
43+
parser = argparse.ArgumentParser()
44+
with (
45+
contextlib.redirect_stderr(None),
46+
mock.patch('argparse._sys.exit')
47+
):
48+
parser.exit(status=0, message='foo')
49+
50+
def test_skip_invalid_stdout(self):
51+
parser = argparse.ArgumentParser()
52+
for func in (
53+
parser.print_usage,
54+
parser.print_help,
55+
functools.partial(parser.parse_args, ['-h'])
56+
):
57+
with (
58+
self.subTest(func=func),
59+
contextlib.redirect_stdout(None),
60+
# argparse uses stderr as a fallback
61+
StdIOBuffer() as mocked_stderr,
62+
contextlib.redirect_stderr(mocked_stderr),
63+
mock.patch('argparse._sys.exit'),
64+
):
65+
func()
66+
self.assertRegex(mocked_stderr.getvalue(), r'usage:')
67+
68+
3869
class TestCase(unittest.TestCase):
3970

4071
def setUp(self):

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.