Skip to content

Commit 8cda849

Browse files
authored
Merge branch 'main' into gh-128571-codecs-doc
2 parents f5923e3 + 58c44c2 commit 8cda849

22 files changed

+281
-131
lines changed

Doc/c-api/long.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
4343
.. impl-detail::
4444
4545
CPython keeps an array of integer objects for all integers
46-
between ``-5`` and ``256``. When you create an int in that range
46+
between ``-5`` and ``1024``. When you create an int in that range
4747
you actually just get back a reference to the existing object.
4848
4949

Doc/library/warnings.rst

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -480,14 +480,21 @@ Available Functions
480480
.. function:: warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None)
481481

482482
This is a low-level interface to the functionality of :func:`warn`, passing in
483-
explicitly the message, category, filename and line number, and optionally the
484-
module name and the registry (which should be the ``__warningregistry__``
485-
dictionary of the module). The module name defaults to the filename with
486-
``.py`` stripped; if no registry is passed, the warning is never suppressed.
483+
explicitly the message, category, filename and line number, and optionally
484+
other arguments.
487485
*message* must be a string and *category* a subclass of :exc:`Warning` or
488486
*message* may be a :exc:`Warning` instance, in which case *category* will be
489487
ignored.
490488

489+
*module*, if supplied, should be the module name.
490+
If no module is passed, the filename with ``.py`` stripped is used.
491+
492+
*registry*, if supplied, should be the ``__warningregistry__`` dictionary
493+
of the module.
494+
If no registry is passed, each warning is treated as the first occurrence,
495+
that is, filter actions ``"default"``, ``"module"`` and ``"once"`` are
496+
handled as ``"always"``.
497+
491498
*module_globals*, if supplied, should be the global namespace in use by the code
492499
for which the warning is issued. (This argument is used to support displaying
493500
source for modules found in zipfiles or other non-filesystem import

Include/internal/pycore_interp_structs.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -769,12 +769,6 @@ struct _is {
769769
* and should be placed at the beginning. */
770770
struct _ceval_state ceval;
771771

772-
/* This structure is carefully allocated so that it's correctly aligned
773-
* to avoid undefined behaviors during LOAD and STORE. The '_malloced'
774-
* field stores the allocated pointer address that will later be freed.
775-
*/
776-
void *_malloced;
777-
778772
PyInterpreterState *next;
779773

780774
int64_t id;

Lib/pathlib/__init__.py

Lines changed: 60 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -611,72 +611,29 @@ class PureWindowsPath(PurePath):
611611
__slots__ = ()
612612

613613

614-
class _Info:
615-
__slots__ = ('_path',)
616-
617-
def __init__(self, path):
618-
self._path = path
619-
620-
def __repr__(self):
621-
path_type = "WindowsPath" if os.name == "nt" else "PosixPath"
622-
return f"<{path_type}.info>"
623-
624-
def _stat(self, *, follow_symlinks=True):
625-
"""Return the status as an os.stat_result."""
626-
raise NotImplementedError
627-
628-
def _posix_permissions(self, *, follow_symlinks=True):
629-
"""Return the POSIX file permissions."""
630-
return S_IMODE(self._stat(follow_symlinks=follow_symlinks).st_mode)
631-
632-
def _file_id(self, *, follow_symlinks=True):
633-
"""Returns the identifier of the file."""
634-
st = self._stat(follow_symlinks=follow_symlinks)
635-
return st.st_dev, st.st_ino
636-
637-
def _access_time_ns(self, *, follow_symlinks=True):
638-
"""Return the access time in nanoseconds."""
639-
return self._stat(follow_symlinks=follow_symlinks).st_atime_ns
640-
641-
def _mod_time_ns(self, *, follow_symlinks=True):
642-
"""Return the modify time in nanoseconds."""
643-
return self._stat(follow_symlinks=follow_symlinks).st_mtime_ns
644-
645-
if hasattr(os.stat_result, 'st_flags'):
646-
def _bsd_flags(self, *, follow_symlinks=True):
647-
"""Return the flags."""
648-
return self._stat(follow_symlinks=follow_symlinks).st_flags
649-
650-
if hasattr(os, 'listxattr'):
651-
def _xattrs(self, *, follow_symlinks=True):
652-
"""Return the xattrs as a list of (attr, value) pairs, or an empty
653-
list if extended attributes aren't supported."""
654-
try:
655-
return [
656-
(attr, os.getxattr(self._path, attr, follow_symlinks=follow_symlinks))
657-
for attr in os.listxattr(self._path, follow_symlinks=follow_symlinks)]
658-
except OSError as err:
659-
if err.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES):
660-
raise
661-
return []
662-
663-
664614
_STAT_RESULT_ERROR = [] # falsy sentinel indicating stat() failed.
665615

666616

667-
class _StatResultInfo(_Info):
617+
class _Info:
668618
"""Implementation of pathlib.types.PathInfo that provides status
669619
information by querying a wrapped os.stat_result object. Don't try to
670620
construct it yourself."""
671-
__slots__ = ('_stat_result', '_lstat_result')
621+
__slots__ = ('_path', '_entry', '_stat_result', '_lstat_result')
672622

673-
def __init__(self, path):
674-
super().__init__(path)
623+
def __init__(self, path, entry=None):
624+
self._path = path
625+
self._entry = entry
675626
self._stat_result = None
676627
self._lstat_result = None
677628

629+
def __repr__(self):
630+
path_type = "WindowsPath" if os.name == "nt" else "PosixPath"
631+
return f"<{path_type}.info>"
632+
678633
def _stat(self, *, follow_symlinks=True):
679634
"""Return the status as an os.stat_result."""
635+
if self._entry:
636+
return self._entry.stat(follow_symlinks=follow_symlinks)
680637
if follow_symlinks:
681638
if not self._stat_result:
682639
try:
@@ -696,6 +653,9 @@ def _stat(self, *, follow_symlinks=True):
696653

697654
def exists(self, *, follow_symlinks=True):
698655
"""Whether this path exists."""
656+
if self._entry:
657+
if not follow_symlinks:
658+
return True
699659
if follow_symlinks:
700660
if self._stat_result is _STAT_RESULT_ERROR:
701661
return False
@@ -710,6 +670,11 @@ def exists(self, *, follow_symlinks=True):
710670

711671
def is_dir(self, *, follow_symlinks=True):
712672
"""Whether this path is a directory."""
673+
if self._entry:
674+
try:
675+
return self._entry.is_dir(follow_symlinks=follow_symlinks)
676+
except OSError:
677+
return False
713678
if follow_symlinks:
714679
if self._stat_result is _STAT_RESULT_ERROR:
715680
return False
@@ -724,6 +689,11 @@ def is_dir(self, *, follow_symlinks=True):
724689

725690
def is_file(self, *, follow_symlinks=True):
726691
"""Whether this path is a regular file."""
692+
if self._entry:
693+
try:
694+
return self._entry.is_file(follow_symlinks=follow_symlinks)
695+
except OSError:
696+
return False
727697
if follow_symlinks:
728698
if self._stat_result is _STAT_RESULT_ERROR:
729699
return False
@@ -738,6 +708,11 @@ def is_file(self, *, follow_symlinks=True):
738708

739709
def is_symlink(self):
740710
"""Whether this path is a symbolic link."""
711+
if self._entry:
712+
try:
713+
return self._entry.is_symlink()
714+
except OSError:
715+
return False
741716
if self._lstat_result is _STAT_RESULT_ERROR:
742717
return False
743718
try:
@@ -746,51 +721,40 @@ def is_symlink(self):
746721
return False
747722
return S_ISLNK(st.st_mode)
748723

724+
def _posix_permissions(self, *, follow_symlinks=True):
725+
"""Return the POSIX file permissions."""
726+
return S_IMODE(self._stat(follow_symlinks=follow_symlinks).st_mode)
749727

750-
class _DirEntryInfo(_Info):
751-
"""Implementation of pathlib.types.PathInfo that provides status
752-
information by querying a wrapped os.DirEntry object. Don't try to
753-
construct it yourself."""
754-
__slots__ = ('_entry',)
755-
756-
def __init__(self, entry):
757-
super().__init__(entry.path)
758-
self._entry = entry
759-
760-
def _stat(self, *, follow_symlinks=True):
761-
"""Return the status as an os.stat_result."""
762-
return self._entry.stat(follow_symlinks=follow_symlinks)
728+
def _file_id(self, *, follow_symlinks=True):
729+
"""Returns the identifier of the file."""
730+
st = self._stat(follow_symlinks=follow_symlinks)
731+
return st.st_dev, st.st_ino
763732

764-
def exists(self, *, follow_symlinks=True):
765-
"""Whether this path exists."""
766-
if not follow_symlinks:
767-
return True
768-
try:
769-
self._stat(follow_symlinks=follow_symlinks)
770-
except OSError:
771-
return False
772-
return True
733+
def _access_time_ns(self, *, follow_symlinks=True):
734+
"""Return the access time in nanoseconds."""
735+
return self._stat(follow_symlinks=follow_symlinks).st_atime_ns
773736

774-
def is_dir(self, *, follow_symlinks=True):
775-
"""Whether this path is a directory."""
776-
try:
777-
return self._entry.is_dir(follow_symlinks=follow_symlinks)
778-
except OSError:
779-
return False
737+
def _mod_time_ns(self, *, follow_symlinks=True):
738+
"""Return the modify time in nanoseconds."""
739+
return self._stat(follow_symlinks=follow_symlinks).st_mtime_ns
780740

781-
def is_file(self, *, follow_symlinks=True):
782-
"""Whether this path is a regular file."""
783-
try:
784-
return self._entry.is_file(follow_symlinks=follow_symlinks)
785-
except OSError:
786-
return False
741+
if hasattr(os.stat_result, 'st_flags'):
742+
def _bsd_flags(self, *, follow_symlinks=True):
743+
"""Return the flags."""
744+
return self._stat(follow_symlinks=follow_symlinks).st_flags
787745

788-
def is_symlink(self):
789-
"""Whether this path is a symbolic link."""
790-
try:
791-
return self._entry.is_symlink()
792-
except OSError:
793-
return False
746+
if hasattr(os, 'listxattr'):
747+
def _xattrs(self, *, follow_symlinks=True):
748+
"""Return the xattrs as a list of (attr, value) pairs, or an empty
749+
list if extended attributes aren't supported."""
750+
try:
751+
return [
752+
(attr, os.getxattr(self._path, attr, follow_symlinks=follow_symlinks))
753+
for attr in os.listxattr(self._path, follow_symlinks=follow_symlinks)]
754+
except OSError as err:
755+
if err.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES):
756+
raise
757+
return []
794758

795759

796760
def _copy_info(info, target, follow_symlinks=True):
@@ -877,7 +841,7 @@ def info(self):
877841
try:
878842
return self._info
879843
except AttributeError:
880-
self._info = _StatResultInfo(str(self))
844+
self._info = _Info(str(self))
881845
return self._info
882846

883847
def stat(self, *, follow_symlinks=True):
@@ -1057,7 +1021,7 @@ def _filter_trailing_slash(self, paths):
10571021
def _from_dir_entry(self, dir_entry, path_str):
10581022
path = self.with_segments(path_str)
10591023
path._str = path_str
1060-
path._info = _DirEntryInfo(dir_entry)
1024+
path._info = _Info(dir_entry.path, dir_entry)
10611025
return path
10621026

10631027
def iterdir(self):

Lib/pathlib/_local.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"""
2+
This module exists so that pathlib objects pickled under Python 3.13 can be
3+
unpickled in 3.14+.
4+
"""
5+
6+
from pathlib import *
7+
8+
__all__ = [
9+
"UnsupportedOperation",
10+
"PurePath", "PurePosixPath", "PureWindowsPath",
11+
"Path", "PosixPath", "WindowsPath",
12+
]

Lib/test/test_pathlib/test_pathlib.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,12 @@ def test_pickling_common(self):
293293
self.assertEqual(hash(pp), hash(p))
294294
self.assertEqual(str(pp), str(p))
295295

296+
def test_unpicking_3_13(self):
297+
data = (b"\x80\x04\x95'\x00\x00\x00\x00\x00\x00\x00\x8c\x0e"
298+
b"pathlib._local\x94\x8c\rPurePosixPath\x94\x93\x94)R\x94.")
299+
p = pickle.loads(data)
300+
self.assertIsInstance(p, pathlib.PurePosixPath)
301+
296302
def test_repr_common(self):
297303
for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
298304
with self.subTest(pathstr=pathstr):

Lib/test/test_threading.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,7 @@ def task():
17761776
self.assertEqual(os.read(r_interp, 1), DONE)
17771777

17781778
@cpython_only
1779+
@support.skip_if_sanitizer(thread=True, memory=True)
17791780
def test_daemon_threads_fatal_error(self):
17801781
import_module("_testcapi")
17811782
subinterp_code = f"""if 1:

Lib/test/test_warnings/__init__.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,85 @@ def test_once(self):
241241
42)
242242
self.assertEqual(len(w), 0)
243243

244+
def test_filter_module(self):
245+
MS_WINDOWS = (sys.platform == 'win32')
246+
with self.module.catch_warnings(record=True) as w:
247+
self.module.simplefilter('error')
248+
self.module.filterwarnings('always', module=r'package\.module\z')
249+
self.module.warn_explicit('msg', UserWarning, 'filename', 42,
250+
module='package.module')
251+
self.assertEqual(len(w), 1)
252+
with self.assertRaises(UserWarning):
253+
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module', 42)
254+
with self.assertRaises(UserWarning):
255+
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module.py', 42)
256+
257+
with self.module.catch_warnings(record=True) as w:
258+
self.module.simplefilter('error')
259+
self.module.filterwarnings('always', module='package')
260+
self.module.warn_explicit('msg', UserWarning, 'filename', 42,
261+
module='package.module')
262+
self.assertEqual(len(w), 1)
263+
with self.assertRaises(UserWarning):
264+
self.module.warn_explicit('msg', UserWarning, 'filename', 42,
265+
module='other.package.module')
266+
with self.assertRaises(UserWarning):
267+
self.module.warn_explicit('msg', UserWarning, '/path/to/otherpackage/module.py', 42)
268+
269+
with self.module.catch_warnings(record=True) as w:
270+
self.module.simplefilter('error')
271+
self.module.filterwarnings('always', module=r'/path/to/package/module\z')
272+
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module', 42)
273+
self.assertEqual(len(w), 1)
274+
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module.py', 42)
275+
self.assertEqual(len(w), 2)
276+
with self.assertRaises(UserWarning):
277+
self.module.warn_explicit('msg', UserWarning, '/PATH/TO/PACKAGE/MODULE', 42)
278+
if MS_WINDOWS:
279+
if self.module is py_warnings:
280+
self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module.PY', 42)
281+
self.assertEqual(len(w), 3)
282+
with self.assertRaises(UserWarning):
283+
self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module/__init__.py', 42)
284+
with self.assertRaises(UserWarning):
285+
self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module.pyw', 42)
286+
with self.assertRaises(UserWarning):
287+
self.module.warn_explicit('msg', UserWarning, r'\path\to\package\module', 42)
288+
289+
with self.module.catch_warnings(record=True) as w:
290+
self.module.simplefilter('error')
291+
self.module.filterwarnings('always', module=r'/path/to/package/__init__\z')
292+
self.module.warn_explicit('msg', UserWarning, '/path/to/package/__init__.py', 42)
293+
self.assertEqual(len(w), 1)
294+
self.module.warn_explicit('msg', UserWarning, '/path/to/package/__init__', 42)
295+
self.assertEqual(len(w), 2)
296+
297+
if MS_WINDOWS:
298+
with self.module.catch_warnings(record=True) as w:
299+
self.module.simplefilter('error')
300+
self.module.filterwarnings('always', module=r'C:\\path\\to\\package\\module\z')
301+
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module', 42)
302+
self.assertEqual(len(w), 1)
303+
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.py', 42)
304+
self.assertEqual(len(w), 2)
305+
if self.module is py_warnings:
306+
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PY', 42)
307+
self.assertEqual(len(w), 3)
308+
with self.assertRaises(UserWarning):
309+
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.pyw', 42)
310+
with self.assertRaises(UserWarning):
311+
self.module.warn_explicit('msg', UserWarning, r'C:\PATH\TO\PACKAGE\MODULE', 42)
312+
with self.assertRaises(UserWarning):
313+
self.module.warn_explicit('msg', UserWarning, r'C:/path/to/package/module', 42)
314+
with self.assertRaises(UserWarning):
315+
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module\__init__.py', 42)
316+
317+
with self.module.catch_warnings(record=True) as w:
318+
self.module.simplefilter('error')
319+
self.module.filterwarnings('always', module=r'<unknown>\z')
320+
self.module.warn_explicit('msg', UserWarning, '', 42)
321+
self.assertEqual(len(w), 1)
322+
244323
def test_module_globals(self):
245324
with self.module.catch_warnings(record=True) as w:
246325
self.module.simplefilter("always", UserWarning)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Check ``statx`` availability only in Linux platforms

0 commit comments

Comments
 (0)