Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ Tools/cases_generator/ @markshannon
Python/assemble.c @markshannon @iritkatriel
Python/codegen.c @markshannon @iritkatriel
Python/compile.c @markshannon @iritkatriel
Python/flowgraph.c @markshannon @iritkatriel
Python/flowgraph.c @markshannon @iritkatriel @eclips4
Python/instruction_sequence.c @iritkatriel
Python/symtable.c @JelleZijlstra @carljm

Expand Down
26 changes: 13 additions & 13 deletions Doc/library/stdtypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ A hexadecimal string takes the form::

[sign] ['0x'] integer ['.' fraction] ['p' exponent]

where the optional ``sign`` may by either ``+`` or ``-``, ``integer``
where the optional ``sign`` may be either ``+`` or ``-``, ``integer``
and ``fraction`` are strings of hexadecimal digits, and ``exponent``
is a decimal integer with an optional leading sign. Case is not
significant, and there must be at least one hexadecimal digit in
Expand Down Expand Up @@ -1345,7 +1345,7 @@ Mutable sequence types also support the following methods:
:no-typesetting:
.. method:: sequence.pop(index=-1, /)

Retrieve the item at *index* and also removes it from *sequence*.
Retrieve the item at *index* and also remove it from *sequence*.
By default, the last item in *sequence* is removed and returned.

.. method:: bytearray.remove(value, /)
Expand Down Expand Up @@ -2120,7 +2120,7 @@ expression support in the :mod:`re` module).
one character, ``False`` otherwise. Alphabetic characters are those characters defined
in the Unicode character database as "Letter", i.e., those with general category
property being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is different
from the `Alphabetic property defined in the section 4.10 'Letters, Alphabetic, and
from the `Alphabetic property defined in section 4.10 'Letters, Alphabetic, and
Ideographic' of the Unicode Standard
<https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-4/#G91002>`__.
For example:
Expand Down Expand Up @@ -3044,7 +3044,7 @@ replacement field. For example::
'0.333333'
>>> f'{one_third:_^+10}'
'___+1/3___'
>>> >>> f'{one_third!r:_^20}'
>>> f'{one_third!r:_^20}'
'___Fraction(1, 3)___'
>>> f'{one_third = :~>10}~'
'one_third = ~~~~~~~1/3~'
Expand All @@ -3054,12 +3054,12 @@ replacement field. For example::
Template String Literals (t-strings)
------------------------------------

An :dfn:`t-string` (formally a :dfn:`template string literal`) is
A :dfn:`t-string` (formally a :dfn:`template string literal`) is
a string literal that is prefixed with ``t`` or ``T``.

These strings follow the same syntax and evaluation rules as
:ref:`formatted string literals <stdtypes-fstrings>`,
with for the following differences:
with the following differences:

* Rather than evaluating to a ``str`` object, template string literals evaluate
to a :class:`string.templatelib.Template` object.
Expand All @@ -3086,7 +3086,7 @@ with for the following differences:
The :class:`!Interpolation` instance for the expression will be created as
normal, except that :attr:`~string.templatelib.Interpolation.conversion` will
be set to '``r``' (:func:`repr`) by default.
If an explicit conversion or format specifier are provided,
If an explicit conversion or format specifier is provided,
this will override the default behaviour.


Expand Down Expand Up @@ -3463,7 +3463,7 @@ objects.

.. classmethod:: fromhex(string, /)

This :class:`bytearray` class method returns bytearray object, decoding
This :class:`bytearray` class method returns a bytearray object, decoding
the given string object. The string must contain two hexadecimal digits
per byte, with ASCII whitespace being ignored.

Expand Down Expand Up @@ -4427,7 +4427,7 @@ the ``%`` operator (modulo).
This is also known as the bytes *formatting* or *interpolation* operator.
Given ``format % values`` (where *format* is a bytes object), ``%`` conversion
specifications in *format* are replaced with zero or more elements of *values*.
The effect is similar to using the :c:func:`sprintf` in the C language.
The effect is similar to using the :c:func:`sprintf` function in the C language.

If *format* requires a single argument, *values* may be a single non-tuple
object. [5]_ Otherwise, *values* must be a tuple with exactly the number of
Expand Down Expand Up @@ -4628,7 +4628,7 @@ copying.
underlying data.

``len(view)`` is equal to the length of :meth:`~memoryview.tolist`, which
is the nested list representation of the view. If ``view.ndim = 1``,
is the nested list representation of the view. If ``view.ndim == 1``,
this is equal to the number of elements in the view.

.. versionchanged:: 3.12
Expand Down Expand Up @@ -4713,7 +4713,7 @@ copying.
:class:`collections.abc.Sequence`

.. versionchanged:: 3.5
memoryviews can now be indexed with tuple of integers.
memoryviews can now be indexed with a tuple of integers.

.. versionchanged:: 3.14
memoryview is now a :term:`generic type`.
Expand Down Expand Up @@ -6182,7 +6182,7 @@ enables cleaner type hinting syntax compared to subscripting :class:`typing.Unio

.. note::

The ``|`` operand cannot be used at runtime to define unions where one or
The ``|`` operator cannot be used at runtime to define unions where one or
more members is a forward reference. For example, ``int | "Foo"``, where
``"Foo"`` is a reference to a class not yet defined, will fail at
runtime. For unions which include forward references, present the
Expand Down Expand Up @@ -6341,7 +6341,7 @@ Methods
Methods are functions that are called using the attribute notation.
There are two flavors: :ref:`built-in methods <builtin-methods>`
(such as :meth:`~list.append` on lists)
and :ref:`class instance method <instance-methods>`.
and :ref:`class instance methods <instance-methods>`.
Built-in methods are described with the types that support them.

If you access a method (a function defined in a class namespace) through an
Expand Down
4 changes: 3 additions & 1 deletion Doc/library/zipfile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,9 @@ ZipFile objects
strict_descriptor=True[, chunk_size])

Rewrites the archive to remove unreferenced local file entries, shrinking
its file size. The archive must be opened with mode ``'a'``.
its file size. The archive must be opened with mode ``'a'``, and any file
object returned by :meth:`ZipFile.open` must be closed first, since
repacking moves the member data such objects refer to.

If *removed* is provided, it must be a sequence of :class:`ZipInfo` objects
representing the recently removed members, and only their corresponding
Expand Down
9 changes: 9 additions & 0 deletions Lib/multiprocessing/pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,11 @@ def _guarded_task_generation(self, result_job, func, iterable, sema=None):
enumerated_iter = iter(enumerate(iterable))
while True:
sema.acquire()
if self._state != RUN:
# The pool is closing or terminating; stop submitting
# the still-throttled tasks so the task handler can
# finish instead of blocking here forever.
break
try:
i, x = next(enumerated_iter)
except StopIteration:
Expand Down Expand Up @@ -661,6 +666,10 @@ def close(self):
self._state = CLOSE
self._worker_handler._state = CLOSE
self._change_notifier.put(None)
# Wake any task generator throttled on a buffersize semaphore so
# it observes the CLOSE state and stops submitting.
for sema in list(self._taskqueue_buffersize_semaphores):
sema.release()

def terminate(self):
util.debug('terminating pool')
Expand Down
21 changes: 21 additions & 0 deletions Lib/test/_test_multiprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3229,6 +3229,27 @@ def produce_args():
p.terminate()
p.join()

@warnings_helper.ignore_fork_in_thread_deprecation_warnings()
@support.subTests('method_name', ("imap", "imap_unordered"))
def test_imap_with_buffersize_close_after_partial_consumption(
self, method_name
):
# close()/join() must not deadlock when a buffersize iterator is
# only partially consumed (the throttled task generator must stop).
p = self.Pool(2)
method = getattr(p, method_name)
it = method(sqr, range(1000), buffersize=2)
next(it)
finished = threading.Event()
def finalize():
p.close()
p.join()
finished.set()
t = threading.Thread(target=finalize)
t.start()
t.join(support.SHORT_TIMEOUT)
self.assertTrue(finished.is_set(), "close()/join() deadlocked")

@support.subTests('method_name', ("imap", "imap_unordered"))
def test_imap_and_imap_unordered_with_buffersize_on_empty_iterable(
self, method_name
Expand Down
17 changes: 17 additions & 0 deletions Lib/test/test_lazy_import/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,23 @@ def test_lazy_import_type_attributes_accessible(self):
proc = assert_python_ok("-c", code)
self.assertIn(b"<built-in method resolve of lazy_import object at", proc.out)

@support.requires_subprocess()
def test_lazy_import_type_attribute_error_message(self):
"""Check that LazyImportType attribute error message is helpful."""
code = textwrap.dedent("""
lazy import asyncio
try:
globals()["asyncio"].Task
except AttributeError as exc:
assert str(exc) == (
"cannot access attribute 'Task' "
"on unresolved lazy import 'asyncio'"
), repr(str(exc))
else:
assert False, 'AttributeError is not raised'
""")
assert_python_ok("-c", code)


class SyntaxRestrictionTests(LazyImportTestCase):
"""Tests for syntax restrictions on lazy imports."""
Expand Down
162 changes: 162 additions & 0 deletions Lib/test/test_peepholer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2470,6 +2470,168 @@ def test_list_to_tuple_get_iter_is_safe(self):
self.assertEqual(b, [3, 2, 1, 0])
self.assertEqual(items, [])

def test_fold_constant_big_list_for_iter(self):
# for x in [c1, c2, ..., cN] (N > 30) should fold to LOAD_CONST tuple
consts = 35
before = (
[("BUILD_LIST", 0, 1)] +
[("LOAD_CONST", 0, 2), ("LIST_APPEND", 1, 3)] * consts +
[("GET_ITER", 0, 4),
top := self.Label(),
("FOR_ITER", end := self.Label(), 5),
("STORE_FAST", 0, 6),
("JUMP", top, 7),
end,
("END_FOR", None, 8),
("POP_ITER", None, 9),
("LOAD_CONST", 0, 10),
("RETURN_VALUE", None, 11)]
)
after = [
("LOAD_CONST", 1, 3),
("GET_ITER", 0, 4),
top := self.Label(),
("FOR_ITER", end := self.Label(), 5),
("STORE_FAST", 0, 6),
("JUMP", top, 7),
end,
("END_FOR", None, 8),
("POP_ITER", None, 9),
("LOAD_CONST", 0, 10),
("RETURN_VALUE", None, 11),
]
result_const = tuple(["test"] * consts)
self.cfg_optimization_test(before, after, consts=["test"],
expected_consts=["test", result_const])

def test_fold_constant_big_set_for_iter(self):
# for x in {c1, c2, ..., cN} (N > 30) should fold to LOAD_CONST frozenset
before = [
("BUILD_SET", 0, 1),
("LOAD_SMALL_INT", 1, 2), ("SET_ADD", 1, 3),
("LOAD_SMALL_INT", 2, 4), ("SET_ADD", 1, 5),
("LOAD_SMALL_INT", 3, 6), ("SET_ADD", 1, 7),
("GET_ITER", 0, 8),
top := self.Label(),
("FOR_ITER", end := self.Label(), 9),
("STORE_FAST", 0, 10),
("JUMP", top, 11),
end,
("END_FOR", None, 12),
("POP_ITER", None, 13),
("LOAD_CONST", 0, 14),
("RETURN_VALUE", None, 15),
]
after = [
("LOAD_CONST", 1, 7),
("GET_ITER", 0, 8),
top := self.Label(),
("FOR_ITER", end := self.Label(), 9),
("STORE_FAST", 0, 10),
("JUMP", top, 11),
end,
("END_FOR", None, 12),
("POP_ITER", None, 13),
("LOAD_CONST", 0, 14),
("RETURN_VALUE", None, 15),
]
self.cfg_optimization_test(before, after, consts=["test"],
expected_consts=["test", frozenset({1, 2, 3})])

def test_fold_constant_list_to_tuple_for_iter(self):
INTRINSIC_LIST_TO_TUPLE = 6
before = [
("BUILD_LIST", 0, 1),
("LOAD_SMALL_INT", 1, 2), ("LIST_APPEND", 1, 3),
("LOAD_SMALL_INT", 2, 4), ("LIST_APPEND", 1, 5),
("LOAD_SMALL_INT", 3, 6), ("LIST_APPEND", 1, 7),
("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 8),
("GET_ITER", 0, 9),
top := self.Label(),
("FOR_ITER", end := self.Label(), 10),
("STORE_FAST", 0, 11),
("JUMP", top, 12),
end,
("END_FOR", None, 13),
("POP_ITER", None, 14),
("LOAD_CONST", 0, 15),
("RETURN_VALUE", None, 16),
]
after = [
("LOAD_CONST", 1, 8),
("GET_ITER", 0, 9),
top := self.Label(),
("FOR_ITER", end := self.Label(), 10),
("STORE_FAST", 0, 11),
("JUMP", top, 12),
end,
("END_FOR", None, 13),
("POP_ITER", None, 14),
("LOAD_CONST", 0, 15),
("RETURN_VALUE", None, 16),
]
self.cfg_optimization_test(before, after, consts=["test"],
expected_consts=["test", (1, 2, 3)])

def test_fold_constant_big_list_contains_op(self):
# x in [c1, c2, ..., cN] (N > 30) should fold to LOAD_CONST tuple
before = [
("LOAD_FAST", 0, 1),
("BUILD_LIST", 0, 2),
("LOAD_SMALL_INT", 1, 3), ("LIST_APPEND", 1, 4),
("LOAD_SMALL_INT", 2, 5), ("LIST_APPEND", 1, 6),
("LOAD_SMALL_INT", 3, 7), ("LIST_APPEND", 1, 8),
("CONTAINS_OP", 0, 9),
("RETURN_VALUE", None, 10),
]
after = [
("LOAD_FAST_BORROW", 0, 1),
("LOAD_CONST", 1, 8),
("CONTAINS_OP", 0, 9),
("RETURN_VALUE", None, 10),
]
self.cfg_optimization_test(before, after, consts=[None],
expected_consts=[None, (1, 2, 3)])

def test_fold_constant_big_set_contains_op(self):
# x in {c1, c2, ..., cN} (N > 30) should fold to LOAD_CONST frozenset
before = [
("LOAD_FAST", 0, 1),
("BUILD_SET", 0, 2),
("LOAD_SMALL_INT", 1, 3), ("SET_ADD", 1, 4),
("LOAD_SMALL_INT", 2, 5), ("SET_ADD", 1, 6),
("LOAD_SMALL_INT", 3, 7), ("SET_ADD", 1, 8),
("CONTAINS_OP", 0, 9),
("RETURN_VALUE", None, 10),
]
after = [
("LOAD_FAST_BORROW", 0, 1),
("LOAD_CONST", 1, 8),
("CONTAINS_OP", 0, 9),
("RETURN_VALUE", None, 10),
]
self.cfg_optimization_test(before, after, consts=[None],
expected_consts=[None, frozenset({1, 2, 3})])

def test_no_fold_big_list_for_iter_with_non_const(self):
same = [
("BUILD_LIST", 0, 1),
("LOAD_SMALL_INT", 1, 2), ("LIST_APPEND", 1, 3),
("LOAD_FAST_BORROW", 0, 4), ("LIST_APPEND", 1, 5),
("LOAD_SMALL_INT", 3, 6), ("LIST_APPEND", 1, 7),
("GET_ITER", 0, 8),
top := self.Label(),
("FOR_ITER", end := self.Label(), 9),
("STORE_FAST", 1, 10),
("JUMP", top, 11),
end,
("END_FOR", None, 12),
("POP_ITER", None, 13),
("LOAD_CONST", 0, 14),
("RETURN_VALUE", None, 15),
]
self.cfg_optimization_test(same, same, consts=["test"])


class OptimizeLoadFastTestCase(DirectCfgOptimizerTests):
def make_bb(self, insts):
Expand Down
12 changes: 12 additions & 0 deletions Lib/test/test_zipfile/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2388,6 +2388,18 @@ def test_repack_writing(self, m_repack):
zh.repack()
m_repack.assert_not_called()

@mock.patch.object(zipfile, '_ZipRepacker')
def test_repack_reading(self, m_repack):
self._prepare_zip_from_test_files(TESTFN, self.test_files)
with zipfile.ZipFile(TESTFN, 'a') as zh:
with zh.open(self.test_files[0][0]):
with self.assertRaises(ValueError):
zh.repack()
m_repack.assert_not_called()
# Allowed once the reading handle is closed.
zh.repack()
m_repack.assert_called_once()

@mock.patch.object(zipfile, '_ZipRepacker')
def test_repack_mode_r(self, m_repack):
self._prepare_zip_from_test_files(TESTFN, self.test_files)
Expand Down
Loading
Loading