Split a project and regenerate¶
Optional guide after the first tutorial. Use this when your generator needs more than one source file. It assumes the installed example environment and the stages from Generate your first class; it is not part of initial setup.
A source map is an explicit mapping of logical filenames to source text. The entry name is a map key, not the module declaration and not a search through the filesystem. Keep logical keys stable when packaging files.
The canonical two-file example is executable on its own:
ASTICHI_LOWER_ENGINE=python build/example-env/bin/python \
tests/data/gold_src/yidl_imported_concepts.py build/imported.py
Source authority: tests/data/gold_src/yidl_imported_concepts.py.
from __future__ import annotations
from support.golden_case import run_case
from yidl.concept_parser import compile_yidl_files
CORE_YIDL = """
module yidl.lifecycle.core
export concept LifecycleCore
concept LifecycleCore {
property Name: str storage name
property Kind: object storage kind
property SourceOrder: int = 0 storage source_order
family FieldSpecs {
common Name, Kind, SourceOrder
variant PlainField {}
}
collection Fields: FieldSpecs identity Name
}
"""
MANAGED_YIDL = """
module yidl.lifecycle.managed
import "core.yidl" as core
export concept ManagedFields
concept ManagedFields extends core.LifecycleCore {
property TxKey: str = "default" storage tx_key
family core.FieldSpecs {
variant ManagedField {
TxKey
Kind
}
}
}
"""
def _compiled():
return compile_yidl_files(
{
"core.yidl": CORE_YIDL,
"managed.yidl": MANAGED_YIDL,
},
"managed.yidl",
)
def render_case() -> str:
return _compiled().concepts["ManagedFields"].plan.emit_runtime_source()
def validate_case(source: str) -> None:
namespace: dict[str, object] = {}
exec(source, namespace)
builder = namespace["new_builder"]()
fields = namespace["FieldsCollection"]
builder.add(
fields,
namespace["PlainField"](
name="count",
kind="plain",
source_order=0,
),
)
builder.add(
fields,
namespace["ManagedField"](
name="owner",
kind="managed",
source_order=1,
tx_key="tx",
),
)
container = builder.freeze()
assert [record.name for record in container.Fields.sequence()] == [
"count",
"owner",
]
assert "FieldSpecsUnion = RuntimeUnion" in source
assert "PlainField" in source
assert "ManagedField" in source
assert source.count("RuntimeProperty('Name'") == 1
assert source.count("RuntimeUnion('FieldSpecs'") == 1
if __name__ == "__main__":
raise SystemExit(run_case("yidl_imported_concepts.py", render_case, validate_case))
export concept LifecycleCore makes the base available to imports. The importing
file uses an alias and extends that concept. The filename spelling in the import
is resolved relative to the logical importer key. For three files, supply all
three texts in the map; imports do not fetch omitted resources from the current
working directory. Relative keys such as shared/base.yidl and app/model.yidl
allow ../shared/base.yidl without a sibling-checkout dependency.
Packaged authority¶
A package can read its .yidl assets with importlib.resources.files(package)
and pass those texts under stable logical names. Include the assets in wheel and
sdist, or distribute a generated runtime base with an explicit build authority.
Runtime requirements depend on the generated module's imports: a checked-in base
still uses YIDL runtime descriptors and Astichi when it assembles models.
A consumer regeneration tool should default to comparing emitted bytes, provide
an explicit write mode, and record source digests. YIDL's concept API does not
provide a universal --write CLI. Existing consumer tools implement their own
check/write contract; do not invent a compiler flag.
After editing authority, regenerate the base, inspect the diff, run behavior checks, then refresh canonical output. Start a new process to discard previously imported generated modules or cached wrappers. Shared resources explains provenance and missing-authority handling.
A missing source-map key is an import/setup error; a concept not exported by its source is a symbol error. Do not patch imports into generated Python as a remedy.