Skip to content

Commit 59672cf

Browse files
committed
Merge remote-tracking branch 'upstream/main' into feat/binary_shift_optimization
2 parents c24ad0a + 360fedc commit 59672cf

23 files changed

+176
-54
lines changed

Doc/library/io.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ explicitly when opening text files. If you want to use UTF-8, pass
131131
``encoding="utf-8"``. To use the current locale encoding,
132132
``encoding="locale"`` is supported in Python 3.10.
133133

134-
When you need to run existing code on Windows that attempts to opens
134+
When you need to run existing code on Windows that attempts to open
135135
UTF-8 files using the default locale encoding, you can enable the UTF-8
136136
mode. See :ref:`UTF-8 mode on Windows <win-utf8-mode>`.
137137

Doc/library/typing.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn
625625

626626
Union type; ``Union[X, Y]`` is equivalent to ``X | Y`` and means either X or Y.
627627

628-
To define a union, use e.g. ``Union[int, str]`` or the shorthand ``int | str``. Details:
628+
To define a union, use e.g. ``Union[int, str]`` or the shorthand ``int | str``. Using that shorthand is recommended. Details:
629629

630630
* The arguments must be types and there must be at least one.
631631

Doc/library/unittest.mock.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1516,7 +1516,7 @@ attribute in a class) that does not exist will fail with :exc:`AttributeError`::
15161516
>>> test()
15171517
Traceback (most recent call last):
15181518
...
1519-
AttributeError: <module 'sys' (built-in)> does not have the attribute 'non_existing'
1519+
AttributeError: <module 'sys' (built-in)> does not have the attribute 'non_existing_attribute'
15201520

15211521
but adding ``create=True`` in the call to :func:`patch` will make the previous example
15221522
work as expected::

Doc/whatsnew/3.10.rst

+9-9
Original file line numberDiff line numberDiff line change
@@ -1437,7 +1437,7 @@ and to match the behavior of static type checkers specified in the PEP.
14371437
14381438
1. ``Literal`` now de-duplicates parameters.
14391439
2. Equality comparisons between ``Literal`` objects are now order independent.
1440-
3. ``Literal`` comparisons now respects types. For example,
1440+
3. ``Literal`` comparisons now respect types. For example,
14411441
``Literal[0] == Literal[False]`` previously evaluated to ``True``. It is
14421442
now ``False``. To support this change, the internally used type cache now
14431443
supports differentiating types.
@@ -1647,13 +1647,12 @@ Deprecated
16471647
:meth:`importlib.machinery.FrozenImporter.find_module`,
16481648
:meth:`importlib.machinery.WindowsRegistryFinder.find_module`,
16491649
:meth:`importlib.machinery.PathFinder.find_module`,
1650-
:meth:`importlib.abc.MetaPathFinder.find_module`),
1650+
:meth:`importlib.abc.MetaPathFinder.find_module` ),
16511651
:meth:`importlib.abc.PathEntryFinder.find_module` (
1652-
:meth:`importlib.machinery.FileFinder.find_module`,
1653-
), and
1652+
:meth:`importlib.machinery.FileFinder.find_module` ), and
16541653
:meth:`importlib.abc.PathEntryFinder.find_loader` (
1655-
:meth:`importlib.machinery.FileFinder.find_loader`
1656-
) now raise :exc:`DeprecationWarning` and are slated for removal in
1654+
:meth:`importlib.machinery.FileFinder.find_loader` )
1655+
now raise :exc:`DeprecationWarning` and are slated for removal in
16571656
Python 3.12 (previously they were documented as deprecated in Python 3.4).
16581657
(Contributed by Brett Cannon in :issue:`42135`.)
16591658
@@ -1694,7 +1693,7 @@ Deprecated
16941693
* :func:`asyncio.get_event_loop` now emits a deprecation warning if there is
16951694
no running event loop. In the future it will be an alias of
16961695
:func:`~asyncio.get_running_loop`.
1697-
:mod:`asyncio` functions which implicitly create a :class:`~asyncio.Future`
1696+
:mod:`asyncio` functions which implicitly create :class:`~asyncio.Future`
16981697
or :class:`~asyncio.Task` objects now emit
16991698
a deprecation warning if there is no running event loop and no explicit
17001699
*loop* argument is passed: :func:`~asyncio.ensure_future`,
@@ -1834,7 +1833,7 @@ Removed
18341833
running in different threads.
18351834
18361835
Note that the low-level API will still accept ``loop``.
1837-
See `Changes in the Python API`_ for examples of how to replace existing code.
1836+
See :ref:`changes-python-api` for examples of how to replace existing code.
18381837
18391838
(Contributed by Yurii Karabas, Andrew Svetlov, Yury Selivanov and Kyle Stanley
18401839
in :issue:`42392`.)
@@ -1858,6 +1857,7 @@ Changes in the Python syntax
18581857
following keyword.
18591858
(Contributed by Serhiy Storchaka in :issue:`43833`).
18601859
1860+
.. _changes-python-api:
18611861
18621862
Changes in the Python API
18631863
-------------------------
@@ -1979,7 +1979,7 @@ Build Changes
19791979
(Contributed by Victor Stinner in :issue:`36020`.)
19801980
19811981
* :mod:`sqlite3` requires SQLite 3.7.15 or higher. (Contributed by Sergey Fedoseev
1982-
and Erlend E. Aasland :issue:`40744` and :issue:`40810`.)
1982+
and Erlend E. Aasland in :issue:`40744` and :issue:`40810`.)
19831983
19841984
* The :mod:`atexit` module must now always be built as a built-in module.
19851985
(Contributed by Victor Stinner in :issue:`42639`.)

Lib/asyncio/base_events.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1285,8 +1285,8 @@ async def create_datagram_endpoint(self, protocol_factory,
12851285
addr_infos = {} # Using order preserving dict
12861286
for idx, addr in ((0, local_addr), (1, remote_addr)):
12871287
if addr is not None:
1288-
assert isinstance(addr, tuple) and len(addr) == 2, (
1289-
'2-tuple is expected')
1288+
if not (isinstance(addr, tuple) and len(addr) == 2):
1289+
raise TypeError('2-tuple is expected')
12901290

12911291
infos = await self._ensure_resolved(
12921292
addr, family=family, type=socket.SOCK_DGRAM,

Lib/functools.py

+16-5
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,7 @@ def _compose_mro(cls, types):
740740
# Remove entries which are already present in the __mro__ or unrelated.
741741
def is_related(typ):
742742
return (typ not in bases and hasattr(typ, '__mro__')
743+
and not isinstance(typ, GenericAlias)
743744
and issubclass(cls, typ))
744745
types = [n for n in types if is_related(n)]
745746
# Remove entries which are strict bases of other entries (they will end up
@@ -841,9 +842,13 @@ def _is_union_type(cls):
841842
from typing import get_origin, Union
842843
return get_origin(cls) in {Union, types.UnionType}
843844

844-
def _is_valid_union_type(cls):
845+
def _is_valid_dispatch_type(cls):
846+
if isinstance(cls, type) and not isinstance(cls, GenericAlias):
847+
return True
845848
from typing import get_args
846-
return _is_union_type(cls) and all(isinstance(arg, type) for arg in get_args(cls))
849+
return (_is_union_type(cls) and
850+
all(isinstance(arg, type) and not isinstance(arg, GenericAlias)
851+
for arg in get_args(cls)))
847852

848853
def register(cls, func=None):
849854
"""generic_func.register(cls, func) -> func
@@ -852,9 +857,15 @@ def register(cls, func=None):
852857
853858
"""
854859
nonlocal cache_token
855-
if func is None:
856-
if isinstance(cls, type) or _is_valid_union_type(cls):
860+
if _is_valid_dispatch_type(cls):
861+
if func is None:
857862
return lambda f: register(cls, f)
863+
else:
864+
if func is not None:
865+
raise TypeError(
866+
f"Invalid first argument to `register()`. "
867+
f"{cls!r} is not a class or union type."
868+
)
858869
ann = getattr(cls, '__annotations__', {})
859870
if not ann:
860871
raise TypeError(
@@ -867,7 +878,7 @@ def register(cls, func=None):
867878
# only import typing if annotation parsing is necessary
868879
from typing import get_type_hints
869880
argname, cls = next(iter(get_type_hints(func).items()))
870-
if not isinstance(cls, type) and not _is_valid_union_type(cls):
881+
if not _is_valid_dispatch_type(cls):
871882
if _is_union_type(cls):
872883
raise TypeError(
873884
f"Invalid annotation for {argname!r}. "

Lib/test/test_asyncio/test_base_events.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1603,11 +1603,11 @@ def test_create_datagram_endpoint_addr_error(self):
16031603
coro = self.loop.create_datagram_endpoint(
16041604
MyDatagramProto, local_addr='localhost')
16051605
self.assertRaises(
1606-
AssertionError, self.loop.run_until_complete, coro)
1606+
TypeError, self.loop.run_until_complete, coro)
16071607
coro = self.loop.create_datagram_endpoint(
16081608
MyDatagramProto, local_addr=('localhost', 1, 2, 3))
16091609
self.assertRaises(
1610-
AssertionError, self.loop.run_until_complete, coro)
1610+
TypeError, self.loop.run_until_complete, coro)
16111611

16121612
def test_create_datagram_endpoint_connect_err(self):
16131613
self.loop.sock_connect = mock.Mock()

Lib/test/test_asyncio/test_proactor_events.py

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def test_loop_reading_data(self):
7777
self.loop._proactor.recv_into.assert_called_with(self.sock, called_buf)
7878
self.protocol.data_received.assert_called_with(bytearray(buf))
7979

80+
@unittest.skipIf(sys.flags.optimize, "Assertions are disabled in optimized mode")
8081
def test_loop_reading_no_data(self):
8182
res = self.loop.create_future()
8283
res.set_result(0)
@@ -869,6 +870,7 @@ def test_datagram_loop_reading_data(self):
869870
self.protocol.datagram_received.assert_called_with(b'data', ('127.0.0.1', 12068))
870871
close_transport(tr)
871872

873+
@unittest.skipIf(sys.flags.optimize, "Assertions are disabled in optimized mode")
872874
def test_datagram_loop_reading_no_data(self):
873875
res = self.loop.create_future()
874876
res.set_result((b'', ('127.0.0.1', 12068)))

Lib/test/test_asyncio/test_selector_events.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Tests for selector_events.py"""
22

3+
import sys
34
import selectors
45
import socket
56
import unittest
@@ -804,6 +805,7 @@ def test_write_ready_closing(self):
804805
self.sock.close.assert_called_with()
805806
self.protocol.connection_lost.assert_called_with(None)
806807

808+
@unittest.skipIf(sys.flags.optimize, "Assertions are disabled in optimized mode")
807809
def test_write_ready_no_data(self):
808810
transport = self.socket_transport()
809811
# This is an internal error.

Lib/test/test_functools.py

+68
Original file line numberDiff line numberDiff line change
@@ -2722,6 +2722,74 @@ def _(arg: int | float):
27222722
self.assertEqual(f(1), "types.UnionType")
27232723
self.assertEqual(f(1.0), "types.UnionType")
27242724

2725+
def test_register_genericalias(self):
2726+
@functools.singledispatch
2727+
def f(arg):
2728+
return "default"
2729+
2730+
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
2731+
f.register(list[int], lambda arg: "types.GenericAlias")
2732+
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
2733+
f.register(typing.List[int], lambda arg: "typing.GenericAlias")
2734+
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
2735+
f.register(list[int] | str, lambda arg: "types.UnionTypes(types.GenericAlias)")
2736+
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
2737+
f.register(typing.List[float] | bytes, lambda arg: "typing.Union[typing.GenericAlias]")
2738+
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
2739+
f.register(typing.Any, lambda arg: "typing.Any")
2740+
2741+
self.assertEqual(f([1]), "default")
2742+
self.assertEqual(f([1.0]), "default")
2743+
self.assertEqual(f(""), "default")
2744+
self.assertEqual(f(b""), "default")
2745+
2746+
def test_register_genericalias_decorator(self):
2747+
@functools.singledispatch
2748+
def f(arg):
2749+
return "default"
2750+
2751+
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
2752+
f.register(list[int])
2753+
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
2754+
f.register(typing.List[int])
2755+
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
2756+
f.register(list[int] | str)
2757+
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
2758+
f.register(typing.List[int] | str)
2759+
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
2760+
f.register(typing.Any)
2761+
2762+
def test_register_genericalias_annotation(self):
2763+
@functools.singledispatch
2764+
def f(arg):
2765+
return "default"
2766+
2767+
with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"):
2768+
@f.register
2769+
def _(arg: list[int]):
2770+
return "types.GenericAlias"
2771+
with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"):
2772+
@f.register
2773+
def _(arg: typing.List[float]):
2774+
return "typing.GenericAlias"
2775+
with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"):
2776+
@f.register
2777+
def _(arg: list[int] | str):
2778+
return "types.UnionType(types.GenericAlias)"
2779+
with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"):
2780+
@f.register
2781+
def _(arg: typing.List[float] | bytes):
2782+
return "typing.Union[typing.GenericAlias]"
2783+
with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"):
2784+
@f.register
2785+
def _(arg: typing.Any):
2786+
return "typing.Any"
2787+
2788+
self.assertEqual(f([1]), "default")
2789+
self.assertEqual(f([1.0]), "default")
2790+
self.assertEqual(f(""), "default")
2791+
self.assertEqual(f(b""), "default")
2792+
27252793

27262794
class CachedCostItem:
27272795
_cost = 1

Lib/test/test_set.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -667,10 +667,13 @@ def __new__(cls, arg, newarg=None):
667667
self = super().__new__(cls, arg)
668668
self.newarg = newarg
669669
return self
670-
u = subclass_with_new([1, 2], newarg=3)
670+
u = subclass_with_new([1, 2])
671671
self.assertIs(type(u), subclass_with_new)
672672
self.assertEqual(set(u), {1, 2})
673-
self.assertEqual(u.newarg, 3)
673+
self.assertIsNone(u.newarg)
674+
# disallow kwargs in __new__ only (https://bugs.python.org/issue43413#msg402000)
675+
with self.assertRaises(TypeError):
676+
subclass_with_new([1, 2], newarg=3)
674677

675678

676679
class TestFrozenSet(TestJointOps, unittest.TestCase):

Lib/tkinter/test/test_tkinter/test_misc.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,13 @@ def test_clipboard_astral(self):
201201
root.clipboard_get()
202202

203203
def test_winfo_rgb(self):
204+
205+
def assertApprox(col1, col2):
206+
# A small amount of flexibility is required (bpo-45496)
207+
# 33 is ~0.05% of 65535, which is a reasonable margin
208+
for col1_channel, col2_channel in zip(col1, col2):
209+
self.assertAlmostEqual(col1_channel, col2_channel, delta=33)
210+
204211
root = self.root
205212
rgb = root.winfo_rgb
206213

@@ -210,9 +217,9 @@ def test_winfo_rgb(self):
210217
# #RGB - extends each 4-bit hex value to be 16-bit.
211218
self.assertEqual(rgb('#F0F'), (0xFFFF, 0x0000, 0xFFFF))
212219
# #RRGGBB - extends each 8-bit hex value to be 16-bit.
213-
self.assertEqual(rgb('#4a3c8c'), (0x4a4a, 0x3c3c, 0x8c8c))
220+
assertApprox(rgb('#4a3c8c'), (0x4a4a, 0x3c3c, 0x8c8c))
214221
# #RRRRGGGGBBBB
215-
self.assertEqual(rgb('#dede14143939'), (0xdede, 0x1414, 0x3939))
222+
assertApprox(rgb('#dede14143939'), (0xdede, 0x1414, 0x3939))
216223
# Invalid string.
217224
with self.assertRaises(tkinter.TclError):
218225
rgb('#123456789a')

Lib/unittest/runner.py

+6
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ def printErrors(self):
142142
self.stream.flush()
143143
self.printErrorList('ERROR', self.errors)
144144
self.printErrorList('FAIL', self.failures)
145+
unexpectedSuccesses = getattr(self, 'unexpectedSuccesses', ())
146+
if unexpectedSuccesses:
147+
self.stream.writeln(self.separator1)
148+
for test in unexpectedSuccesses:
149+
self.stream.writeln(f"UNEXPECTED SUCCESS: {self.getDescription(test)}")
150+
self.stream.flush()
145151

146152
def printErrorList(self, flavour, errors):
147153
for test, err in errors:

Lib/unittest/test/test_program.py

+32-8
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@ def testPass(self):
6161
pass
6262
def testFail(self):
6363
raise AssertionError
64+
def testError(self):
65+
1/0
66+
@unittest.skip('skipping')
67+
def testSkipped(self):
68+
raise AssertionError
69+
@unittest.expectedFailure
70+
def testExpectedFailure(self):
71+
raise AssertionError
72+
@unittest.expectedFailure
73+
def testUnexpectedSuccess(self):
74+
pass
6475

6576
class FooBarLoader(unittest.TestLoader):
6677
"""Test loader that returns a suite containing FooBar."""
@@ -111,9 +122,13 @@ def test_NonExit(self):
111122
testRunner=unittest.TextTestRunner(stream=stream),
112123
testLoader=self.FooBarLoader())
113124
self.assertTrue(hasattr(program, 'result'))
114-
self.assertIn('\nFAIL: testFail ', stream.getvalue())
115-
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
116-
125+
out = stream.getvalue()
126+
self.assertIn('\nFAIL: testFail ', out)
127+
self.assertIn('\nERROR: testError ', out)
128+
self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out)
129+
expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, '
130+
'expected failures=1, unexpected successes=1)\n')
131+
self.assertTrue(out.endswith(expected))
117132

118133
def test_Exit(self):
119134
stream = BufferedWriter()
@@ -124,9 +139,13 @@ def test_Exit(self):
124139
testRunner=unittest.TextTestRunner(stream=stream),
125140
exit=True,
126141
testLoader=self.FooBarLoader())
127-
self.assertIn('\nFAIL: testFail ', stream.getvalue())
128-
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
129-
142+
out = stream.getvalue()
143+
self.assertIn('\nFAIL: testFail ', out)
144+
self.assertIn('\nERROR: testError ', out)
145+
self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out)
146+
expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, '
147+
'expected failures=1, unexpected successes=1)\n')
148+
self.assertTrue(out.endswith(expected))
130149

131150
def test_ExitAsDefault(self):
132151
stream = BufferedWriter()
@@ -136,8 +155,13 @@ def test_ExitAsDefault(self):
136155
argv=["foobar"],
137156
testRunner=unittest.TextTestRunner(stream=stream),
138157
testLoader=self.FooBarLoader())
139-
self.assertIn('\nFAIL: testFail ', stream.getvalue())
140-
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
158+
out = stream.getvalue()
159+
self.assertIn('\nFAIL: testFail ', out)
160+
self.assertIn('\nERROR: testError ', out)
161+
self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out)
162+
expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, '
163+
'expected failures=1, unexpected successes=1)\n')
164+
self.assertTrue(out.endswith(expected))
141165

142166

143167
class InitialisableProgram(unittest.TestProgram):

0 commit comments

Comments
 (0)