Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into feat/binary_shift_o…
Browse files Browse the repository at this point in the history
…ptimization
  • Loading branch information
mdickinson committed Dec 27, 2021
2 parents c24ad0a + 360fedc commit 59672cf
Show file tree
Hide file tree
Showing 23 changed files with 176 additions and 54 deletions.
2 changes: 1 addition & 1 deletion Doc/library/io.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ explicitly when opening text files. If you want to use UTF-8, pass
``encoding="utf-8"``. To use the current locale encoding,
``encoding="locale"`` is supported in Python 3.10.

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

Expand Down
2 changes: 1 addition & 1 deletion Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn

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

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

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

Expand Down
2 changes: 1 addition & 1 deletion Doc/library/unittest.mock.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1516,7 +1516,7 @@ attribute in a class) that does not exist will fail with :exc:`AttributeError`::
>>> test()
Traceback (most recent call last):
...
AttributeError: <module 'sys' (built-in)> does not have the attribute 'non_existing'
AttributeError: <module 'sys' (built-in)> does not have the attribute 'non_existing_attribute'

but adding ``create=True`` in the call to :func:`patch` will make the previous example
work as expected::
Expand Down
18 changes: 9 additions & 9 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1437,7 +1437,7 @@ and to match the behavior of static type checkers specified in the PEP.
1. ``Literal`` now de-duplicates parameters.
2. Equality comparisons between ``Literal`` objects are now order independent.
3. ``Literal`` comparisons now respects types. For example,
3. ``Literal`` comparisons now respect types. For example,
``Literal[0] == Literal[False]`` previously evaluated to ``True``. It is
now ``False``. To support this change, the internally used type cache now
supports differentiating types.
Expand Down Expand Up @@ -1647,13 +1647,12 @@ Deprecated
:meth:`importlib.machinery.FrozenImporter.find_module`,
:meth:`importlib.machinery.WindowsRegistryFinder.find_module`,
:meth:`importlib.machinery.PathFinder.find_module`,
:meth:`importlib.abc.MetaPathFinder.find_module`),
:meth:`importlib.abc.MetaPathFinder.find_module` ),
:meth:`importlib.abc.PathEntryFinder.find_module` (
:meth:`importlib.machinery.FileFinder.find_module`,
), and
:meth:`importlib.machinery.FileFinder.find_module` ), and
:meth:`importlib.abc.PathEntryFinder.find_loader` (
:meth:`importlib.machinery.FileFinder.find_loader`
) now raise :exc:`DeprecationWarning` and are slated for removal in
:meth:`importlib.machinery.FileFinder.find_loader` )
now raise :exc:`DeprecationWarning` and are slated for removal in
Python 3.12 (previously they were documented as deprecated in Python 3.4).
(Contributed by Brett Cannon in :issue:`42135`.)
Expand Down Expand Up @@ -1694,7 +1693,7 @@ Deprecated
* :func:`asyncio.get_event_loop` now emits a deprecation warning if there is
no running event loop. In the future it will be an alias of
:func:`~asyncio.get_running_loop`.
:mod:`asyncio` functions which implicitly create a :class:`~asyncio.Future`
:mod:`asyncio` functions which implicitly create :class:`~asyncio.Future`
or :class:`~asyncio.Task` objects now emit
a deprecation warning if there is no running event loop and no explicit
*loop* argument is passed: :func:`~asyncio.ensure_future`,
Expand Down Expand Up @@ -1834,7 +1833,7 @@ Removed
running in different threads.
Note that the low-level API will still accept ``loop``.
See `Changes in the Python API`_ for examples of how to replace existing code.
See :ref:`changes-python-api` for examples of how to replace existing code.
(Contributed by Yurii Karabas, Andrew Svetlov, Yury Selivanov and Kyle Stanley
in :issue:`42392`.)
Expand All @@ -1858,6 +1857,7 @@ Changes in the Python syntax
following keyword.
(Contributed by Serhiy Storchaka in :issue:`43833`).
.. _changes-python-api:
Changes in the Python API
-------------------------
Expand Down Expand Up @@ -1979,7 +1979,7 @@ Build Changes
(Contributed by Victor Stinner in :issue:`36020`.)
* :mod:`sqlite3` requires SQLite 3.7.15 or higher. (Contributed by Sergey Fedoseev
and Erlend E. Aasland :issue:`40744` and :issue:`40810`.)
and Erlend E. Aasland in :issue:`40744` and :issue:`40810`.)
* The :mod:`atexit` module must now always be built as a built-in module.
(Contributed by Victor Stinner in :issue:`42639`.)
Expand Down
4 changes: 2 additions & 2 deletions Lib/asyncio/base_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -1285,8 +1285,8 @@ async def create_datagram_endpoint(self, protocol_factory,
addr_infos = {} # Using order preserving dict
for idx, addr in ((0, local_addr), (1, remote_addr)):
if addr is not None:
assert isinstance(addr, tuple) and len(addr) == 2, (
'2-tuple is expected')
if not (isinstance(addr, tuple) and len(addr) == 2):
raise TypeError('2-tuple is expected')

infos = await self._ensure_resolved(
addr, family=family, type=socket.SOCK_DGRAM,
Expand Down
21 changes: 16 additions & 5 deletions Lib/functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,7 @@ def _compose_mro(cls, types):
# Remove entries which are already present in the __mro__ or unrelated.
def is_related(typ):
return (typ not in bases and hasattr(typ, '__mro__')
and not isinstance(typ, GenericAlias)
and issubclass(cls, typ))
types = [n for n in types if is_related(n)]
# Remove entries which are strict bases of other entries (they will end up
Expand Down Expand Up @@ -841,9 +842,13 @@ def _is_union_type(cls):
from typing import get_origin, Union
return get_origin(cls) in {Union, types.UnionType}

def _is_valid_union_type(cls):
def _is_valid_dispatch_type(cls):
if isinstance(cls, type) and not isinstance(cls, GenericAlias):
return True
from typing import get_args
return _is_union_type(cls) and all(isinstance(arg, type) for arg in get_args(cls))
return (_is_union_type(cls) and
all(isinstance(arg, type) and not isinstance(arg, GenericAlias)
for arg in get_args(cls)))

def register(cls, func=None):
"""generic_func.register(cls, func) -> func
Expand All @@ -852,9 +857,15 @@ def register(cls, func=None):
"""
nonlocal cache_token
if func is None:
if isinstance(cls, type) or _is_valid_union_type(cls):
if _is_valid_dispatch_type(cls):
if func is None:
return lambda f: register(cls, f)
else:
if func is not None:
raise TypeError(
f"Invalid first argument to `register()`. "
f"{cls!r} is not a class or union type."
)
ann = getattr(cls, '__annotations__', {})
if not ann:
raise TypeError(
Expand All @@ -867,7 +878,7 @@ def register(cls, func=None):
# only import typing if annotation parsing is necessary
from typing import get_type_hints
argname, cls = next(iter(get_type_hints(func).items()))
if not isinstance(cls, type) and not _is_valid_union_type(cls):
if not _is_valid_dispatch_type(cls):
if _is_union_type(cls):
raise TypeError(
f"Invalid annotation for {argname!r}. "
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_asyncio/test_base_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -1603,11 +1603,11 @@ def test_create_datagram_endpoint_addr_error(self):
coro = self.loop.create_datagram_endpoint(
MyDatagramProto, local_addr='localhost')
self.assertRaises(
AssertionError, self.loop.run_until_complete, coro)
TypeError, self.loop.run_until_complete, coro)
coro = self.loop.create_datagram_endpoint(
MyDatagramProto, local_addr=('localhost', 1, 2, 3))
self.assertRaises(
AssertionError, self.loop.run_until_complete, coro)
TypeError, self.loop.run_until_complete, coro)

def test_create_datagram_endpoint_connect_err(self):
self.loop.sock_connect = mock.Mock()
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_asyncio/test_proactor_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def test_loop_reading_data(self):
self.loop._proactor.recv_into.assert_called_with(self.sock, called_buf)
self.protocol.data_received.assert_called_with(bytearray(buf))

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

@unittest.skipIf(sys.flags.optimize, "Assertions are disabled in optimized mode")
def test_datagram_loop_reading_no_data(self):
res = self.loop.create_future()
res.set_result((b'', ('127.0.0.1', 12068)))
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_asyncio/test_selector_events.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Tests for selector_events.py"""

import sys
import selectors
import socket
import unittest
Expand Down Expand Up @@ -804,6 +805,7 @@ def test_write_ready_closing(self):
self.sock.close.assert_called_with()
self.protocol.connection_lost.assert_called_with(None)

@unittest.skipIf(sys.flags.optimize, "Assertions are disabled in optimized mode")
def test_write_ready_no_data(self):
transport = self.socket_transport()
# This is an internal error.
Expand Down
68 changes: 68 additions & 0 deletions Lib/test/test_functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2722,6 +2722,74 @@ def _(arg: int | float):
self.assertEqual(f(1), "types.UnionType")
self.assertEqual(f(1.0), "types.UnionType")

def test_register_genericalias(self):
@functools.singledispatch
def f(arg):
return "default"

with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
f.register(list[int], lambda arg: "types.GenericAlias")
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
f.register(typing.List[int], lambda arg: "typing.GenericAlias")
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
f.register(list[int] | str, lambda arg: "types.UnionTypes(types.GenericAlias)")
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
f.register(typing.List[float] | bytes, lambda arg: "typing.Union[typing.GenericAlias]")
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
f.register(typing.Any, lambda arg: "typing.Any")

self.assertEqual(f([1]), "default")
self.assertEqual(f([1.0]), "default")
self.assertEqual(f(""), "default")
self.assertEqual(f(b""), "default")

def test_register_genericalias_decorator(self):
@functools.singledispatch
def f(arg):
return "default"

with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
f.register(list[int])
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
f.register(typing.List[int])
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
f.register(list[int] | str)
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
f.register(typing.List[int] | str)
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
f.register(typing.Any)

def test_register_genericalias_annotation(self):
@functools.singledispatch
def f(arg):
return "default"

with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"):
@f.register
def _(arg: list[int]):
return "types.GenericAlias"
with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"):
@f.register
def _(arg: typing.List[float]):
return "typing.GenericAlias"
with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"):
@f.register
def _(arg: list[int] | str):
return "types.UnionType(types.GenericAlias)"
with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"):
@f.register
def _(arg: typing.List[float] | bytes):
return "typing.Union[typing.GenericAlias]"
with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"):
@f.register
def _(arg: typing.Any):
return "typing.Any"

self.assertEqual(f([1]), "default")
self.assertEqual(f([1.0]), "default")
self.assertEqual(f(""), "default")
self.assertEqual(f(b""), "default")


class CachedCostItem:
_cost = 1
Expand Down
7 changes: 5 additions & 2 deletions Lib/test/test_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -667,10 +667,13 @@ def __new__(cls, arg, newarg=None):
self = super().__new__(cls, arg)
self.newarg = newarg
return self
u = subclass_with_new([1, 2], newarg=3)
u = subclass_with_new([1, 2])
self.assertIs(type(u), subclass_with_new)
self.assertEqual(set(u), {1, 2})
self.assertEqual(u.newarg, 3)
self.assertIsNone(u.newarg)
# disallow kwargs in __new__ only (https://bugs.python.org/issue43413#msg402000)
with self.assertRaises(TypeError):
subclass_with_new([1, 2], newarg=3)


class TestFrozenSet(TestJointOps, unittest.TestCase):
Expand Down
11 changes: 9 additions & 2 deletions Lib/tkinter/test/test_tkinter/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,13 @@ def test_clipboard_astral(self):
root.clipboard_get()

def test_winfo_rgb(self):

def assertApprox(col1, col2):
# A small amount of flexibility is required (bpo-45496)
# 33 is ~0.05% of 65535, which is a reasonable margin
for col1_channel, col2_channel in zip(col1, col2):
self.assertAlmostEqual(col1_channel, col2_channel, delta=33)

root = self.root
rgb = root.winfo_rgb

Expand All @@ -210,9 +217,9 @@ def test_winfo_rgb(self):
# #RGB - extends each 4-bit hex value to be 16-bit.
self.assertEqual(rgb('#F0F'), (0xFFFF, 0x0000, 0xFFFF))
# #RRGGBB - extends each 8-bit hex value to be 16-bit.
self.assertEqual(rgb('#4a3c8c'), (0x4a4a, 0x3c3c, 0x8c8c))
assertApprox(rgb('#4a3c8c'), (0x4a4a, 0x3c3c, 0x8c8c))
# #RRRRGGGGBBBB
self.assertEqual(rgb('#dede14143939'), (0xdede, 0x1414, 0x3939))
assertApprox(rgb('#dede14143939'), (0xdede, 0x1414, 0x3939))
# Invalid string.
with self.assertRaises(tkinter.TclError):
rgb('#123456789a')
Expand Down
6 changes: 6 additions & 0 deletions Lib/unittest/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ def printErrors(self):
self.stream.flush()
self.printErrorList('ERROR', self.errors)
self.printErrorList('FAIL', self.failures)
unexpectedSuccesses = getattr(self, 'unexpectedSuccesses', ())
if unexpectedSuccesses:
self.stream.writeln(self.separator1)
for test in unexpectedSuccesses:
self.stream.writeln(f"UNEXPECTED SUCCESS: {self.getDescription(test)}")
self.stream.flush()

def printErrorList(self, flavour, errors):
for test, err in errors:
Expand Down
40 changes: 32 additions & 8 deletions Lib/unittest/test/test_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ def testPass(self):
pass
def testFail(self):
raise AssertionError
def testError(self):
1/0
@unittest.skip('skipping')
def testSkipped(self):
raise AssertionError
@unittest.expectedFailure
def testExpectedFailure(self):
raise AssertionError
@unittest.expectedFailure
def testUnexpectedSuccess(self):
pass

class FooBarLoader(unittest.TestLoader):
"""Test loader that returns a suite containing FooBar."""
Expand Down Expand Up @@ -111,9 +122,13 @@ def test_NonExit(self):
testRunner=unittest.TextTestRunner(stream=stream),
testLoader=self.FooBarLoader())
self.assertTrue(hasattr(program, 'result'))
self.assertIn('\nFAIL: testFail ', stream.getvalue())
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))

out = stream.getvalue()
self.assertIn('\nFAIL: testFail ', out)
self.assertIn('\nERROR: testError ', out)
self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out)
expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, '
'expected failures=1, unexpected successes=1)\n')
self.assertTrue(out.endswith(expected))

def test_Exit(self):
stream = BufferedWriter()
Expand All @@ -124,9 +139,13 @@ def test_Exit(self):
testRunner=unittest.TextTestRunner(stream=stream),
exit=True,
testLoader=self.FooBarLoader())
self.assertIn('\nFAIL: testFail ', stream.getvalue())
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))

out = stream.getvalue()
self.assertIn('\nFAIL: testFail ', out)
self.assertIn('\nERROR: testError ', out)
self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out)
expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, '
'expected failures=1, unexpected successes=1)\n')
self.assertTrue(out.endswith(expected))

def test_ExitAsDefault(self):
stream = BufferedWriter()
Expand All @@ -136,8 +155,13 @@ def test_ExitAsDefault(self):
argv=["foobar"],
testRunner=unittest.TextTestRunner(stream=stream),
testLoader=self.FooBarLoader())
self.assertIn('\nFAIL: testFail ', stream.getvalue())
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
out = stream.getvalue()
self.assertIn('\nFAIL: testFail ', out)
self.assertIn('\nERROR: testError ', out)
self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out)
expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, '
'expected failures=1, unexpected successes=1)\n')
self.assertTrue(out.endswith(expected))


class InitialisableProgram(unittest.TestProgram):
Expand Down
Loading

0 comments on commit 59672cf

Please sign in to comment.