Factory metadata provider system.
Provides a provider-based system for attaching structured metadata
(device type, ports, models, tags, display hints) to cell factories
without coupling to schematic-driven layout.
Bases: BaseModel
Resolved metadata for a cell factory.
Aggregated from all registered providers for a given factory.
Fields are intentionally loosely typed so consumers (gfp, PDKs,
simulation packages) can define their own schemas on top.
Fields:
-
device_type
(str | None)
-
ports
(tuple[PortSpec, ...])
-
models
(list)
-
tags
(tuple[str, ...])
-
display
(dict)
-
info
(dict[str, JSONSerializable])
Source code in kfactory/factory_metadata.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69 | class FactoryMetadata(BaseModel):
"""Resolved metadata for a cell factory.
Aggregated from all registered providers for a given factory.
Fields are intentionally loosely typed so consumers (gfp, PDKs,
simulation packages) can define their own schemas on top.
"""
device_type: str | None = None
ports: tuple[PortSpec, ...] = ()
models: list = Field(default_factory=list)
tags: tuple[str, ...] = ()
display: dict = Field(default_factory=dict)
info: dict[str, JSONSerializable] = Field(default_factory=dict)
|
Stores metadata provider registrations and resolves them per factory.
Source code in kfactory/factory_metadata.py
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145 | class FactoryMetadataRegistry:
"""Stores metadata provider registrations and resolves them per factory."""
def __init__(self) -> None:
self._records: list[_FactoryMetadataProviderRecord] = []
self._counter = 0
def add(
self,
*,
target_kind: Literal["name", "fqn", "object"],
target_key: str | int,
kind: FactoryMetadataProviderKind,
provider: Callable[..., Any],
replace: bool = False,
position: Literal["append", "prepend"] = "append",
) -> Callable[..., Any]:
"""Register a metadata provider for a target factory."""
if position not in ("append", "prepend"):
raise ValueError(f"Unknown model provider position: {position!r}")
self._counter += 1
self._records.append(
_FactoryMetadataProviderRecord(
target_kind=target_kind,
target_key=target_key,
kind=kind,
provider=provider,
replace=replace,
position=position,
order=self._counter,
)
)
return provider
def providers_for(
self,
*,
name: str,
qualified_name: str,
obj: object,
) -> tuple[_FactoryMetadataProviderRecord, ...]:
"""Return all provider records matching a factory by name, FQN, or identity."""
object_id = id(obj)
return tuple(
record
for record in sorted(self._records, key=lambda r: r.order)
if (
(record.target_kind == "name" and record.target_key == name)
or (record.target_kind == "fqn" and record.target_key == qualified_name)
or (record.target_kind == "object" and record.target_key == object_id)
)
)
|
add(
*,
target_kind: Literal["name", "fqn", "object"],
target_key: str | int,
kind: FactoryMetadataProviderKind,
provider: Callable[..., Any],
replace: bool = False,
position: Literal["append", "prepend"] = "append",
) -> Callable[..., Any]
Register a metadata provider for a target factory.
Source code in kfactory/factory_metadata.py
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 | def add(
self,
*,
target_kind: Literal["name", "fqn", "object"],
target_key: str | int,
kind: FactoryMetadataProviderKind,
provider: Callable[..., Any],
replace: bool = False,
position: Literal["append", "prepend"] = "append",
) -> Callable[..., Any]:
"""Register a metadata provider for a target factory."""
if position not in ("append", "prepend"):
raise ValueError(f"Unknown model provider position: {position!r}")
self._counter += 1
self._records.append(
_FactoryMetadataProviderRecord(
target_kind=target_kind,
target_key=target_key,
kind=kind,
provider=provider,
replace=replace,
position=position,
order=self._counter,
)
)
return provider
|
providers_for(
*, name: str, qualified_name: str, obj: object
) -> tuple[_FactoryMetadataProviderRecord, ...]
Return all provider records matching a factory by name, FQN, or identity.
Source code in kfactory/factory_metadata.py
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145 | def providers_for(
self,
*,
name: str,
qualified_name: str,
obj: object,
) -> tuple[_FactoryMetadataProviderRecord, ...]:
"""Return all provider records matching a factory by name, FQN, or identity."""
object_id = id(obj)
return tuple(
record
for record in sorted(self._records, key=lambda r: r.order)
if (
(record.target_kind == "name" and record.target_key == name)
or (record.target_kind == "fqn" and record.target_key == qualified_name)
or (record.target_kind == "object" and record.target_key == object_id)
)
)
|
Bases: TypedDict
Structured port descriptor for cell metadata.
Declares a logical port with its kind, physical side, and optional
cross-section or aliasing information. Used by external tools
(simulation runners, schematic editors) to understand a cell's
interface without instantiating it.
Source code in kfactory/factory_metadata.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 | class PortSpec(TypedDict):
"""Structured port descriptor for cell metadata.
Declares a logical port with its kind, physical side, and optional
cross-section or aliasing information. Used by external tools
(simulation runners, schematic editors) to understand a cell's
interface without instantiating it.
"""
name: str
kind: str
side: NotRequired[Literal["left", "right", "top", "bottom"] | None]
orientation: NotRequired[Literal[0, 90, 180, 270] | None]
order: NotRequired[int | None]
cross_section: NotRequired[str | None]
role: NotRequired[str | None]
aliases: NotRequired[tuple[str, ...]]
|
call_provider(
provider: Callable[..., Any], params: dict[str, Any]
) -> Any
Invoke a provider with the subset of cell params its signature accepts.
Source code in kfactory/factory_metadata.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 | def call_provider(provider: Callable[..., Any], params: dict[str, Any]) -> Any:
"""Invoke a provider with the subset of cell params its signature accepts."""
sig = inspect.signature(provider)
accepts_kwargs = any(
p.kind is inspect.Parameter.VAR_KEYWORD for p in sig.parameters.values()
)
if accepts_kwargs:
return provider(**params)
provider_kwargs: dict[str, Any] = {}
missing: list[str] = []
for name, param in sig.parameters.items():
if param.kind in (
inspect.Parameter.POSITIONAL_ONLY,
inspect.Parameter.VAR_POSITIONAL,
):
raise TypeError(
f"Metadata provider {provider!r} has unsupported parameter {name!r}."
)
if name in params:
provider_kwargs[name] = params[name]
elif param.default is inspect.Parameter.empty:
missing.append(name)
if missing:
raise TypeError(
f"Metadata provider {provider!r} requires parameters unavailable "
f"from the cell factory: {missing!r}."
)
return provider(**provider_kwargs)
|
provider_result_to_patch(
record: _FactoryMetadataProviderRecord, result: Any
) -> _FactoryMetadataPatch
Convert a provider's return value into a metadata patch.
Source code in kfactory/factory_metadata.py
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209 | def provider_result_to_patch(
record: _FactoryMetadataProviderRecord, result: Any
) -> _FactoryMetadataPatch:
"""Convert a provider's return value into a metadata patch."""
match record.kind:
case "metadata":
return _metadata_result_to_patch(result)
case "model":
models = _coerce_models(result)
return _FactoryMetadataPatch(
models=models,
models_position=record.position,
)
case "device_type":
return _FactoryMetadataPatch(
device_type=None if result is None else str(result)
)
case "ports":
return _FactoryMetadataPatch(ports=_coerce_ports(result))
case "tags":
return _FactoryMetadataPatch(tags=_coerce_tags(result))
case "display":
return _FactoryMetadataPatch(
display=None if result is None else _coerce_display(result)
)
case "info":
if result is None:
return _FactoryMetadataPatch()
if not isinstance(result, Mapping):
raise TypeError("info provider must return a mapping.")
return _FactoryMetadataPatch(info={str(k): v for k, v in result.items()})
|
resolve_metadata(
providers: Iterable[_FactoryMetadataProviderRecord],
params: dict[str, Any],
) -> FactoryMetadata
Resolve all providers for a factory into a single FactoryMetadata.
Source code in kfactory/factory_metadata.py
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272 | def resolve_metadata(
providers: Iterable[_FactoryMetadataProviderRecord],
params: dict[str, Any],
) -> FactoryMetadata:
"""Resolve all providers for a factory into a single FactoryMetadata."""
device_type: str | None = None
ports: tuple[PortSpec, ...] | None = None
models: list = []
tags: tuple[str, ...] = ()
display: dict = {}
info: dict[str, JSONSerializable] = {}
for record in providers:
result = call_provider(record.provider, params)
patch = provider_result_to_patch(record, result)
if patch.device_type is not None:
if (
device_type is not None
and device_type != patch.device_type
and not record.replace
):
raise ValueError(
"Conflicting metadata device_type values: "
f"{device_type!r} and {patch.device_type!r}."
)
device_type = patch.device_type
if patch.ports is not None:
if ports is not None and ports != patch.ports and not record.replace:
raise ValueError("Conflicting metadata port declarations.")
ports = patch.ports
if patch.models is not None:
if patch.models_position == "prepend":
models = patch.models + models
else:
models = models + patch.models
if patch.tags:
tags = _merge_tags(tags, patch.tags)
if patch.display:
if display and patch.display != display and not record.replace:
raise ValueError("Conflicting metadata display declarations.")
display = patch.display
if patch.info:
for key, value in patch.info.items():
if key in info and info[key] != value:
raise ValueError(f"Conflicting metadata info key: {key!r}.")
info[key] = value
return FactoryMetadata(
device_type=device_type,
ports=ports or (),
models=models,
tags=tags,
display=display,
info=info,
)
|