Skip to content
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

Make collections.abc.* generic #5

Merged
merged 5 commits into from
Jan 31, 2020
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
38 changes: 38 additions & 0 deletions Lib/_collections_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from abc import ABCMeta, abstractmethod
import sys
from types import GenericAlias

__all__ = ["Awaitable", "Coroutine",
"AsyncIterable", "AsyncIterator", "AsyncGenerator",
Expand Down Expand Up @@ -110,6 +111,10 @@ def __subclasshook__(cls, C):
return _check_methods(C, "__await__")
return NotImplemented

def __class_getitem__(cls, item):
"""Internal: PEP 585."""
return GenericAlias(cls, item)


class Coroutine(Awaitable):

Expand Down Expand Up @@ -169,6 +174,10 @@ def __subclasshook__(cls, C):
return _check_methods(C, "__aiter__")
return NotImplemented

def __class_getitem__(cls, item):
"""Internal: PEP 585."""
return GenericAlias(cls, item)


class AsyncIterator(AsyncIterable):

Expand Down Expand Up @@ -255,6 +264,10 @@ def __subclasshook__(cls, C):
return _check_methods(C, "__iter__")
return NotImplemented

def __class_getitem__(cls, item):
"""Internal: PEP 585."""
return GenericAlias(cls, item)


class Iterator(Iterable):

Expand All @@ -274,6 +287,7 @@ def __subclasshook__(cls, C):
return _check_methods(C, '__iter__', '__next__')
return NotImplemented


Iterator.register(bytes_iterator)
Iterator.register(bytearray_iterator)
#Iterator.register(callable_iterator)
Expand Down Expand Up @@ -353,6 +367,7 @@ def __subclasshook__(cls, C):
'send', 'throw', 'close')
return NotImplemented


Generator.register(generator)


Expand Down Expand Up @@ -385,6 +400,11 @@ def __subclasshook__(cls, C):
return _check_methods(C, "__contains__")
return NotImplemented

def __class_getitem__(cls, item):
"""Internal: PEP 585."""
return GenericAlias(cls, item)


class Collection(Sized, Iterable, Container):

__slots__ = ()
Expand All @@ -395,6 +415,7 @@ def __subclasshook__(cls, C):
return _check_methods(C, "__len__", "__iter__", "__contains__")
return NotImplemented


class Callable(metaclass=ABCMeta):

__slots__ = ()
Expand All @@ -409,6 +430,10 @@ def __subclasshook__(cls, C):
return _check_methods(C, "__call__")
return NotImplemented

def __class_getitem__(cls, item):
"""Internal: PEP 585."""
return GenericAlias(cls, item)


### SETS ###

Expand Down Expand Up @@ -550,6 +575,7 @@ def _hash(self):
h = 590923713
return h


Set.register(frozenset)


Expand Down Expand Up @@ -632,6 +658,7 @@ def __isub__(self, it):
self.discard(value)
return self


MutableSet.register(set)


Expand Down Expand Up @@ -688,6 +715,7 @@ def __eq__(self, other):

__reversed__ = None


Mapping.register(mappingproxy)


Expand All @@ -704,6 +732,10 @@ def __len__(self):
def __repr__(self):
return '{0.__class__.__name__}({0._mapping!r})'.format(self)

def __class_getitem__(cls, item):
"""Internal: PEP 585."""
return GenericAlias(cls, item)


class KeysView(MappingView, Set):

Expand All @@ -719,6 +751,7 @@ def __contains__(self, key):
def __iter__(self):
yield from self._mapping


KeysView.register(dict_keys)


Expand All @@ -743,6 +776,7 @@ def __iter__(self):
for key in self._mapping:
yield (key, self._mapping[key])


ItemsView.register(dict_items)


Expand All @@ -761,6 +795,7 @@ def __iter__(self):
for key in self._mapping:
yield self._mapping[key]


ValuesView.register(dict_values)


Expand Down Expand Up @@ -847,6 +882,7 @@ def setdefault(self, key, default=None):
self[key] = default
return default


MutableMapping.register(dict)


Expand Down Expand Up @@ -914,6 +950,7 @@ def count(self, value):
'S.count(value) -> integer -- return number of occurrences of value'
return sum(1 for v in self if v is value or v == value)


Sequence.register(tuple)
Sequence.register(str)
Sequence.register(range)
Expand Down Expand Up @@ -1000,5 +1037,6 @@ def __iadd__(self, values):
self.extend(values)
return self


MutableSequence.register(list)
MutableSequence.register(bytearray) # Multiply inheriting, see ByteString
6 changes: 0 additions & 6 deletions Lib/collections/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -962,10 +962,6 @@ def __init__(self, dict=None, /, **kwargs):
if kwargs:
self.update(kwargs)

# It's a generic class, just like dict.
def __class_getitem__(cls, item):
return _GenericAlias(cls, item)

def __len__(self): return len(self.data)
def __getitem__(self, key):
if key in self.data:
Expand Down Expand Up @@ -1029,8 +1025,6 @@ def __init__(self, initlist=None):
self.data[:] = initlist.data[:]
else:
self.data = list(initlist)
def __class_getitem__(cls, item):
return _GenericAlias(cls, item)
def __repr__(self): return repr(self.data)
def __lt__(self, other): return self.data < self.__cast(other)
def __le__(self, other): return self.data <= self.__cast(other)
Expand Down
22 changes: 19 additions & 3 deletions Lib/test/test_genericalias.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
"""Tests for C-implemented GenericAlias."""

import unittest
from collections import defaultdict, deque
from collections import (
defaultdict, deque, OrderedDict, Counter, UserDict, UserList
)
from collections.abc import *
from contextlib import AbstractContextManager, AbstractAsyncContextManager
from io import IOBase
from re import Pattern, Match


class BaseTest(unittest.TestCase):
"""Test basics."""

def test_subscriptable(self):
for t in (tuple, list, dict, set, frozenset,
defaultdict, deque,
defaultdict, deque,
OrderedDict, Counter, UserDict, UserList,
IOBase,
Pattern, Match,
AbstractContextManager, AbstractAsyncContextManager,
Awaitable, Coroutine,
AsyncIterable, AsyncIterator,
AsyncGenerator, Generator,
Iterable, Iterator,
Reversible,
Container, Collection,
Callable,
Set, MutableSet,
Mapping, MutableMapping, MappingView,
KeysView, ItemsView, ValuesView,
Sequence, MutableSequence,
):
tname = t.__name__
with self.subTest(f"Testing {tname}"):
Expand All @@ -23,7 +39,7 @@ def test_subscriptable(self):
self.assertEqual(alias.__parameters__, (int,))

def test_unsubscriptable(self):
for t in int, str, float:
for t in int, str, float, Sized, Hashable:
tname = t.__name__
with self.subTest(f"Testing {tname}"):
with self.assertRaises(TypeError):
Expand Down
2 changes: 1 addition & 1 deletion Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@ class _TypingEllipsis:

_SPECIAL_NAMES = ['__abstractmethods__', '__annotations__', '__dict__', '__doc__',
'__init__', '__module__', '__new__', '__slots__',
'__subclasshook__', '__weakref__']
'__subclasshook__', '__weakref__', '__class_getitem__']

# These special attributes will be not collected as protocol members.
EXCLUDED_ATTRIBUTES = _TYPING_INTERNALS + _SPECIAL_NAMES + ['_MutableMapping__marker']
Expand Down