Skip to content

Commit ecb313c

Browse files
committed
Merge branch 'main' into inlinecomp2
* main: (37 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 73dc0ed + f105fe4 commit ecb313c

File tree

74 files changed

+891
-760
lines changed

Some content is hidden

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

74 files changed

+891
-760
lines changed

Doc/c-api/buffer.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ Buffer-related functions
499499
This function fails if *len* != *src->len*.
500500
501501
502-
.. c:function:: int PyObject_CopyData(Py_buffer *dest, Py_buffer *src)
502+
.. c:function:: int PyObject_CopyData(PyObject *dest, PyObject *src)
503503
504504
Copy data from *src* to *dest* buffer. Can convert between C-style and
505505
or Fortran-style buffers.

Doc/conf.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@
268268
ogp_site_name = 'Python documentation'
269269
ogp_image = '_static/og-image.png'
270270
ogp_custom_meta_tags = [
271-
'<meta property="og:image:width" content="200">',
272-
'<meta property="og:image:height" content="200">',
273-
'<meta name="theme-color" content="#3776ab">',
271+
'<meta property="og:image:width" content="200" />',
272+
'<meta property="og:image:height" content="200" />',
273+
'<meta name="theme-color" content="#3776ab" />',
274274
]

Doc/library/itertools.rst

+6-3
Original file line numberDiff line numberDiff line change
@@ -886,9 +886,12 @@ which incur interpreter overhead.
886886
except AttributeError:
887887
# Slow path for general iterables
888888
it = islice(iterable, start, None)
889-
for i, element in enumerate(it, start):
890-
if element is value or element == value:
891-
yield i
889+
i = start - 1
890+
try:
891+
while True:
892+
yield (i := i + operator.indexOf(it, value) + 1)
893+
except ValueError:
894+
pass
892895
else:
893896
# Fast path for sequences
894897
i = start - 1

Doc/library/os.rst

+5
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,11 @@ process and user.
201201
``'surrogateescape'`` error handler. Use :data:`environb` if you would like
202202
to use a different encoding.
203203

204+
On Windows, the keys are converted to uppercase. This also applies when
205+
getting, setting, or deleting an item. For example,
206+
``environ['monty'] = 'python'`` maps the key ``'MONTY'`` to the value
207+
``'python'``.
208+
204209
.. note::
205210

206211
Calling :func:`putenv` directly does not change :data:`os.environ`, so it's better

Doc/library/pathlib.rst

+3-2
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/sqlite3.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ including `cursors`_ and `transactions`_.
7272

7373
First, we need to create a new database and open
7474
a database connection to allow :mod:`!sqlite3` to work with it.
75-
Call :func:`sqlite3.connect` to to create a connection to
75+
Call :func:`sqlite3.connect` to create a connection to
7676
the database :file:`tutorial.db` in the current working directory,
7777
implicitly creating it if it does not exist:
7878

Doc/library/stdtypes.rst

+4-2
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

+7
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,13 @@ The :mod:`test.support` module defines the following functions:
536536
:func:`doctest.testmod`.
537537

538538

539+
.. function:: get_pagesize()
540+
541+
Get size of a page in bytes.
542+
543+
.. versionadded:: 3.12
544+
545+
539546
.. function:: setswitchinterval(interval)
540547

541548
Set the :func:`sys.setswitchinterval` to the given *interval*. Defines

Doc/library/typing.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1345,7 +1345,7 @@ These are not used in annotations. They are building blocks for creating generic
13451345

13461346
x: Ts # Not valid
13471347
x: tuple[Ts] # Not valid
1348-
x: tuple[*Ts] # The correct way to to do it
1348+
x: tuple[*Ts] # The correct way to do it
13491349

13501350
Type variable tuples can be used in the same contexts as normal type
13511351
variables. For example, in class definitions, arguments, and return types::

Doc/library/unittest.mock.rst

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ available, and then make assertions about how they have been used:
7272
:attr:`side_effect` allows you to perform side effects, including raising an
7373
exception when a mock is called:
7474

75+
>>> from unittest.mock import Mock
7576
>>> mock = Mock(side_effect=KeyError('foo'))
7677
>>> mock()
7778
Traceback (most recent call last):

Doc/using/configure.rst

+5
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_compile.h

-6
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,6 @@ PyAPI_FUNC(PyCodeObject*) _PyAST_Compile(
1919
int optimize,
2020
struct _arena *arena);
2121

22-
int _PyFuture_FromAST(
23-
struct _mod * mod,
24-
PyObject *filename,
25-
PyFutureFeatures* futures);
26-
27-
extern PyObject* _Py_Mangle(PyObject *p, PyObject *name);
2822

2923
typedef struct {
3024
int optimize;

Include/internal/pycore_pymath.h

-15
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
//

Include/internal/pycore_symtable.h

+7
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ PyAPI_FUNC(PySTEntryObject *) PySymtable_Lookup(struct symtable *, void *);
9191

9292
extern void _PySymtable_Free(struct symtable *);
9393

94+
extern PyObject* _Py_Mangle(PyObject *p, PyObject *name);
95+
9496
/* Flags for def-use information */
9597

9698
#define DEF_GLOBAL 1 /* global stmt */
@@ -129,6 +131,11 @@ extern struct symtable* _Py_SymtableStringObjectFlags(
129131
int start,
130132
PyCompilerFlags *flags);
131133

134+
int _PyFuture_FromAST(
135+
struct _mod * mod,
136+
PyObject *filename,
137+
PyFutureFeatures* futures);
138+
132139
#ifdef __cplusplus
133140
}
134141
#endif

Lib/argparse.py

+10-3
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

+1-1
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

+26-31
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

+16-7
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"

0 commit comments

Comments
 (0)