metaobjects 0.25.0__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {metaobjects-0.25.0 → metaobjects-1.0.0}/PKG-INFO +1 -1
- {metaobjects-0.25.0 → metaobjects-1.0.0}/pyproject.toml +1 -1
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/agent_context/scaffold.py +105 -21
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/cli.py +159 -15
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/config.py +33 -0
- metaobjects-1.0.0/src/metaobjects/codegen/format.py +72 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/names_generator.py +20 -16
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/router_generator.py +46 -4
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/overwrite_policy.py +69 -21
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/runner.py +55 -3
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/registry_manifest.py +1 -1
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/source_resolution.py +26 -6
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/ui.json +2 -2
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_cli.py +103 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_cli_config_verify.py +54 -0
- metaobjects-1.0.0/tests/codegen/test_format.py +85 -0
- metaobjects-1.0.0/tests/codegen/test_gen_state_keying.py +182 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_names_extends_chain.py +42 -10
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_runner.py +96 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/api_contract_server.py +15 -1
- metaobjects-1.0.0/tests/unit/test_agent_context_staleness.py +200 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/uv.lock +1 -1
- metaobjects-0.25.0/src/metaobjects/codegen/format.py +0 -42
- metaobjects-0.25.0/tests/codegen/test_format.py +0 -30
- metaobjects-0.25.0/tests/unit/test_agent_context_staleness.py +0 -102
- {metaobjects-0.25.0 → metaobjects-1.0.0}/.gitignore +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/LICENSE +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/README.md +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/hatch_build.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/scripts/generate_embedded_library.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/agent_context/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/apidocs/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/apidocs/api_model.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/apidocs/builder.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/apidocs/naming.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/apidocs/paths.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/apidocs/renderer.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/attr_class_map.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/collision_names.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generator_registry.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/entity_model.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/find_inbound.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/payload_vo_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/template_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/instance_artifacts.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/project_config.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/runtime/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/codegen/type_map.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/config/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/config/neutral_config.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/config/source_resolver.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/core_types.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/datatype.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/documentation/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/documentation/doc_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/documentation/doc_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/documentation/doc_schema.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/errors.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/library/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/library/embedded_library.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/library/library_sources.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/merge.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/meta_data_loader.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/registered_validation.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/sources/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/sources/directory_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/sources/file_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/sources/uri_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/validate_discriminator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/validate_field_mutability.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/validate_source_escapes.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/loader/validation_passes.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/attr/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/field/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/field/field_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/field/meta_field.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/identity/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/index/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/index/index_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/index/meta_index.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/object/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/object/meta_object.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/object/object_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/object/object_extract.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/object/value_object.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/validator/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/meta_data.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/meta_root.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/persistence/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/presentation/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/provider_extends.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/template/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/template/meta_template.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/template/prompt_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/meta/template/template_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/naming.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/naming_refs.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/parser.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/parser_yaml.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/py.typed +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/registry.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/email_document.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/escapers.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/extract/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/extract/coerce.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/extract/extract.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/extract/extract_map.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/extract/locate.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/extract/normalize.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/extract/strip.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/extract/types.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/filesystem_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/payload_accessors.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/prompt/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/prompt/prompt_field.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/prompt/prompt_style.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/renderer.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/render/verify.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/runtime/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/runtime/llm_recorder.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/runtime/n2m_resolver.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/runtime/object_manager.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/runtime/tph.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/serializer_json.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/shared/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/shared/base_types.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/shared/separators.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/shared/structural.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/source/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/source/error_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/source/json_path.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/source/semantic_diff.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/source/yaml_positions.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/attr.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/db.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/documentation.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/field.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/identity.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/index.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/layout.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/object.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/origin.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/prompt.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/relationship.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/requirement.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/source.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/template.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/validator.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/spec_metamodel/view.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/super_resolve.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/validation_types.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/src/metaobjects/yaml_desugar.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/golden/extends/expected/Program.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/golden/extends/meta.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/golden/nested-array/meta.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/golden/scalars/expected/Report.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/golden/scalars/meta.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/golden/vanilla/meta.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_abstract_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_api_docs_builder.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_api_docs_paths.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_cli_config_gen.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_cli_providers.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_cli_registry.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_cli_staleness_nudge.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_cli_verify_strict.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_cli_verify_subverbs.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_constants_config.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_entity_model.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_enum_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_extract_tier_collision.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_extractor_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_filter_allowlist_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_fr010_output_codegen.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_generator_extension_seams.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_golden.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_inheritance_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_instance_artifacts.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_m2m_codegen.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_names_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_no_magic_physical_names.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_origin_nullability.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_output_parser_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_overwrite_policy.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_overwrite_policy_hash.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_payload_vo_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_project_config.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_projection_compile.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_render_helper_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_render_helper_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_reverse_finders.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_router_autoset.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_router_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_source_resolution.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_sourceless_projection.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_template_data.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_template_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_template_output_pattern.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_template_scope_helpers.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_template_scope_walk.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_template_spec.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_tph_codegen.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_trace_helper_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_type_map.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_validation_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/codegen/test_write_through.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/config/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/config/test_neutral_config.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/config/test_source_resolver.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/capabilities.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/conformance-expected-failures.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/conformance_adapter.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/corpus.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/expected_failures.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/fixture_discovery.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/navigator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_extract_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_extract_object_verdict.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_fr010_loader_attrs.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_fr011_attrs.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_generator_registry_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_object_model_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_provider_composition_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_registry_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_runner_hardfail.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_source_resolution_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_spec_metamodel_embed.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_strict_attr_load.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_template_codegen_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_template_generator_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/test_yaml_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/api_contract_assertions.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/api_contract_jsonb_server.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/api_contract_m2m_server.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/generated_jsonb_app.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/generated_m2m_app.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/generated_router_app.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/generated_tph_app.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/meta_ai_trace.yaml +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/normalization.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/postgres_container.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/query_runner.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/scenarios.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/test_api_contract.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/test_api_contract_generated.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/test_api_contract_jsonb.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/test_api_contract_m2m.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/test_api_contract_m2m_generated.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/test_api_contract_tph_generated.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/test_generated_router_uuid_pk.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/test_llm_call_trace.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/test_normalization.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/test_query_scenarios.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/integration/test_runtime_return_types.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/loader/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/loader/test_abstract_subtype_authored.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/loader/test_enum_extends_values_conflict.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/loader/test_field_mutability_order.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/loader/test_shipped_library_ai.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/loader/test_template_payload_target_210.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/open_closed_proof_test.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/extract/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/extract/test_coerce.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/extract/test_extract.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/extract/test_extract_map.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/extract/test_json_forgiving_reader.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/extract/test_locate.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/extract/test_model.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/extract/test_normalize.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/extract/test_strip.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/prompt/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/prompt/test_output_format_renderer.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/test_email_document.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/test_filesystem_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/test_output_format_renderer_nested.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/test_output_prompt_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/test_render_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/test_render_max_chars.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/test_verify.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/render/test_verify_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/runtime/test_object_manager_enum_intvaluemap.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/runtime/test_object_manager_table_name.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/source/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/source/test_fr5c_merge_attribution.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/source/test_fr5d_reference_resolution.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/source/test_fr5e_database_source_shape.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/source/test_json_path.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/source/test_semantic_diff.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/source/test_source_on_node.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/source/test_yaml_positions.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/test_api_docs_accuracy.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_capabilities.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_column_naming_strategy.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_common_attrs.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_core_types.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_effective_children_sibling_shadowing.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_effective_package.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_errors.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_field_enum.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_field_enum_intvaluemap.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_field_map_validation.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_index_lookup.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_llm_recorder.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_loader.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_loader_bom.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_loader_class.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_merge.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_meta_attr.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_meta_data.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_meta_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_module_shortcuts.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_n2m_resolver.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_n2m_resolver_inherited.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_no_dead_config_fields.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_object_manager_write_through.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_one_primary_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_parser.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_parser_yaml.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_provider_extension.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_registry.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_registry_completeness.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_registry_extend.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_registry_sealed.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_relationship_referential_actions.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_resolution_key.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_serializer.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_shared_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_smoke.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_source_escapes.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_sources.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_strict_child_placement.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_super_resolve.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_template_toolcall.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_validation_attr_schema.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_validation_filter_values.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_validation_origin_195.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_validation_origin_paths.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_validation_sort_field.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_validation_warnings.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_write_coercion_arrays.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0}/tests/unit/test_yaml_desugar.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: metaobjects
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: Cross-language metadata standard: declare typed entities once, generate idiomatic drift-checked code across languages — Python port.
|
|
5
5
|
Project-URL: Homepage, https://metaobjects.dev
|
|
6
6
|
Project-URL: Repository, https://github.com/metaobjectsdev/metaobjects
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "metaobjects"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "1.0.0"
|
|
4
4
|
description = "Cross-language metadata standard: declare typed entities once, generate idiomatic drift-checked code across languages — Python port."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -80,31 +80,112 @@ class Manifest:
|
|
|
80
80
|
# The sentinel a port stamps when it cannot resolve its own installed version.
|
|
81
81
|
_UNRESOLVED_VERSION = "0.0.0"
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
83
|
+
#: A release with an optional PRE-RELEASE segment, in either spelling one ecosystem uses.
|
|
84
|
+
#: npm/NuGet/Maven write ``1.0.0-rc.5``; PEP 440 writes ``1.0.0rc5``. Both are the SAME
|
|
85
|
+
#: release, and comparing their SPELLINGS is what made the nudge unsatisfiable — see
|
|
86
|
+
#: ``_same_release``.
|
|
87
|
+
_PRERELEASE_RE = re.compile(
|
|
88
|
+
r"^(\d+)\.(\d+)\.(\d+)" # release
|
|
89
|
+
r"(?:-?([A-Za-z]+)\.?(\d+)?)?$" # optional pre-release: -rc.5 | rc5 | -beta | b2
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
#: PEP 440 abbreviates the pre-release labels that npm spells out, and normalizing to ONE
|
|
94
|
+
#: of them is what makes `1.1.0-beta.2` and `1.1.0b2` the same release. Only the spellings
|
|
95
|
+
#: PEP 440 itself defines as equivalent — this is a rename table, not a similarity guess.
|
|
96
|
+
_PEP440_LABEL_ALIASES = {
|
|
97
|
+
"a": "alpha",
|
|
98
|
+
"b": "beta",
|
|
99
|
+
"c": "rc",
|
|
100
|
+
"pre": "rc",
|
|
101
|
+
"preview": "rc",
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _release_coordinate(version: object) -> tuple[int, int, int, str, int] | None:
|
|
106
|
+
"""``(major, minor, patch, pre_label, pre_number)`` for a version in ANY ecosystem
|
|
107
|
+
spelling.
|
|
108
|
+
|
|
109
|
+
The MAJOR is INFORMATION on this port, and both helpers here used to drop it. That
|
|
110
|
+
reduction is correct on the JVM and only there: Maven Central carries a historical
|
|
111
|
+
major of npm-major + 7 by design, so ``7.24.1`` and ``0.24.1`` genuinely name one
|
|
112
|
+
release and the coordinate must ignore the major to see it. Nothing of the kind holds
|
|
113
|
+
here — ``generatedBy`` is stamped by the Node CLI (an npm version) and
|
|
114
|
+
:func:`installed_metaobjects_version` reads the PyPI distribution version, and npm and
|
|
115
|
+
PyPI share the major by policy. Dropping it made ``1.0.0`` and ``2.0.0`` compare EQUAL,
|
|
116
|
+
and made a ``0.25.0``-stamped context read as NEWER than a ``1.0.0`` install — so the
|
|
117
|
+
1.0 upgrade, the single upgrade this advisory exists to catch, produced no nudge.
|
|
118
|
+
|
|
119
|
+
The pre-release label is lower-cased and its separators dropped, so ``-rc.5``,
|
|
120
|
+
``rc5`` and ``-RC5`` all reduce to ``("rc", 5)``. A final release sorts ABOVE every
|
|
121
|
+
pre-release of the same number, which is what ``("", 0)`` vs ``("rc", 5)`` gives under
|
|
122
|
+
tuple ordering only because ``""`` < ``"rc"`` — so finals carry a sentinel label that
|
|
123
|
+
sorts last instead.
|
|
124
|
+
|
|
125
|
+
``None`` means "not orderable, so nudge": the ``0.0.0`` unresolved-install sentinel,
|
|
126
|
+
build metadata, or anything this cannot parse. Those must never assert "in sync".
|
|
98
127
|
"""
|
|
99
128
|
if not isinstance(version, str):
|
|
100
129
|
return None
|
|
101
130
|
v = version.strip()
|
|
102
131
|
if v == _UNRESOLVED_VERSION:
|
|
103
132
|
return None
|
|
104
|
-
m =
|
|
133
|
+
m = _PRERELEASE_RE.match(v)
|
|
105
134
|
if m is None:
|
|
106
135
|
return None
|
|
107
|
-
|
|
136
|
+
label = _PEP440_LABEL_ALIASES.get((m.group(4) or "").lower(), (m.group(4) or "").lower())
|
|
137
|
+
number = int(m.group(5)) if m.group(5) is not None else 0
|
|
138
|
+
# A FINAL release is newer than every pre-release of the same number. "~" sorts above
|
|
139
|
+
# every ASCII letter, so the sentinel does that with plain tuple comparison.
|
|
140
|
+
return (
|
|
141
|
+
int(m.group(1)),
|
|
142
|
+
int(m.group(2)),
|
|
143
|
+
int(m.group(3)),
|
|
144
|
+
label if label else "~",
|
|
145
|
+
number,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _same_release(generated_by: object, current_version: str) -> bool:
|
|
150
|
+
"""True when two version strings name the SAME release in different spellings.
|
|
151
|
+
|
|
152
|
+
The nudge compared spellings, so on the 1.0 RC line it could never be satisfied: the
|
|
153
|
+
canonical scaffolder is the Node CLI (ADR-0033), which stamps npm's ``1.0.0-rc.5``,
|
|
154
|
+
while this port reports PEP 440's ``1.0.0rc5``. Those are one release written two
|
|
155
|
+
ways, ``==`` says otherwise, and the remedy re-runs the scaffolder, which re-stamps
|
|
156
|
+
the same npm string — so the advisory fires on every invocation, forever, including
|
|
157
|
+
when the context is perfectly in sync. That is issue #347 with a different pair of
|
|
158
|
+
ecosystems; the fix for it reasoned about ORDERING and never about spelling.
|
|
159
|
+
|
|
160
|
+
Deliberately narrow. Only two versions that parse as the same release coordinate are
|
|
161
|
+
equal; anything unparseable (including the ``0.0.0`` sentinel) still nudges, and an
|
|
162
|
+
``rc.4`` context against an ``rc.5`` install is a REAL difference and still nudges.
|
|
163
|
+
"""
|
|
164
|
+
stamped = _release_coordinate(generated_by)
|
|
165
|
+
installed = _release_coordinate(current_version)
|
|
166
|
+
return stamped is not None and stamped == installed
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _release_series(version: object) -> tuple[int, int, int] | None:
|
|
170
|
+
"""Ordered release coordinate ``(major, minor, patch)``, or ``None`` when not orderable.
|
|
171
|
+
|
|
172
|
+
Derived from :func:`_release_coordinate` rather than parsed again. These two functions
|
|
173
|
+
used to answer the same grammar with two different regexes — differential-checked
|
|
174
|
+
identical over 200k inputs, which is the good outcome of a coin flip, not a guarantee.
|
|
175
|
+
The ordering coordinate simply IS the equality coordinate restricted to FINAL releases,
|
|
176
|
+
and saying so in code means the two cannot drift apart.
|
|
177
|
+
|
|
178
|
+
``None`` means "not orderable, so nudge", and deliberately covers prereleases
|
|
179
|
+
(``0.24.5-rc.1``, ``1.0.0rc5``), build metadata (``0.24.5+abc``) and the ``0.0.0``
|
|
180
|
+
sentinel. Each must keep nudging: an RC-scaffolded context against a final release is
|
|
181
|
+
still worth refreshing, and an unknown install must never assert "in sync".
|
|
182
|
+
"""
|
|
183
|
+
coord = _release_coordinate(version)
|
|
184
|
+
# A pre-release carries a real label; a final carries the "~" sentinel. Only finals are
|
|
185
|
+
# orderable here, which is what the previous release-only regex enforced by construction.
|
|
186
|
+
if coord is None or coord[3] != "~":
|
|
187
|
+
return None
|
|
188
|
+
return coord[0], coord[1], coord[2]
|
|
108
189
|
|
|
109
190
|
|
|
110
191
|
def _context_is_ahead_of_install(generated_by: object, current_version: str) -> bool:
|
|
@@ -141,16 +222,19 @@ def agent_context_staleness(
|
|
|
141
222
|
is in sync — and a one-line advisory message otherwise. Pure + advisory:
|
|
142
223
|
never raises, never blocks, never writes.
|
|
143
224
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
``
|
|
225
|
+
ANY REAL drift nudges (a re-scaffold is cheap + idempotent), so this is not a semver
|
|
226
|
+
compare — an ``rc.4`` context against an ``rc.5`` install is still a reason to
|
|
227
|
+
refresh. Two exemptions, both for cases where nudging can never be SATISFIED:
|
|
228
|
+
``_same_release`` (one release, two ecosystem spellings) and
|
|
229
|
+
``_context_is_ahead_of_install`` (a port legitimately behind the npm scaffolder).
|
|
148
230
|
"""
|
|
149
231
|
if manifest is None:
|
|
150
232
|
return None # no agent context here → nothing to nudge
|
|
151
233
|
generated_by = manifest.get("generatedBy")
|
|
152
234
|
if generated_by == current_version:
|
|
153
235
|
return None # in sync
|
|
236
|
+
if _same_release(generated_by, current_version):
|
|
237
|
+
return None # one release, two ecosystem spellings — see below
|
|
154
238
|
if _context_is_ahead_of_install(generated_by, current_version):
|
|
155
239
|
return None # scaffolded by a NEWER release than this install — see below
|
|
156
240
|
frm = generated_by if generated_by else "an older MetaObjects"
|
|
@@ -44,6 +44,7 @@ from __future__ import annotations
|
|
|
44
44
|
import argparse
|
|
45
45
|
import dataclasses
|
|
46
46
|
import json
|
|
47
|
+
import os
|
|
47
48
|
import re
|
|
48
49
|
import sys
|
|
49
50
|
import tempfile
|
|
@@ -376,6 +377,9 @@ def _run_suite(
|
|
|
376
377
|
emit_package_init: bool = True,
|
|
377
378
|
gen_state_dir: str | None = None,
|
|
378
379
|
column_naming: str = DEFAULT_COLUMN_NAMING,
|
|
380
|
+
project_root: str | None = None,
|
|
381
|
+
baseline: str = "default",
|
|
382
|
+
refused_out: list[str] | None = None,
|
|
379
383
|
) -> list[str]:
|
|
380
384
|
"""Run a generator suite against an ALREADY-LOADED ``root`` into ``out_dir``.
|
|
381
385
|
|
|
@@ -405,11 +409,26 @@ def _run_suite(
|
|
|
405
409
|
emit_package_init=emit_package_init,
|
|
406
410
|
gen_state_dir=gen_state_dir,
|
|
407
411
|
column_naming=column_naming,
|
|
412
|
+
# Manifest keys are relative to the PROJECT, which is what the manifest is
|
|
413
|
+
# anchored on — not to ``--out``, which varies per run while the manifest does
|
|
414
|
+
# not. Passed alongside gen_state_dir because the two are one decision: state
|
|
415
|
+
# that lives in the project must be keyed by the project.
|
|
416
|
+
project_root=project_root,
|
|
417
|
+
# `--baseline=adopt`: record what is on disk and write nothing. The refusal it
|
|
418
|
+
# exists for is the pre-manifest one, so it reaches every real gen path and no
|
|
419
|
+
# verify path (those pass gen_state_dir=None and record nothing at all).
|
|
420
|
+
baseline=baseline,
|
|
408
421
|
)
|
|
409
422
|
suite = generators if generators is not None else _default_generators()
|
|
410
423
|
result = run_gen(config, root, generators=suite, entity_filter=entity_filter)
|
|
411
424
|
for warning in result.warnings:
|
|
412
425
|
print(f"warning: {warning}")
|
|
426
|
+
# A refusal is a FAILED gate, and the return value carries only what was WRITTEN — so
|
|
427
|
+
# without this the one fact a CI step reads (the exit code) could not see it. An
|
|
428
|
+
# out-list rather than a changed return type: five call sites read the written paths,
|
|
429
|
+
# and only the ones that own an exit code care about the refusals.
|
|
430
|
+
if refused_out is not None:
|
|
431
|
+
refused_out.extend(path for path, status in result.files if status == "refused")
|
|
413
432
|
return [path for path, status in result.files if status != "refused"]
|
|
414
433
|
|
|
415
434
|
|
|
@@ -463,12 +482,17 @@ def _generate(
|
|
|
463
482
|
def gen_state_dir_for(metadata_dir: str) -> str:
|
|
464
483
|
"""Where a project's codegen hash manifest lives.
|
|
465
484
|
|
|
466
|
-
Anchored on the project —
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
485
|
+
Anchored on the project — never on ``Path.cwd()``, which is whatever directory the
|
|
486
|
+
process happens to sit in and would scatter ``.metaobjects/`` into any package that
|
|
487
|
+
merely runs a generator.
|
|
488
|
+
|
|
489
|
+
It resolves the project through :func:`project_root_for` rather than repeating
|
|
490
|
+
``Path(metadata_dir).resolve().parent``. That function's own docstring already claimed
|
|
491
|
+
this one "is anchored here" while the code spelled the rule out a second time, and the
|
|
492
|
+
manifest key and the manifest LOCATION have to agree on where the project is or a
|
|
493
|
+
lookup finds nothing and every file reads as "not ours".
|
|
470
494
|
"""
|
|
471
|
-
return str(
|
|
495
|
+
return str(project_root_for(metadata_dir) / ".metaobjects" / ".gen-state")
|
|
472
496
|
|
|
473
497
|
|
|
474
498
|
#: The conventional declarative-template-spec file (SP-1 §4), discovered when
|
|
@@ -792,10 +816,16 @@ def _cmd_gen(args: argparse.Namespace) -> int:
|
|
|
792
816
|
print(f" {msg}", file=sys.stderr)
|
|
793
817
|
return 1
|
|
794
818
|
gen_state = gen_state_dir_for(args.metadata_dir)
|
|
819
|
+
# Same anchor the manifest itself uses. Both passes below key against it, so a
|
|
820
|
+
# `--template-spec` artifact and a default-suite artifact land in one key space.
|
|
821
|
+
gen_project_root = str(project_root_for(args.metadata_dir))
|
|
795
822
|
column_naming = getattr(args, "column_naming", None) or DEFAULT_COLUMN_NAMING
|
|
823
|
+
baseline = getattr(args, "baseline", None) or "default"
|
|
824
|
+
refused: list[str] = []
|
|
796
825
|
written = _run_suite(
|
|
797
826
|
root, args.out, generators, entities,
|
|
798
827
|
gen_state_dir=gen_state, column_naming=column_naming,
|
|
828
|
+
project_root=gen_project_root, baseline=baseline, refused_out=refused,
|
|
799
829
|
)
|
|
800
830
|
if spec_gens:
|
|
801
831
|
# The template-spec pass renders user-supplied templates: a bad ref or a
|
|
@@ -807,6 +837,7 @@ def _cmd_gen(args: argparse.Namespace) -> int:
|
|
|
807
837
|
spec_written = _run_suite(
|
|
808
838
|
root, args.out, spec_gens, entities, emit_package_init=False,
|
|
809
839
|
gen_state_dir=gen_state, column_naming=column_naming,
|
|
840
|
+
project_root=gen_project_root, baseline=baseline, refused_out=refused,
|
|
810
841
|
)
|
|
811
842
|
except RenderError as exc:
|
|
812
843
|
print(
|
|
@@ -819,6 +850,17 @@ def _cmd_gen(args: argparse.Namespace) -> int:
|
|
|
819
850
|
for path in written:
|
|
820
851
|
print(path)
|
|
821
852
|
print(f"metaobjects gen: wrote {len(written)} file(s) to {args.out}")
|
|
853
|
+
if refused:
|
|
854
|
+
# A refusal is a failed gate, matching TypeScript's `meta gen` (exit 1). Python and
|
|
855
|
+
# C# used to warn and exit 0, so an adopter wiring this into CI as a drift gate was
|
|
856
|
+
# green while codegen refused to write — a gate that did not gate. The warnings
|
|
857
|
+
# above carry the detail; this line carries the verdict.
|
|
858
|
+
print(
|
|
859
|
+
f"metaobjects gen: FAILED — {len(refused)} file(s) refused (see the warnings "
|
|
860
|
+
f"above; `--baseline=adopt` records what you have and writes nothing)",
|
|
861
|
+
file=sys.stderr,
|
|
862
|
+
)
|
|
863
|
+
return 1
|
|
822
864
|
return 0
|
|
823
865
|
|
|
824
866
|
|
|
@@ -828,9 +870,17 @@ def _run_gen_targets(
|
|
|
828
870
|
root: MetaData,
|
|
829
871
|
*,
|
|
830
872
|
gen_state_dir: str | None = None,
|
|
873
|
+
project_root: str | None = None,
|
|
874
|
+
baseline: str = "default",
|
|
875
|
+
refused_out: list[str] | None = None,
|
|
831
876
|
) -> tuple[list[str], list[str]]:
|
|
832
877
|
"""Run each target's suite into its ``outDir``. Returns (all_written, errors).
|
|
833
878
|
|
|
879
|
+
This is the path the manifest keying matters most on: every target writes into its
|
|
880
|
+
OWN ``outDir`` while all of them share ONE ``gen_state_dir``, so out-dir-relative
|
|
881
|
+
keys meant target B's hash could claim ownership of target A's identically-named
|
|
882
|
+
file. ``project_root`` is the common anchor that makes the keys distinct.
|
|
883
|
+
|
|
834
884
|
Cross-target duplicate-output-path guard (#267): ``run_gen``'s collision guard
|
|
835
885
|
is per-pass, so two targets writing the same full path would silently clobber
|
|
836
886
|
(generated files carry the @generated header). We accumulate every written full
|
|
@@ -851,7 +901,8 @@ def _run_gen_targets(
|
|
|
851
901
|
out_dir = config.out_dir_for(t)
|
|
852
902
|
try:
|
|
853
903
|
written = _run_suite(
|
|
854
|
-
root, out_dir, gens, t.entities, gen_state_dir=gen_state_dir
|
|
904
|
+
root, out_dir, gens, t.entities, gen_state_dir=gen_state_dir,
|
|
905
|
+
project_root=project_root, baseline=baseline, refused_out=refused_out,
|
|
855
906
|
)
|
|
856
907
|
except ValueError as exc: # intra-target run_gen collision → clean error
|
|
857
908
|
errors.append(f"target '{t.name}': {exc}")
|
|
@@ -918,13 +969,28 @@ def _cmd_gen_neutral_fallback(args: argparse.Namespace) -> int:
|
|
|
918
969
|
|
|
919
970
|
gen_state = str(root_dir.resolve() / ".metaobjects" / ".gen-state")
|
|
920
971
|
column_naming = getattr(args, "column_naming", None) or DEFAULT_COLUMN_NAMING
|
|
972
|
+
refused: list[str] = []
|
|
921
973
|
written = _run_suite(
|
|
922
974
|
root, args.out, generators, entities,
|
|
923
975
|
gen_state_dir=gen_state, column_naming=column_naming,
|
|
976
|
+
project_root=str(root_dir.resolve()),
|
|
977
|
+
baseline=getattr(args, "baseline", None) or "default",
|
|
978
|
+
refused_out=refused,
|
|
924
979
|
)
|
|
925
980
|
for path in written:
|
|
926
981
|
print(path)
|
|
927
982
|
print(f"metaobjects gen: wrote {len(written)} file(s) to {args.out}")
|
|
983
|
+
if refused:
|
|
984
|
+
# A refusal is a failed gate, matching TypeScript's `meta gen` (exit 1). Python and
|
|
985
|
+
# C# used to warn and exit 0, so an adopter wiring this into CI as a drift gate was
|
|
986
|
+
# green while codegen refused to write — a gate that did not gate. The warnings
|
|
987
|
+
# above carry the detail; this line carries the verdict.
|
|
988
|
+
print(
|
|
989
|
+
f"metaobjects gen: FAILED — {len(refused)} file(s) refused (see the warnings "
|
|
990
|
+
f"above; `--baseline=adopt` records what you have and writes nothing)",
|
|
991
|
+
file=sys.stderr,
|
|
992
|
+
)
|
|
993
|
+
return 1
|
|
928
994
|
return 0
|
|
929
995
|
|
|
930
996
|
|
|
@@ -981,8 +1047,13 @@ def _cmd_gen_config(args: argparse.Namespace) -> int:
|
|
|
981
1047
|
print(f" {msg}", file=sys.stderr)
|
|
982
1048
|
return 1
|
|
983
1049
|
|
|
1050
|
+
refused: list[str] = []
|
|
984
1051
|
written, errors = _run_gen_targets(
|
|
985
|
-
config, targets, root,
|
|
1052
|
+
config, targets, root,
|
|
1053
|
+
gen_state_dir=gen_state_dir_for(config.metadata_dir()),
|
|
1054
|
+
project_root=str(project_root_for(config.metadata_dir())),
|
|
1055
|
+
baseline=getattr(args, "baseline", None) or "default",
|
|
1056
|
+
refused_out=refused,
|
|
986
1057
|
)
|
|
987
1058
|
if errors:
|
|
988
1059
|
for msg in errors:
|
|
@@ -993,6 +1064,17 @@ def _cmd_gen_config(args: argparse.Namespace) -> int:
|
|
|
993
1064
|
print(
|
|
994
1065
|
f"metaobjects gen: wrote {len(written)} file(s) across {len(targets)} target(s)."
|
|
995
1066
|
)
|
|
1067
|
+
if refused:
|
|
1068
|
+
# A refusal is a failed gate, matching TypeScript's `meta gen` (exit 1). Python and
|
|
1069
|
+
# C# used to warn and exit 0, so an adopter wiring this into CI as a drift gate was
|
|
1070
|
+
# green while codegen refused to write — a gate that did not gate. The warnings
|
|
1071
|
+
# above carry the detail; this line carries the verdict.
|
|
1072
|
+
print(
|
|
1073
|
+
f"metaobjects gen: FAILED — {len(refused)} file(s) refused (see the warnings "
|
|
1074
|
+
f"above; `--baseline=adopt` records what you have and writes nothing)",
|
|
1075
|
+
file=sys.stderr,
|
|
1076
|
+
)
|
|
1077
|
+
return 1
|
|
996
1078
|
return 0
|
|
997
1079
|
|
|
998
1080
|
|
|
@@ -1033,7 +1115,22 @@ def _relative_set(root: Path) -> dict[str, str]:
|
|
|
1033
1115
|
return files
|
|
1034
1116
|
|
|
1035
1117
|
|
|
1036
|
-
def
|
|
1118
|
+
def _out_prefix(out_dir: str, project_root: Path) -> str:
|
|
1119
|
+
"""The out dir, relative to the project — the translation between this diff's
|
|
1120
|
+
out-dir-relative keys and the manifest's project-relative ones.
|
|
1121
|
+
|
|
1122
|
+
BOTH SIDES RESOLVED, and that is the whole content of this function. `project_root`
|
|
1123
|
+
arrives resolved; relpath from a resolved anchor to an unresolved path is not the
|
|
1124
|
+
path between the two directories, and under a directory symlink it walks OUT of the
|
|
1125
|
+
project. Every lookup then misses, `is_ours` is false for every file, and the gate
|
|
1126
|
+
prints a clean verdict over stale output — silent in the direction that matters.
|
|
1127
|
+
It is written once here rather than at each of the three call sites, because three
|
|
1128
|
+
spellings of one translation is how they came to disagree in the first place.
|
|
1129
|
+
"""
|
|
1130
|
+
return os.path.relpath(Path(out_dir).resolve(), project_root)
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
def _is_ours_for(gen_state_dir: str | None, out_prefix: str = ""):
|
|
1037
1134
|
"""Jurisdiction predicate for the ``extra`` verdict: did WE write this path?
|
|
1038
1135
|
|
|
1039
1136
|
``out_dir`` is a DIRECTORY, not a namespace this tool owns — the same ruling the
|
|
@@ -1041,20 +1138,36 @@ def _is_ours_for(gen_state_dir: str | None):
|
|
|
1041
1138
|
beyond ``*.py`` means the gate now sees every stranger's file too, and convicting
|
|
1042
1139
|
those turns a project with zero drift into a red build.
|
|
1043
1140
|
|
|
1044
|
-
The manifest already records what we WROTE,
|
|
1045
|
-
|
|
1141
|
+
The manifest already records what we WROTE, so it answers the ownership question
|
|
1142
|
+
exactly — but it is keyed relative to the PROJECT while this diff is keyed relative
|
|
1143
|
+
to ``out_dir``. ``out_prefix`` (the out dir, relative to the project) is what turns
|
|
1144
|
+
one into the other. Getting this wrong is silent in the direction that matters: a
|
|
1145
|
+
lookup that finds nothing makes ``is_ours`` false for every file, and the gate simply
|
|
1146
|
+
stops reporting stale output while still printing a clean verdict.
|
|
1147
|
+
|
|
1148
|
+
The out-dir-relative name is tried as a fallback, because that is how a manifest
|
|
1149
|
+
written before the re-keying spells it — the same fallback ``decide_and_write``
|
|
1150
|
+
makes, so the write path and the gate cannot disagree about which entry is a record
|
|
1151
|
+
of this file.
|
|
1152
|
+
|
|
1046
1153
|
FAILS CLOSED, matching :func:`is_pristine_generated`: with no manifest at all
|
|
1047
1154
|
nothing is proven, so every file stays in scope and the old verdict stands.
|
|
1048
1155
|
"""
|
|
1049
1156
|
if gen_state_dir is None or not has_hash_manifest(gen_state_dir):
|
|
1050
1157
|
return lambda _rel: True
|
|
1051
|
-
|
|
1158
|
+
|
|
1159
|
+
def is_ours(rel: str) -> bool:
|
|
1160
|
+
key = os.path.join(out_prefix, rel) if out_prefix else rel
|
|
1161
|
+
return read_generated_hash(gen_state_dir, key, legacy_rel_path=rel) is not None
|
|
1162
|
+
|
|
1163
|
+
return is_ours
|
|
1052
1164
|
|
|
1053
1165
|
|
|
1054
1166
|
def _diff_report(
|
|
1055
1167
|
expected: dict[str, str],
|
|
1056
1168
|
committed: dict[str, str],
|
|
1057
1169
|
gen_state_dir: str | None = None,
|
|
1170
|
+
out_prefix: str = "",
|
|
1058
1171
|
) -> int:
|
|
1059
1172
|
"""Compare a regenerated file map against the committed one; print the
|
|
1060
1173
|
standard ``verify --codegen`` drift report. Returns 0 (in sync) or 1.
|
|
@@ -1065,8 +1178,11 @@ def _diff_report(
|
|
|
1065
1178
|
|
|
1066
1179
|
``gen_state_dir`` scopes the ``extra`` verdict to files we have a record of
|
|
1067
1180
|
writing — see :func:`_is_ours_for`. Omit it to keep the unscoped verdict.
|
|
1181
|
+
``out_prefix`` is the committed out dir relative to the project, which is what
|
|
1182
|
+
translates this diff's out-dir-relative keys into the manifest's project-relative
|
|
1183
|
+
ones; omit it only when the two coincide.
|
|
1068
1184
|
"""
|
|
1069
|
-
is_ours = _is_ours_for(gen_state_dir)
|
|
1185
|
+
is_ours = _is_ours_for(gen_state_dir, out_prefix)
|
|
1070
1186
|
changed = sorted(
|
|
1071
1187
|
k for k in expected if k in committed and expected[k] != committed[k]
|
|
1072
1188
|
)
|
|
@@ -1179,7 +1295,14 @@ def _verify_codegen(args: argparse.Namespace) -> int:
|
|
|
1179
1295
|
expected = _relative_set(Path(tmp))
|
|
1180
1296
|
committed = _relative_set(Path(args.out))
|
|
1181
1297
|
|
|
1182
|
-
|
|
1298
|
+
# The manifest is keyed relative to the project; this diff is keyed relative to
|
|
1299
|
+
# `--out`. Hand over the prefix that translates one into the other, or the
|
|
1300
|
+
# jurisdiction lookup finds nothing and the `extra` verdict silently empties.
|
|
1301
|
+
project_root = project_root_for(args.metadata_dir)
|
|
1302
|
+
return _diff_report(
|
|
1303
|
+
expected, committed, gen_state_dir_for(args.metadata_dir),
|
|
1304
|
+
_out_prefix(args.out, project_root),
|
|
1305
|
+
)
|
|
1183
1306
|
|
|
1184
1307
|
|
|
1185
1308
|
def _verify_codegen_neutral_fallback(args: argparse.Namespace) -> int:
|
|
@@ -1234,7 +1357,8 @@ def _verify_codegen_neutral_fallback(args: argparse.Namespace) -> int:
|
|
|
1234
1357
|
# `_cmd_gen_neutral_fallback` writes its manifest to), so the jurisdiction lookup
|
|
1235
1358
|
# must be built from that, not from args.metadata_dir (None here by definition).
|
|
1236
1359
|
return _diff_report(
|
|
1237
|
-
expected, committed, str(root_dir.resolve() / ".metaobjects" / ".gen-state")
|
|
1360
|
+
expected, committed, str(root_dir.resolve() / ".metaobjects" / ".gen-state"),
|
|
1361
|
+
_out_prefix(args.out, root_dir.resolve()),
|
|
1238
1362
|
)
|
|
1239
1363
|
|
|
1240
1364
|
|
|
@@ -1351,7 +1475,14 @@ def _verify_codegen_config(args: argparse.Namespace) -> int:
|
|
|
1351
1475
|
# Same jurisdiction rule as _diff_report — this rung inlines its diff to
|
|
1352
1476
|
# report per-target, so the guard has to be inlined with it. Without it,
|
|
1353
1477
|
# broadening the comparison past *.py convicts every stranger's file.
|
|
1354
|
-
|
|
1478
|
+
#
|
|
1479
|
+
# PER-TARGET prefix, because that is the whole point on this rung: two
|
|
1480
|
+
# targets with different outDirs share one manifest, and the key that tells
|
|
1481
|
+
# their identically-named files apart is the one anchored on the project.
|
|
1482
|
+
is_ours = _is_ours_for(
|
|
1483
|
+
gen_state_dir_for(config.metadata_dir()),
|
|
1484
|
+
_out_prefix(real_outdir, project_root_for(config.metadata_dir())),
|
|
1485
|
+
)
|
|
1355
1486
|
extra = sorted(k for k in committed if k not in expected and is_ours(k))
|
|
1356
1487
|
|
|
1357
1488
|
names = "+".join(
|
|
@@ -1640,6 +1771,19 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
1640
1771
|
action="store_true",
|
|
1641
1772
|
help="list registered generators (stable name + description) and exit",
|
|
1642
1773
|
)
|
|
1774
|
+
gen.add_argument(
|
|
1775
|
+
"--baseline",
|
|
1776
|
+
choices=("default", "adopt"),
|
|
1777
|
+
default="default",
|
|
1778
|
+
help=(
|
|
1779
|
+
"first-time-on-existing-file behaviour. 'default' refuses a file that cannot "
|
|
1780
|
+
"be proved to be generated output; 'adopt' records the files you have as the "
|
|
1781
|
+
"baseline and writes NOTHING — the one run a project with no committed "
|
|
1782
|
+
".gen-state/.hashes.json can perform, since nothing writes a manifest until a "
|
|
1783
|
+
"gen succeeds. Adopting DECLARES those files to be generated output: the next "
|
|
1784
|
+
"gen regenerates over them, so commit before you run it."
|
|
1785
|
+
),
|
|
1786
|
+
)
|
|
1643
1787
|
gen.add_argument(
|
|
1644
1788
|
"--template-spec",
|
|
1645
1789
|
dest="template_spec",
|
|
@@ -17,6 +17,22 @@ class GenConfig:
|
|
|
17
17
|
# ``<project>/.metaobjects/.gen-state``. COMMIT the manifest: it is the only thing
|
|
18
18
|
# that makes hand-edit detection work on a machine that did not generate the code.
|
|
19
19
|
gen_state_dir: str | None = None
|
|
20
|
+
# The project the manifest belongs to — the directory holding ``metaobjects/`` and
|
|
21
|
+
# ``.metaobjects/``. Manifest keys are relative to THIS, not to ``out_dir``.
|
|
22
|
+
#
|
|
23
|
+
# They used to be out-dir-relative while the manifest itself is anchored on the
|
|
24
|
+
# project, so two runs with different ``--out`` shared one manifest keyed by names
|
|
25
|
+
# that mean different files: `gen --out /tmp/a` and `gen --out /tmp/b` both record
|
|
26
|
+
# `alarm_names.py`, and run B's hash then claims ownership of run A's file. The
|
|
27
|
+
# manifest is the only thing that can tell "this is exactly what I wrote" from
|
|
28
|
+
# "somebody edited this" on a machine that did not generate the code, so one that can
|
|
29
|
+
# be populated from an unrelated tree and keyed ambiguously is one that can say yes to
|
|
30
|
+
# the wrong file. TS keys project-root-relative, which is also what makes multiple
|
|
31
|
+
# output targets work.
|
|
32
|
+
#
|
|
33
|
+
# None keeps the out-dir-relative keys, so a programmatic caller that never had a
|
|
34
|
+
# project root is unchanged. The CLI always sets it.
|
|
35
|
+
project_root: str | None = None
|
|
20
36
|
# Only "flat" is implemented; a non-default value is REFUSED below rather than
|
|
21
37
|
# silently ignored (see __post_init__).
|
|
22
38
|
output_layout: str = "flat"
|
|
@@ -37,6 +53,12 @@ class GenConfig:
|
|
|
37
53
|
# generator emits names a different column than the one a row actually lands
|
|
38
54
|
# in.
|
|
39
55
|
column_naming: str = DEFAULT_COLUMN_NAMING
|
|
56
|
+
# First-time-on-existing-file behaviour. "default" refuses a file that cannot be
|
|
57
|
+
# proved to be generated output; "adopt" records what is on disk as the baseline and
|
|
58
|
+
# writes nothing — the one run a project with no committed manifest can perform (the
|
|
59
|
+
# refusal used to prescribe committing a manifest nothing had yet produced). A value
|
|
60
|
+
# this port does not implement is REFUSED in __post_init__ rather than ignored.
|
|
61
|
+
baseline: str = "default"
|
|
40
62
|
provided_enum_namespace: str | None = None
|
|
41
63
|
provided_enum_packages: dict[str, str] = field(default_factory=dict)
|
|
42
64
|
|
|
@@ -64,6 +86,17 @@ class GenConfig:
|
|
|
64
86
|
f"GenConfig.output_layout={self.output_layout!r}: only 'flat' is "
|
|
65
87
|
"implemented in this port."
|
|
66
88
|
)
|
|
89
|
+
if self.baseline not in ("default", "adopt"):
|
|
90
|
+
# `fresh` is deliberately absent from this port rather than silently accepted:
|
|
91
|
+
# TypeScript implements it (overwrite from fresh + re-baseline) and this port
|
|
92
|
+
# does not, and taking the value while refusing files anyway is the kind of
|
|
93
|
+
# cross-port lie this whole method exists to prevent.
|
|
94
|
+
raise ValueError(
|
|
95
|
+
f"GenConfig.baseline={self.baseline!r}: this port implements 'default' and "
|
|
96
|
+
"'adopt'. To discard a refused file's content here, delete the file and "
|
|
97
|
+
"re-run — it is then written as new. (TypeScript's '--baseline=fresh' does "
|
|
98
|
+
"that in one step; it is not implemented in this port.)"
|
|
99
|
+
)
|
|
67
100
|
if self.emit_abstract_shapes is not True:
|
|
68
101
|
raise ValueError(
|
|
69
102
|
"GenConfig.emit_abstract_shapes=False: this port always emits the abstract "
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Canonicalize emitted source via ruff: sort imports (isort), then format.
|
|
2
|
+
|
|
3
|
+
Both passes read stdin / write stdout, so generated code is import-sorted AND
|
|
4
|
+
formatted — i.e. `ruff check`- and `ruff format`-clean for downstream consumers."""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import importlib.util
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
_STDIN_NAME = "generated.py"
|
|
12
|
+
|
|
13
|
+
#: ruff is a codegen-time convenience (import-sort + format), not a runtime requirement
|
|
14
|
+
#: of the emitted code. When it's absent we emit valid-but-unformatted Python rather
|
|
15
|
+
#: than hard-failing the whole ``gen``.
|
|
16
|
+
_RUFF_AVAILABLE = importlib.util.find_spec("ruff") is not None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _run_ruff(args: list[str], source: str) -> str:
|
|
20
|
+
proc = subprocess.run(
|
|
21
|
+
[sys.executable, "-m", "ruff", *args],
|
|
22
|
+
input=source,
|
|
23
|
+
capture_output=True,
|
|
24
|
+
text=True,
|
|
25
|
+
)
|
|
26
|
+
if proc.returncode != 0:
|
|
27
|
+
# A non-zero exit is read by the caller as "ruff rejected the source" — a
|
|
28
|
+
# generator bug. Two things make that reading unsafe, so record what actually
|
|
29
|
+
# happened instead of asserting a cause.
|
|
30
|
+
#
|
|
31
|
+
# First, ruff reports a source it cannot parse as exit 2 WITH stderr (measured,
|
|
32
|
+
# ruff 0.15.14: `error: Failed to parse at 1:7: ...`). So an EMPTY stderr is not
|
|
33
|
+
# a source rejection — the process did not get far enough to say anything.
|
|
34
|
+
# Second, a NEGATIVE returncode is death by signal, which is not a verdict on
|
|
35
|
+
# the source at all.
|
|
36
|
+
#
|
|
37
|
+
# This branch used to raise `ruff format failed:` — trailing off after the colon
|
|
38
|
+
# whenever stderr was empty, naming neither the exit status nor the fact that
|
|
39
|
+
# ruff never looked at the source, and sending a reader hunting a syntax error
|
|
40
|
+
# that did not exist. Always carry the status; never claim a source error for a
|
|
41
|
+
# process that did not finish, and do not guess at WHY it did not finish.
|
|
42
|
+
detail = proc.stderr.strip()
|
|
43
|
+
if proc.returncode < 0:
|
|
44
|
+
raise RuntimeError(
|
|
45
|
+
f"ruff {args[0]} was killed by signal {-proc.returncode} before it could "
|
|
46
|
+
f"format the source — this is not a source error; the formatter never ran "
|
|
47
|
+
f"to completion" + (f": {detail}" if detail else "")
|
|
48
|
+
)
|
|
49
|
+
raise RuntimeError(
|
|
50
|
+
f"ruff {args[0]} failed (exit {proc.returncode})"
|
|
51
|
+
+ (
|
|
52
|
+
f": {detail}"
|
|
53
|
+
if detail
|
|
54
|
+
else " and wrote nothing to stderr — ruff reports an unparseable source"
|
|
55
|
+
" WITH stderr, so this is not a source error"
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
return proc.stdout
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def ruff_format(source: str) -> str:
|
|
62
|
+
"""Sort imports then format *source*; return the canonical text.
|
|
63
|
+
|
|
64
|
+
A no-op (returns *source* unchanged) when ruff is not installed — the emitted
|
|
65
|
+
code is still valid Python, just unformatted. Still raises RuntimeError if ruff
|
|
66
|
+
IS present but fails (e.g. a syntax error in emitted code — that's a generator bug)."""
|
|
67
|
+
if not _RUFF_AVAILABLE:
|
|
68
|
+
return source
|
|
69
|
+
sorted_src = _run_ruff(
|
|
70
|
+
["check", "--select", "I", "--fix", "--stdin-filename", _STDIN_NAME, "-"], source
|
|
71
|
+
)
|
|
72
|
+
return _run_ruff(["format", "-"], sorted_src)
|