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 33dda2a

Browse filesBrowse files
committed
Merge branch 'main' into nodeaddict
* main: (21 commits) pythongh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives in sub interpreters module (python#102472) pythongh-95672: Fix versionadded indentation of get_pagesize in test.rst (pythongh-102455) pythongh-102416: Do not memoize incorrectly loop rules in the parser (python#102467) pythonGH-101362: Optimise PurePath(PurePath(...)) (pythonGH-101667) pythonGH-101362: Check pathlib.Path flavour compatibility at import time (pythonGH-101664) pythonGH-101362: Call join() only when >1 argument supplied to pathlib.PurePath() (python#101665) pythongh-102444: Fix minor bugs in `test_typing` highlighted by pyflakes (python#102445) pythonGH-102341: Improve the test function for pow (python#102342) Fix unused classes in a typing test (pythonGH-102437) pythongh-101979: argparse: fix a bug where parentheses in metavar argument of add_argument() were dropped (python#102318) pythongh-102356: Add thrashcan macros to filter object dealloc (python#102426) Move around example in to_bytes() to avoid confusion (python#101595) pythonGH-97546: fix flaky asyncio `test_wait_for_race_condition` test (python#102421) pythongh-96821: Add config option `--with-strict-overflow` (python#96823) pythongh-101992: update pstlib module documentation (python#102133) pythongh-63301: Set exit code when tabnanny CLI exits on error (python#7699) pythongh-101863: Fix wrong comments in EUC-KR codec (pythongh-102417) pythongh-102302 Micro-optimize `inspect.Parameter.__hash__` (python#102303) pythongh-102179: Fix `os.dup2` error reporting for negative fds (python#102180) pythongh-101892: Fix `SystemError` when a callable iterator call exhausts the iterator (python#101896) ...
2 parents 4894127 + f105fe4 commit 33dda2a
Copy full SHA for 33dda2a
Expand file treeCollapse file tree

40 files changed

+355
-362
lines changed

‎Doc/library/pathlib.rst

Copy file name to clipboardExpand all lines: Doc/library/pathlib.rst
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ we also call *flavours*:
105105
PurePosixPath('setup.py')
106106

107107
Each element of *pathsegments* can be either a string representing a
108-
path segment, an object implementing the :class:`os.PathLike` interface
109-
which returns a string, or another path object::
108+
path segment, or an object implementing the :class:`os.PathLike` interface
109+
where the :meth:`~os.PathLike.__fspath__` method returns a string,
110+
such as another path object::
110111

111112
>>> PurePath('foo', 'some/path', 'bar')
112113
PurePosixPath('foo/some/path/bar')

‎Doc/library/stdtypes.rst

Copy file name to clipboardExpand all lines: Doc/library/stdtypes.rst
+4-2Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,12 +530,14 @@ class`. In addition, it provides a few more methods:
530530
is ``False``.
531531

532532
The default values can be used to conveniently turn an integer into a
533-
single byte object. However, when using the default arguments, don't try
534-
to convert a value greater than 255 or you'll get an :exc:`OverflowError`::
533+
single byte object::
535534

536535
>>> (65).to_bytes()
537536
b'A'
538537

538+
However, when using the default arguments, don't try
539+
to convert a value greater than 255 or you'll get an :exc:`OverflowError`.
540+
539541
Equivalent to::
540542

541543
def to_bytes(n, length=1, byteorder='big', signed=False):

‎Doc/library/test.rst

Copy file name to clipboardExpand all lines: Doc/library/test.rst
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ The :mod:`test.support` module defines the following functions:
540540

541541
Get size of a page in bytes.
542542

543-
.. versionadded:: 3.12
543+
.. versionadded:: 3.12
544544

545545

546546
.. function:: setswitchinterval(interval)

‎Doc/using/configure.rst

Copy file name to clipboardExpand all lines: Doc/using/configure.rst
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,11 @@ also be used to improve performance.
326326

327327
Enable C-level code profiling with ``gprof`` (disabled by default).
328328

329+
.. cmdoption:: --with-strict-overflow
330+
331+
Add ``-fstrict-overflow`` to the C compiler flags (by default we add
332+
``-fno-strict-overflow`` instead).
333+
329334

330335
.. _debug-build:
331336

‎Include/internal/pycore_pymath.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_pymath.h
-15Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,6 @@ static inline void _Py_ADJUST_ERANGE2(double x, double y)
5656
}
5757
}
5858

59-
// Return the maximum value of integral type *type*.
60-
#define _Py_IntegralTypeMax(type) \
61-
(_Py_IS_TYPE_SIGNED(type) ? (((((type)1 << (sizeof(type)*CHAR_BIT - 2)) - 1) << 1) + 1) : ~(type)0)
62-
63-
// Return the minimum value of integral type *type*.
64-
#define _Py_IntegralTypeMin(type) \
65-
(_Py_IS_TYPE_SIGNED(type) ? -_Py_IntegralTypeMax(type) - 1 : 0)
66-
67-
// Check whether *v* is in the range of integral type *type*. This is most
68-
// useful if *v* is floating-point, since demoting a floating-point *v* to an
69-
// integral type that cannot represent *v*'s integral part is undefined
70-
// behavior.
71-
#define _Py_InIntegralTypeRange(type, v) \
72-
(_Py_IntegralTypeMin(type) <= v && v <= _Py_IntegralTypeMax(type))
73-
7459

7560
//--- HAVE_PY_SET_53BIT_PRECISION macro ------------------------------------
7661
//

‎Lib/argparse.py

Copy file name to clipboardExpand all lines: Lib/argparse.py
+10-3Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -403,10 +403,18 @@ def _format_actions_usage(self, actions, groups):
403403
except ValueError:
404404
continue
405405
else:
406-
end = start + len(group._group_actions)
406+
group_action_count = len(group._group_actions)
407+
end = start + group_action_count
407408
if actions[start:end] == group._group_actions:
409+
410+
suppressed_actions_count = 0
408411
for action in group._group_actions:
409412
group_actions.add(action)
413+
if action.help is SUPPRESS:
414+
suppressed_actions_count += 1
415+
416+
exposed_actions_count = group_action_count - suppressed_actions_count
417+
410418
if not group.required:
411419
if start in inserts:
412420
inserts[start] += ' ['
@@ -416,7 +424,7 @@ def _format_actions_usage(self, actions, groups):
416424
inserts[end] += ']'
417425
else:
418426
inserts[end] = ']'
419-
else:
427+
elif exposed_actions_count > 1:
420428
if start in inserts:
421429
inserts[start] += ' ('
422430
else:
@@ -490,7 +498,6 @@ def _format_actions_usage(self, actions, groups):
490498
text = _re.sub(r'(%s) ' % open, r'\1', text)
491499
text = _re.sub(r' (%s)' % close, r'\1', text)
492500
text = _re.sub(r'%s *%s' % (open, close), r'', text)
493-
text = _re.sub(r'\(([^|]*)\)', r'\1', text)
494501
text = text.strip()
495502

496503
# return the text

‎Lib/inspect.py

Copy file name to clipboardExpand all lines: Lib/inspect.py
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2805,7 +2805,7 @@ def __repr__(self):
28052805
return '<{} "{}">'.format(self.__class__.__name__, self)
28062806

28072807
def __hash__(self):
2808-
return hash((self.name, self.kind, self.annotation, self.default))
2808+
return hash((self._name, self._kind, self._annotation, self._default))
28092809

28102810
def __eq__(self, other):
28112811
if self is other:

‎Lib/pathlib.py

Copy file name to clipboardExpand all lines: Lib/pathlib.py
+26-31Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,20 @@ def __reduce__(self):
275275
def _parse_parts(cls, parts):
276276
if not parts:
277277
return '', '', []
278+
elif len(parts) == 1:
279+
path = os.fspath(parts[0])
280+
else:
281+
path = cls._flavour.join(*parts)
278282
sep = cls._flavour.sep
279283
altsep = cls._flavour.altsep
280-
path = cls._flavour.join(*parts)
284+
if isinstance(path, str):
285+
# Force-cast str subclasses to str (issue #21127)
286+
path = str(path)
287+
else:
288+
raise TypeError(
289+
"argument should be a str or an os.PathLike "
290+
"object where __fspath__ returns a str, "
291+
f"not {type(path).__name__!r}")
281292
if altsep:
282293
path = path.replace(altsep, sep)
283294
drv, root, rel = cls._flavour.splitroot(path)
@@ -288,32 +299,10 @@ def _parse_parts(cls, parts):
288299
parsed = [sys.intern(x) for x in unfiltered_parsed if x and x != '.']
289300
return drv, root, parsed
290301

291-
@classmethod
292-
def _parse_args(cls, args):
293-
# This is useful when you don't want to create an instance, just
294-
# canonicalize some constructor arguments.
295-
parts = []
296-
for a in args:
297-
if isinstance(a, PurePath):
298-
parts += a._parts
299-
else:
300-
a = os.fspath(a)
301-
if isinstance(a, str):
302-
# Force-cast str subclasses to str (issue #21127)
303-
parts.append(str(a))
304-
else:
305-
raise TypeError(
306-
"argument should be a str object or an os.PathLike "
307-
"object returning str, not %r"
308-
% type(a))
309-
return cls._parse_parts(parts)
310-
311302
@classmethod
312303
def _from_parts(cls, args):
313-
# We need to call _parse_args on the instance, so as to get the
314-
# right flavour.
315304
self = object.__new__(cls)
316-
drv, root, parts = self._parse_args(args)
305+
drv, root, parts = self._parse_parts(args)
317306
self._drv = drv
318307
self._root = root
319308
self._parts = parts
@@ -572,7 +561,7 @@ def joinpath(self, *args):
572561
anchored).
573562
"""
574563
drv1, root1, parts1 = self._drv, self._root, self._parts
575-
drv2, root2, parts2 = self._parse_args(args)
564+
drv2, root2, parts2 = self._parse_parts(args)
576565
if root2:
577566
if not drv2 and drv1:
578567
return self._from_parsed_parts(drv1, root2, [drv1 + root2] + parts2[1:])
@@ -659,7 +648,7 @@ def match(self, path_pattern):
659648
return True
660649

661650
# Can't subclass os.PathLike from PurePath and keep the constructor
662-
# optimizations in PurePath._parse_args().
651+
# optimizations in PurePath.__slots__.
663652
os.PathLike.register(PurePath)
664653

665654

@@ -704,11 +693,7 @@ def __new__(cls, *args, **kwargs):
704693
warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14))
705694
if cls is Path:
706695
cls = WindowsPath if os.name == 'nt' else PosixPath
707-
self = cls._from_parts(args)
708-
if self._flavour is not os.path:
709-
raise NotImplementedError("cannot instantiate %r on your system"
710-
% (cls.__name__,))
711-
return self
696+
return cls._from_parts(args)
712697

713698
def _make_child_relpath(self, part):
714699
# This is an optimization used for dir walking. `part` must be
@@ -1258,9 +1243,19 @@ class PosixPath(Path, PurePosixPath):
12581243
"""
12591244
__slots__ = ()
12601245

1246+
if os.name == 'nt':
1247+
def __new__(cls, *args, **kwargs):
1248+
raise NotImplementedError(
1249+
f"cannot instantiate {cls.__name__!r} on your system")
1250+
12611251
class WindowsPath(Path, PureWindowsPath):
12621252
"""Path subclass for Windows systems.
12631253
12641254
On a Windows system, instantiating a Path should return this object.
12651255
"""
12661256
__slots__ = ()
1257+
1258+
if os.name != 'nt':
1259+
def __new__(cls, *args, **kwargs):
1260+
raise NotImplementedError(
1261+
f"cannot instantiate {cls.__name__!r} on your system")

‎Lib/plistlib.py

Copy file name to clipboardExpand all lines: Lib/plistlib.py
+16-7Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,38 @@
2121
2222
Generate Plist example:
2323
24+
import datetime
25+
import plistlib
26+
2427
pl = dict(
2528
aString = "Doodah",
2629
aList = ["A", "B", 12, 32.1, [1, 2, 3]],
2730
aFloat = 0.1,
2831
anInt = 728,
2932
aDict = dict(
3033
anotherString = "<hello & hi there!>",
31-
aUnicodeValue = "M\xe4ssig, Ma\xdf",
34+
aThirdString = "M\xe4ssig, Ma\xdf",
3235
aTrueValue = True,
3336
aFalseValue = False,
3437
),
3538
someData = b"<binary gunk>",
3639
someMoreData = b"<lots of binary gunk>" * 10,
37-
aDate = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())),
40+
aDate = datetime.datetime.now()
3841
)
39-
with open(fileName, 'wb') as fp:
40-
dump(pl, fp)
42+
print(plistlib.dumps(pl).decode())
4143
4244
Parse Plist example:
4345
44-
with open(fileName, 'rb') as fp:
45-
pl = load(fp)
46-
print(pl["aKey"])
46+
import plistlib
47+
48+
plist = b'''<plist version="1.0">
49+
<dict>
50+
<key>foo</key>
51+
<string>bar</string>
52+
</dict>
53+
</plist>'''
54+
pl = plistlib.loads(plist)
55+
print(pl["foo"])
4756
"""
4857
__all__ = [
4958
"InvalidFileException", "FMT_XML", "FMT_BINARY", "load", "dump", "loads", "dumps", "UID"

‎Lib/tabnanny.py

Copy file name to clipboardExpand all lines: Lib/tabnanny.py
+1-2Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def errprint(*args):
3535
sys.stderr.write(sep + str(arg))
3636
sep = " "
3737
sys.stderr.write("\n")
38+
sys.exit(1)
3839

3940
def main():
4041
import getopt
@@ -44,15 +45,13 @@ def main():
4445
opts, args = getopt.getopt(sys.argv[1:], "qv")
4546
except getopt.error as msg:
4647
errprint(msg)
47-
return
4848
for o, a in opts:
4949
if o == '-q':
5050
filename_only = filename_only + 1
5151
if o == '-v':
5252
verbose = verbose + 1
5353
if not args:
5454
errprint("Usage:", sys.argv[0], "[-v] file_or_directory ...")
55-
return
5655
for arg in args:
5756
check(arg)
5857

‎Lib/test/test_argparse.py

Copy file name to clipboardExpand all lines: Lib/test/test_argparse.py
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3764,6 +3764,28 @@ class TestHelpUsage(HelpTestCase):
37643764
version = ''
37653765

37663766

3767+
class TestHelpUsageWithParentheses(HelpTestCase):
3768+
parser_signature = Sig(prog='PROG')
3769+
argument_signatures = [
3770+
Sig('positional', metavar='(example) positional'),
3771+
Sig('-p', '--optional', metavar='{1 (option A), 2 (option B)}'),
3772+
]
3773+
3774+
usage = '''\
3775+
usage: PROG [-h] [-p {1 (option A), 2 (option B)}] (example) positional
3776+
'''
3777+
help = usage + '''\
3778+
3779+
positional arguments:
3780+
(example) positional
3781+
3782+
options:
3783+
-h, --help show this help message and exit
3784+
-p {1 (option A), 2 (option B)}, --optional {1 (option A), 2 (option B)}
3785+
'''
3786+
version = ''
3787+
3788+
37673789
class TestHelpOnlyUserGroups(HelpTestCase):
37683790
"""Test basic usage messages"""
37693791

‎Lib/test/test_asyncio/test_waitfor.py

Copy file name to clipboardExpand all lines: Lib/test/test_asyncio/test_waitfor.py
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ async def test_wait_for_race_condition(self):
159159

160160
fut = loop.create_future()
161161
task = asyncio.wait_for(fut, timeout=0.2)
162-
loop.call_later(0.1, fut.set_result, "ok")
162+
loop.call_soon(fut.set_result, "ok")
163163
res = await task
164164
self.assertEqual(res, "ok")
165165

‎Lib/test/test_builtin.py

Copy file name to clipboardExpand all lines: Lib/test/test_builtin.py
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,16 @@ def test_filter_pickle(self):
926926
f2 = filter(filter_char, "abcdeabcde")
927927
self.check_iter_pickle(f1, list(f2), proto)
928928

929+
def test_filter_dealloc(self):
930+
# Tests recursive deallocation of nested filter objects using the
931+
# thrashcan mechanism. See gh-102356 for more details.
932+
max_iters = 1000000
933+
i = filter(bool, range(max_iters))
934+
for _ in range(max_iters):
935+
i = filter(bool, i)
936+
del i
937+
gc.collect()
938+
929939
def test_getattr(self):
930940
self.assertTrue(getattr(sys, 'stdout') is sys.stdout)
931941
self.assertRaises(TypeError, getattr)

‎Lib/test/test_iter.py

Copy file name to clipboardExpand all lines: Lib/test/test_iter.py
+25Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,31 @@ def spam(state=[0]):
348348
return i
349349
self.check_iterator(iter(spam, 20), list(range(10)), pickle=False)
350350

351+
def test_iter_function_concealing_reentrant_exhaustion(self):
352+
# gh-101892: Test two-argument iter() with a function that
353+
# exhausts its associated iterator but forgets to either return
354+
# a sentinel value or raise StopIteration.
355+
HAS_MORE = 1
356+
NO_MORE = 2
357+
358+
def exhaust(iterator):
359+
"""Exhaust an iterator without raising StopIteration."""
360+
list(iterator)
361+
362+
def spam():
363+
# Touching the iterator with exhaust() below will call
364+
# spam() once again so protect against recursion.
365+
if spam.is_recursive_call:
366+
return NO_MORE
367+
spam.is_recursive_call = True
368+
exhaust(spam.iterator)
369+
return HAS_MORE
370+
371+
spam.is_recursive_call = False
372+
spam.iterator = iter(spam, NO_MORE)
373+
with self.assertRaises(StopIteration):
374+
next(spam.iterator)
375+
351376
# Test exception propagation through function iterator
352377
def test_exception_function(self):
353378
def spam(state=[0]):

0 commit comments

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