Skip to content

Commit 5f6d00d

Browse files
authored
Merge branch '3.13' into backport-dff074d-3.13
2 parents 9ecb41a + bf40fdb commit 5f6d00d

Some content is hidden

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

48 files changed

+410
-65
lines changed

Doc/library/pprint.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ let's fetch information about a project from `PyPI <https://pypi.org>`_::
267267
>>> import json
268268
>>> import pprint
269269
>>> from urllib.request import urlopen
270-
>>> with urlopen('https://pypi.org/pypi/sampleproject/json') as resp:
270+
>>> with urlopen('https://pypi.org/pypi/sampleproject/1.2.0/json') as resp:
271271
... project_info = json.load(resp)['info']
272272

273273
In its basic form, :func:`~pprint.pp` shows the whole object::

Doc/reference/expressions.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,8 @@ a user-defined function:
11561156
first thing the code block will do is bind the formal parameters to the
11571157
arguments; this is described in section :ref:`function`. When the code block
11581158
executes a :keyword:`return` statement, this specifies the return value of the
1159-
function call.
1159+
function call. If execution reaches the end of the code block without
1160+
executing a :keyword:`return` statement, the return value is ``None``.
11601161

11611162
a built-in function or method:
11621163
.. index::

Doc/whatsnew/3.13.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,8 @@ and are now removed:
15681568
For audio playback, use the :pypi:`pygame` library from PyPI instead.
15691569
* :mod:`!pipes`:
15701570
Use the :mod:`subprocess` module instead.
1571+
Use :func:`shlex.quote` to replace the undocumented ``pipes.quote``
1572+
function.
15711573
* :mod:`!sndhdr`:
15721574
The :pypi:`filetype`, :pypi:`puremagic`, or :pypi:`python-magic` libraries
15731575
should be used as replacements.

Include/internal/pycore_import.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extern int _PyImport_SetModuleString(const char *name, PyObject* module);
2121

2222
extern void _PyImport_AcquireLock(PyInterpreterState *interp);
2323
extern void _PyImport_ReleaseLock(PyInterpreterState *interp);
24+
extern void _PyImport_ReInitLock(PyInterpreterState *interp);
2425

2526
// This is used exclusively for the sys and builtins modules:
2627
extern int _PyImport_FixupBuiltin(

Lib/_pyrepl/_minimal_curses.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def _find_clib() -> str:
3434
clib.setupterm.restype = ctypes.c_int
3535

3636
clib.tigetstr.argtypes = [ctypes.c_char_p]
37-
clib.tigetstr.restype = ctypes.POINTER(ctypes.c_char)
37+
clib.tigetstr.restype = ctypes.c_ssize_t
3838

3939
clib.tparm.argtypes = [ctypes.c_char_p] + 9 * [ctypes.c_int] # type: ignore[operator]
4040
clib.tparm.restype = ctypes.c_char_p
@@ -56,7 +56,7 @@ def tigetstr(cap):
5656
if not isinstance(cap, bytes):
5757
cap = cap.encode("ascii")
5858
result = clib.tigetstr(cap)
59-
if ctypes.cast(result, ctypes.c_void_p).value == ERR:
59+
if result == ERR:
6060
return None
6161
return ctypes.cast(result, ctypes.c_char_p).value
6262

Lib/ensurepip/__init__.py

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

1111

1212
__all__ = ["version", "bootstrap"]
13-
_PIP_VERSION = "24.2"
13+
_PIP_VERSION = "24.3.1"
1414

1515
# Directory of system wheel packages. Some Linux distribution packaging
1616
# policies recommend against bundling dependencies. For example, Fedora
1.73 MB
Binary file not shown.

Lib/importlib/_bootstrap_external.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,11 @@ def _write_atomic(path, data, mode=0o666):
209209
# We first write data to a temporary file, and then use os.replace() to
210210
# perform an atomic rename.
211211
with _io.FileIO(fd, 'wb') as file:
212-
file.write(data)
212+
bytes_written = file.write(data)
213+
if bytes_written != len(data):
214+
# Raise an OSError so the 'except' below cleans up the partially
215+
# written file.
216+
raise OSError("os.write() didn't write the full pyc file")
213217
_os.replace(path_tmp, path)
214218
except OSError:
215219
try:

Lib/nturl2path.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,21 @@ def pathname2url(p):
4444
import urllib.parse
4545
# First, clean up some special forms. We are going to sacrifice
4646
# the additional information anyway
47-
if p[:4] == '\\\\?\\':
47+
p = p.replace('\\', '/')
48+
if p[:4] == '//?/':
4849
p = p[4:]
49-
if p[:4].upper() == 'UNC\\':
50-
p = '\\\\' + p[4:]
50+
if p[:4].upper() == 'UNC/':
51+
p = '//' + p[4:]
5152
elif p[1:2] != ':':
5253
raise OSError('Bad path: ' + p)
5354
if not ':' in p:
54-
# No drive specifier, just convert slashes and quote the name
55-
return urllib.parse.quote(p.replace('\\', '/'))
55+
# No DOS drive specified, just quote the pathname
56+
return urllib.parse.quote(p)
5657
comp = p.split(':', maxsplit=2)
5758
if len(comp) != 2 or len(comp[0]) > 1:
5859
error = 'Bad path: ' + p
5960
raise OSError(error)
6061

6162
drive = urllib.parse.quote(comp[0].upper())
62-
tail = urllib.parse.quote(comp[1].replace('\\', '/'))
63+
tail = urllib.parse.quote(comp[1])
6364
return '///' + drive + ':' + tail

Lib/posixpath.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
altsep = None
2323
devnull = '/dev/null'
2424

25+
import errno
2526
import os
2627
import sys
2728
import stat
@@ -408,6 +409,10 @@ def realpath(filename, *, strict=False):
408409
# very fast way of spelling list(reversed(...)).
409410
rest = filename.split(sep)[::-1]
410411

412+
# Number of unprocessed parts in 'rest'. This can differ from len(rest)
413+
# later, because 'rest' might contain markers for unresolved symlinks.
414+
part_count = len(rest)
415+
411416
# The resolved path, which is absolute throughout this function.
412417
# Note: getcwd() returns a normalized and symlink-free path.
413418
path = sep if filename.startswith(sep) else getcwd()
@@ -418,12 +423,13 @@ def realpath(filename, *, strict=False):
418423
# the same links.
419424
seen = {}
420425

421-
while rest:
426+
while part_count:
422427
name = rest.pop()
423428
if name is None:
424429
# resolved symlink target
425430
seen[rest.pop()] = path
426431
continue
432+
part_count -= 1
427433
if not name or name == curdir:
428434
# current dir
429435
continue
@@ -436,8 +442,11 @@ def realpath(filename, *, strict=False):
436442
else:
437443
newpath = path + sep + name
438444
try:
439-
st = os.lstat(newpath)
440-
if not stat.S_ISLNK(st.st_mode):
445+
st_mode = os.lstat(newpath).st_mode
446+
if not stat.S_ISLNK(st_mode):
447+
if strict and part_count and not stat.S_ISDIR(st_mode):
448+
raise OSError(errno.ENOTDIR, os.strerror(errno.ENOTDIR),
449+
newpath)
441450
path = newpath
442451
continue
443452
if newpath in seen:
@@ -469,7 +478,9 @@ def realpath(filename, *, strict=False):
469478
rest.append(newpath)
470479
rest.append(None)
471480
# Push the unresolved symlink target parts onto the stack.
472-
rest.extend(target.split(sep)[::-1])
481+
target_parts = target.split(sep)[::-1]
482+
rest.extend(target_parts)
483+
part_count += len(target_parts)
473484

474485
return path
475486

0 commit comments

Comments
 (0)