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

Skip to content

Commit 70a1313

Browse files
committed
Merge branch 'python:main' into main
2 parents f6f52bc + 2544159 commit 70a1313

27 files changed

Lines changed: 299 additions & 28 deletions

Doc/library/inspect.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,13 @@ attributes (see :ref:`import-mod-attrs` for module attributes):
374374
Return ``True`` if the object is a bound method written in Python.
375375

376376

377+
.. function:: ispackage(object)
378+
379+
Return ``True`` if the object is a :term:`package`.
380+
381+
.. versionadded:: 3.14
382+
383+
377384
.. function:: isfunction(object)
378385

379386
Return ``True`` if the object is a Python function, which includes functions

Doc/library/stdtypes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3889,6 +3889,9 @@ copying.
38893889
.. versionchanged:: 3.5
38903890
memoryviews can now be indexed with tuple of integers.
38913891

3892+
.. versionchanged:: next
3893+
memoryview is now a :term:`generic type`.
3894+
38923895
:class:`memoryview` has several methods:
38933896

38943897
.. method:: __eq__(exporter)

Doc/whatsnew/3.14.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ Other language changes
194194
:mod:`copyable <copy>`.
195195
(Contributed by Serhiy Storchaka in :gh:`125767`.)
196196

197+
* The :class:`memoryview` type now supports subscription,
198+
making it a :term:`generic type`.
199+
(Contributed by Brian Schubert in :gh:`126012`.)
200+
197201

198202
New modules
199203
===========
@@ -326,6 +330,10 @@ inspect
326330
If true, string :term:`annotations <annotation>` are displayed without surrounding quotes.
327331
(Contributed by Jelle Zijlstra in :gh:`101552`.)
328332

333+
* Add function :func:`inspect.ispackage` to determine whether an object is a
334+
:term:`package` or not.
335+
(Contributed by Zhikang Yan in :gh:`125634`.)
336+
329337

330338
json
331339
----

Include/internal/pycore_opcode_metadata.h

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

Lib/inspect.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
77
Here are some of the useful functions provided by this module:
88
9-
ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(),
10-
isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(),
11-
isroutine() - check object types
9+
ismodule(), isclass(), ismethod(), ispackage(), isfunction(),
10+
isgeneratorfunction(), isgenerator(), istraceback(), isframe(),
11+
iscode(), isbuiltin(), isroutine() - check object types
1212
getmembers() - get members of an object that satisfy a given condition
1313
1414
getfile(), getsourcefile(), getsource() - find an object's source code
@@ -128,6 +128,7 @@
128128
"ismethoddescriptor",
129129
"ismethodwrapper",
130130
"ismodule",
131+
"ispackage",
131132
"isroutine",
132133
"istraceback",
133134
"markcoroutinefunction",
@@ -186,6 +187,10 @@ def ismethod(object):
186187
"""Return true if the object is an instance method."""
187188
return isinstance(object, types.MethodType)
188189

190+
def ispackage(object):
191+
"""Return true if the object is a package."""
192+
return ismodule(object) and hasattr(object, "__path__")
193+
189194
def ismethoddescriptor(object):
190195
"""Return true if the object is a method descriptor.
191196

Lib/test/audit-tests.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,17 @@ def hook(event, args):
567567
_winapi.CreateNamedPipe(pipe_name, _winapi.PIPE_ACCESS_DUPLEX, 8, 2, 0, 0, 0, 0)
568568

569569

570+
def test_assert_unicode():
571+
import sys
572+
sys.addaudithook(lambda *args: None)
573+
try:
574+
sys.audit(9)
575+
except TypeError:
576+
pass
577+
else:
578+
raise RuntimeError("Expected sys.audit(9) to fail.")
579+
580+
570581
if __name__ == "__main__":
571582
from test.support import suppress_msvcrt_asserts
572583

Lib/test/test_argparse.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
import operator
88
import os
99
import py_compile
10+
import re
1011
import shutil
1112
import stat
13+
import subprocess
1214
import sys
1315
import textwrap
1416
import tempfile
@@ -17,10 +19,15 @@
1719
import warnings
1820

1921
from enum import StrEnum
22+
from pathlib import Path
23+
from test.support import REPO_ROOT
24+
from test.support import TEST_HOME_DIR
2025
from test.support import captured_stderr
2126
from test.support import import_helper
2227
from test.support import os_helper
28+
from test.support import requires_subprocess
2329
from test.support import script_helper
30+
from test.test_tools import skip_if_missing
2431
from unittest import mock
2532

2633

@@ -7014,6 +7021,55 @@ def test_directory_in_zipfile(self, compiled=False):
70147021
def test_directory_in_zipfile_compiled(self):
70157022
self.test_directory_in_zipfile(compiled=True)
70167023

7024+
# =================
7025+
# Translation tests
7026+
# =================
7027+
7028+
pygettext = Path(REPO_ROOT) / 'Tools' / 'i18n' / 'pygettext.py'
7029+
snapshot_path = Path(TEST_HOME_DIR) / 'translationdata' / 'argparse' / 'msgids.txt'
7030+
7031+
msgid_pattern = re.compile(r'msgid(.*?)(?:msgid_plural|msgctxt|msgstr)', re.DOTALL)
7032+
msgid_string_pattern = re.compile(r'"((?:\\"|[^"])*)"')
7033+
7034+
7035+
@requires_subprocess()
7036+
class TestTranslations(unittest.TestCase):
7037+
7038+
def test_translations(self):
7039+
# Test messages extracted from the argparse module against a snapshot
7040+
skip_if_missing('i18n')
7041+
res = generate_po_file(stdout_only=False)
7042+
self.assertEqual(res.returncode, 0)
7043+
self.assertEqual(res.stderr, '')
7044+
msgids = extract_msgids(res.stdout)
7045+
snapshot = snapshot_path.read_text().splitlines()
7046+
self.assertListEqual(msgids, snapshot)
7047+
7048+
7049+
def generate_po_file(*, stdout_only=True):
7050+
res = subprocess.run([sys.executable, pygettext,
7051+
'--no-location', '-o', '-', argparse.__file__],
7052+
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
7053+
if stdout_only:
7054+
return res.stdout
7055+
return res
7056+
7057+
7058+
def extract_msgids(po):
7059+
msgids = []
7060+
for msgid in msgid_pattern.findall(po):
7061+
msgid_string = ''.join(msgid_string_pattern.findall(msgid))
7062+
msgid_string = msgid_string.replace(r'\"', '"')
7063+
if msgid_string:
7064+
msgids.append(msgid_string)
7065+
return sorted(msgids)
7066+
7067+
7068+
def update_translation_snapshots():
7069+
contents = generate_po_file()
7070+
msgids = extract_msgids(contents)
7071+
snapshot_path.write_text('\n'.join(msgids))
7072+
70177073

70187074
def tearDownModule():
70197075
# Remove global references to avoid looking like we have refleaks.
@@ -7022,4 +7078,8 @@ def tearDownModule():
70227078

70237079

70247080
if __name__ == '__main__':
7081+
# To regenerate translation snapshots
7082+
if len(sys.argv) > 1 and sys.argv[1] == '--snapshot-update':
7083+
update_translation_snapshots()
7084+
sys.exit(0)
70257085
unittest.main()

Lib/test/test_asyncio/test_futures.py

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,25 @@ def last_cb():
3232
pass
3333

3434

35+
class ReachableCode(Exception):
36+
"""Exception to raise to indicate that some code was reached.
37+
38+
Use this exception if using mocks is not a good alternative.
39+
"""
40+
41+
42+
class SimpleEvilEventLoop(asyncio.base_events.BaseEventLoop):
43+
"""Base class for UAF and other evil stuff requiring an evil event loop."""
44+
45+
def get_debug(self): # to suppress tracebacks
46+
return False
47+
48+
def __del__(self):
49+
# Automatically close the evil event loop to avoid warnings.
50+
if not self.is_closed() and not self.is_running():
51+
self.close()
52+
53+
3554
class DuckFuture:
3655
# Class that does not inherit from Future but aims to be duck-type
3756
# compatible with it.
@@ -948,6 +967,7 @@ def __eq__(self, other):
948967
fut.remove_done_callback(evil())
949968

950969
def test_evil_call_soon_list_mutation(self):
970+
# see: https://github.com/python/cpython/issues/125969
951971
called_on_fut_callback0 = False
952972

953973
pad = lambda: ...
@@ -962,9 +982,8 @@ def evil_call_soon(*args, **kwargs):
962982
else:
963983
called_on_fut_callback0 = True
964984

965-
fake_event_loop = lambda: ...
985+
fake_event_loop = SimpleEvilEventLoop()
966986
fake_event_loop.call_soon = evil_call_soon
967-
fake_event_loop.get_debug = lambda: False # suppress traceback
968987

969988
with mock.patch.object(self, 'loop', fake_event_loop):
970989
fut = self._new_future()
@@ -980,6 +999,74 @@ def evil_call_soon(*args, **kwargs):
980999
# returns an empty list but the C implementation returns None.
9811000
self.assertIn(fut._callbacks, (None, []))
9821001

1002+
def test_use_after_free_on_fut_callback_0_with_evil__eq__(self):
1003+
# Special thanks to Nico-Posada for the original PoC.
1004+
# See https://github.com/python/cpython/issues/125966.
1005+
1006+
fut = self._new_future()
1007+
1008+
class cb_pad:
1009+
def __eq__(self, other):
1010+
return True
1011+
1012+
class evil(cb_pad):
1013+
def __eq__(self, other):
1014+
fut.remove_done_callback(None)
1015+
return NotImplemented
1016+
1017+
fut.add_done_callback(cb_pad())
1018+
fut.remove_done_callback(evil())
1019+
1020+
def test_use_after_free_on_fut_callback_0_with_evil__getattribute__(self):
1021+
# see: https://github.com/python/cpython/issues/125984
1022+
1023+
class EvilEventLoop(SimpleEvilEventLoop):
1024+
def call_soon(self, *args, **kwargs):
1025+
super().call_soon(*args, **kwargs)
1026+
raise ReachableCode
1027+
1028+
def __getattribute__(self, name):
1029+
nonlocal fut_callback_0
1030+
if name == 'call_soon':
1031+
fut.remove_done_callback(fut_callback_0)
1032+
del fut_callback_0
1033+
return object.__getattribute__(self, name)
1034+
1035+
evil_loop = EvilEventLoop()
1036+
with mock.patch.object(self, 'loop', evil_loop):
1037+
fut = self._new_future()
1038+
self.assertIs(fut.get_loop(), evil_loop)
1039+
1040+
fut_callback_0 = lambda: ...
1041+
fut.add_done_callback(fut_callback_0)
1042+
self.assertRaises(ReachableCode, fut.set_result, "boom")
1043+
1044+
def test_use_after_free_on_fut_context_0_with_evil__getattribute__(self):
1045+
# see: https://github.com/python/cpython/issues/125984
1046+
1047+
class EvilEventLoop(SimpleEvilEventLoop):
1048+
def call_soon(self, *args, **kwargs):
1049+
super().call_soon(*args, **kwargs)
1050+
raise ReachableCode
1051+
1052+
def __getattribute__(self, name):
1053+
if name == 'call_soon':
1054+
# resets the future's event loop
1055+
fut.__init__(loop=SimpleEvilEventLoop())
1056+
return object.__getattribute__(self, name)
1057+
1058+
evil_loop = EvilEventLoop()
1059+
with mock.patch.object(self, 'loop', evil_loop):
1060+
fut = self._new_future()
1061+
self.assertIs(fut.get_loop(), evil_loop)
1062+
1063+
fut_callback_0 = mock.Mock()
1064+
fut_context_0 = mock.Mock()
1065+
fut.add_done_callback(fut_callback_0, context=fut_context_0)
1066+
del fut_context_0
1067+
del fut_callback_0
1068+
self.assertRaises(ReachableCode, fut.set_result, "boom")
1069+
9831070

9841071
@unittest.skipUnless(hasattr(futures, '_CFuture'),
9851072
'requires the C _asyncio module')

Lib/test/test_audit.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,5 +307,12 @@ def test_winapi_createnamedpipe(self):
307307

308308
self.assertEqual(actual, expected)
309309

310+
def test_assert_unicode(self):
311+
# See gh-126018
312+
returncode, _, stderr = self.run_python("test_assert_unicode")
313+
if returncode:
314+
self.fail(stderr)
315+
316+
310317
if __name__ == "__main__":
311318
unittest.main()

Lib/test/test_genericalias.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100

101101
class BaseTest(unittest.TestCase):
102102
"""Test basics."""
103-
generic_types = [type, tuple, list, dict, set, frozenset, enumerate,
103+
generic_types = [type, tuple, list, dict, set, frozenset, enumerate, memoryview,
104104
defaultdict, deque,
105105
SequenceMatcher,
106106
dircmp,

0 commit comments

Comments
 (0)