metaobjects 1.0.10__tar.gz → 1.0.12__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-1.0.10 → metaobjects-1.0.12}/PKG-INFO +1 -1
- {metaobjects-1.0.10 → metaobjects-1.0.12}/pyproject.toml +1 -1
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/agent_context/scaffold.py +2 -2
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/cli.py +179 -12
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/metaobjects-config.schema.json +1 -1
- metaobjects-1.0.12/src/metaobjects/fmt.py +214 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/__init__.py +2 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/extract.py +34 -2
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/types.py +28 -1
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli.py +19 -0
- metaobjects-1.0.12/tests/codegen/test_cli_fmt.py +137 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_extractor_generator.py +41 -0
- metaobjects-1.0.12/tests/codegen/test_fmt_format_file.py +45 -0
- metaobjects-1.0.12/tests/conformance/test_fmt_conformance.py +54 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_extract.py +100 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_agent_context_staleness.py +8 -2
- {metaobjects-1.0.10 → metaobjects-1.0.12}/uv.lock +1 -1
- {metaobjects-1.0.10 → metaobjects-1.0.12}/.gitignore +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/LICENSE +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/README.md +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/hatch_build.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/scripts/generate_embedded_library.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/agent_context/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/apidocs/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/apidocs/api_model.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/apidocs/builder.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/apidocs/naming.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/apidocs/paths.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/apidocs/renderer.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/attr_class_map.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/collision_names.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/config.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/eject.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/format.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generator_registry.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/entity_model.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/find_inbound.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/names_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/router_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/template_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/instance_artifacts.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/model_walk.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/overwrite_policy.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/project_config.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/runner.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/runtime/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/runtime/constraint_errors.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/type_map.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/value_objects.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/config/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/config/dependencies.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/config/neutral_config.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/config/source_resolver.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/core_types.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/datatype.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/documentation/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/documentation/doc_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/documentation/doc_provider.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/documentation/doc_schema.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/errors.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/library/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/library/embedded_library.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/library/library_sources.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/merge.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/meta_data_loader.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/registered_validation.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/sources/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/sources/directory_source.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/sources/file_source.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/sources/uri_source.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validate_discriminator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validate_field_mutability.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validate_source_escapes.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validation_passes.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/attr/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/field/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/field/field_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/field/meta_field.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/identity/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/index/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/index/index_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/index/meta_index.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/meta_object.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/object_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/object_extract.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/value_object.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/relationship_references.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/validator/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/meta_data.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/meta_root.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/provider_extends.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/template/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/template/meta_template.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/template/prompt_provider.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/template/template_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta_endpoint.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/naming.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/naming_refs.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/parser.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/parser_yaml.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/provider.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/py.typed +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/registry.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/registry_manifest.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/email_document.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/escapers.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/coerce.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/extract_map.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/locate.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/normalize.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/strip.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/filesystem_provider.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/payload_accessors.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/prompt/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/prompt/prompt_field.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/prompt/prompt_style.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/renderer.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/verify.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/runtime/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/runtime/llm_recorder.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/runtime/n2m_resolver.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/runtime/object_manager.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/runtime/tph.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/scope.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/serializer_json.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/shared/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/shared/base_types.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/shared/separators.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/shared/structural.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/source/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/source/error_source.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/source/json_path.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/source/semantic_diff.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/source/yaml_positions.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/source_resolution.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/attr.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/db.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/documentation.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/field.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/identity.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/index.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/layout.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/object.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/origin.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/prompt.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/relationship.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/requirement.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/source.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/template.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/ui.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/validator.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/view.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/super_resolve.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/validation_types.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/yaml_desugar.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/gen_suite.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/extends/expected/Program.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/extends/meta.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/nested-array/meta.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/scalars/expected/Report.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/scalars/meta.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/vanilla/meta.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_abstract_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_api_docs_builder.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_api_docs_paths.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_config_gen.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_config_verify.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_dependencies.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_gen_unknown_attr.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_providers.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_registry.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_render_helper_template_root.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_staleness_nudge.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_verify_strict.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_verify_subverbs.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_codegen_compile_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_constants_config.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_eject.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_eject_runtime.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_entity_model.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_enum_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_extract_tier_collision.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_filter_allowlist_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_format.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_fr010_output_codegen.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_gen_state_keying.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_generator_extension_seams.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_golden.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_inheritance_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_instance_artifacts.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_m2m_codegen.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_names_extends_chain.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_names_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_no_magic_physical_names.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_origin_nullability.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_output_parser_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_overwrite_policy.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_overwrite_policy_hash.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_project_config.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_projection_compile.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_recipe_generators.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_render_helper_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_render_helper_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_reverse_finders.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_route_path_naming.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_router_autoset.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_router_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_router_generator_m2m_target_tph.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_router_generator_tph_m2m.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_router_generator_tph_m2m_shadowed.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_runner.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_source_resolution.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_sourceless_entity_surface.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_sourceless_projection.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_template_data.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_template_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_template_output_pattern.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_template_scope_helpers.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_template_scope_walk.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_template_spec.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_tph_codegen.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_trace_helper_generator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_type_map.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_validation_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_value_objects.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_write_through.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/config/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/config/test_dependencies.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/config/test_library_package_guard.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/config/test_neutral_config.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/config/test_source_resolver.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/capabilities.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/conformance-expected-failures.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/conformance_adapter.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/corpus.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/expected_failures.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/fixture_discovery.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/navigator.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_dependency_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_extract_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_extract_object_array_bounds.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_extract_object_verdict.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_fr010_loader_attrs.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_fr011_attrs.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_generator_registry_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_object_model_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_provider_composition_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_registry_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_runner_hardfail.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_scope_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_source_resolution_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_spec_metamodel_embed.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_strict_attr_load.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_template_codegen_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_template_generator_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_yaml_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/api_contract_assertions.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/api_contract_jsonb_server.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/api_contract_m2m_server.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/api_contract_server.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/generated_jsonb_app.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/generated_m2m_app.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/generated_projection_app.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/generated_router_app.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/generated_tph_app.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/meta_ai_trace.yaml +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/normalization.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/postgres_container.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/query_runner.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/scenarios.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract_generated.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract_jsonb.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract_m2m.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract_m2m_generated.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract_projection.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract_tph_generated.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_generated_router_uuid_pk.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_llm_call_trace.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_m2m_target_tph_generated.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_normalization.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_query_scenarios.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_runtime_return_types.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_tph_m2m_generated.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_tph_m2m_shadowed_generated.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/test_abstract_subtype_authored.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/test_child_wrapper_body_shape.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/test_enum_extends_values_conflict.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/test_field_mutability_order.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/test_shipped_library_ai.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/test_template_payload_target_210.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/open_closed_proof_test.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_coerce.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_extract_map.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_json_forgiving_reader.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_locate.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_model.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_normalize.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_strip.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/prompt/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/prompt/test_output_format_renderer.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_email_document.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_filesystem_provider.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_output_format_renderer_nested.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_output_prompt_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_render_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_render_max_chars.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_render_model_payload.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_verify.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_verify_conformance.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/runtime/test_constraint_errors.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/runtime/test_object_manager_currency_read.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/runtime/test_object_manager_enum_intvaluemap.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/runtime/test_object_manager_table_name.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_fr5c_merge_attribution.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_fr5d_reference_resolution.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_fr5e_database_source_shape.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_json_path.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_semantic_diff.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_source_on_node.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_yaml_positions.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/test_api_docs_accuracy.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/test_meta_endpoint.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/__init__.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_capabilities.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_column_naming_strategy.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_common_attrs.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_core_types.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_derive_m2m_declaring_entity.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_effective_children_sibling_shadowing.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_effective_package.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_errors.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_field_enum.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_field_enum_intvaluemap.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_field_map_validation.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_file_source_id.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_index_lookup.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_llm_recorder.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_loader.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_loader_bom.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_loader_class.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_merge.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_meta_attr.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_meta_data.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_meta_source.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_module_shortcuts.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_n2m_resolver.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_n2m_resolver_inherited.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_no_dead_config_fields.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_object_manager_write_through.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_one_primary_source.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_parser.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_parser_yaml.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_provider.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_provider_extension.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_registry.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_registry_completeness.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_registry_extend.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_registry_sealed.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_relationship_m2m_validation.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_relationship_references.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_relationship_referential_actions.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_resolution_key.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_serializer.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_serializer_shared_document.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_shared_constants.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_smoke.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_source_escapes.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_sources.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_strict_child_placement.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_super_resolve.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_template_toolcall.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_validation_attr_schema.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_validation_filter_values.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_validation_origin_195.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_validation_origin_paths.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_validation_sort_field.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_validation_warnings.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_write_coercion_arrays.py +0 -0
- {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_yaml_desugar.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: metaobjects
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.12
|
|
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 = "1.0.
|
|
3
|
+
version = "1.0.12"
|
|
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"
|
|
@@ -240,6 +240,6 @@ def agent_context_staleness(
|
|
|
240
240
|
frm = generated_by if generated_by else "an older MetaObjects"
|
|
241
241
|
return (
|
|
242
242
|
f"MetaObjects agent context was generated by {frm}; "
|
|
243
|
-
f"you're on {current_version}. Run 'npx meta agent-docs
|
|
244
|
-
f"
|
|
243
|
+
f"you're on {current_version}. Run 'npx meta agent-docs' to refresh the "
|
|
244
|
+
f".claude/skills docs (it keeps the stack recorded in .metaobjects/)."
|
|
245
245
|
)
|
|
@@ -1069,6 +1069,132 @@ def _cmd_list(_args: argparse.Namespace) -> int:
|
|
|
1069
1069
|
return 0
|
|
1070
1070
|
|
|
1071
1071
|
|
|
1072
|
+
def _describe_fmt_report(report: "object", cwd: Path) -> str:
|
|
1073
|
+
from metaobjects import fmt
|
|
1074
|
+
|
|
1075
|
+
try:
|
|
1076
|
+
rel = report.path.relative_to(cwd)
|
|
1077
|
+
except ValueError:
|
|
1078
|
+
rel = report.path
|
|
1079
|
+
if report.status == fmt.STATUS_FORMATTED:
|
|
1080
|
+
return f" reformatted {rel}"
|
|
1081
|
+
if report.status == fmt.STATUS_WOULD_FORMAT:
|
|
1082
|
+
return f" not canonical {rel}"
|
|
1083
|
+
if report.status == fmt.STATUS_UNCHANGED:
|
|
1084
|
+
return f" ok {rel}"
|
|
1085
|
+
if report.status == fmt.STATUS_SKIPPED_YAML:
|
|
1086
|
+
return f" skipped (yaml) {rel} — {report.detail}"
|
|
1087
|
+
if report.status == fmt.STATUS_SKIPPED_OVERLAY:
|
|
1088
|
+
return (
|
|
1089
|
+
f" skipped (overlay) {rel} — this file declares an overlay fmt "
|
|
1090
|
+
"cannot resolve standalone"
|
|
1091
|
+
)
|
|
1092
|
+
if report.status == fmt.STATUS_ERROR:
|
|
1093
|
+
return f" error {rel} — {report.detail}"
|
|
1094
|
+
return f" {report.status} {rel}" # pragma: no cover — exhaustive in practice
|
|
1095
|
+
|
|
1096
|
+
|
|
1097
|
+
def _cmd_fmt(args: argparse.Namespace) -> int:
|
|
1098
|
+
"""``fmt`` (#304) — rewrite metadata files into canonical form; ``--check``
|
|
1099
|
+
lists non-canonical files and exits non-zero without changing anything.
|
|
1100
|
+
|
|
1101
|
+
Mirrors the TS reference surface exactly: no ``metadata_dir`` positional —
|
|
1102
|
+
files come from the neutral ``.metaobjects/config.json`` ladder
|
|
1103
|
+
(:func:`resolve_metadata_location`, rungs 3-4; this command does not read
|
|
1104
|
+
this port's own ``metaobjects.config.yaml`` rung 2, matching the scope the
|
|
1105
|
+
C# and Java ports also keep for `fmt`), optionally narrowed by explicit
|
|
1106
|
+
file arguments.
|
|
1107
|
+
"""
|
|
1108
|
+
from metaobjects import fmt
|
|
1109
|
+
from metaobjects.core_types import core_providers
|
|
1110
|
+
from metaobjects.library import library_sources
|
|
1111
|
+
from metaobjects.provider import compose_registry
|
|
1112
|
+
|
|
1113
|
+
providers_extra, providers_ok = _providers_from_args(args)
|
|
1114
|
+
if not providers_ok:
|
|
1115
|
+
return 1
|
|
1116
|
+
providers = [*core_providers, *providers_extra]
|
|
1117
|
+
registry = compose_registry(providers)
|
|
1118
|
+
|
|
1119
|
+
cwd = Path.cwd()
|
|
1120
|
+
collection = _resolve_metadata_location_or_print_error(None, cwd)
|
|
1121
|
+
if collection is None:
|
|
1122
|
+
return 1
|
|
1123
|
+
|
|
1124
|
+
all_files = list(collection.files)
|
|
1125
|
+
own_files = list(collection.own_files)
|
|
1126
|
+
|
|
1127
|
+
if args.files:
|
|
1128
|
+
wanted = [Path(f).resolve() for f in args.files]
|
|
1129
|
+
owned_set = {p.resolve() for p in own_files}
|
|
1130
|
+
missing = [str(p) for p in wanted if p not in owned_set]
|
|
1131
|
+
if missing:
|
|
1132
|
+
print(
|
|
1133
|
+
"error: not among this project's resolved metadata sources: "
|
|
1134
|
+
+ ", ".join(missing),
|
|
1135
|
+
file=sys.stderr,
|
|
1136
|
+
)
|
|
1137
|
+
print(
|
|
1138
|
+
"metaobjects fmt only formats files the metadata-location ladder "
|
|
1139
|
+
"already resolves — pass no arguments to format every one of them.",
|
|
1140
|
+
file=sys.stderr,
|
|
1141
|
+
)
|
|
1142
|
+
return 1
|
|
1143
|
+
wanted_set = {p for p in wanted}
|
|
1144
|
+
targets = [p for p in own_files if p.resolve() in wanted_set]
|
|
1145
|
+
else:
|
|
1146
|
+
targets = own_files
|
|
1147
|
+
|
|
1148
|
+
lib_sources = library_sources(list(collection.libraries)) if collection.libraries else []
|
|
1149
|
+
|
|
1150
|
+
result = fmt.run(
|
|
1151
|
+
all_files=all_files,
|
|
1152
|
+
target_files=targets,
|
|
1153
|
+
file_ids=dict(collection.file_ids),
|
|
1154
|
+
registry=registry,
|
|
1155
|
+
lib_sources=lib_sources,
|
|
1156
|
+
check=bool(args.check),
|
|
1157
|
+
providers=providers,
|
|
1158
|
+
)
|
|
1159
|
+
|
|
1160
|
+
if result.fatal is not None:
|
|
1161
|
+
print(f"error: {result.fatal}", file=sys.stderr)
|
|
1162
|
+
return 1
|
|
1163
|
+
|
|
1164
|
+
if not result.files:
|
|
1165
|
+
print("metaobjects fmt — no metadata files to format.")
|
|
1166
|
+
return 0
|
|
1167
|
+
|
|
1168
|
+
for report in result.files:
|
|
1169
|
+
print(_describe_fmt_report(report, cwd))
|
|
1170
|
+
|
|
1171
|
+
errored = sum(1 for r in result.files if r.status == fmt.STATUS_ERROR)
|
|
1172
|
+
needs_format = sum(1 for r in result.files if r.status == fmt.STATUS_WOULD_FORMAT)
|
|
1173
|
+
reformatted = sum(1 for r in result.files if r.status == fmt.STATUS_FORMATTED)
|
|
1174
|
+
|
|
1175
|
+
if args.check:
|
|
1176
|
+
if needs_format or errored:
|
|
1177
|
+
suffix = f", {errored} error(s)" if errored else ""
|
|
1178
|
+
print(
|
|
1179
|
+
f"metaobjects fmt --check — {needs_format} file(s) not canonical{suffix}. "
|
|
1180
|
+
"Run `metaobjects fmt` to fix.",
|
|
1181
|
+
file=sys.stderr,
|
|
1182
|
+
)
|
|
1183
|
+
return 1
|
|
1184
|
+
print("metaobjects fmt --check — every file is already canonical.")
|
|
1185
|
+
return 0
|
|
1186
|
+
|
|
1187
|
+
if errored:
|
|
1188
|
+
print(
|
|
1189
|
+
f"metaobjects fmt — {errored} file(s) could not be formatted safely (left unchanged).",
|
|
1190
|
+
file=sys.stderr,
|
|
1191
|
+
)
|
|
1192
|
+
return 1
|
|
1193
|
+
|
|
1194
|
+
print(f"metaobjects fmt — {reformatted} file(s) reformatted.")
|
|
1195
|
+
return 0
|
|
1196
|
+
|
|
1197
|
+
|
|
1072
1198
|
def _cmd_eject(args: argparse.Namespace) -> int:
|
|
1073
1199
|
"""Copy reference generators into ``codegen/generators/`` to own (ADR-0034 Am. 3)."""
|
|
1074
1200
|
root = Path(args.root) if args.root else Path.cwd()
|
|
@@ -1612,6 +1738,32 @@ def _diff_report(
|
|
|
1612
1738
|
return 1
|
|
1613
1739
|
|
|
1614
1740
|
|
|
1741
|
+
|
|
1742
|
+
def _no_generators_selected(out_dir: str) -> int:
|
|
1743
|
+
"""``verify --codegen`` with nothing selected: pass only if nothing would go unchecked.
|
|
1744
|
+
|
|
1745
|
+
There is no default suite (1.0.4), so with no ``--generators`` nothing is regenerated.
|
|
1746
|
+
If ``out_dir`` already holds generated files, reporting success would be a false green
|
|
1747
|
+
— a gate written before 1.0.4, relying on the default, silently stopped checking
|
|
1748
|
+
anything. That is an error; an empty or absent ``out_dir`` is not.
|
|
1749
|
+
"""
|
|
1750
|
+
committed = [p for p in Path(out_dir).rglob("*.py") if p.name != "__init__.py"] if Path(out_dir).is_dir() else []
|
|
1751
|
+
if committed:
|
|
1752
|
+
print(
|
|
1753
|
+
f"error: verify --codegen: no generators selected, but {out_dir} holds "
|
|
1754
|
+
f"{len(committed)} generated file(s) that would go unchecked. There is no "
|
|
1755
|
+
"default suite: pass --generators <a,b,c> naming the same suite `gen` ran "
|
|
1756
|
+
"(metaobjects gen --list is the catalog).",
|
|
1757
|
+
file=sys.stderr,
|
|
1758
|
+
)
|
|
1759
|
+
return 1
|
|
1760
|
+
print(
|
|
1761
|
+
"verify --codegen: no generators selected and no generated output to check. "
|
|
1762
|
+
"Pass --generators <a,b,c> naming the same suite `gen` ran "
|
|
1763
|
+
"(metaobjects gen --list is the catalog).",
|
|
1764
|
+
)
|
|
1765
|
+
return 0
|
|
1766
|
+
|
|
1615
1767
|
def _verify_codegen(args: argparse.Namespace) -> int:
|
|
1616
1768
|
"""``verify --codegen`` — regenerate to a temp dir + diff vs committed ``--out``.
|
|
1617
1769
|
|
|
@@ -1676,12 +1828,7 @@ def _verify_codegen(args: argparse.Namespace) -> int:
|
|
|
1676
1828
|
print(f" {msg}", file=sys.stderr)
|
|
1677
1829
|
return 1
|
|
1678
1830
|
elif not spec_gens:
|
|
1679
|
-
|
|
1680
|
-
"verify --codegen: no generators selected, so there is no generated output "
|
|
1681
|
-
"to check. Pass --generators <a,b,c> naming the same suite `gen` ran "
|
|
1682
|
-
"(metaobjects gen --list is the catalog).",
|
|
1683
|
-
)
|
|
1684
|
-
return 0
|
|
1831
|
+
return _no_generators_selected(args.out)
|
|
1685
1832
|
|
|
1686
1833
|
with tempfile.TemporaryDirectory() as tmp:
|
|
1687
1834
|
entities = _parse_entities(getattr(args, "entities", None))
|
|
@@ -1767,12 +1914,7 @@ def _verify_codegen_neutral_fallback(args: argparse.Namespace) -> int:
|
|
|
1767
1914
|
# Same rule as _verify_codegen: the selection must be named, because there is no
|
|
1768
1915
|
# default suite to regenerate and diff against.
|
|
1769
1916
|
if not getattr(args, "generators", None):
|
|
1770
|
-
|
|
1771
|
-
"verify --codegen: no generators selected, so there is no generated output "
|
|
1772
|
-
"to check. Pass --generators <a,b,c> naming the same suite `gen` ran "
|
|
1773
|
-
"(metaobjects gen --list is the catalog).",
|
|
1774
|
-
)
|
|
1775
|
-
return 0
|
|
1917
|
+
return _no_generators_selected(args.out)
|
|
1776
1918
|
selection, gen_errors = _resolve_generators(
|
|
1777
1919
|
args.generators, GeneratorBuildContext(_template_root_for(args)))
|
|
1778
1920
|
if gen_errors:
|
|
@@ -2477,6 +2619,31 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
2477
2619
|
)
|
|
2478
2620
|
verify.set_defaults(func=_cmd_verify)
|
|
2479
2621
|
|
|
2622
|
+
fmt_p = sub.add_parser(
|
|
2623
|
+
"fmt",
|
|
2624
|
+
help="rewrite metadata files into canonical form (#304)",
|
|
2625
|
+
)
|
|
2626
|
+
fmt_p.add_argument(
|
|
2627
|
+
"files",
|
|
2628
|
+
nargs="*",
|
|
2629
|
+
metavar="FILE",
|
|
2630
|
+
help="optional explicit file(s) to format — must be members of this "
|
|
2631
|
+
"project's resolved metadata sources; omit to format every one of them",
|
|
2632
|
+
)
|
|
2633
|
+
fmt_p.add_argument(
|
|
2634
|
+
"--check",
|
|
2635
|
+
action="store_true",
|
|
2636
|
+
help="list files that are not canonical and exit non-zero; changes nothing",
|
|
2637
|
+
)
|
|
2638
|
+
fmt_p.add_argument(
|
|
2639
|
+
"--provider",
|
|
2640
|
+
action="append",
|
|
2641
|
+
default=None,
|
|
2642
|
+
metavar="MODULE:SYMBOL",
|
|
2643
|
+
help="consumer-registered Provider(s), repeatable (module:symbol)",
|
|
2644
|
+
)
|
|
2645
|
+
fmt_p.set_defaults(func=_cmd_fmt)
|
|
2646
|
+
|
|
2480
2647
|
eject_p = sub.add_parser(
|
|
2481
2648
|
"eject",
|
|
2482
2649
|
help="copy reference generators into codegen/generators/ to own and edit",
|
{metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/metaobjects-config.schema.json
RENAMED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"generators": {
|
|
39
39
|
"type": "array",
|
|
40
40
|
"items": { "type": "string" },
|
|
41
|
-
"description": "Stable generator names (see `metaobjects gen --list`).
|
|
41
|
+
"description": "Stable generator names (see `metaobjects gen --list`). Required: there is no default suite, so a target that names none generates nothing and `verify --codegen` checks nothing."
|
|
42
42
|
},
|
|
43
43
|
"entities": {
|
|
44
44
|
"type": "array",
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""``metaobjects fmt`` (#304) — rewrite metadata files into the canonical form
|
|
2
|
+
the cross-port canonical serializer already produces. ``--check`` lists files
|
|
3
|
+
that are not canonical and exits non-zero without changing anything.
|
|
4
|
+
|
|
5
|
+
Mirrors the TS reference (``packages/metadata/src/fmt.ts`` +
|
|
6
|
+
``packages/cli/src/lib/fmt-engine.ts``) and the C#/Java ports exactly:
|
|
7
|
+
|
|
8
|
+
- Each file is formatted STANDALONE — own-mode, declared-here layer only
|
|
9
|
+
(ADR-0039). ``parse_document`` already builds a fresh, unmerged tree per
|
|
10
|
+
document (this port's loader does parse -> merge -> super-resolve as three
|
|
11
|
+
separate steps, unlike TS/C#'s accumulating-root parser) — calling it
|
|
12
|
+
directly and never running ``merge_roots``/``resolve_supers`` is what makes
|
|
13
|
+
a cross-file ``extends`` round-trip untouched (the raw ``super_ref`` string
|
|
14
|
+
is read directly by ``canonical_serialize``, never its resolution) and an
|
|
15
|
+
``overlay: true`` node never even attempt a merge.
|
|
16
|
+
- An ``overlay: true`` node is tagged (``is_overlay``) by the parser but never
|
|
17
|
+
resolved here — Python's overlay MERGE only happens in ``loader/merge.py``,
|
|
18
|
+
which this module never calls. A file containing one anywhere in its tree
|
|
19
|
+
(detected by :func:`_contains_overlay`) is reported as a skip rather than
|
|
20
|
+
guessed at — the concrete shape of "overlay files stay overlays".
|
|
21
|
+
- YAML is always skipped: no canonical YAML emitter exists (ADR-0006).
|
|
22
|
+
- Before writing, the whole project is reloaded with the candidate
|
|
23
|
+
substituted in via an in-memory source (never touching disk until proven
|
|
24
|
+
safe) and the write is refused unless that reload has no errors AND its
|
|
25
|
+
canonical form is byte-identical to the untouched baseline.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import json
|
|
31
|
+
from dataclasses import dataclass, field
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
from typing import Callable
|
|
34
|
+
|
|
35
|
+
from metaobjects.errors import MetaError
|
|
36
|
+
from metaobjects.loader.meta_data_loader import MetaDataLoader
|
|
37
|
+
from metaobjects.loader.sources.file_source import FileSource
|
|
38
|
+
from metaobjects.loader.sources.meta_data_source import InMemoryStringSource, MetaDataSource
|
|
39
|
+
from metaobjects.meta.meta_data import MetaData
|
|
40
|
+
from metaobjects.parser import parse_document
|
|
41
|
+
from metaobjects.registry import TypeRegistry
|
|
42
|
+
from metaobjects.serializer_json import canonical_serialize
|
|
43
|
+
|
|
44
|
+
#: Statuses a single file's run can report.
|
|
45
|
+
STATUS_FORMATTED = "formatted"
|
|
46
|
+
STATUS_WOULD_FORMAT = "would-format"
|
|
47
|
+
STATUS_UNCHANGED = "unchanged"
|
|
48
|
+
STATUS_SKIPPED_YAML = "skipped-yaml"
|
|
49
|
+
STATUS_SKIPPED_OVERLAY = "skipped-overlay"
|
|
50
|
+
STATUS_ERROR = "error"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class FormatFileResult:
|
|
55
|
+
ok: bool
|
|
56
|
+
overlay: bool = False
|
|
57
|
+
text: str | None = None
|
|
58
|
+
message: str | None = None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _contains_overlay(node: MetaData) -> bool:
|
|
62
|
+
"""Whether *node* or any descendant (own children only — this tree was
|
|
63
|
+
never merged, so every child already is its own) carries ``overlay: true``.
|
|
64
|
+
"""
|
|
65
|
+
if getattr(node, "is_overlay", False):
|
|
66
|
+
return True
|
|
67
|
+
return any(_contains_overlay(child) for child in node.own_children())
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def format_file(content: str, registry: TypeRegistry, source_id: str) -> FormatFileResult:
|
|
71
|
+
"""Format one file's own content. Parses *content* standalone via
|
|
72
|
+
:func:`parse_document` — never merged with any other file, super
|
|
73
|
+
resolution never run — and, on a clean parse with no overlay anywhere in
|
|
74
|
+
the tree, returns the canonical serialization of the resulting file root.
|
|
75
|
+
Never raises for a malformed file; that comes back as ``ok=False``.
|
|
76
|
+
"""
|
|
77
|
+
# Strip a UTF-8 BOM before parsing — json.loads rejects one outright
|
|
78
|
+
# ("Unexpected UTF-8 BOM (decode using utf-8-sig)"), and Java-authored
|
|
79
|
+
# files often carry one.
|
|
80
|
+
normalized = content[1:] if content.startswith("") else content
|
|
81
|
+
try:
|
|
82
|
+
doc = json.loads(normalized)
|
|
83
|
+
except json.JSONDecodeError as exc:
|
|
84
|
+
return FormatFileResult(ok=False, message=f"invalid JSON: {exc}")
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
result = parse_document(doc, registry, source_id)
|
|
88
|
+
except Exception as exc: # a few structural failures raise rather than record
|
|
89
|
+
return FormatFileResult(ok=False, message=str(exc))
|
|
90
|
+
|
|
91
|
+
if result.errors:
|
|
92
|
+
message = "; ".join(e.message for e in result.errors)
|
|
93
|
+
return FormatFileResult(ok=False, message=message)
|
|
94
|
+
|
|
95
|
+
if _contains_overlay(result.root):
|
|
96
|
+
return FormatFileResult(
|
|
97
|
+
ok=False,
|
|
98
|
+
overlay=True,
|
|
99
|
+
message="this file declares an overlay fmt cannot resolve standalone",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
return FormatFileResult(ok=True, text=canonical_serialize(result.root))
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@dataclass
|
|
106
|
+
class FileReport:
|
|
107
|
+
path: Path
|
|
108
|
+
status: str
|
|
109
|
+
detail: str | None = None
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@dataclass
|
|
113
|
+
class RunResult:
|
|
114
|
+
files: list[FileReport] = field(default_factory=list)
|
|
115
|
+
fatal: str | None = None
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def run(
|
|
119
|
+
all_files: list[Path],
|
|
120
|
+
target_files: list[Path],
|
|
121
|
+
file_ids: dict[Path, str],
|
|
122
|
+
registry: TypeRegistry,
|
|
123
|
+
lib_sources: list[MetaDataSource],
|
|
124
|
+
check: bool,
|
|
125
|
+
providers: list[object] | None = None,
|
|
126
|
+
) -> RunResult:
|
|
127
|
+
"""Run fmt over *target_files* (a subset of *all_files* — the project's
|
|
128
|
+
FULL resolved file set, needed for the whole-project safety-check reload
|
|
129
|
+
regardless of which files are in scope to format).
|
|
130
|
+
|
|
131
|
+
*providers* must be the SAME provider list *registry* (used for every
|
|
132
|
+
standalone per-file parse) was composed from — the whole-project baseline
|
|
133
|
+
and safety-check reloads build their own `MetaDataLoader`, which recomposes
|
|
134
|
+
a registry from *providers* itself rather than taking `registry` directly,
|
|
135
|
+
so passing a different set here would silently check two vocabularies
|
|
136
|
+
against each other.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
def source_id(path: Path) -> str:
|
|
140
|
+
return file_ids.get(path) or path.name
|
|
141
|
+
|
|
142
|
+
def build_sources(
|
|
143
|
+
override_path: Path | None = None, override_text: str | None = None
|
|
144
|
+
) -> list[MetaDataSource]:
|
|
145
|
+
sources: list[MetaDataSource] = list(lib_sources)
|
|
146
|
+
for p in all_files:
|
|
147
|
+
if override_path is not None and p == override_path:
|
|
148
|
+
sources.append(InMemoryStringSource(override_text or "", id=source_id(p)))
|
|
149
|
+
else:
|
|
150
|
+
sources.append(FileSource(p, id=source_id(p)))
|
|
151
|
+
return sources
|
|
152
|
+
|
|
153
|
+
baseline = MetaDataLoader(providers=providers, strict=False).load(build_sources())
|
|
154
|
+
if baseline.errors:
|
|
155
|
+
detail = "\n".join(f" {e.code}: {e.message}" for e in baseline.errors)
|
|
156
|
+
return RunResult(
|
|
157
|
+
fatal=(
|
|
158
|
+
"this project's metadata does not currently load cleanly — fix the "
|
|
159
|
+
f"error(s) below, then re-run fmt:\n{detail}"
|
|
160
|
+
)
|
|
161
|
+
)
|
|
162
|
+
baseline_canonical = canonical_serialize(baseline.root)
|
|
163
|
+
|
|
164
|
+
reports: list[FileReport] = []
|
|
165
|
+
for path in target_files:
|
|
166
|
+
ext = path.suffix.lower()
|
|
167
|
+
if ext in (".yaml", ".yml"):
|
|
168
|
+
reports.append(
|
|
169
|
+
FileReport(
|
|
170
|
+
path,
|
|
171
|
+
STATUS_SKIPPED_YAML,
|
|
172
|
+
"no canonical YAML emitter exists (ADR-0006: JSON is the canonical "
|
|
173
|
+
"interchange form) — left untouched",
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
continue
|
|
177
|
+
|
|
178
|
+
content = path.read_text(encoding="utf-8")
|
|
179
|
+
formatted = format_file(content, registry, source_id(path))
|
|
180
|
+
if not formatted.ok:
|
|
181
|
+
reports.append(
|
|
182
|
+
FileReport(
|
|
183
|
+
path,
|
|
184
|
+
STATUS_SKIPPED_OVERLAY if formatted.overlay else STATUS_ERROR,
|
|
185
|
+
formatted.message,
|
|
186
|
+
)
|
|
187
|
+
)
|
|
188
|
+
continue
|
|
189
|
+
|
|
190
|
+
if formatted.text == content:
|
|
191
|
+
reports.append(FileReport(path, STATUS_UNCHANGED))
|
|
192
|
+
continue
|
|
193
|
+
|
|
194
|
+
test_load = MetaDataLoader(providers=providers, strict=False).load(
|
|
195
|
+
build_sources(path, formatted.text)
|
|
196
|
+
)
|
|
197
|
+
safe = not test_load.errors and canonical_serialize(test_load.root) == baseline_canonical
|
|
198
|
+
if not safe:
|
|
199
|
+
reports.append(
|
|
200
|
+
FileReport(
|
|
201
|
+
path,
|
|
202
|
+
STATUS_ERROR,
|
|
203
|
+
"formatting this file would change the loaded model's meaning — left unchanged",
|
|
204
|
+
)
|
|
205
|
+
)
|
|
206
|
+
continue
|
|
207
|
+
|
|
208
|
+
if check:
|
|
209
|
+
reports.append(FileReport(path, STATUS_WOULD_FORMAT))
|
|
210
|
+
else:
|
|
211
|
+
path.write_text(formatted.text, encoding="utf-8")
|
|
212
|
+
reports.append(FileReport(path, STATUS_FORMATTED))
|
|
213
|
+
|
|
214
|
+
return RunResult(files=reports)
|
|
@@ -25,6 +25,7 @@ from metaobjects.render.extract.types import (
|
|
|
25
25
|
Format,
|
|
26
26
|
Normalizer,
|
|
27
27
|
OnField,
|
|
28
|
+
OnLocate,
|
|
28
29
|
ExtractOptions,
|
|
29
30
|
ExtractionOutcome,
|
|
30
31
|
ExtractSchema,
|
|
@@ -45,6 +46,7 @@ __all__ = [
|
|
|
45
46
|
"JsonForgivingReader",
|
|
46
47
|
"Normalizer",
|
|
47
48
|
"OnField",
|
|
49
|
+
"OnLocate",
|
|
48
50
|
"ExtractOptions",
|
|
49
51
|
"ExtractionOutcome",
|
|
50
52
|
"ExtractSchema",
|
|
@@ -38,23 +38,55 @@ def extract(
|
|
|
38
38
|
stripped = _strip.strip(text)
|
|
39
39
|
ci = o.tolerance != Tolerance.STRICT
|
|
40
40
|
|
|
41
|
+
# FR-364: the document-level on_locate hook runs BEFORE the default locator. A non-None
|
|
42
|
+
# return is the payload span, fed into the same format-specific forgiving reader a
|
|
43
|
+
# default-located span would be — tolerance/coercion/normalizers/on_field downstream are
|
|
44
|
+
# unaffected. A None return (or no hook) falls through to the default locate strategy
|
|
45
|
+
# unchanged. A raised exception propagates (not swallowed), matching on_field.
|
|
46
|
+
located: str | None = None if o.on_locate is None else o.on_locate(text if text is not None else "", schema.format)
|
|
47
|
+
|
|
41
48
|
# XML rootless (opts.rootless): the payload's fields ARE the top-level elements — there
|
|
42
49
|
# is no enclosing root to locate — so parse the whole stripped text's top-level elements
|
|
43
50
|
# directly. Otherwise locate the <rootName> span as before. JSON is unaffected. Mirrors
|
|
44
51
|
# Java Extract.extract.
|
|
45
52
|
span: str | None
|
|
46
53
|
raw: dict[str, object]
|
|
47
|
-
|
|
54
|
+
# Whether the SELECTED region (not the original reply) was itself empty/blank — the signal
|
|
55
|
+
# mark_empty() keys on below. For the default path this is the pre-existing "nothing to
|
|
56
|
+
# parse" test (stripped == "" or span is None); for on_locate it must be judged against the
|
|
57
|
+
# hook's OWN return, not the original text — otherwise an empty located span (e.g. the hook
|
|
58
|
+
# deliberately returning "") reports "not empty" while every field is LOST, because the
|
|
59
|
+
# original reply was non-blank even though the thing on_locate chose to parse was.
|
|
60
|
+
region_blank: bool
|
|
61
|
+
if located is not None:
|
|
62
|
+
span = located
|
|
63
|
+
if schema.format == Format.JSON:
|
|
64
|
+
raw = JsonForgivingReader().read(located)
|
|
65
|
+
elif o.rootless:
|
|
66
|
+
raw = XmlForgivingReader().read_rootless(located, ci)
|
|
67
|
+
else:
|
|
68
|
+
raw = XmlForgivingReader().read(located, ci)
|
|
69
|
+
# `from_` is deliberately left empty rather than the original text: a document-level
|
|
70
|
+
# audit entry that copied the whole raw reply (which can be arbitrarily large) into the
|
|
71
|
+
# report on every call would make the report itself heavy for no benefit `to`'s length
|
|
72
|
+
# doesn't already give. `to` is the located span's LENGTH, not the span text, for the
|
|
73
|
+
# same reason.
|
|
74
|
+
report.add_coercion(Coercion("", "", str(len(located)), "onLocate"))
|
|
75
|
+
region_blank = located.strip() == ""
|
|
76
|
+
elif schema.format == Format.JSON:
|
|
48
77
|
span = _select_json(text, stripped, schema.fields, ci)
|
|
49
78
|
raw = {} if span is None else JsonForgivingReader().read(span)
|
|
79
|
+
region_blank = stripped == "" or span is None
|
|
50
80
|
elif o.rootless:
|
|
51
81
|
span = None if stripped == "" else stripped
|
|
52
82
|
raw = {} if span is None else XmlForgivingReader().read_rootless(stripped, ci)
|
|
83
|
+
region_blank = stripped == "" or span is None
|
|
53
84
|
else:
|
|
54
85
|
span = _locate.xml(stripped, schema.root_name, ci)
|
|
55
86
|
raw = {} if span is None else XmlForgivingReader().read(span, ci)
|
|
87
|
+
region_blank = stripped == "" or span is None
|
|
56
88
|
|
|
57
|
-
if not raw and
|
|
89
|
+
if not raw and region_blank:
|
|
58
90
|
report.mark_empty()
|
|
59
91
|
|
|
60
92
|
_extract(schema.fields, raw, "", data, report, o, ci)
|
|
@@ -27,6 +27,17 @@ T = TypeVar("T")
|
|
|
27
27
|
OnField = Callable[[str, str, "FieldSpec"], object | None]
|
|
28
28
|
Normalizer = Callable[[str], object | None]
|
|
29
29
|
|
|
30
|
+
# FR-364: the document-level locate hook: (text, format) -> payload substring | None.
|
|
31
|
+
# Receives the RAW reply text (never None; an absent document is normalized to ``""``
|
|
32
|
+
# before the hook runs) and the schema's declared ``Format``. Returning ``None`` falls
|
|
33
|
+
# back to the default locator (the fenced-then-first-object rule #363 fixed). A non-None
|
|
34
|
+
# return is parsed by the normal pipeline exactly like a default-located span —
|
|
35
|
+
# tolerance, coercion, ``normalizers``, and ``on_field`` downstream are unaffected — so
|
|
36
|
+
# this hook only decides WHICH text is the payload, never how it is parsed. The returned
|
|
37
|
+
# text need not be a literal substring of the input (the hook may synthesize it). A
|
|
38
|
+
# raised exception propagates (it is not swallowed), matching ``on_field``.
|
|
39
|
+
OnLocate = Callable[[str, "Format"], "str | None"]
|
|
40
|
+
|
|
30
41
|
|
|
31
42
|
class Format(Enum):
|
|
32
43
|
"""Document format the extract pipeline targets."""
|
|
@@ -248,7 +259,8 @@ class ExtractOptions:
|
|
|
248
259
|
"""Bounded runtime override surface (the "20%").
|
|
249
260
|
|
|
250
261
|
``aliases``/``normalizers`` are MERGED with the schema's, runtime winning on key
|
|
251
|
-
conflict. ``on_field`` is the single bespoke-coercion hook
|
|
262
|
+
conflict. ``on_field`` is the single per-field bespoke-coercion hook; ``on_locate``
|
|
263
|
+
is the single document-level (payload-location) hook.
|
|
252
264
|
|
|
253
265
|
``rootless`` (XML only): when ``True``, the input has NO enclosing root element —
|
|
254
266
|
the payload's fields ARE the top-level elements (a flat sequence like
|
|
@@ -259,6 +271,7 @@ class ExtractOptions:
|
|
|
259
271
|
aliases: dict[str, str] = field(default_factory=dict)
|
|
260
272
|
normalizers: dict[str, Normalizer] = field(default_factory=dict)
|
|
261
273
|
on_field: OnField | None = None
|
|
274
|
+
on_locate: OnLocate | None = None
|
|
262
275
|
rootless: bool = False
|
|
263
276
|
|
|
264
277
|
@staticmethod
|
|
@@ -271,6 +284,19 @@ class ExtractOptions:
|
|
|
271
284
|
aliases=dict(self.aliases),
|
|
272
285
|
normalizers=dict(self.normalizers),
|
|
273
286
|
on_field=self.on_field,
|
|
287
|
+
on_locate=self.on_locate,
|
|
288
|
+
rootless=self.rootless,
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
def with_on_locate(self, hook: OnLocate | None) -> "ExtractOptions":
|
|
292
|
+
"""The single document-level locate hook. See ``OnLocate``. Returns a copy
|
|
293
|
+
with ``on_locate`` set."""
|
|
294
|
+
return ExtractOptions(
|
|
295
|
+
tolerance=self.tolerance,
|
|
296
|
+
aliases=dict(self.aliases),
|
|
297
|
+
normalizers=dict(self.normalizers),
|
|
298
|
+
on_field=self.on_field,
|
|
299
|
+
on_locate=hook,
|
|
274
300
|
rootless=self.rootless,
|
|
275
301
|
)
|
|
276
302
|
|
|
@@ -282,6 +308,7 @@ class ExtractOptions:
|
|
|
282
308
|
aliases=dict(self.aliases),
|
|
283
309
|
normalizers=dict(self.normalizers),
|
|
284
310
|
on_field=self.on_field,
|
|
311
|
+
on_locate=self.on_locate,
|
|
285
312
|
rootless=r,
|
|
286
313
|
)
|
|
287
314
|
|
|
@@ -495,3 +495,22 @@ def test_prompts_and_templates_root_are_the_same_flag(tmp_path: Path) -> None:
|
|
|
495
495
|
rc = main(["verify", "--codegen", "--generators", GEN_SUITE, str(root / "meta"), "--out", str(out),
|
|
496
496
|
"--prompts", str(root / "no-such-dir")])
|
|
497
497
|
assert rc != 0, "--prompts value was ignored — a missing dir still regenerated the spec files"
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
# `verify --codegen` with no --generators used to print a note and exit 0. Since 1.0.4
|
|
501
|
+
# there is no default suite, so a CI step written before then — naming no generators
|
|
502
|
+
# because the default used to be implied — regenerated nothing and passed while the
|
|
503
|
+
# committed output went unchecked (found upgrading an adopter: 159 generated files, gate
|
|
504
|
+
# green). With committed generated output present and nothing selected, it now fails.
|
|
505
|
+
def test_verify_without_generators_fails_when_committed_output_would_go_unchecked(tmp_path: Path) -> None:
|
|
506
|
+
meta_dir = _meta_dir(tmp_path)
|
|
507
|
+
out = tmp_path / "out"
|
|
508
|
+
assert main(["gen", "--generators", GEN_SUITE, meta_dir, "--out", str(out)]) == 0
|
|
509
|
+
assert main(["verify", meta_dir, "--out", str(out)]) != 0
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def test_verify_without_generators_still_passes_with_no_generated_output(tmp_path: Path) -> None:
|
|
513
|
+
meta_dir = _meta_dir(tmp_path)
|
|
514
|
+
out = tmp_path / "out"
|
|
515
|
+
out.mkdir()
|
|
516
|
+
assert main(["verify", meta_dir, "--out", str(out)]) == 0
|