Skip to content

Commit 109e250

Browse files
Merge branch '3.13' into fix-slot-wrapper-inheritance-tests-3.13
2 parents 5d1cfc0 + 6b9a5af commit 109e250

37 files changed

+331
-170
lines changed

.github/workflows/build.yml

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -249,27 +249,38 @@ jobs:
249249
arch: ${{ matrix.arch }}
250250

251251
build_macos:
252-
name: 'macOS'
253-
needs: check_source
254-
if: needs.check_source.outputs.run_tests == 'true'
255-
uses: ./.github/workflows/reusable-macos.yml
256-
with:
257-
config_hash: ${{ needs.check_source.outputs.config_hash }}
258-
# Cirrus and macos-14 are M1, macos-13 is default GHA Intel.
259-
# Cirrus used for upstream, macos-14 for forks.
260-
os-matrix: '["ghcr.io/cirruslabs/macos-runner:sonoma", "macos-14", "macos-13"]'
261-
262-
build_macos_free_threading:
263-
name: 'macOS (free-threading)'
252+
name: >-
253+
macOS
254+
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
264255
needs: check_source
265256
if: needs.check_source.outputs.run_tests == 'true'
257+
strategy:
258+
fail-fast: false
259+
matrix:
260+
# Cirrus and macos-14 are M1, macos-13 is default GHA Intel.
261+
# macOS 13 only runs tests against the GIL-enabled CPython.
262+
# Cirrus used for upstream, macos-14 for forks.
263+
os:
264+
- ghcr.io/cirruslabs/macos-runner:sonoma
265+
- macos-14
266+
- macos-13
267+
is-fork: # only used for the exclusion trick
268+
- ${{ github.repository_owner != 'python' }}
269+
free-threading:
270+
- false
271+
- true
272+
exclude:
273+
- os: ghcr.io/cirruslabs/macos-runner:sonoma
274+
is-fork: true
275+
- os: macos-14
276+
is-fork: false
277+
- os: macos-13
278+
free-threading: true
266279
uses: ./.github/workflows/reusable-macos.yml
267280
with:
268281
config_hash: ${{ needs.check_source.outputs.config_hash }}
269-
free-threading: true
270-
# Cirrus and macos-14 are M1.
271-
# Cirrus used for upstream, macos-14 for forks.
272-
os-matrix: '["ghcr.io/cirruslabs/macos-runner:sonoma", "macos-14"]'
282+
free-threading: ${{ matrix.free-threading }}
283+
os: ${{ matrix.os }}
273284

274285
build_ubuntu:
275286
name: >-
@@ -595,7 +606,6 @@ jobs:
595606
- check-docs
596607
- check_generated_files
597608
- build_macos
598-
- build_macos_free_threading
599609
- build_ubuntu
600610
- build_ubuntu_ssltests
601611
- build_wasi
@@ -631,7 +641,6 @@ jobs:
631641
&& '
632642
check_generated_files,
633643
build_macos,
634-
build_macos_free_threading,
635644
build_ubuntu,
636645
build_ubuntu_ssltests,
637646
build_wasi,

.github/workflows/reusable-macos.yml

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ on:
88
required: false
99
type: boolean
1010
default: false
11-
os-matrix:
12-
required: false
11+
os:
12+
description: OS to run the job
13+
required: true
1314
type: string
1415

1516
jobs:
1617
build_macos:
17-
name: build and test (${{ matrix.os }})
18+
name: build and test (${{ inputs.os }})
1819
timeout-minutes: 60
1920
env:
2021
HOMEBREW_NO_ANALYTICS: 1
@@ -23,18 +24,7 @@ jobs:
2324
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
2425
PYTHONSTRICTEXTENSIONBUILD: 1
2526
TERM: linux
26-
strategy:
27-
fail-fast: false
28-
matrix:
29-
os: ${{fromJson(inputs.os-matrix)}}
30-
is-fork:
31-
- ${{ github.repository_owner != 'python' }}
32-
exclude:
33-
- os: "ghcr.io/cirruslabs/macos-runner:sonoma"
34-
is-fork: true
35-
- os: "macos-14"
36-
is-fork: false
37-
runs-on: ${{ matrix.os }}
27+
runs-on: ${{ inputs.os }}
3828
steps:
3929
- uses: actions/checkout@v4
4030
- name: Runner image version
@@ -43,7 +33,7 @@ jobs:
4333
uses: actions/cache@v4
4434
with:
4535
path: config.cache
46-
key: ${{ github.job }}-${{ matrix.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}
36+
key: ${{ github.job }}-${{ inputs.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}
4737
- name: Install Homebrew dependencies
4838
run: brew install pkg-config [email protected] xz gdbm tcl-tk
4939
- name: Configure CPython

Doc/library/mimetypes.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,3 +295,13 @@ than one MIME-type database; it provides an interface similar to the one of the
295295
types, else to the list of non-standard types.
296296

297297
.. versionadded:: 3.2
298+
299+
300+
.. method:: MimeTypes.add_type(type, ext, strict=True)
301+
302+
Add a mapping from the MIME type *type* to the extension *ext*. When the
303+
extension is already known, the new type will replace the old one. When the type
304+
is already known the extension will be added to the list of known extensions.
305+
306+
When *strict* is ``True`` (the default), the mapping will be added to the
307+
official MIME types, otherwise to the non-standard ones.

Include/cpython/bytesobject.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,7 @@ static inline Py_ssize_t PyBytes_GET_SIZE(PyObject *op) {
3131
return Py_SIZE(self);
3232
}
3333
#define PyBytes_GET_SIZE(self) PyBytes_GET_SIZE(_PyObject_CAST(self))
34+
35+
/* _PyBytes_Join(sep, x) is like sep.join(x). sep must be PyBytesObject*,
36+
x must be an iterable object. */
37+
PyAPI_FUNC(PyObject*) _PyBytes_Join(PyObject *sep, PyObject *x);

Include/internal/pycore_bytesobject.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@ extern PyObject* _PyBytes_FromHex(
2323
PyAPI_FUNC(PyObject*) _PyBytes_DecodeEscape(const char *, Py_ssize_t,
2424
const char *, const char **);
2525

26-
/* _PyBytes_Join(sep, x) is like sep.join(x). sep must be PyBytesObject*,
27-
x must be an iterable object. */
28-
extern PyObject* _PyBytes_Join(PyObject *sep, PyObject *x);
29-
3026

3127
// Substring Search.
3228
//

Lib/asyncio/base_events.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,8 +1028,7 @@ async def _connect_sock(self, exceptions, addr_info, local_addr_infos=None):
10281028
except OSError as exc:
10291029
msg = (
10301030
f'error while attempting to bind on '
1031-
f'address {laddr!r}: '
1032-
f'{exc.strerror.lower()}'
1031+
f'address {laddr!r}: {str(exc).lower()}'
10331032
)
10341033
exc = OSError(exc.errno, msg)
10351034
my_exceptions.append(exc)
@@ -1599,7 +1598,7 @@ async def create_server(
15991598
except OSError as err:
16001599
msg = ('error while attempting '
16011600
'to bind on address %r: %s'
1602-
% (sa, err.strerror.lower()))
1601+
% (sa, str(err).lower()))
16031602
if err.errno == errno.EADDRNOTAVAIL:
16041603
# Assume the family is not enabled (bpo-30945)
16051604
sockets.pop()

Lib/inspect.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,11 @@ def ismethoddescriptor(object):
325325
if isclass(object) or ismethod(object) or isfunction(object):
326326
# mutual exclusion
327327
return False
328+
if isinstance(object, functools.partial):
329+
# Lie for children. The addition of partial.__get__
330+
# doesn't currently change the partial objects behaviour,
331+
# not counting a warning about future changes.
332+
return False
328333
tp = type(object)
329334
return (hasattr(tp, "__get__")
330335
and not hasattr(tp, "__set__")

Lib/pickle.py

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,11 +1110,35 @@ def save_global(self, obj, name=None):
11101110
self.save(module_name)
11111111
self.save(name)
11121112
write(STACK_GLOBAL)
1113-
elif parent is not module:
1114-
self.save_reduce(getattr, (parent, lastname))
1115-
elif self.proto >= 3:
1116-
write(GLOBAL + bytes(module_name, "utf-8") + b'\n' +
1117-
bytes(name, "utf-8") + b'\n')
1113+
elif '.' in name:
1114+
# In protocol < 4, objects with multi-part __qualname__
1115+
# are represented as
1116+
# getattr(getattr(..., attrname1), attrname2).
1117+
dotted_path = name.split('.')
1118+
name = dotted_path.pop(0)
1119+
save = self.save
1120+
for attrname in dotted_path:
1121+
save(getattr)
1122+
if self.proto < 2:
1123+
write(MARK)
1124+
self._save_toplevel_by_name(module_name, name)
1125+
for attrname in dotted_path:
1126+
save(attrname)
1127+
if self.proto < 2:
1128+
write(TUPLE)
1129+
else:
1130+
write(TUPLE2)
1131+
write(REDUCE)
1132+
else:
1133+
self._save_toplevel_by_name(module_name, name)
1134+
1135+
self.memoize(obj)
1136+
1137+
def _save_toplevel_by_name(self, module_name, name):
1138+
if self.proto >= 3:
1139+
# Non-ASCII identifiers are supported only with protocols >= 3.
1140+
self.write(GLOBAL + bytes(module_name, "utf-8") + b'\n' +
1141+
bytes(name, "utf-8") + b'\n')
11181142
else:
11191143
if self.fix_imports:
11201144
r_name_mapping = _compat_pickle.REVERSE_NAME_MAPPING
@@ -1124,14 +1148,12 @@ def save_global(self, obj, name=None):
11241148
elif module_name in r_import_mapping:
11251149
module_name = r_import_mapping[module_name]
11261150
try:
1127-
write(GLOBAL + bytes(module_name, "ascii") + b'\n' +
1128-
bytes(name, "ascii") + b'\n')
1151+
self.write(GLOBAL + bytes(module_name, "ascii") + b'\n' +
1152+
bytes(name, "ascii") + b'\n')
11291153
except UnicodeEncodeError:
11301154
raise PicklingError(
11311155
"can't pickle global identifier '%s.%s' using "
1132-
"pickle protocol %i" % (module, name, self.proto)) from None
1133-
1134-
self.memoize(obj)
1156+
"pickle protocol %i" % (module_name, name, self.proto)) from None
11351157

11361158
def save_type(self, obj):
11371159
if obj is type(None):

Lib/sysconfig/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ def get_platform():
642642
release = m.group()
643643
elif osname[:6] == "darwin":
644644
if sys.platform == "ios":
645-
release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "12.0")
645+
release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "13.0")
646646
osname = sys.platform
647647
machine = sys.implementation._multiarch
648648
else:

Lib/test/pickletester.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2818,6 +2818,18 @@ class Recursive:
28182818
self.assertIs(unpickled, Recursive)
28192819
del Recursive.mod # break reference loop
28202820

2821+
def test_recursive_nested_names2(self):
2822+
global Recursive
2823+
class Recursive:
2824+
pass
2825+
Recursive.ref = Recursive
2826+
Recursive.__qualname__ = 'Recursive.ref'
2827+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
2828+
with self.subTest(proto=proto):
2829+
unpickled = self.loads(self.dumps(Recursive, proto))
2830+
self.assertIs(unpickled, Recursive)
2831+
del Recursive.ref # break reference loop
2832+
28212833
def test_py_methods(self):
28222834
global PyMethodsTest
28232835
class PyMethodsTest:

Lib/test/test_asyncio/test_eager_task_factory.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,18 @@ class DummyLoop:
241241
_, out, err = assert_python_ok("-c", code)
242242
self.assertFalse(err)
243243

244+
def test_issue122332(self):
245+
async def coro():
246+
pass
247+
248+
async def run():
249+
task = self.loop.create_task(coro())
250+
await task
251+
self.assertIsNone(task.get_coro())
252+
253+
self.run_coro(run())
254+
255+
244256
class AsyncTaskCounter:
245257
def __init__(self, loop, *, task_class, eager):
246258
self.suspense_count = 0

Lib/test/test_asyncio/utils.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,12 +301,17 @@ def run_udp_echo_server(*, host='127.0.0.1', port=0):
301301
family, type, proto, _, sockaddr = addr_info[0]
302302
sock = socket.socket(family, type, proto)
303303
sock.bind((host, port))
304+
sockname = sock.getsockname()
304305
thread = threading.Thread(target=lambda: echo_datagrams(sock))
305306
thread.start()
306307
try:
307-
yield sock.getsockname()
308+
yield sockname
308309
finally:
309-
sock.sendto(b'STOP', sock.getsockname())
310+
# gh-122187: use a separate socket to send the stop message to avoid
311+
# TSan reported race on the same socket.
312+
sock2 = socket.socket(family, type, proto)
313+
sock2.sendto(b'STOP', sockname)
314+
sock2.close()
310315
thread.join()
311316

312317

Lib/test/test_csv.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,10 @@ def test_read_quoting(self):
454454
quoting=csv.QUOTE_STRINGS)
455455
self._read_test(['1,@,3,@,5'], [['1', ',3,', '5']], quotechar='@')
456456
self._read_test(['1,\0,3,\0,5'], [['1', ',3,', '5']], quotechar='\0')
457+
self._read_test(['1\\.5,\\.5,.5'], [[1.5, 0.5, 0.5]],
458+
quoting=csv.QUOTE_NONNUMERIC, escapechar='\\')
459+
self._read_test(['1\\.5,\\.5,"\\.5"'], [[1.5, 0.5, ".5"]],
460+
quoting=csv.QUOTE_STRINGS, escapechar='\\')
457461

458462
def test_read_skipinitialspace(self):
459463
self._read_test(['no space, space, spaces,\ttab'],

Lib/test/test_generated_cases.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,56 @@ def test_deopt_and_exit(self):
813813
with self.assertRaises(Exception):
814814
self.run_cases_test(input, output)
815815

816+
def test_pop_on_error_peeks(self):
817+
818+
input = """
819+
op(FIRST, (x, y -- a, b)) {
820+
a = x;
821+
b = y;
822+
}
823+
824+
op(SECOND, (a, b -- a, b)) {
825+
}
826+
827+
op(THIRD, (j, k --)) {
828+
ERROR_IF(cond, error);
829+
}
830+
831+
macro(TEST) = FIRST + SECOND + THIRD;
832+
"""
833+
output = """
834+
TARGET(TEST) {
835+
frame->instr_ptr = next_instr;
836+
next_instr += 1;
837+
INSTRUCTION_STATS(TEST);
838+
PyObject *y;
839+
PyObject *x;
840+
PyObject *a;
841+
PyObject *b;
842+
PyObject *k;
843+
PyObject *j;
844+
// FIRST
845+
y = stack_pointer[-1];
846+
x = stack_pointer[-2];
847+
{
848+
a = x;
849+
b = y;
850+
}
851+
// SECOND
852+
{
853+
}
854+
// THIRD
855+
k = b;
856+
j = a;
857+
{
858+
if (cond) goto pop_2_error;
859+
}
860+
stack_pointer += -2;
861+
DISPATCH();
862+
}
863+
"""
864+
self.run_cases_test(input, output)
865+
816866
class TestGeneratedAbstractCases(unittest.TestCase):
817867
def setUp(self) -> None:
818868
super().setUp()

Lib/test/test_inspect/test_inspect.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,8 @@ def test_isroutine(self):
405405
self.assertFalse(inspect.isroutine(type))
406406
self.assertFalse(inspect.isroutine(int))
407407
self.assertFalse(inspect.isroutine(type('some_class', (), {})))
408+
# partial
409+
self.assertFalse(inspect.isroutine(functools.partial(mod.spam)))
408410

409411
def test_isclass(self):
410412
self.istest(inspect.isclass, 'mod.StupidGit')
@@ -1906,6 +1908,7 @@ def function():
19061908
self.assertFalse(inspect.ismethoddescriptor(Owner.static_method))
19071909
self.assertFalse(inspect.ismethoddescriptor(function))
19081910
self.assertFalse(inspect.ismethoddescriptor(a_lambda))
1911+
self.assertFalse(inspect.ismethoddescriptor(functools.partial(function)))
19091912

19101913
def test_descriptor_being_a_class(self):
19111914
class MethodDescriptorMeta(type):

0 commit comments

Comments
 (0)