Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 83d7ec2

Browse files
committed
Merge branch 'main' into runtime-protocols-getattr_static
2 parents 0812183 + d828b35 commit 83d7ec2

12 files changed

Lines changed: 434 additions & 296 deletions

File tree

Doc/whatsnew/3.12.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,10 @@ New Features
986986
This is less error prone and a bit more efficient.
987987
(Contributed by Mark Shannon in :gh:`101578`.)
988988

989+
* Add ``_PyErr_ChainExceptions1``, which takes an exception instance,
990+
to replace the legacy-API ``_PyErr_ChainExceptions``, which is now
991+
deprecated. (Contributed by Mark Shannon in :gh:`101578`.)
992+
989993
* Add :c:func:`PyException_GetArgs` and :c:func:`PyException_SetArgs`
990994
as convenience functions for retrieving and modifying
991995
the :attr:`~BaseException.args` passed to the exception's constructor.
@@ -1136,6 +1140,8 @@ Deprecated
11361140
* :c:func:`!PyErr_Display` is deprecated. Use :c:func:`PyErr_DisplayException`
11371141
instead. (Contributed by Irit Katriel in :gh:`102755`).
11381142

1143+
* ``_PyErr_ChainExceptions`` is deprecated. Use ``_PyErr_ChainExceptions1``
1144+
instead. (Contributed by Irit Katriel in :gh:`102192`.)
11391145

11401146
Removed
11411147
-------

Include/cpython/pyerrors.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ PyAPI_FUNC(void) _PyErr_GetExcInfo(PyThreadState *, PyObject **, PyObject **, Py
9898

9999
/* Context manipulation (PEP 3134) */
100100

101-
PyAPI_FUNC(void) _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *);
101+
Py_DEPRECATED(3.12) PyAPI_FUNC(void) _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *);
102102
PyAPI_FUNC(void) _PyErr_ChainExceptions1(PyObject *);
103103

104104
/* Like PyErr_Format(), but saves current exception as __context__ and

Lib/base64.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -558,12 +558,12 @@ def decodebytes(s):
558558
def main():
559559
"""Small main program"""
560560
import sys, getopt
561-
usage = f"""usage: {sys.argv[0]} [-h|-d|-e|-u|-t] [file|-]
561+
usage = f"""usage: {sys.argv[0]} [-h|-d|-e|-u] [file|-]
562562
-h: print this help message and exit
563563
-d, -u: decode
564564
-e: encode (default)"""
565565
try:
566-
opts, args = getopt.getopt(sys.argv[1:], 'hdeut')
566+
opts, args = getopt.getopt(sys.argv[1:], 'hdeu')
567567
except getopt.error as msg:
568568
sys.stdout = sys.stderr
569569
print(msg)

Lib/enum.py

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -266,23 +266,20 @@ def __set_name__(self, enum_class, member_name):
266266
args = (args, ) # wrap it one more time
267267
if not enum_class._use_args_:
268268
enum_member = enum_class._new_member_(enum_class)
269-
if not hasattr(enum_member, '_value_'):
269+
else:
270+
enum_member = enum_class._new_member_(enum_class, *args)
271+
if not hasattr(enum_member, '_value_'):
272+
if enum_class._member_type_ is object:
273+
enum_member._value_ = value
274+
else:
270275
try:
271276
enum_member._value_ = enum_class._member_type_(*args)
272277
except Exception as exc:
273-
enum_member._value_ = value
274-
else:
275-
enum_member = enum_class._new_member_(enum_class, *args)
276-
if not hasattr(enum_member, '_value_'):
277-
if enum_class._member_type_ is object:
278-
enum_member._value_ = value
279-
else:
280-
try:
281-
enum_member._value_ = enum_class._member_type_(*args)
282-
except Exception as exc:
283-
raise TypeError(
284-
'_value_ not set in __new__, unable to create it'
285-
) from None
278+
new_exc = TypeError(
279+
'_value_ not set in __new__, unable to create it'
280+
)
281+
new_exc.__cause__ = exc
282+
raise new_exc
286283
value = enum_member._value_
287284
enum_member._name_ = member_name
288285
enum_member.__objclass__ = enum_class

Lib/test/test_enum.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2916,6 +2916,26 @@ def __new__(cls, c):
29162916
self.assertEqual(FlagFromChar.a, 158456325028528675187087900672)
29172917
self.assertEqual(FlagFromChar.a|1, 158456325028528675187087900673)
29182918

2919+
def test_init_exception(self):
2920+
class Base:
2921+
def __init__(self, x):
2922+
raise ValueError("I don't like", x)
2923+
with self.assertRaises(TypeError):
2924+
class MyEnum(Base, enum.Enum):
2925+
A = 'a'
2926+
def __init__(self, y):
2927+
self.y = y
2928+
with self.assertRaises(ValueError):
2929+
class MyEnum(Base, enum.Enum):
2930+
A = 'a'
2931+
def __init__(self, y):
2932+
self.y = y
2933+
def __new__(cls, value):
2934+
member = Base.__new__(cls)
2935+
member._value_ = Base(value)
2936+
return member
2937+
2938+
29192939
class TestOrder(unittest.TestCase):
29202940
"test usage of the `_order_` attribute"
29212941

Lib/test/test_import/__init__.py

Lines changed: 106 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import glob
55
import importlib.util
66
from importlib._bootstrap_external import _get_sourcefile
7+
from importlib.machinery import (
8+
BuiltinImporter, ExtensionFileLoader, FrozenImporter, SourceFileLoader,
9+
)
710
import marshal
811
import os
912
import py_compile
@@ -44,6 +47,49 @@
4447
sys.dont_write_bytecode,
4548
"test meaningful only when writing bytecode")
4649

50+
51+
def _require_loader(module, loader, skip):
52+
if isinstance(module, str):
53+
module = __import__(module)
54+
55+
MODULE_KINDS = {
56+
BuiltinImporter: 'built-in',
57+
ExtensionFileLoader: 'extension',
58+
FrozenImporter: 'frozen',
59+
SourceFileLoader: 'pure Python',
60+
}
61+
62+
expected = loader
63+
assert isinstance(expected, type), expected
64+
expected = MODULE_KINDS[expected]
65+
66+
actual = module.__spec__.loader
67+
if not isinstance(actual, type):
68+
actual = type(actual)
69+
actual = MODULE_KINDS[actual]
70+
71+
if actual != expected:
72+
err = f'expected module to be {expected}, got {module.__spec__}'
73+
if skip:
74+
raise unittest.SkipTest(err)
75+
raise Exception(err)
76+
return module
77+
78+
def require_builtin(module, *, skip=False):
79+
module = _require_loader(module, BuiltinImporter, skip)
80+
assert module.__spec__.origin == 'built-in', module.__spec__
81+
82+
def require_extension(module, *, skip=False):
83+
_require_loader(module, ExtensionFileLoader, skip)
84+
85+
def require_frozen(module, *, skip=True):
86+
module = _require_loader(module, FrozenImporter, skip)
87+
assert module.__spec__.origin == 'frozen', module.__spec__
88+
89+
def require_pure_python(module, *, skip=False):
90+
_require_loader(module, SourceFileLoader, skip)
91+
92+
4793
def remove_files(name):
4894
for f in (name + ".py",
4995
name + ".pyc",
@@ -1437,10 +1483,10 @@ def import_script(self, name, fd, check_override=None):
14371483
os.write({fd}, text.encode('utf-8'))
14381484
''')
14391485

1440-
def run_shared(self, name, *,
1441-
check_singlephase_setting=False,
1442-
check_singlephase_override=None,
1443-
):
1486+
def run_here(self, name, *,
1487+
check_singlephase_setting=False,
1488+
check_singlephase_override=None,
1489+
):
14441490
"""
14451491
Try importing the named module in a subinterpreter.
14461492
@@ -1470,27 +1516,35 @@ def run_shared(self, name, *,
14701516
self.assertEqual(ret, 0)
14711517
return os.read(r, 100)
14721518

1473-
def check_compatible_shared(self, name, *, strict=False):
1519+
def check_compatible_here(self, name, *, strict=False):
14741520
# Verify that the named module may be imported in a subinterpreter.
1475-
# (See run_shared() for more info.)
1476-
out = self.run_shared(name, check_singlephase_setting=strict)
1521+
# (See run_here() for more info.)
1522+
out = self.run_here(name,
1523+
check_singlephase_setting=strict,
1524+
)
14771525
self.assertEqual(out, b'okay')
14781526

1479-
def check_incompatible_shared(self, name):
1480-
# Differences from check_compatible_shared():
1527+
def check_incompatible_here(self, name):
1528+
# Differences from check_compatible_here():
14811529
# * verify that import fails
14821530
# * "strict" is always True
1483-
out = self.run_shared(name, check_singlephase_setting=True)
1531+
out = self.run_here(name,
1532+
check_singlephase_setting=True,
1533+
)
14841534
self.assertEqual(
14851535
out.decode('utf-8'),
14861536
f'ImportError: module {name} does not support loading in subinterpreters',
14871537
)
14881538

1489-
def check_compatible_isolated(self, name, *, strict=False):
1490-
# Differences from check_compatible_shared():
1539+
def check_compatible_fresh(self, name, *, strict=False):
1540+
# Differences from check_compatible_here():
14911541
# * subinterpreter in a new process
14921542
# * module has never been imported before in that process
14931543
# * this tests importing the module for the first time
1544+
kwargs = dict(
1545+
**self.RUN_KWARGS,
1546+
check_multi_interp_extensions=strict,
1547+
)
14941548
_, out, err = script_helper.assert_python_ok('-c', textwrap.dedent(f'''
14951549
import _testcapi, sys
14961550
assert (
@@ -1499,25 +1553,27 @@ def check_compatible_isolated(self, name, *, strict=False):
14991553
), repr({name!r})
15001554
ret = _testcapi.run_in_subinterp_with_config(
15011555
{self.import_script(name, "sys.stdout.fileno()")!r},
1502-
**{self.RUN_KWARGS},
1503-
check_multi_interp_extensions={strict},
1556+
**{kwargs},
15041557
)
15051558
assert ret == 0, ret
15061559
'''))
15071560
self.assertEqual(err, b'')
15081561
self.assertEqual(out, b'okay')
15091562

1510-
def check_incompatible_isolated(self, name):
1511-
# Differences from check_compatible_isolated():
1563+
def check_incompatible_fresh(self, name):
1564+
# Differences from check_compatible_fresh():
15121565
# * verify that import fails
15131566
# * "strict" is always True
1567+
kwargs = dict(
1568+
**self.RUN_KWARGS,
1569+
check_multi_interp_extensions=True,
1570+
)
15141571
_, out, err = script_helper.assert_python_ok('-c', textwrap.dedent(f'''
15151572
import _testcapi, sys
15161573
assert {name!r} not in sys.modules, {name!r}
15171574
ret = _testcapi.run_in_subinterp_with_config(
15181575
{self.import_script(name, "sys.stdout.fileno()")!r},
1519-
**{self.RUN_KWARGS},
1520-
check_multi_interp_extensions=True,
1576+
**{kwargs},
15211577
)
15221578
assert ret == 0, ret
15231579
'''))
@@ -1528,67 +1584,73 @@ def check_incompatible_isolated(self, name):
15281584
)
15291585

15301586
def test_builtin_compat(self):
1531-
module = 'sys'
1587+
# For now we avoid using sys or builtins
1588+
# since they still don't implement multi-phase init.
1589+
module = '_imp'
1590+
require_builtin(module)
15321591
with self.subTest(f'{module}: not strict'):
1533-
self.check_compatible_shared(module, strict=False)
1534-
with self.subTest(f'{module}: strict, shared'):
1535-
self.check_compatible_shared(module, strict=True)
1592+
self.check_compatible_here(module, strict=False)
1593+
with self.subTest(f'{module}: strict, not fresh'):
1594+
self.check_compatible_here(module, strict=True)
15361595

15371596
@cpython_only
15381597
def test_frozen_compat(self):
15391598
module = '_frozen_importlib'
1599+
require_frozen(module, skip=True)
15401600
if __import__(module).__spec__.origin != 'frozen':
15411601
raise unittest.SkipTest(f'{module} is unexpectedly not frozen')
15421602
with self.subTest(f'{module}: not strict'):
1543-
self.check_compatible_shared(module, strict=False)
1544-
with self.subTest(f'{module}: strict, shared'):
1545-
self.check_compatible_shared(module, strict=True)
1603+
self.check_compatible_here(module, strict=False)
1604+
with self.subTest(f'{module}: strict, not fresh'):
1605+
self.check_compatible_here(module, strict=True)
15461606

15471607
@unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module")
15481608
def test_single_init_extension_compat(self):
15491609
module = '_testsinglephase'
1610+
require_extension(module)
15501611
with self.subTest(f'{module}: not strict'):
1551-
self.check_compatible_shared(module, strict=False)
1552-
with self.subTest(f'{module}: strict, shared'):
1553-
self.check_incompatible_shared(module)
1554-
with self.subTest(f'{module}: strict, isolated'):
1555-
self.check_incompatible_isolated(module)
1612+
self.check_compatible_here(module, strict=False)
1613+
with self.subTest(f'{module}: strict, not fresh'):
1614+
self.check_incompatible_here(module)
1615+
with self.subTest(f'{module}: strict, fresh'):
1616+
self.check_incompatible_fresh(module)
15561617

15571618
@unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module")
15581619
def test_multi_init_extension_compat(self):
15591620
module = '_testmultiphase'
1621+
require_extension(module)
15601622
with self.subTest(f'{module}: not strict'):
1561-
self.check_compatible_shared(module, strict=False)
1562-
with self.subTest(f'{module}: strict, shared'):
1563-
self.check_compatible_shared(module, strict=True)
1564-
with self.subTest(f'{module}: strict, isolated'):
1565-
self.check_compatible_isolated(module, strict=True)
1623+
self.check_compatible_here(module, strict=False)
1624+
with self.subTest(f'{module}: strict, not fresh'):
1625+
self.check_compatible_here(module, strict=True)
1626+
with self.subTest(f'{module}: strict, fresh'):
1627+
self.check_compatible_fresh(module, strict=True)
15661628

15671629
def test_python_compat(self):
15681630
module = 'threading'
1569-
if __import__(module).__spec__.origin == 'frozen':
1570-
raise unittest.SkipTest(f'{module} is unexpectedly frozen')
1631+
require_pure_python(module)
15711632
with self.subTest(f'{module}: not strict'):
1572-
self.check_compatible_shared(module, strict=False)
1573-
with self.subTest(f'{module}: strict, shared'):
1574-
self.check_compatible_shared(module, strict=True)
1575-
with self.subTest(f'{module}: strict, isolated'):
1576-
self.check_compatible_isolated(module, strict=True)
1633+
self.check_compatible_here(module, strict=False)
1634+
with self.subTest(f'{module}: strict, not fresh'):
1635+
self.check_compatible_here(module, strict=True)
1636+
with self.subTest(f'{module}: strict, fresh'):
1637+
self.check_compatible_fresh(module, strict=True)
15771638

15781639
@unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module")
15791640
def test_singlephase_check_with_setting_and_override(self):
15801641
module = '_testsinglephase'
1642+
require_extension(module)
15811643

15821644
def check_compatible(setting, override):
1583-
out = self.run_shared(
1645+
out = self.run_here(
15841646
module,
15851647
check_singlephase_setting=setting,
15861648
check_singlephase_override=override,
15871649
)
15881650
self.assertEqual(out, b'okay')
15891651

15901652
def check_incompatible(setting, override):
1591-
out = self.run_shared(
1653+
out = self.run_here(
15921654
module,
15931655
check_singlephase_setting=setting,
15941656
check_singlephase_override=override,

Lib/typing.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,15 +1903,19 @@ class _TypingEllipsis:
19031903
"""Internal placeholder for ... (ellipsis)."""
19041904

19051905

1906-
_TYPING_INTERNALS = ['__parameters__', '__orig_bases__', '__orig_class__',
1907-
'_is_protocol', '_is_runtime_protocol']
1906+
_TYPING_INTERNALS = frozenset({
1907+
'__parameters__', '__orig_bases__', '__orig_class__',
1908+
'_is_protocol', '_is_runtime_protocol'
1909+
})
19081910

1909-
_SPECIAL_NAMES = ['__abstractmethods__', '__annotations__', '__dict__', '__doc__',
1910-
'__init__', '__module__', '__new__', '__slots__',
1911-
'__subclasshook__', '__weakref__', '__class_getitem__']
1911+
_SPECIAL_NAMES = frozenset({
1912+
'__abstractmethods__', '__annotations__', '__dict__', '__doc__',
1913+
'__init__', '__module__', '__new__', '__slots__',
1914+
'__subclasshook__', '__weakref__', '__class_getitem__'
1915+
})
19121916

19131917
# These special attributes will be not collected as protocol members.
1914-
EXCLUDED_ATTRIBUTES = _TYPING_INTERNALS + _SPECIAL_NAMES + ['_MutableMapping__marker']
1918+
EXCLUDED_ATTRIBUTES = _TYPING_INTERNALS | _SPECIAL_NAMES | {'_MutableMapping__marker'}
19151919

19161920

19171921
def _get_protocol_attrs(cls):
@@ -1922,10 +1926,10 @@ def _get_protocol_attrs(cls):
19221926
"""
19231927
attrs = set()
19241928
for base in cls.__mro__[:-1]: # without object
1925-
if base.__name__ in ('Protocol', 'Generic'):
1929+
if base.__name__ in {'Protocol', 'Generic'}:
19261930
continue
19271931
annotations = getattr(base, '__annotations__', {})
1928-
for attr in list(base.__dict__.keys()) + list(annotations.keys()):
1932+
for attr in (*base.__dict__, *annotations):
19291933
if not attr.startswith('_abc_') and attr not in EXCLUDED_ATTRIBUTES:
19301934
attrs.add(attr)
19311935
return attrs

0 commit comments

Comments
 (0)