collections module
deque, namedtuple, defaultdict, and Counter are implemented and
feature-complete against CPython 3.14 apart from the divergences below. The
exact supported surface is pinned by the custom typeshed stub
(crates/monty-typeshed/custom/collections/__init__.pyi) and
crates/monty/tests/collections.rs. defaultdict and Counter are exposed as
the type objects themselves (like deque), so type(d) is defaultdict and
isinstance(c, Counter) hold.
OrderedDict, ChainMap, UserDict, UserList, UserString, and the
collections.abc submodule. Importing one raises
ImportError: cannot import name 'OrderedDict' from 'collections' (unknown location) (or AttributeError
as an attribute); import collections.abc raises ModuleNotFoundError. The
narrowed typeshed stub makes from collections import OrderedDict a type error
too, rather than something that type-checks and then fails at runtime.
d * 1.5raisesTypeError: unsupported operand type(s) for *: 'collections.deque' and 'float', where CPython sayscan't multiply sequence by non-int of type 'float'. Shared withlist.- Repeat counts in
[2**63, 2**64)are accepted where CPython rejects them: Monty’s repeat count is ausize, CPython’s a Cssize_t. Only observable for a bounded deque, whose result truncates tomaxlen:deque([1, 2], maxlen=2) * 2**63yieldsdeque([1, 2], maxlen=2)in Monty butOverflowErrorin CPython.2**64or more raisesOverflowErrorin both. - Returned to the host as a plain
list, so themaxlenbound and the deque-ness are lost; sending it back yields alist. (Same as defaultdict/Counter, which arrive as plain dicts.) - Mutation during iteration is not detected through
enumerate/zip/map/filter/reversed: those are eager (see builtins.md), so the deque is fully read before the loop body runs.for x in dand explicititer()/next()detect it exactly as CPython does. d += <any iterable>works (it isextend), even thoughlist’s+=still accepts only another list.- Extending from an eager builtin loses the partial result when it raises.
extend/extendleft/+=append each item as the source yields it, so an iterator raising part-way leaves the earlier items in place, as in CPython. Butmap/filter/zip/enumerateare eager (see builtins.md), sod += map(f, xs)with a raisingfraises before the extend begins and appends nothing, where CPython appends whatever was yielded first.
del d[i] and subclassing (class Q(deque)) both fail at compile time: the
del statement and class inheritance are unimplemented Monty-wide (see
language.md / classes.md), not deque limitations.
Field-name validation matches CPython’s messages exactly; see
namedtuple.md for the tuple-inherited surface and its
divergences. repr(Point) is <class 'Point'> where CPython gives
<class '__main__.Point'>, the repo-wide unqualified-class-name pattern.
- A
default_factorycannot call an external orosfunction; a missing-key access then raisesNotImplementedError. Plain factories (int,list,lambda, ordinary functions) work. This applies to every callback Monty invokes mid-expression (thekey=ofsorted/min/max,map,filter,__repr__), not just defaultdict. - Crosses the host boundary as a plain
dict: thedefault_factoryis a function and cannot cross, so sending the dict back yields a plaindict.
elements()returns a list, not CPython’s lazy iterator. The values and order match, but the whole sequence is built up front, so a very large count can hit the memory limit where CPython would stream.- Crosses the host boundary as a plain
dict. - In-place
c &= [list](a non-mapping) subscriptsother[elem]like CPython and raisesTypeError, but with Monty’s list-index wording (list indices must be integers, not 'str'vs CPython’s... or slices, not str). Mapping operands (c &= {'a': 1}) match CPython exactly, including theKeyErrorfor a key missing from a plain dict.
deque and defaultdict are C types, so CPython qualifies them
(collections.deque) in repr(T) and in every type-naming error message
(unsupported operand type(s), object is not callable, object has no attribute) while __name__ stays bare
('deque'); Monty matches both
surfaces.
Counter is a Python-level class, so CPython gives the bare name everywhere
except repr(Counter), which is <class 'collections.Counter'> where Monty
writes <class 'Counter'>. Everywhere else — __name__, the cannot use ...
unhashable clause, other type-naming errors — the bare name matches.