Skip to content

Commit 13f1006

Browse files
Merge branch 'main' into fix/129640
2 parents 94fa2a8 + 98fa4a4 commit 13f1006

File tree

12 files changed

+474
-410
lines changed

12 files changed

+474
-410
lines changed

Doc/library/pdb.rst

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,25 +75,34 @@ The debugger's prompt is ``(Pdb)``, which is the indicator that you are in debug
7575
arguments of the ``p`` command.
7676

7777

78+
.. program:: pdb
79+
7880
You can also invoke :mod:`pdb` from the command line to debug other scripts. For
7981
example::
8082

81-
python -m pdb myscript.py
83+
python -m pdb [-c command] (-m module | pyfile) [args ...]
8284

8385
When invoked as a module, pdb will automatically enter post-mortem debugging if
8486
the program being debugged exits abnormally. After post-mortem debugging (or
8587
after normal exit of the program), pdb will restart the program. Automatic
8688
restarting preserves pdb's state (such as breakpoints) and in most cases is more
8789
useful than quitting the debugger upon program's exit.
8890

89-
.. versionchanged:: 3.2
90-
Added the ``-c`` option to execute commands as if given
91-
in a :file:`.pdbrc` file; see :ref:`debugger-commands`.
91+
.. option:: -c, --command <command>
9292

93-
.. versionchanged:: 3.7
94-
Added the ``-m`` option to execute modules similar to the way
95-
``python -m`` does. As with a script, the debugger will pause execution just
96-
before the first line of the module.
93+
To execute commands as if given in a :file:`.pdbrc` file; see
94+
:ref:`debugger-commands`.
95+
96+
.. versionchanged:: 3.2
97+
Added the ``-c`` option.
98+
99+
.. option:: -m <module>
100+
101+
To execute modules similar to the way ``python -m`` does. As with a script,
102+
the debugger will pause execution just before the first line of the module.
103+
104+
.. versionchanged:: 3.7
105+
Added the ``-m`` option.
97106

98107
Typical usage to execute a statement under control of the debugger is::
99108

Doc/library/time.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,13 @@ An explanation of some terminology and conventions is in order.
5252
single: Coordinated Universal Time
5353
single: Greenwich Mean Time
5454

55-
* UTC is Coordinated Universal Time (formerly known as Greenwich Mean Time, or
56-
GMT). The acronym UTC is not a mistake but a compromise between English and
57-
French.
55+
* UTC is `Coordinated Universal Time`_ and superseded `Greenwich Mean Time`_ or
56+
GMT as the basis of international timekeeping. The acronym UTC is not a
57+
mistake but conforms to an earlier, language-agnostic naming scheme for time
58+
standards such as UT0, UT1, and UT2.
59+
60+
.. _Coordinated Universal Time: https://en.wikipedia.org/wiki/Coordinated_Universal_Time
61+
.. _Greenwich Mean Time: https://en.wikipedia.org/wiki/Greenwich_Mean_Time
5862

5963
.. index:: single: Daylight Saving Time
6064

Doc/library/webbrowser.rst

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,23 @@ a new tab, with the browser being brought to the foreground. The use of the
4040
:mod:`webbrowser` module on iOS requires the :mod:`ctypes` module. If
4141
:mod:`ctypes` isn't available, calls to :func:`.open` will fail.
4242

43+
.. program:: webbrowser
44+
4345
The script :program:`webbrowser` can be used as a command-line interface for the
4446
module. It accepts a URL as the argument. It accepts the following optional
4547
parameters:
4648

47-
* ``-n``/``--new-window`` opens the URL in a new browser window, if possible.
48-
* ``-t``/``--new-tab`` opens the URL in a new browser page ("tab").
49+
.. option:: -n, --new-window
50+
51+
Opens the URL in a new browser window, if possible.
52+
53+
.. option:: -t, --new-tab
54+
55+
Opens the URL in a new browser tab.
56+
57+
The options are, naturally, mutually exclusive. Usage example:
4958

50-
The options are, naturally, mutually exclusive. Usage example::
59+
.. code-block:: bash
5160
5261
python -m webbrowser -t "https://www.python.org"
5362

Doc/library/zipfile.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,14 @@ Path Objects
554554
e.g. 'dir/file.txt', 'dir/', or ''. Defaults to the empty string,
555555
indicating the root.
556556

557+
.. note::
558+
The :class:`Path` class does not sanitize filenames within the ZIP archive. Unlike
559+
the :meth:`ZipFile.extract` and :meth:`ZipFile.extractall` methods, it is the
560+
caller's responsibility to validate or sanitize filenames to prevent path traversal
561+
vulnerabilities (e.g., filenames containing ".." or absolute paths). When handling
562+
untrusted archives, consider resolving filenames using :func:`os.path.abspath`
563+
and checking against the target directory with :func:`os.path.commonpath`.
564+
557565
Path objects expose the following features of :mod:`pathlib.Path`
558566
objects:
559567

Lib/glob.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -320,11 +320,11 @@ def translate(pat, *, recursive=False, include_hidden=False, seps=None):
320320

321321

322322
@functools.lru_cache(maxsize=512)
323-
def _compile_pattern(pat, sep, case_sensitive, recursive=True):
323+
def _compile_pattern(pat, seps, case_sensitive, recursive=True):
324324
"""Compile given glob pattern to a re.Pattern object (observing case
325325
sensitivity)."""
326326
flags = re.NOFLAG if case_sensitive else re.IGNORECASE
327-
regex = translate(pat, recursive=recursive, include_hidden=True, seps=sep)
327+
regex = translate(pat, recursive=recursive, include_hidden=True, seps=seps)
328328
return re.compile(regex, flags=flags).match
329329

330330

@@ -360,8 +360,9 @@ def concat_path(path, text):
360360

361361
# High-level methods
362362

363-
def compile(self, pat):
364-
return _compile_pattern(pat, self.sep, self.case_sensitive, self.recursive)
363+
def compile(self, pat, altsep=None):
364+
seps = (self.sep, altsep) if altsep else self.sep
365+
return _compile_pattern(pat, seps, self.case_sensitive, self.recursive)
365366

366367
def selector(self, parts):
367368
"""Returns a function that selects from a given path, walking and

Lib/pathlib/types.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from glob import _PathGlobber, _no_recurse_symlinks
1515
from pathlib import PurePath, Path
1616
from pathlib._os import magic_open, ensure_distinct_paths, copy_file
17-
from typing import Protocol, runtime_checkable
17+
from typing import Optional, Protocol, runtime_checkable
1818

1919

2020
def _explode_path(path):
@@ -44,6 +44,7 @@ class _PathParser(Protocol):
4444
"""
4545

4646
sep: str
47+
altsep: Optional[str]
4748
def split(self, path: str) -> tuple[str, str]: ...
4849
def splitext(self, path: str) -> tuple[str, str]: ...
4950
def normcase(self, path: str) -> str: ...
@@ -135,7 +136,9 @@ def with_name(self, name):
135136
split = self.parser.split
136137
if split(name)[0]:
137138
raise ValueError(f"Invalid name {name!r}")
138-
return self.with_segments(split(str(self))[0], name)
139+
path = str(self)
140+
path = path.removesuffix(split(path)[1]) + name
141+
return self.with_segments(path)
139142

140143
def with_stem(self, stem):
141144
"""Return a new path with the stem changed."""
@@ -223,7 +226,7 @@ def full_match(self, pattern, *, case_sensitive=None):
223226
if case_sensitive is None:
224227
case_sensitive = self.parser.normcase('Aa') == 'Aa'
225228
globber = _PathGlobber(pattern.parser.sep, case_sensitive, recursive=True)
226-
match = globber.compile(str(pattern))
229+
match = globber.compile(str(pattern), altsep=pattern.parser.altsep)
227230
return match(str(self)) is not None
228231

229232

Lib/test/_test_multiprocessing.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,12 +1654,10 @@ def test_notify(self):
16541654
p = self.Process(target=self.f, args=(cond, sleeping, woken))
16551655
p.daemon = True
16561656
p.start()
1657-
self.addCleanup(p.join)
16581657

1659-
p = threading.Thread(target=self.f, args=(cond, sleeping, woken))
1660-
p.daemon = True
1661-
p.start()
1662-
self.addCleanup(p.join)
1658+
t = threading.Thread(target=self.f, args=(cond, sleeping, woken))
1659+
t.daemon = True
1660+
t.start()
16631661

16641662
# wait for both children to start sleeping
16651663
sleeping.acquire()
@@ -1686,7 +1684,9 @@ def test_notify(self):
16861684

16871685
# check state is not mucked up
16881686
self.check_invariant(cond)
1689-
p.join()
1687+
1688+
threading_helper.join_thread(t)
1689+
join_process(p)
16901690

16911691
def test_notify_all(self):
16921692
cond = self.Condition()
@@ -1763,16 +1763,17 @@ def test_notify_n(self):
17631763
woken = self.Semaphore(0)
17641764

17651765
# start some threads/processes
1766+
workers = []
17661767
for i in range(3):
17671768
p = self.Process(target=self.f, args=(cond, sleeping, woken))
17681769
p.daemon = True
17691770
p.start()
1770-
self.addCleanup(p.join)
1771+
workers.append(p)
17711772

17721773
t = threading.Thread(target=self.f, args=(cond, sleeping, woken))
17731774
t.daemon = True
17741775
t.start()
1775-
self.addCleanup(t.join)
1776+
workers.append(t)
17761777

17771778
# wait for them to all sleep
17781779
for i in range(6):
@@ -1807,6 +1808,10 @@ def test_notify_n(self):
18071808
# check state is not mucked up
18081809
self.check_invariant(cond)
18091810

1811+
for w in workers:
1812+
# NOTE: join_process and join_thread are the same
1813+
threading_helper.join_thread(w)
1814+
18101815
def test_timeout(self):
18111816
cond = self.Condition()
18121817
wait = TimingWrapper(cond.wait)

Lib/test/test_pathlib/support/__init__.py

Whitespace-only changes.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""
2+
Simple implementation of JoinablePath, for use in pathlib tests.
3+
"""
4+
5+
import os.path
6+
import pathlib.types
7+
8+
9+
class LexicalPath(pathlib.types._JoinablePath):
10+
__slots__ = ('_segments',)
11+
parser = os.path
12+
13+
def __init__(self, *pathsegments):
14+
self._segments = pathsegments
15+
16+
def __hash__(self):
17+
return hash(str(self))
18+
19+
def __eq__(self, other):
20+
if not isinstance(other, LexicalPath):
21+
return NotImplemented
22+
return str(self) == str(other)
23+
24+
def __str__(self):
25+
if not self._segments:
26+
return ''
27+
return self.parser.join(*self._segments)
28+
29+
def __repr__(self):
30+
return f'{type(self).__name__}({str(self)!r})'
31+
32+
def with_segments(self, *pathsegments):
33+
return type(self)(*pathsegments)

0 commit comments

Comments
 (0)