Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

updated _collections_abc.py and test_collections.py to CPython 3.11.2 #5016

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 18, 2023
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
68 changes: 13 additions & 55 deletions 68 Lib/_collections_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,25 +430,13 @@ def __new__(cls, origin, args):
raise TypeError(
"Callable must be used as Callable[[arg, ...], result].")
t_args, t_result = args
if isinstance(t_args, list):
if isinstance(t_args, (tuple, list)):
args = (*t_args, t_result)
elif not _is_param_expr(t_args):
raise TypeError(f"Expected a list of types, an ellipsis, "
f"ParamSpec, or Concatenate. Got {t_args}")
return super().__new__(cls, origin, args)

@property
def __parameters__(self):
params = []
for arg in self.__args__:
# Looks like a genericalias
if hasattr(arg, "__parameters__") and isinstance(arg.__parameters__, tuple):
params.extend(arg.__parameters__)
else:
if _is_typevarlike(arg):
params.append(arg)
return tuple(dict.fromkeys(params))

def __repr__(self):
if len(self.__args__) == 2 and _is_param_expr(self.__args__[0]):
return super().__repr__()
Expand All @@ -468,54 +456,24 @@ def __getitem__(self, item):
# code is copied from typing's _GenericAlias and the builtin
# types.GenericAlias.

# A special case in PEP 612 where if X = Callable[P, int],
# then X[int, str] == X[[int, str]].
param_len = len(self.__parameters__)
if param_len == 0:
raise TypeError(f'{self} is not a generic class')
if not isinstance(item, tuple):
item = (item,)
if (param_len == 1 and _is_param_expr(self.__parameters__[0])
# A special case in PEP 612 where if X = Callable[P, int],
# then X[int, str] == X[[int, str]].
if (len(self.__parameters__) == 1
and _is_param_expr(self.__parameters__[0])
and item and not _is_param_expr(item[0])):
item = (list(item),)
item_len = len(item)
if item_len != param_len:
raise TypeError(f'Too {"many" if item_len > param_len else "few"}'
f' arguments for {self};'
f' actual {item_len}, expected {param_len}')
subst = dict(zip(self.__parameters__, item))
new_args = []
for arg in self.__args__:
if _is_typevarlike(arg):
if _is_param_expr(arg):
arg = subst[arg]
if not _is_param_expr(arg):
raise TypeError(f"Expected a list of types, an ellipsis, "
f"ParamSpec, or Concatenate. Got {arg}")
else:
arg = subst[arg]
# Looks like a GenericAlias
elif hasattr(arg, '__parameters__') and isinstance(arg.__parameters__, tuple):
subparams = arg.__parameters__
if subparams:
subargs = tuple(subst[x] for x in subparams)
arg = arg[subargs]
new_args.append(arg)
item = (item,)

new_args = super().__getitem__(item).__args__

# args[0] occurs due to things like Z[[int, str, bool]] from PEP 612
if not isinstance(new_args[0], list):
if not isinstance(new_args[0], (tuple, list)):
t_result = new_args[-1]
t_args = new_args[:-1]
new_args = (t_args, t_result)
return _CallableGenericAlias(Callable, tuple(new_args))


def _is_typevarlike(arg):
obj = type(arg)
# looks like a TypeVar/ParamSpec
return (obj.__module__ == 'typing'
and obj.__name__ in {'ParamSpec', 'TypeVar'})

def _is_param_expr(obj):
"""Checks if obj matches either a list of types, ``...``, ``ParamSpec`` or
``_ConcatenateGenericAlias`` from typing.py
Expand Down Expand Up @@ -868,7 +826,7 @@ class KeysView(MappingView, Set):
__slots__ = ()

@classmethod
def _from_iterable(self, it):
def _from_iterable(cls, it):
return set(it)

def __contains__(self, key):
Expand All @@ -886,7 +844,7 @@ class ItemsView(MappingView, Set):
__slots__ = ()

@classmethod
def _from_iterable(self, it):
def _from_iterable(cls, it):
return set(it)

def __contains__(self, item):
Expand Down Expand Up @@ -1064,10 +1022,10 @@ def index(self, value, start=0, stop=None):
while stop is None or i < stop:
try:
v = self[i]
if v is value or v == value:
return i
except IndexError:
break
if v is value or v == value:
return i
i += 1
raise ValueError

Expand Down
50 changes: 31 additions & 19 deletions 50 Lib/test/test_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,14 +685,16 @@ def test_field_descriptor(self):
self.assertRaises(AttributeError, Point.x.__set__, p, 33)
self.assertRaises(AttributeError, Point.x.__delete__, p)

class NewPoint(tuple):
x = pickle.loads(pickle.dumps(Point.x))
y = pickle.loads(pickle.dumps(Point.y))
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
with self.subTest(proto=proto):
class NewPoint(tuple):
x = pickle.loads(pickle.dumps(Point.x, proto))
y = pickle.loads(pickle.dumps(Point.y, proto))

np = NewPoint([1, 2])
np = NewPoint([1, 2])

self.assertEqual(np.x, 1)
self.assertEqual(np.y, 2)
self.assertEqual(np.x, 1)
self.assertEqual(np.y, 2)

# TODO: RUSTPYTHON
@unittest.expectedFailure
Expand All @@ -706,6 +708,18 @@ def test_match_args(self):
Point = namedtuple('Point', 'x y')
self.assertEqual(Point.__match_args__, ('x', 'y'))

def test_non_generic_subscript(self):
# For backward compatibility, subscription works
# on arbitrary named tuple types.
Group = collections.namedtuple('Group', 'key group')
A = Group[int, list[int]]
self.assertEqual(A.__origin__, Group)
self.assertEqual(A.__parameters__, ())
self.assertEqual(A.__args__, (int, list[int]))
a = A(1, [2])
self.assertIs(type(a), Group)
self.assertEqual(a, (1, [2]))


################################################################################
### Abstract Base Classes
Expand Down Expand Up @@ -800,6 +814,8 @@ def throw(self, typ, val=None, tb=None):
def __await__(self):
yield

self.validate_abstract_methods(Awaitable, '__await__')

non_samples = [None, int(), gen(), object()]
for x in non_samples:
self.assertNotIsInstance(x, Awaitable)
Expand Down Expand Up @@ -852,6 +868,8 @@ def throw(self, typ, val=None, tb=None):
def __await__(self):
yield

self.validate_abstract_methods(Coroutine, '__await__', 'send', 'throw')

non_samples = [None, int(), gen(), object(), Bar()]
for x in non_samples:
self.assertNotIsInstance(x, Coroutine)
Expand Down Expand Up @@ -1597,6 +1615,7 @@ def __len__(self):
containers = [
seq,
ItemsView({1: nan, 2: obj}),
KeysView({1: nan, 2: obj}),
ValuesView({1: nan, 2: obj})
]
for container in containers:
Expand Down Expand Up @@ -1866,6 +1885,8 @@ def test_MutableMapping_subclass(self):
mymap['red'] = 5
self.assertIsInstance(mymap.keys(), Set)
self.assertIsInstance(mymap.keys(), KeysView)
self.assertIsInstance(mymap.values(), Collection)
self.assertIsInstance(mymap.values(), ValuesView)
self.assertIsInstance(mymap.items(), Set)
self.assertIsInstance(mymap.items(), ItemsView)

Expand Down Expand Up @@ -2381,19 +2402,10 @@ def test_gt(self):
self.assertFalse(Counter(a=2, b=1, c=0) > Counter('aab'))


################################################################################
### Run tests
################################################################################

def test_main(verbose=None):
NamedTupleDocs = doctest.DocTestSuite(module=collections)
test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs,
TestCollectionABCs, TestCounter, TestChainMap,
TestUserObjects,
]
support.run_unittest(*test_classes)
support.run_doctest(collections, verbose)
def load_tests(loader, tests, pattern):
tests.addTest(doctest.DocTestSuite(collections))
return tests


if __name__ == "__main__":
test_main(verbose=True)
unittest.main()
6 changes: 6 additions & 0 deletions 6 Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,10 @@ def test_consistency(self):

class CollectionsCallableTests(BaseCallableTests, BaseTestCase):
Callable = collections.abc.Callable
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_errors(self): # TODO: RUSTPYTHON, remove when this passes
super().test_errors() # TODO: RUSTPYTHON, remove when this passes

# TODO: RUSTPYTHON, AssertionError: 'collections.abc.Callable[__main__.ParamSpec, typing.TypeVar]' != 'collections.abc.Callable[~P, ~T]'
@unittest.expectedFailure
Expand Down Expand Up @@ -4916,6 +4920,8 @@ def test_basic_plain(self):
self.assertEqual(P, P)
self.assertIsInstance(P, ParamSpec)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_valid_uses(self):
P = ParamSpec('P')
T = TypeVar('T')
Expand Down
Morty Proxy This is a proxified and sanitized view of the page, visit original site.