dataclasses module
Native, in-sandbox @dataclass: sandboxed code can define its own dataclasses,
executed entirely inside the sandbox (unlike host-supplied class instances,
which enter via the ClassInstance wrapper and dispatch back to the host —
see classes.md).
Host-supplied instances and this module barely interact:
dataclasses.is_dataclass(x) honours the flag the host sent, but fields()
and asdict() do not work on host instances (they are not native
dataclasses). Bare dataclasses are NOT accepted as inputs — the host must
wrap them in ClassInstance explicitly.
@dataclass, @dataclass(...) with eq and/or frozen, and is_dataclass
exist. Everything below raises at decoration time rather than producing a
subtly wrong class.
Each raises NotImplementedError, marking a feature Monty has not built yet
rather than a mistake in the calling code. CPython accepts all of them, so the
exception type is a divergence in its own right: code catching TypeError
around a decoration will not catch these.
- Every
@dataclass(...)option excepteqandfrozen—init,repr,order,unsafe_hash,match_args,kw_only,slotsandweakref_slot. Setting one away from its CPython default raisesNotImplementedError: dataclass() does not yet support the <name> option; each is named individually rather than reported as an unknown keyword. Ordering dunders therefore do not exist, and hashing is whatevereq/frozenimply. __post_init__— raisesNotImplementedError: dataclass() does not yet support __post_init__ in a class body, which would be silently skipped.InitVar[...]— raisesNotImplementedError: dataclass() does not yet support InitVar (field <name>), which would become an ordinary field. Detected textually, since annotations are never evaluated: the name need not be imported to be rejected.field()/default_factory/MISSING—field(...)in a class body raisesNameError. There is noMISSINGobject, so theFieldattributes whose value would be one raiseNotImplementedError: Field.default is not yet supported, dataclasses.MISSING is not implemented(likewisedefault_factory, anddefaultonly for a field that has none).Field.metadataandField._field_typeraise the same way, fortypes.MappingProxyTypeanddataclasses._FIELD.- Module helpers —
fields,asdict,astupleandreplacedo not exist: accessing them raisesAttributeError, notNotImplementedError, since the module has no such attribute.
Mutable defaults are rejected as CPython rejects them
(ValueError: mutable default <class 'list'> for field xs is not allowed: use default_factory), and so is a non-default
field after a defaulted one
(TypeError: non-default argument 'b' follows default argument 'a').
- Annotations are stringized. Fields come from the class’s
__annotations__, which Monty stores as never-evaluated source text (always PEP 563); see typing.md. Field discovery and the generated methods are unaffected, the field type being inert metadata, butC.__dataclass_fields__['x'].typeis the string'int', not theinttype object. __dataclass_fields__holds only real fields. CPython keepsClassVar(andInitVar) entries in the mapping, marked_FIELD_CLASSVAR, and filters them infields(). Monty has no field kinds, so the mapping is the field list and class variables never appear in it.Fieldrenders differently.repr(field)follows CPython’s layout but writesMISSINGwhere CPython writes<dataclasses._MISSING_TYPE object at 0x..>, and the stringizedtype.repr(type(field))is<class 'Field'>, not<class 'dataclasses.Field'>(Field.__name__matches either way, so attribute errors read the same).- Overwriting
__dataclass_fields__un-marks the class. Every dunder reads the mapping from the class namespace, soC.__dataclass_fields__ = 5makesis_dataclass(C)false andC(...)construct like a plain class. CPython keeps its generated methods and still callsCa dataclass. ClassVar/InitVardetection is purely textual. Monty matches the annotation text (bare, dotted, subscripted, or quoted) without checking that the name is actually imported, where CPython resolves a string annotation through the defining module’s namespace. Soc: "ClassVar[int]"withoutClassVarin scope is excluded by Monty but is an ordinary field to CPython. Conversely any dotted spelling matches, so a same-named attribute on an unrelated module (mymod.ClassVar) is treated astyping.ClassVar.- A field holding a function or bound method reprs differently, since
Monty’s own
reprfor those differs (see classes.md). Only the text differs; the value and its equality match CPython. - A class-body
__setattr__never runs for the synthesized__init__, which writes fields straight into the instance__dict__. This is the never-dispatched attribute hook described in classes.md rather than something dataclass-specific, so@dataclassdoes not reject it. @dataclasson a non-class (e.g.dataclasses.dataclass(5)) raisesTypeError: dataclass() should be called on a class, not '<type>'. CPython instead raises an incidentalAttributeErrorabout__module__from its implementation. The@decosyntax only ever targets a class, so this affects only direct calls.dataclass(...)returns a native callable, not a Python function. CPython builds a closure, which Monty cannot: a native function has nowhere to keep the bound options but its own value. Applying it to a class is identical, and it reprs as<function dataclass at 0x..>, buttype()saysbuiltin_function_or_methodwhere CPython saysfunction, and CPython’s repr names the closure (dataclass.<locals>.wrap). Having nowhere to live but the value, the options are the value:dataclass(frozen=True) is dataclass(frozen=True)isTrue, where each CPython call builds a fresh closure. Fixable only if Monty gains closures over native functions; nothing else depends on that, so it is not planned.del obj.fieldon a frozen instance never raisescannot delete field, because Monty’s parser has nodelstatement at all. (Assignment matches CPython, message included, anddataclasses.FrozenInstanceErroris importable.)- Re-decorating a dataclass rebuilds it.
C = dataclass(frozen=True)(C)gives Monty a fully frozen class, where CPython keeps the__init__its first decoration generated — one that writes fields through the new frozen__setattr__, so CPython’s re-decorated class raisesFrozenInstanceErrorthe moment you construct it. Monty synthesizes from the current metadata, so it constructs normally. __dataclass_params__reads back normalised.C.__dataclass_params__exists, reprs like CPython’s and answers all ten flags, but each is theboolMonty acted on:@dataclass(frozen=1)reportsfrozen=Truewhere CPython echoes the1you passed. As in CPython the object only reports the options — the class acts on what it was decorated with — so assigning another one changes what you read back and nothing else.
- No inheritance, so field inheritance across base dataclasses is unsupported (Monty has no class inheritance at all).
slots=True/weakref_slot=True— no__slots__, no weakrefs.