record module#
What a provider returns#
A provider answers with a ResolvedPart: an object of its own carrying
a PartIdentity, a JSON payload, and a materialize that attaches
geometry to the component.
ResolvedPart is a runtime-checkable protocol rather than a base class, so there is nothing to subclass. Write a frozen dataclass with identity and payload attributes and a materialize method:
>>> @dataclass(frozen=True)
... class AcmePart:
... identity: PartIdentity
... payload: dict[str, JSON]
...
... def materialize(self, component: Any) -> None:
... component.landpattern = ...
... component.symbol = ...
... apply_fields(component, decode_payload(self.payload))
The split between the two halves is about what the core may look at. The core defines PartIdentity, so it can serialize, filter, rank, pin and report on it; put in attributes whatever a design may reasonably select on. The provider defines everything else: the core stores payload verbatim, hands it back to rehydrate without reading it, and never builds geometry itself.
apply_fields() is the supported way to surface payload data on a
component, and RESERVED_FIELDS is what it refuses to touch.
- apply_fields(component, fields)[source]#
Set fields on a resolved component, skipping the reserved names.
For a provider surfacing what it carried in its payload; the core uses it for identity.attributes. Ordinary attribute sets, so the framework sees each one: object.__setattr__ or writing __dict__ would go around it.
Skips RESERVED_FIELDS and underscore names, so a catalogue cannot decide what the design decides or overwrite geometry the core owns.
- class PartIdentity(mpn, manufacturer=None, category='', provider='', provider_ref=None, attributes=dict())[source]#
Bases:
objectThe core-defined, serializable half of a resolved part.
An MPN identifies a part only together with its manufacturer. Leave manufacturer unset to mark a part as not orderable, which is what generator providers do for synthesized parts.
attributes is for selection: whatever is put here must also be filtered and ordered by, since filter keys and rank keys are one namespace. Distributor part numbers belong here; so does anything a design may reasonably ask for.
Data the source reports but cannot select on, or that may be stale, belongs in the provider’s payload instead. A remote catalogue that returns stock or lifecycle without accepting them as query terms must not claim them here.
Both reach the component as fields: the core sets attributes, and materialize sets whatever the provider carried in its payload.
- Parameters:
- class ResolvedPart(*args, **kwargs)[source]#
Bases:
ProtocolA part a provider has selected. Authored by the provider.
Must not be list-like, dict-like, or a JITX structural type: traverse descends into those, and since the component holds the part, provider internals would surface under the component’s refpath. A frozen dataclass or plain object is fine; a NamedTuple is not.
- property identity: PartIdentity#
- property payload: dict[str, JSON]#
what it needs to reconstruct itself, and anything it reports but cannot be queried on.
The second half is the counterpart to PartIdentity.attributes. An attribute is a promise to filter and rank on it, so a value the source only reports, such as a datasheet URL or a stock level that may be stale by the next run, goes here and is set on the component in materialize.
Opaque to the core, versioned by the provider, and JSON only: it is written to the lockfile verbatim, so a quantity or any other non-JSON value here fails the write. encode_payload and decode_payload render quantities for it and read them back.
- Type:
This provider’s own data
- materialize(component)[source]#
Attach geometry to a freshly constructed category component.
The provider builds or reuses whatever landpattern and symbol it sees fit, by any means.
- Contract:
MAY assign landpattern, symbol, and pad/symbol mappings.
MUST NOT create, remove or replace ports. The category owns its arity, and the ports already exist.
MUST be callable across distinct component instances; it is called exactly once per instance.