|
| 1 | +# Constructor PRE snapshots |
| 2 | + |
| 3 | +When argument dumping is enabled for a class's `__init__`, TrainCheck records |
| 4 | +the receiver before the initializer body runs. The receiver may be empty, |
| 5 | +partially initialized by a subclass, or being initialized again. The instrumenter |
| 6 | +identifies initializers from their owning class and attribute name; a standalone |
| 7 | +function named `__init__` keeps ordinary argument serialization. |
| 8 | + |
| 9 | +The receiver is encoded under its static, fully qualified type name with an |
| 10 | +`_TRAINCHECK_CONSTRUCTOR_SNAPSHOT` marker. This is a deliberate change from |
| 11 | +ordinary object introspection for **all selected initializers**, including |
| 12 | +metaclass initializers. Other arguments and ordinary method calls keep their |
| 13 | +existing representation. The function's PRE, POST, and exception records remain. |
| 14 | + |
| 15 | +## Stored-state contract |
| 16 | + |
| 17 | +The marker contains: |
| 18 | + |
| 19 | +| Field | Meaning | |
| 20 | +| --- | --- | |
| 21 | +| `phase` | `before_init`; this does not claim initialization succeeded. | |
| 22 | +| `coverage` | `stored_attributes_only`; computed properties are not captured. | |
| 23 | +| `object_id` | Identity of the actual receiver. | |
| 24 | +| `dictionary_status` | `captured`, `absent`, or `unavailable` when storage exists but no native accessor remains accessible. | |
| 25 | +| `attributes` | Selected entries from the instance dictionary or native class namespace. | |
| 26 | +| `slots` | Selected populated native slots, each with its declaring `owner_type`, `name`, and tagged `value`. | |
| 27 | +| `unset_slots` | Selected declared slots whose storage has not been assigned. | |
| 28 | +| `requested_attributes` | The explicit selector, or `null` for all accessible stored fields. | |
| 29 | +| `unavailable_attributes` | Requested names with no captured dictionary entry or populated slot. | |
| 30 | + |
| 31 | +Dictionary entries and slot records are separate. A base slot, a derived slot, |
| 32 | +and a dictionary entry can all have the same name and hold different values; |
| 33 | +none overwrites another. Slot selectors use the stored name, including Python's |
| 34 | +name mangling for private slots. A requested name selects each matching storage |
| 35 | +location. An unset location stays explicit even if another matching slot has a |
| 36 | +value. An empty selector is distinct from unselected/all-field collection. |
| 37 | + |
| 38 | +Exact built-in scalars retain their values. Nonfinite floats have explicit |
| 39 | +`nan`, `+inf`, and `-inf` tags. Other values, including containers and tensors, |
| 40 | +are **identity/type references**, not recursive content snapshots or tensor |
| 41 | +hashes. Missing storage is never represented as a stored `None` value. |
| 42 | + |
| 43 | +## Avoiding application execution |
| 44 | + |
| 45 | +The snapshot reads native dictionary and slot descriptors from raw class |
| 46 | +namespaces. It bypasses receiver `__getattribute__`, `__getattr__`, `__dir__`, |
| 47 | +properties, custom descriptors, and custom metaclass lookup/properties. It also |
| 48 | +bypasses overridden dictionary iteration methods and custom metaclass equality. |
| 49 | +Constructor receivers are excluded from proxy-marker scans and argument |
| 50 | +unproxying on this dumping path; ordinary arguments keep those behaviors. |
| 51 | + |
| 52 | +Normal positional construction and explicit keyword-receiver calls are covered. |
| 53 | +If a native callable exposes no signature, its positional receiver is supported; |
| 54 | +no keyword receiver name is guessed. Missing-receiver errors are produced by |
| 55 | +the original callable and retain an exception record. |
| 56 | + |
| 57 | +Native extension state without a recognized storage descriptor, replaced slot |
| 58 | +descriptors, and computed attributes are outside this snapshot's coverage. |
| 59 | +Dictionary storage hidden behind a replacement property is marked unavailable |
| 60 | +unless an inherited native accessor still exposes it. Snapshots are synchronous, |
| 61 | +do not cache application metadata, and do not promise an atomic view during |
| 62 | +concurrent mutation of the same object's storage. |
| 63 | + |
| 64 | +Existing invariants that depended on introspected constructor receiver fields |
| 65 | +need recollection and activation validation against this representation. A |
| 66 | +requested property is explicitly unavailable, not a successfully observed value. |
0 commit comments