-
Notifications
You must be signed in to change notification settings - Fork 386
Add collections module
#535
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,201 @@ | ||
| import sys | ||
| from _collections_abc import dict_items, dict_keys, dict_values | ||
| from types import GenericAlias | ||
| from typing import Any, ClassVar, Generic, NoReturn, SupportsIndex, TypeVar, final, overload, type_check_only | ||
|
|
||
| from _typeshed import SupportsItems, SupportsKeysAndGetItem, SupportsRichComparison, SupportsRichComparisonT | ||
| from typing_extensions import Self, disjoint_base | ||
|
|
||
| if sys.version_info >= (3, 10): | ||
| from collections.abc import ( | ||
| Callable, | ||
| ItemsView, | ||
| Iterable, | ||
| Iterator, | ||
| KeysView, | ||
| Mapping, | ||
| MutableMapping, | ||
| MutableSequence, | ||
| Sequence, | ||
| ValuesView, | ||
| ) | ||
| else: | ||
| from _collections_abc import * | ||
|
|
||
| __all__ = [ | ||
| 'Counter', | ||
| 'defaultdict', | ||
| 'deque', | ||
| 'namedtuple', | ||
| ] | ||
|
|
||
| _S = TypeVar('_S') | ||
| _T = TypeVar('_T') | ||
| _T1 = TypeVar('_T1') | ||
| _T2 = TypeVar('_T2') | ||
| _KT = TypeVar('_KT') | ||
| _VT = TypeVar('_VT') | ||
| _KT_co = TypeVar('_KT_co', covariant=True) | ||
| _VT_co = TypeVar('_VT_co', covariant=True) | ||
|
|
||
| # namedtuple is special-cased in the type checker; the initializer is ignored. | ||
| def namedtuple( | ||
| typename: str, | ||
| field_names: str | Iterable[str], | ||
| *, | ||
| rename: bool = False, | ||
| module: str | None = None, | ||
| defaults: Iterable[Any] | None = None, | ||
| ) -> type[tuple[Any, ...]]: ... | ||
|
|
||
|
|
||
| # NOTE: This is a Monty-narrowed copy of the upstream typeshed stub. Only the | ||
| # members implemented by Monty's runtime are exposed (deque, defaultdict, | ||
| # Counter, namedtuple); OrderedDict, ChainMap, UserDict, UserList and | ||
| # UserString are intentionally omitted so type-checking matches the runtime. | ||
| # The source of truth is custom/collections/__init__.pyi (see custom/README.md). | ||
|
|
||
| @disjoint_base | ||
| class deque(MutableSequence[_T]): | ||
| @property | ||
| def maxlen(self) -> int | None: ... | ||
| @overload | ||
| def __init__(self, *, maxlen: int | None = None) -> None: ... | ||
| @overload | ||
| def __init__(self, iterable: Iterable[_T], maxlen: int | None = None) -> None: ... | ||
| def append(self, x: _T, /) -> None: ... | ||
| def appendleft(self, x: _T, /) -> None: ... | ||
| def copy(self) -> Self: ... | ||
| def count(self, x: _T, /) -> int: ... | ||
| def extend(self, iterable: Iterable[_T], /) -> None: ... | ||
| def extendleft(self, iterable: Iterable[_T], /) -> None: ... | ||
| def insert(self, i: int, x: _T, /) -> None: ... | ||
| def index(self, x: _T, start: int = 0, stop: int = ..., /) -> int: ... | ||
| def pop(self) -> _T: ... # type: ignore[override] | ||
| def popleft(self) -> _T: ... | ||
| def remove(self, value: _T, /) -> None: ... | ||
| def rotate(self, n: int = 1, /) -> None: ... | ||
| def __copy__(self) -> Self: ... | ||
| def __len__(self) -> int: ... | ||
| __hash__: ClassVar[None] # type: ignore[assignment] | ||
| # These methods of deque don't take slices, unlike MutableSequence, hence the type: ignores | ||
| def __getitem__(self, key: SupportsIndex, /) -> _T: ... # type: ignore[override] | ||
| def __setitem__(self, key: SupportsIndex, value: _T, /) -> None: ... # type: ignore[override] | ||
| def __delitem__(self, key: SupportsIndex, /) -> None: ... # type: ignore[override] | ||
| def __contains__(self, key: object, /) -> bool: ... | ||
| def __reduce__(self) -> tuple[type[Self], tuple[()], None, Iterator[_T]]: ... | ||
| def __iadd__(self, value: Iterable[_T], /) -> Self: ... | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The Prompt for AI agents |
||
| def __add__(self, value: Self, /) -> Self: ... | ||
| def __mul__(self, value: int, /) -> Self: ... | ||
| def __imul__(self, value: int, /) -> Self: ... | ||
| def __lt__(self, value: deque[_T], /) -> bool: ... | ||
| def __le__(self, value: deque[_T], /) -> bool: ... | ||
| def __gt__(self, value: deque[_T], /) -> bool: ... | ||
| def __ge__(self, value: deque[_T], /) -> bool: ... | ||
| def __eq__(self, value: object, /) -> bool: ... | ||
| def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... | ||
|
|
||
| class Counter(dict[_T, int], Generic[_T]): | ||
| @overload | ||
| def __init__(self, iterable: None = None, /) -> None: ... | ||
| @overload | ||
| def __init__(self: Counter[str], iterable: None = None, /, **kwargs: int) -> None: ... | ||
| @overload | ||
| def __init__(self, mapping: SupportsKeysAndGetItem[_T, int], /) -> None: ... | ||
| @overload | ||
| def __init__(self, iterable: Iterable[_T], /) -> None: ... | ||
| def copy(self) -> Self: ... | ||
| def elements(self) -> Iterator[_T]: ... | ||
| def most_common(self, n: int | None = None) -> list[tuple[_T, int]]: ... | ||
| @classmethod | ||
| def fromkeys(cls, iterable: Any, v: int | None = None) -> NoReturn: ... # type: ignore[override] | ||
| @overload | ||
| def subtract(self, iterable: None = None, /) -> None: ... | ||
| @overload | ||
| def subtract(self, mapping: Mapping[_T, int], /) -> None: ... | ||
| @overload | ||
| def subtract(self, iterable: Iterable[_T], /) -> None: ... | ||
| # Unlike dict.update(), use Mapping instead of SupportsKeysAndGetItem for the first overload | ||
| # (source code does an `isinstance(other, Mapping)` check) | ||
| # | ||
| # The second overload is also deliberately different to dict.update() | ||
| # (if it were `Iterable[_T] | Iterable[tuple[_T, int]]`, | ||
| # the tuples would be added as keys, breaking type safety) | ||
| @overload # type: ignore[override] | ||
| def update(self, m: Mapping[_T, int], /, **kwargs: int) -> None: ... | ||
| @overload | ||
| def update(self, iterable: Iterable[_T], /, **kwargs: int) -> None: ... | ||
| @overload | ||
| def update(self, iterable: None = None, /, **kwargs: int) -> None: ... | ||
| def __missing__(self, key: _T) -> int: ... | ||
| def __delitem__(self, elem: object) -> None: ... | ||
| if sys.version_info >= (3, 10): | ||
| def __eq__(self, other: object) -> bool: ... | ||
| def __ne__(self, other: object) -> bool: ... | ||
|
|
||
| def __add__(self, other: Counter[_S]) -> Counter[_T | _S]: ... | ||
| def __sub__(self, other: Counter[_T]) -> Counter[_T]: ... | ||
| def __and__(self, other: Counter[_T]) -> Counter[_T]: ... | ||
| def __or__(self, other: Counter[_S]) -> Counter[_T | _S]: ... # type: ignore[override] | ||
| def __pos__(self) -> Counter[_T]: ... | ||
| def __neg__(self) -> Counter[_T]: ... | ||
| # several type: ignores because __iadd__ is supposedly incompatible with __add__, etc. | ||
| def __iadd__(self, other: SupportsItems[_T, int]) -> Self: ... # type: ignore[misc] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The Prompt for AI agents |
||
| def __isub__(self, other: SupportsItems[_T, int]) -> Self: ... | ||
| def __iand__(self, other: SupportsItems[_T, int]) -> Self: ... | ||
| def __ior__(self, other: SupportsItems[_T, int]) -> Self: ... # type: ignore[override,misc] | ||
| if sys.version_info >= (3, 10): | ||
| def total(self) -> int: ... | ||
| def __le__(self, other: Counter[Any]) -> bool: ... | ||
| def __lt__(self, other: Counter[Any]) -> bool: ... | ||
| def __ge__(self, other: Counter[Any]) -> bool: ... | ||
| def __gt__(self, other: Counter[Any]) -> bool: ... | ||
|
|
||
| @disjoint_base | ||
| class defaultdict(dict[_KT, _VT]): | ||
| default_factory: Callable[[], _VT] | None | ||
| @overload | ||
| def __init__(self) -> None: ... | ||
| @overload | ||
| def __init__(self: defaultdict[str, _VT], **kwargs: _VT) -> None: ... # pyright: ignore[reportInvalidTypeVarUse] #11780 | ||
| @overload | ||
| def __init__(self, default_factory: Callable[[], _VT] | None, /) -> None: ... | ||
| @overload | ||
| def __init__( | ||
| self: defaultdict[str, _VT], # pyright: ignore[reportInvalidTypeVarUse] #11780 | ||
| default_factory: Callable[[], _VT] | None, | ||
| /, | ||
| **kwargs: _VT, | ||
| ) -> None: ... | ||
| @overload | ||
| def __init__(self, default_factory: Callable[[], _VT] | None, map: SupportsKeysAndGetItem[_KT, _VT], /) -> None: ... | ||
| @overload | ||
| def __init__( | ||
| self: defaultdict[str, _VT], # pyright: ignore[reportInvalidTypeVarUse] #11780 | ||
| default_factory: Callable[[], _VT] | None, | ||
| map: SupportsKeysAndGetItem[str, _VT], | ||
| /, | ||
| **kwargs: _VT, | ||
| ) -> None: ... | ||
| @overload | ||
| def __init__(self, default_factory: Callable[[], _VT] | None, iterable: Iterable[tuple[_KT, _VT]], /) -> None: ... | ||
| @overload | ||
| def __init__( | ||
| self: defaultdict[str, _VT], # pyright: ignore[reportInvalidTypeVarUse] #11780 | ||
| default_factory: Callable[[], _VT] | None, | ||
| iterable: Iterable[tuple[str, _VT]], | ||
| /, | ||
| **kwargs: _VT, | ||
| ) -> None: ... | ||
| def __missing__(self, key: _KT, /) -> _VT: ... | ||
| def __copy__(self) -> Self: ... | ||
| def copy(self) -> Self: ... | ||
| @overload | ||
| def __or__(self, value: dict[_KT, _VT], /) -> Self: ... | ||
| @overload | ||
| def __or__(self, value: dict[_T1, _T2], /) -> defaultdict[_KT | _T1, _VT | _T2]: ... | ||
| @overload | ||
| def __ror__(self, value: dict[_KT, _VT], /) -> Self: ... | ||
| @overload | ||
| def __ror__(self, value: dict[_T1, _T2], /) -> defaultdict[_KT | _T1, _VT | _T2]: ... # type: ignore[misc] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -334,6 +334,17 @@ def main() -> int: | |
| for file in CUSTOM_DIR.glob('*.pyi'): | ||
| shutil.copy2(file, STDLIB_DIR) | ||
| custom_count += 1 | ||
| # Package overrides: a `custom/<pkg>/` directory replaces the matching | ||
| # module file within the vendored `stdlib/<pkg>/` package (e.g. | ||
| # `custom/collections/__init__.pyi` narrows `collections` to Monty's | ||
| # implemented members while leaving `collections/abc.pyi` untouched). | ||
| for pkg_dir in CUSTOM_DIR.iterdir(): | ||
| if not pkg_dir.is_dir(): | ||
| continue | ||
| dest_pkg = STDLIB_DIR / pkg_dir.name | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Package overrides can fail at runtime — Prompt for AI agents |
||
| for file in pkg_dir.glob('*.pyi'): | ||
| shutil.copy2(file, dest_pkg / file.name) | ||
| custom_count += 1 | ||
| print(f'Copied {custom_count} custom typeshed files') | ||
|
|
||
| return 0 | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: The
dequetype stub includes__reduce__, but the runtime does not implement it (the limitations doc explicitly says "No__copy__/ pickling /__reduce__"). Type checkers will consider it valid, leading to false positives. Consider removing it from the stub.Prompt for AI agents