Skip to content

Commit f882e26

Browse files
authored
Merge branch 'main' into fix/cve-realpath
2 parents 1cf6fde + eab7385 commit f882e26

15 files changed

Lines changed: 125 additions & 45 deletions

File tree

Doc/c-api/sys.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,24 @@ Operating System Utilities
123123
This is a thin wrapper around either :c:func:`!sigaction` or :c:func:`!signal`. Do
124124
not call those functions directly!
125125
126+
127+
.. c:function:: int PyOS_InterruptOccurred(void)
128+
129+
Check if a :c:macro:`!SIGINT` signal has been received.
130+
131+
Returns ``1`` if a :c:macro:`!SIGINT` has occurred and clears the signal flag,
132+
or ``0`` otherwise.
133+
134+
In most cases, you should prefer :c:func:`PyErr_CheckSignals` over this function.
135+
:c:func:`!PyErr_CheckSignals` invokes the appropriate signal handlers
136+
for all pending signals, allowing Python code to handle the signal properly.
137+
This function only detects :c:macro:`!SIGINT` and does not invoke any Python
138+
signal handlers.
139+
140+
This function is async-signal-safe and this function cannot fail.
141+
The caller must hold an :term:`attached thread state`.
142+
143+
126144
.. c:function:: wchar_t* Py_DecodeLocale(const char* arg, size_t *size)
127145
128146
.. warning::

Doc/deprecations/pending-removal-in-3.13.rst

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,3 @@ APIs:
3838
* :meth:`!unittest.TestProgram.usageExit` (:gh:`67048`)
3939
* :class:`!webbrowser.MacOSX` (:gh:`86421`)
4040
* :class:`classmethod` descriptor chaining (:gh:`89519`)
41-
* :mod:`importlib.resources` deprecated methods:
42-
43-
* ``contents()``
44-
* ``is_resource()``
45-
* ``open_binary()``
46-
* ``open_text()``
47-
* ``path()``
48-
* ``read_binary()``
49-
* ``read_text()``
50-
51-
Use :func:`importlib.resources.files` instead. Refer to `importlib-resources: Migrating from Legacy
52-
<https://importlib-resources.readthedocs.io/en/latest/using.html#migrating-from-legacy>`_ (:gh:`106531`)

Lib/linecache.py

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -224,21 +224,58 @@ def lazycache(filename, module_globals):
224224
def _make_lazycache_entry(filename, module_globals):
225225
if not filename or (filename.startswith('<') and filename.endswith('>')):
226226
return None
227-
# Try for a __loader__, if available
228-
if module_globals and '__name__' in module_globals:
229-
spec = module_globals.get('__spec__')
230-
name = getattr(spec, 'name', None) or module_globals['__name__']
231-
loader = getattr(spec, 'loader', None)
232-
if loader is None:
233-
loader = module_globals.get('__loader__')
234-
get_source = getattr(loader, 'get_source', None)
235-
236-
if name and get_source:
237-
def get_lines(name=name, *args, **kwargs):
238-
return get_source(name, *args, **kwargs)
239-
return (get_lines,)
240-
return None
241227

228+
if module_globals is not None and not isinstance(module_globals, dict):
229+
raise TypeError(f'module_globals must be a dict, not {type(module_globals).__qualname__}')
230+
if not module_globals or '__name__' not in module_globals:
231+
return None
232+
233+
spec = module_globals.get('__spec__')
234+
name = getattr(spec, 'name', None) or module_globals['__name__']
235+
if name is None:
236+
return None
237+
238+
loader = _bless_my_loader(module_globals)
239+
if loader is None:
240+
return None
241+
242+
get_source = getattr(loader, 'get_source', None)
243+
if get_source is None:
244+
return None
245+
246+
def get_lines(name=name, *args, **kwargs):
247+
return get_source(name, *args, **kwargs)
248+
return (get_lines,)
249+
250+
def _bless_my_loader(module_globals):
251+
# Similar to _bless_my_loader() in importlib._bootstrap_external,
252+
# but always emits warnings instead of errors.
253+
loader = module_globals.get('__loader__')
254+
if loader is None and '__spec__' not in module_globals:
255+
return None
256+
spec = module_globals.get('__spec__')
257+
258+
# The __main__ module has __spec__ = None.
259+
if spec is None and module_globals.get('__name__') == '__main__':
260+
return loader
261+
262+
spec_loader = getattr(spec, 'loader', None)
263+
if spec_loader is None:
264+
import warnings
265+
warnings.warn(
266+
'Module globals is missing a __spec__.loader',
267+
DeprecationWarning)
268+
return loader
269+
270+
assert spec_loader is not None
271+
if loader is not None and loader != spec_loader:
272+
import warnings
273+
warnings.warn(
274+
'Module globals; __loader__ != __spec__.loader',
275+
DeprecationWarning)
276+
return loader
277+
278+
return spec_loader
242279

243280

244281
def _register_code(code, string, name):

Lib/test/test_import/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3261,6 +3261,7 @@ def test_basic_multiple_interpreters_main_no_reset(self):
32613261
# * m_copy was copied from interp2 (was from interp1)
32623262
# * module's global state was updated, not reset
32633263

3264+
@unittest.skip("gh-131229: This is suddenly very flaky")
32643265
@no_rerun(reason="rerun not possible; module state is never cleared (see gh-102251)")
32653266
@requires_subinterpreters
32663267
def test_basic_multiple_interpreters_deleted_no_reset(self):

Lib/test/test_interpreters/test_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ def test_cleanup_in_repl(self):
432432
exit()"""
433433
stdout, stderr = repl.communicate(script)
434434
self.assertIsNone(stderr)
435-
self.assertIn(b"remaining subinterpreters", stdout)
435+
self.assertIn(b"Interpreter.close()", stdout)
436436
self.assertNotIn(b"Traceback", stdout)
437437

438438
@support.requires_subprocess()

Lib/test/test_linecache.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,22 +259,44 @@ def raise_memoryerror(*args, **kwargs):
259259
def test_loader(self):
260260
filename = 'scheme://path'
261261

262-
for loader in (None, object(), NoSourceLoader()):
262+
linecache.clearcache()
263+
module_globals = {'__name__': 'a.b.c', '__loader__': None}
264+
self.assertEqual(linecache.getlines(filename, module_globals), [])
265+
266+
for loader in object(), NoSourceLoader():
263267
linecache.clearcache()
264268
module_globals = {'__name__': 'a.b.c', '__loader__': loader}
265-
self.assertEqual(linecache.getlines(filename, module_globals), [])
269+
with self.assertWarns(DeprecationWarning) as w:
270+
self.assertEqual(linecache.getlines(filename, module_globals), [])
271+
self.assertEqual(str(w.warning),
272+
'Module globals is missing a __spec__.loader')
266273

267274
linecache.clearcache()
268275
module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader()}
269-
self.assertEqual(linecache.getlines(filename, module_globals),
270-
['source for a.b.c\n'])
276+
with self.assertWarns(DeprecationWarning) as w:
277+
self.assertEqual(linecache.getlines(filename, module_globals),
278+
['source for a.b.c\n'])
279+
self.assertEqual(str(w.warning),
280+
'Module globals is missing a __spec__.loader')
271281

272-
for spec in (None, object(), ModuleSpec('', FakeLoader())):
282+
for spec in None, object():
273283
linecache.clearcache()
274284
module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader(),
275285
'__spec__': spec}
286+
with self.assertWarns(DeprecationWarning) as w:
287+
self.assertEqual(linecache.getlines(filename, module_globals),
288+
['source for a.b.c\n'])
289+
self.assertEqual(str(w.warning),
290+
'Module globals is missing a __spec__.loader')
291+
292+
linecache.clearcache()
293+
module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader(),
294+
'__spec__': ModuleSpec('', FakeLoader())}
295+
with self.assertWarns(DeprecationWarning) as w:
276296
self.assertEqual(linecache.getlines(filename, module_globals),
277297
['source for a.b.c\n'])
298+
self.assertEqual(str(w.warning),
299+
'Module globals; __loader__ != __spec__.loader')
278300

279301
linecache.clearcache()
280302
spec = ModuleSpec('x.y.z', FakeLoader())

Lib/test/test_range.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,16 @@ def test_iterator_setstate(self):
470470
it.__setstate__(2**64 - 7)
471471
self.assertEqual(list(it), [12, 10])
472472

473+
def test_iterator_invalid_setstate(self):
474+
for invalid_value in (1.0, ""):
475+
ranges = (('rangeiter', range(10, 100, 2)),
476+
('longrangeiter', range(10, 2**65, 2)))
477+
for rng_name, rng in ranges:
478+
with self.subTest(invalid_value=invalid_value, range=rng_name):
479+
it = iter(rng)
480+
with self.assertRaises(TypeError):
481+
it.__setstate__(invalid_value)
482+
473483
def test_odd_bug(self):
474484
# This used to raise a "SystemError: NULL result without error"
475485
# because the range validation step was eating the exception

Lib/test/test_warnings/__init__.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ def check_module_globals(self, module_globals):
727727

728728
def check_module_globals_error(self, module_globals, errmsg, errtype=ValueError):
729729
if self.module is py_warnings:
730-
self.check_module_globals(module_globals)
730+
self.check_module_globals_deprecated(module_globals, errmsg)
731731
return
732732
with self.module.catch_warnings(record=True) as w:
733733
self.module.filterwarnings('always')
@@ -738,9 +738,6 @@ def check_module_globals_error(self, module_globals, errmsg, errtype=ValueError)
738738
self.assertEqual(len(w), 0)
739739

740740
def check_module_globals_deprecated(self, module_globals, msg):
741-
if self.module is py_warnings:
742-
self.check_module_globals(module_globals)
743-
return
744741
with self.module.catch_warnings(record=True) as w:
745742
self.module.filterwarnings('always')
746743
self.module.warn_explicit(
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix the assertion failure in the ``__setstate__`` method of the range iterator
2+
when a non-integer argument is passed. Patch by Sergey Miryanov.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Suggest using :meth:`concurrent.interpreters.Interpreter.close` instead of the
2+
private ``_interpreters.destroy`` function when warning about remaining subinterpreters.
3+
Patch by Sergey Miryanov.

0 commit comments

Comments
 (0)