metaobjects 0.19.2__tar.gz → 0.19.4__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.19.2 → metaobjects-0.19.4}/PKG-INFO +1 -1
- {metaobjects-0.19.2 → metaobjects-0.19.4}/pyproject.toml +1 -1
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/cli.py +26 -4
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/payload_vo_generator.py +196 -34
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/router_generator.py +133 -1
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/errors.py +3 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_cli_verify_subverbs.py +110 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_payload_vo_generator.py +89 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_render_helper_conformance.py +43 -1
- metaobjects-0.19.4/tests/codegen/test_router_autoset.py +168 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/api_contract_assertions.py +42 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/api_contract_server.py +72 -17
- {metaobjects-0.19.2 → metaobjects-0.19.4}/.gitignore +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/LICENSE +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/README.md +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/hatch_build.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/agent_context/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/agent_context/scaffold.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/apidocs/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/apidocs/api_model.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/apidocs/builder.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/apidocs/naming.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/apidocs/paths.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/apidocs/renderer.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/attr_class_map.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/config.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/format.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generator_registry.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/entity_model.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/template_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/instance_artifacts.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/overwrite_policy.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/runner.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/runtime/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/type_map.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/core_types.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/datatype.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/documentation/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/documentation/doc_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/documentation/doc_provider.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/documentation/doc_schema.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/merge.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/meta_data_loader.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/registered_validation.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/sources/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/sources/directory_source.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/sources/file_source.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/sources/uri_source.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/validate_discriminator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/validate_field_readonly.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/validate_source_escapes.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/loader/validation_passes.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/attr/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/field/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/field/field_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/field/meta_field.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/identity/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/index/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/index/index_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/index/meta_index.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/object/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/object/meta_object.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/object/object_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/object/object_extract.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/object/value_object.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/validator/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/meta_data.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/meta_root.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/persistence/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/presentation/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/provider_extends.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/template/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/template/meta_template.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/template/prompt_provider.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/meta/template/template_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/naming_refs.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/parser.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/parser_yaml.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/provider.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/py.typed +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/registry.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/registry_manifest.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/email_document.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/escapers.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/extract/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/extract/coerce.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/extract/extract.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/extract/extract_map.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/extract/locate.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/extract/normalize.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/extract/strip.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/extract/types.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/filesystem_provider.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/prompt/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/prompt/prompt_field.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/prompt/prompt_style.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/renderer.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/render/verify.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/runtime/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/runtime/llm_recorder.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/runtime/n2m_resolver.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/runtime/object_manager.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/runtime/tph.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/serializer_json.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/shared/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/shared/base_types.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/shared/separators.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/shared/structural.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/source/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/source/error_source.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/source/json_path.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/source/semantic_diff.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/source/yaml_positions.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/attr.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/db.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/documentation.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/field.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/identity.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/index.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/layout.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/object.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/origin.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/prompt.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/relationship.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/source.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/template.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/ui.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/validator.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/spec_metamodel/view.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/super_resolve.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/validation_types.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/yaml_desugar.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/golden/extends/expected/Program.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/golden/extends/meta.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/golden/nested-array/meta.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/golden/scalars/expected/Report.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/golden/scalars/meta.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/golden/vanilla/meta.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_abstract_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_api_docs_builder.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_api_docs_paths.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_cli.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_cli_providers.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_cli_registry.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_cli_staleness_nudge.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_cli_verify_strict.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_constants_config.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_entity_model.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_enum_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_extractor_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_filter_allowlist_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_format.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_fr010_output_codegen.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_generator_extension_seams.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_golden.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_inheritance_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_instance_artifacts.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_m2m_codegen.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_origin_nullability.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_output_parser_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_overwrite_policy.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_projection_compile.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_render_helper_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_reverse_finders.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_router_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_runner.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_template_data.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_template_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_template_output_pattern.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_template_scope_helpers.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_template_scope_walk.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_template_spec.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_tph_codegen.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_trace_helper_generator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_type_map.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_validation_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/codegen/test_write_through.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/capabilities.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/conformance-expected-failures.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/conformance_adapter.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/corpus.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/expected_failures.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/fixture_discovery.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/navigator.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_extract_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_extract_object_verdict.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_fr010_loader_attrs.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_fr011_attrs.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_generator_registry_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_object_model_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_provider_composition_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_registry_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_runner_hardfail.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_spec_metamodel_embed.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_strict_attr_load.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_template_codegen_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_template_generator_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/test_yaml_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/api_contract_jsonb_server.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/api_contract_m2m_server.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/generated_jsonb_app.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/generated_m2m_app.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/generated_router_app.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/generated_tph_app.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/meta_ai_trace.yaml +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/normalization.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/postgres_container.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/query_runner.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/scenarios.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/test_api_contract.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/test_api_contract_generated.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/test_api_contract_jsonb.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/test_api_contract_m2m.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/test_api_contract_m2m_generated.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/test_api_contract_tph_generated.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/test_generated_router_uuid_pk.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/test_llm_call_trace.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/test_normalization.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/test_query_scenarios.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/integration/test_runtime_return_types.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/open_closed_proof_test.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/extract/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/extract/test_coerce.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/extract/test_extract.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/extract/test_extract_map.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/extract/test_json_forgiving_reader.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/extract/test_locate.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/extract/test_model.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/extract/test_normalize.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/extract/test_strip.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/prompt/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/prompt/test_output_format_renderer.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/test_email_document.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/test_filesystem_provider.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/test_output_format_renderer_nested.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/test_output_prompt_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/test_render_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/test_render_max_chars.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/test_verify.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/render/test_verify_conformance.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/source/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/source/test_fr5c_merge_attribution.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/source/test_fr5d_reference_resolution.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/source/test_fr5e_database_source_shape.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/source/test_json_path.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/source/test_semantic_diff.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/source/test_source_on_node.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/source/test_yaml_positions.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/test_api_docs_accuracy.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/__init__.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_agent_context_staleness.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_capabilities.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_common_attrs.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_core_types.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_effective_package.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_errors.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_field_enum.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_field_map_validation.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_index_lookup.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_llm_recorder.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_loader.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_loader_bom.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_loader_class.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_merge.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_meta_attr.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_meta_data.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_meta_source.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_module_shortcuts.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_n2m_resolver.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_n2m_resolver_inherited.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_object_manager_write_through.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_one_primary_source.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_parser.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_parser_yaml.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_provider.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_provider_extension.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_registry.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_registry_completeness.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_registry_extend.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_registry_sealed.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_relationship_referential_actions.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_resolution_key.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_serializer.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_shared_constants.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_smoke.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_source_escapes.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_sources.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_strict_child_placement.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_super_resolve.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_template_toolcall.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_validation_attr_schema.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_validation_filter_values.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_validation_origin_195.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_validation_origin_paths.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_validation_sort_field.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_validation_warnings.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_write_coercion_arrays.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/tests/unit/test_yaml_desugar.py +0 -0
- {metaobjects-0.19.2 → metaobjects-0.19.4}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metaobjects
|
|
3
|
-
Version: 0.19.
|
|
3
|
+
Version: 0.19.4
|
|
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.19.
|
|
3
|
+
version = "0.19.4"
|
|
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"
|
|
@@ -573,6 +573,16 @@ _TEMPLATE_TEXT_REF_ATTRS = (
|
|
|
573
573
|
)
|
|
574
574
|
|
|
575
575
|
|
|
576
|
+
def _attr_str_list(raw: object) -> list[str] | None:
|
|
577
|
+
"""Coerce a string-array attr (a list, or a single string) to ``list[str]``; ``None``
|
|
578
|
+
when absent — the shape :func:`render.verify` expects for required_slots/required_tags."""
|
|
579
|
+
if isinstance(raw, str):
|
|
580
|
+
return [raw]
|
|
581
|
+
if isinstance(raw, (list, tuple)):
|
|
582
|
+
return [str(x) for x in raw]
|
|
583
|
+
return None
|
|
584
|
+
|
|
585
|
+
|
|
576
586
|
def _verify_templates(args: argparse.Namespace) -> int:
|
|
577
587
|
"""``verify --templates`` — the template/prompt ``{{field}}`` ↔ payload drift gate.
|
|
578
588
|
|
|
@@ -659,6 +669,16 @@ def _verify_templates(args: argparse.Namespace) -> int:
|
|
|
659
669
|
error_count += 1
|
|
660
670
|
continue
|
|
661
671
|
|
|
672
|
+
# #193/#230: @requiredSlots/@requiredTags are a template.prompt concept — enforced ONLY on
|
|
673
|
+
# the prompt path (the email/document output gate does not apply them per-part; the #193
|
|
674
|
+
# cross-port consensus). A prompt whose body omits a required output tag →
|
|
675
|
+
# ERR_OUTPUT_TAG_MISSING (drift, fails); an unused required slot → ERR_REQUIRED_SLOT_UNUSED
|
|
676
|
+
# (warning). This brings Python to parity with TS/Java/C# (previously it enforced neither).
|
|
677
|
+
is_prompt = tmpl.sub_type == tc.TEMPLATE_SUBTYPE_PROMPT
|
|
678
|
+
# ADR-0039: resolving read — an inherited @requiredSlots/@requiredTags is honored.
|
|
679
|
+
req_slots = _attr_str_list(tmpl.get_meta_attr(tc.TEMPLATE_ATTR_REQUIRED_SLOTS)) if is_prompt else None
|
|
680
|
+
req_tags = _attr_str_list(tmpl.get_meta_attr(tc.TEMPLATE_ATTR_REQUIRED_TAGS)) if is_prompt else None
|
|
681
|
+
|
|
662
682
|
for ref in refs:
|
|
663
683
|
text = provider.resolve(ref)
|
|
664
684
|
if text is None:
|
|
@@ -670,12 +690,14 @@ def _verify_templates(args: argparse.Namespace) -> int:
|
|
|
670
690
|
error_count += 1
|
|
671
691
|
continue
|
|
672
692
|
checked += 1
|
|
673
|
-
for e in render_verify(
|
|
693
|
+
for e in render_verify(
|
|
694
|
+
text, fields, provider=provider,
|
|
695
|
+
required_slots=req_slots, required_tags=req_tags,
|
|
696
|
+
):
|
|
674
697
|
if e.code == ERR_REQUIRED_SLOT_UNUSED:
|
|
675
|
-
continue # warning, not drift
|
|
698
|
+
continue # an unused required slot is a warning, not drift
|
|
676
699
|
print(
|
|
677
|
-
f"error: [{tmpl.name}] ref '{ref}' — {e.code}: "
|
|
678
|
-
f"{{{{{e.path}}}}} not on payload VO '{payload_ref}'.",
|
|
700
|
+
f"error: [{tmpl.name}] ref '{ref}' — {e.code}: {e.path}",
|
|
679
701
|
file=sys.stderr,
|
|
680
702
|
)
|
|
681
703
|
error_count += 1
|
{metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/payload_vo_generator.py
RENAMED
|
@@ -69,6 +69,13 @@ from metaobjects.shared.separators import PACKAGE_SEP
|
|
|
69
69
|
|
|
70
70
|
_GENERATOR_NAME = "payload-vo-generator"
|
|
71
71
|
|
|
72
|
+
# ADR-0044 backstop error code — a codegen-time (not loader) error, peer of the
|
|
73
|
+
# render tier's ERR_VAR_NOT_ON_PAYLOAD. Declared LOCALLY here for the same reason
|
|
74
|
+
# the TS reference (codegen-ts/src/payload-codegen.ts) declares it locally rather
|
|
75
|
+
# than in the shared cross-port ledger: promoting it to the ledger is coordinated
|
|
76
|
+
# with the Java/Kotlin follow-up so no port reddens on a code it doesn't yet emit.
|
|
77
|
+
ERR_PAYLOAD_NAME_COLLISION = "ERR_PAYLOAD_NAME_COLLISION"
|
|
78
|
+
|
|
72
79
|
|
|
73
80
|
# ---------------------------------------------------------------------------
|
|
74
81
|
# Naming helpers (snake_case mirrors the router/output-parser local helpers).
|
|
@@ -193,13 +200,17 @@ def _resolve_object_field_type(
|
|
|
193
200
|
field: MetaField,
|
|
194
201
|
root: MetaData,
|
|
195
202
|
nested_emit_queue: list[tuple[MetaObject, str]],
|
|
196
|
-
|
|
203
|
+
emitted_nested_keys: set[str],
|
|
204
|
+
name_map: dict[str, str],
|
|
197
205
|
) -> tuple[str, set[str]]:
|
|
198
206
|
"""A plain ``field.object`` (``@objectRef``, no origin child) — resolve to the
|
|
199
|
-
nested
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
207
|
+
nested payload class (single) or ``list[...]`` (array). The class name comes
|
|
208
|
+
from the ADR-0044 *name_map* (bare ``<Short>Payload`` when unique in the module
|
|
209
|
+
closure, package-qualified on a cross-package short-name collision). The target
|
|
210
|
+
VO is scheduled for in-file emission, deduped by ``resolution_key()`` (NOT
|
|
211
|
+
``fqn()``, which returns the bare name and would collapse two same-short-name
|
|
212
|
+
VOs from different packages into one). Falls back to the bare type-map form when
|
|
213
|
+
the ``@objectRef`` can't be resolved (defensive — loader validation gates it)."""
|
|
203
214
|
ref = field.attrs().get(fc.FIELD_ATTR_OBJECT_REF)
|
|
204
215
|
if not isinstance(ref, str) or not ref:
|
|
205
216
|
return _fallback_type(field)
|
|
@@ -211,12 +222,14 @@ def _resolve_object_field_type(
|
|
|
211
222
|
# both loaded trees (file_default_package) and programmatic trees (root package).
|
|
212
223
|
referrer_pkg = _pkg_of(field.parent) if field.parent is not None else ""
|
|
213
224
|
target = resolve_object_ref(root, ref, referrer_pkg)
|
|
214
|
-
if target
|
|
225
|
+
if not isinstance(target, MetaObject): # narrows MetaData|None -> MetaObject
|
|
215
226
|
return _fallback_type(field)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
227
|
+
target_key = target.resolution_key()
|
|
228
|
+
# name_map was populated by the ADR-0044 closure walk (pass 1/2), which visits
|
|
229
|
+
# the identical targets; the fallback guards a defensive gap only.
|
|
230
|
+
nested_class = name_map.get(target_key) or payload_class_name(target.name)
|
|
231
|
+
if target_key not in emitted_nested_keys:
|
|
232
|
+
emitted_nested_keys.add(target_key)
|
|
220
233
|
nested_emit_queue.append((target, nested_class))
|
|
221
234
|
if type_map.field_is_array(field):
|
|
222
235
|
return f"list[{nested_class}]", set()
|
|
@@ -345,16 +358,20 @@ def _resolve_collection_type(
|
|
|
345
358
|
root: MetaData,
|
|
346
359
|
fallback: MetaField,
|
|
347
360
|
nested_emit_queue: list[tuple[MetaObject, str]],
|
|
348
|
-
|
|
361
|
+
emitted_nested_keys: set[str],
|
|
362
|
+
name_map: dict[str, str],
|
|
349
363
|
) -> tuple[str, set[str]]:
|
|
350
364
|
"""``origin.collection @via "Parent.rel"`` — walk Parent's relationship to
|
|
351
|
-
its ``@objectRef`` target, schedule a nested
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
365
|
+
its ``@objectRef`` target, schedule a nested payload class for in-file
|
|
366
|
+
emission, return ``list[<NestedClass>]``. The class name comes from the
|
|
367
|
+
ADR-0044 *name_map* (bare when unique in the module closure, package-qualified
|
|
368
|
+
on a cross-package short-name collision).
|
|
369
|
+
|
|
370
|
+
Dedupe is per-file via *emitted_nested_keys*, keyed by ``resolution_key()`` —
|
|
371
|
+
if the same target is referenced by two fields in the same payload module,
|
|
372
|
+
only one nested class is emitted; two same-short-name targets in DIFFERENT
|
|
373
|
+
packages are NOT collapsed (each keeps its own key + qualified name).
|
|
374
|
+
Cross-file dedupe would leave forward-references dangling (module docstring)."""
|
|
358
375
|
via = origin.attr(ORIGIN_ATTR_VIA) # ADR-0039 sanctioned own: origin.* never inherits (ADR-0029)
|
|
359
376
|
if not isinstance(via, str) or not via:
|
|
360
377
|
return _fallback_type(fallback)
|
|
@@ -374,11 +391,10 @@ def _resolve_collection_type(
|
|
|
374
391
|
target = _resolve_object_by_short_or_fqn(root, target_ref)
|
|
375
392
|
if target is None:
|
|
376
393
|
return _fallback_type(fallback)
|
|
377
|
-
|
|
378
|
-
nested_class = payload_class_name(target.name)
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
emitted_nested_fqns.add(target_fqn)
|
|
394
|
+
target_key = target.resolution_key()
|
|
395
|
+
nested_class = name_map.get(target_key) or payload_class_name(target.name)
|
|
396
|
+
if target_key not in emitted_nested_keys:
|
|
397
|
+
emitted_nested_keys.add(target_key)
|
|
382
398
|
nested_emit_queue.append((target, nested_class))
|
|
383
399
|
return f"list[{nested_class}]", set()
|
|
384
400
|
|
|
@@ -393,8 +409,9 @@ def _resolve_field_type(
|
|
|
393
409
|
field: MetaField,
|
|
394
410
|
root: MetaData,
|
|
395
411
|
nested_emit_queue: list[tuple[MetaObject, str]],
|
|
396
|
-
|
|
412
|
+
emitted_nested_keys: set[str],
|
|
397
413
|
enum_aliases: dict[str, str],
|
|
414
|
+
name_map: dict[str, str],
|
|
398
415
|
) -> tuple[str, set[str]]:
|
|
399
416
|
"""Resolve the Python annotation for one payload-VO field, honoring any
|
|
400
417
|
``origin.*`` child. Falls back to ``type_map.py_type_for`` when none.
|
|
@@ -415,7 +432,7 @@ def _resolve_field_type(
|
|
|
415
432
|
# reference an undefined bare entity name (Pydantic "not fully defined").
|
|
416
433
|
if field.sub_type == fc.FIELD_SUBTYPE_OBJECT:
|
|
417
434
|
return _resolve_object_field_type(
|
|
418
|
-
field, root, nested_emit_queue,
|
|
435
|
+
field, root, nested_emit_queue, emitted_nested_keys, name_map
|
|
419
436
|
)
|
|
420
437
|
# A ``field.enum`` → Literal[...] (inline) or a named module alias (shared).
|
|
421
438
|
enum_type = _enum_field_type(field, enum_aliases)
|
|
@@ -429,11 +446,142 @@ def _resolve_field_type(
|
|
|
429
446
|
return _resolve_aggregate_type(origin, root, field)
|
|
430
447
|
if origin.sub_type == "collection":
|
|
431
448
|
return _resolve_collection_type(
|
|
432
|
-
origin, root, field, nested_emit_queue,
|
|
449
|
+
origin, root, field, nested_emit_queue, emitted_nested_keys, name_map
|
|
433
450
|
)
|
|
434
451
|
return _fallback_type(field)
|
|
435
452
|
|
|
436
453
|
|
|
454
|
+
# ---------------------------------------------------------------------------
|
|
455
|
+
# ADR-0044 — collision-scoped nested-payload naming (three-pass pipeline).
|
|
456
|
+
#
|
|
457
|
+
# A payload module is a SINGLE self-contained file, so its `@objectRef` /
|
|
458
|
+
# `origin.collection` closure is the collision domain (ADR-0044's "closure of the
|
|
459
|
+
# payload root(s) emitted into one artifact"). Two value-objects sharing a bare
|
|
460
|
+
# short name across packages (`acme::alpha::Note` + `acme::beta::Note`, both
|
|
461
|
+
# reachable from one payload) must emit as DISTINCT classes — the pre-ADR-0044
|
|
462
|
+
# code deduped by `fqn()` (which returns the BARE name here), collapsing them to
|
|
463
|
+
# one class, last-wins, silently dropping the second shape. Pass 1 collects the
|
|
464
|
+
# closure keyed by `resolution_key()` (the true package-qualified FQN); pass 2
|
|
465
|
+
# assigns names as a pure function of the closure (bare when unique, package-
|
|
466
|
+
# qualified on collision, hard fail on a still-colliding derived name); pass 3
|
|
467
|
+
# (the existing emit path) uses the name map for both declaration and reference.
|
|
468
|
+
# ---------------------------------------------------------------------------
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def _package_qualified_name(pkg: str, short_name: str) -> str:
|
|
472
|
+
"""ADR-0044 — PascalCase each ``::``-segment of *pkg*, concatenate, append the
|
|
473
|
+
bare *short_name* (``acme::alpha`` + ``Note`` → ``AcmeAlphaNote``). A root-level
|
|
474
|
+
(empty-package) node keeps its bare short name — the loader's own-package
|
|
475
|
+
uniqueness already precludes two root-level VOs sharing a name, so this can't
|
|
476
|
+
silently under-qualify."""
|
|
477
|
+
if pkg == "":
|
|
478
|
+
return short_name
|
|
479
|
+
return "".join(_pascal(seg) for seg in pkg.split(PACKAGE_SEP)) + short_name
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def _nested_target_of(field: MetaField, root: MetaData) -> MetaObject | None:
|
|
483
|
+
"""The nested-payload target VO a *field* contributes to the module closure,
|
|
484
|
+
or ``None`` when it contributes no nested class. Mirrors the resolution in
|
|
485
|
+
:func:`_resolve_object_field_type` (a plain ``field.object`` ``@objectRef``)
|
|
486
|
+
and :func:`_resolve_collection_type` (``origin.collection`` ``@via``) EXACTLY,
|
|
487
|
+
so the ADR-0044 closure walk and the emission walk agree on the target set.
|
|
488
|
+
``origin.passthrough`` / ``origin.aggregate`` yield scalar types (no nested
|
|
489
|
+
class) and so contribute nothing."""
|
|
490
|
+
origin = _find_origin_child(field)
|
|
491
|
+
if origin is None:
|
|
492
|
+
if field.sub_type != fc.FIELD_SUBTYPE_OBJECT:
|
|
493
|
+
return None
|
|
494
|
+
ref = field.attrs().get(fc.FIELD_ATTR_OBJECT_REF)
|
|
495
|
+
if not isinstance(ref, str) or not ref:
|
|
496
|
+
return None
|
|
497
|
+
referrer_pkg = _pkg_of(field.parent) if field.parent is not None else ""
|
|
498
|
+
target = resolve_object_ref(root, ref, referrer_pkg)
|
|
499
|
+
return target if isinstance(target, MetaObject) else None
|
|
500
|
+
if origin.sub_type == "collection":
|
|
501
|
+
via = origin.attr(ORIGIN_ATTR_VIA) # ADR-0039 sanctioned own: origin.* never inherits
|
|
502
|
+
if not isinstance(via, str) or not via:
|
|
503
|
+
return None
|
|
504
|
+
parts = _split_dotted_ref(via)
|
|
505
|
+
if parts is None:
|
|
506
|
+
return None
|
|
507
|
+
parent_name, rel_name = parts
|
|
508
|
+
parent = _resolve_object_by_short_or_fqn(root, parent_name)
|
|
509
|
+
if parent is None:
|
|
510
|
+
return None
|
|
511
|
+
rel = _find_relationship_on(parent, rel_name)
|
|
512
|
+
if rel is None:
|
|
513
|
+
return None
|
|
514
|
+
target_ref = rel.object_ref()
|
|
515
|
+
if not target_ref:
|
|
516
|
+
return None
|
|
517
|
+
return _resolve_object_by_short_or_fqn(root, target_ref)
|
|
518
|
+
return None
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
def _collect_nested_closure(
|
|
522
|
+
root: MetaData,
|
|
523
|
+
payload_vo: MetaObject,
|
|
524
|
+
closure: dict[str, MetaObject],
|
|
525
|
+
seen: set[str],
|
|
526
|
+
) -> None:
|
|
527
|
+
"""ADR-0044 pass 1 — walk *payload_vo*'s transitive nested-payload closure,
|
|
528
|
+
collecting each target VO keyed by ``resolution_key()`` (never ``fqn()`` —
|
|
529
|
+
which returns the bare name and would collapse a cross-package short-name
|
|
530
|
+
collision). *seen* is seeded with the primary payload VO's key so the primary
|
|
531
|
+
(which is named after the TEMPLATE, outside the VO-short-name collision
|
|
532
|
+
domain) is never treated as a nested class, and doubles as the cycle guard."""
|
|
533
|
+
for field in payload_vo.fields():
|
|
534
|
+
if not isinstance(field, MetaField):
|
|
535
|
+
continue
|
|
536
|
+
target = _nested_target_of(field, root)
|
|
537
|
+
if target is None:
|
|
538
|
+
continue
|
|
539
|
+
key = target.resolution_key()
|
|
540
|
+
if key in seen:
|
|
541
|
+
continue
|
|
542
|
+
seen.add(key)
|
|
543
|
+
closure[key] = target
|
|
544
|
+
_collect_nested_closure(root, target, closure, seen)
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def _assign_nested_names(closure: dict[str, MetaObject]) -> dict[str, str]:
|
|
548
|
+
"""ADR-0044 pass 2 — ``resolution_key()`` → emitted class name. A PURE function
|
|
549
|
+
of the closure's ``(key, short-name, package)`` triples, never of traversal
|
|
550
|
+
order: a bare short name unique in the closure emits ``<Short>Payload``
|
|
551
|
+
(byte-identical to pre-ADR-0044 output); a short-name collision emits EVERY
|
|
552
|
+
member under its package-qualified derived name
|
|
553
|
+
(``<PkgSegmentsPascal><Short>Payload``). If two distinct keys still derive the
|
|
554
|
+
same name, fail loud with ``ERR_PAYLOAD_NAME_COLLISION`` — never silently
|
|
555
|
+
collide a second time."""
|
|
556
|
+
by_short: dict[str, list[str]] = {}
|
|
557
|
+
for key, node in closure.items():
|
|
558
|
+
by_short.setdefault(node.name, []).append(key)
|
|
559
|
+
|
|
560
|
+
name_map: dict[str, str] = {}
|
|
561
|
+
for short, keys in by_short.items():
|
|
562
|
+
if len(keys) == 1:
|
|
563
|
+
name_map[keys[0]] = payload_class_name(short)
|
|
564
|
+
continue
|
|
565
|
+
for key in keys:
|
|
566
|
+
node = closure[key]
|
|
567
|
+
name_map[key] = payload_class_name(_package_qualified_name(_pkg_of(node), short))
|
|
568
|
+
|
|
569
|
+
# Backstop — sorted by key so both the emptiness of the colliding set and the
|
|
570
|
+
# pair named in the message are a pure function of the closure, not dict order.
|
|
571
|
+
owner: dict[str, str] = {}
|
|
572
|
+
for key in sorted(name_map):
|
|
573
|
+
emitted = name_map[key]
|
|
574
|
+
existing = owner.get(emitted)
|
|
575
|
+
if existing is not None and existing != key:
|
|
576
|
+
raise ValueError(
|
|
577
|
+
f"{ERR_PAYLOAD_NAME_COLLISION}: payload record name collision: "
|
|
578
|
+
f'"{emitted}" derives from both "{existing}" and "{key}" — rename one '
|
|
579
|
+
"value-object or move it to a package that derives a distinct name"
|
|
580
|
+
)
|
|
581
|
+
owner[emitted] = key
|
|
582
|
+
return name_map
|
|
583
|
+
|
|
584
|
+
|
|
437
585
|
# ---------------------------------------------------------------------------
|
|
438
586
|
# Class-block emission.
|
|
439
587
|
# ---------------------------------------------------------------------------
|
|
@@ -444,10 +592,11 @@ def _emit_payload_class(
|
|
|
444
592
|
payload_vo: MetaObject,
|
|
445
593
|
root: MetaData,
|
|
446
594
|
nested_emit_queue: list[tuple[MetaObject, str]],
|
|
447
|
-
|
|
595
|
+
emitted_nested_keys: set[str],
|
|
448
596
|
extra_imports: set[str],
|
|
449
597
|
enum_aliases: dict[str, str],
|
|
450
598
|
docstring: str,
|
|
599
|
+
name_map: dict[str, str],
|
|
451
600
|
) -> list[str]:
|
|
452
601
|
"""Build the source lines for one Pydantic ``BaseModel`` subclass."""
|
|
453
602
|
lines: list[str] = [f"class {class_name}(BaseModel):", f' """{docstring}"""']
|
|
@@ -456,7 +605,7 @@ def _emit_payload_class(
|
|
|
456
605
|
if not isinstance(field, MetaField):
|
|
457
606
|
continue
|
|
458
607
|
annotation, imports = _resolve_field_type(
|
|
459
|
-
field, root, nested_emit_queue,
|
|
608
|
+
field, root, nested_emit_queue, emitted_nested_keys, enum_aliases, name_map
|
|
460
609
|
)
|
|
461
610
|
extra_imports.update(imports)
|
|
462
611
|
# Optionality mirrors the cross-port (TS) payload-codegen: a ``@required``
|
|
@@ -515,9 +664,18 @@ def render_payload_vo(
|
|
|
515
664
|
if payload is None:
|
|
516
665
|
return None
|
|
517
666
|
|
|
667
|
+
# ADR-0044 pass 1/2 — the collision domain is this module's nested-payload
|
|
668
|
+
# closure. Seed `seen` with the primary VO's key so the primary (named after
|
|
669
|
+
# the TEMPLATE, not the VO) stays out of the VO-short-name collision domain.
|
|
670
|
+
closure: dict[str, MetaObject] = {}
|
|
671
|
+
_collect_nested_closure(root, payload, closure, {payload.resolution_key()})
|
|
672
|
+
name_map = _assign_nested_names(closure)
|
|
673
|
+
|
|
518
674
|
# Per-file dedupe set: scoped to this single render call so each emitted
|
|
519
|
-
# module is self-contained (no cross-template forward references).
|
|
520
|
-
|
|
675
|
+
# module is self-contained (no cross-template forward references). Keyed by
|
|
676
|
+
# ``resolution_key()`` (see _resolve_object_field_type) so two same-short-name
|
|
677
|
+
# VOs from different packages both emit.
|
|
678
|
+
emitted_nested_keys: set[str] = set()
|
|
521
679
|
class_name = payload_class_name(template.name)
|
|
522
680
|
extra_imports: set[str] = set()
|
|
523
681
|
nested_emit_queue: list[tuple[MetaObject, str]] = []
|
|
@@ -541,13 +699,14 @@ def render_payload_vo(
|
|
|
541
699
|
payload_vo=payload,
|
|
542
700
|
root=root,
|
|
543
701
|
nested_emit_queue=nested_emit_queue,
|
|
544
|
-
|
|
702
|
+
emitted_nested_keys=emitted_nested_keys,
|
|
545
703
|
extra_imports=extra_imports,
|
|
546
704
|
enum_aliases=enum_aliases,
|
|
547
705
|
docstring=(
|
|
548
706
|
f"GENERATED payload for template ``{template.name}``.\n\n"
|
|
549
707
|
f" Field shape derived from the ``{payload.name}`` object.value."
|
|
550
708
|
),
|
|
709
|
+
name_map=name_map,
|
|
551
710
|
)
|
|
552
711
|
if strict_extras:
|
|
553
712
|
primary_block = _with_strict_extras(primary_block)
|
|
@@ -564,12 +723,13 @@ def render_payload_vo(
|
|
|
564
723
|
payload_vo=target,
|
|
565
724
|
root=root,
|
|
566
725
|
nested_emit_queue=nested_emit_queue,
|
|
567
|
-
|
|
726
|
+
emitted_nested_keys=emitted_nested_keys,
|
|
568
727
|
extra_imports=extra_imports,
|
|
569
728
|
enum_aliases=enum_aliases,
|
|
570
729
|
docstring=(
|
|
571
730
|
f"GENERATED nested payload for collection target ``{target.name}``."
|
|
572
731
|
),
|
|
732
|
+
name_map=name_map,
|
|
573
733
|
)
|
|
574
734
|
if strict_extras:
|
|
575
735
|
block = _with_strict_extras(block)
|
|
@@ -650,10 +810,11 @@ class PayloadVoGenerator:
|
|
|
650
810
|
payload_vo: MetaObject,
|
|
651
811
|
root: MetaData,
|
|
652
812
|
nested_emit_queue: list[tuple[MetaObject, str]],
|
|
653
|
-
|
|
813
|
+
emitted_nested_keys: set[str],
|
|
654
814
|
extra_imports: set[str],
|
|
655
815
|
enum_aliases: dict[str, str],
|
|
656
816
|
docstring: str,
|
|
817
|
+
name_map: dict[str, str],
|
|
657
818
|
) -> list[str]:
|
|
658
819
|
"""EXTENSION SEAM — the source lines for one Pydantic ``BaseModel`` subclass
|
|
659
820
|
(primary OR a nested collection target). Defaults to the module-level
|
|
@@ -664,10 +825,11 @@ class PayloadVoGenerator:
|
|
|
664
825
|
payload_vo,
|
|
665
826
|
root,
|
|
666
827
|
nested_emit_queue,
|
|
667
|
-
|
|
828
|
+
emitted_nested_keys,
|
|
668
829
|
extra_imports,
|
|
669
830
|
enum_aliases,
|
|
670
831
|
docstring,
|
|
832
|
+
name_map,
|
|
671
833
|
)
|
|
672
834
|
|
|
673
835
|
def _render_module(self, template: MetaTemplate, root: MetaData) -> str | None:
|
{metaobjects-0.19.2 → metaobjects-0.19.4}/src/metaobjects/codegen/generators/router_generator.py
RENAMED
|
@@ -52,6 +52,7 @@ from metaobjects.codegen.instance_artifacts import emits_instance_artifacts
|
|
|
52
52
|
from metaobjects.codegen.type_map import PyType, py_type_for
|
|
53
53
|
from metaobjects.meta.core.field import field_constants as fc
|
|
54
54
|
from metaobjects.meta.core.field.meta_field import MetaField
|
|
55
|
+
from metaobjects.meta.persistence.db import db_constants as dbc
|
|
55
56
|
from metaobjects.meta.core.identity.identity_constants import (
|
|
56
57
|
IDENTITY_ATTR_FIELDS,
|
|
57
58
|
IDENTITY_REFERENCE_ATTR_REFERENCES,
|
|
@@ -95,7 +96,73 @@ def _required_field_names(entity: MetaObject) -> list[str]:
|
|
|
95
96
|
_scalar_fields, which drops object fields for the sort allowlist). FR-035
|
|
96
97
|
PATCH-2 guards present-null on any of these, and a @required jsonb column can
|
|
97
98
|
be nulled just like a scalar one."""
|
|
98
|
-
|
|
99
|
+
# #203/ADR-0045: an @autoSet field is server-owned — never a caller-facing PATCH field, so
|
|
100
|
+
# it is not present-null-checked (a caller-sent null is ignored/stamped, not a 400). Mirrors
|
|
101
|
+
# the Kotlin controller (which excludes @autoSet from its patch-settable set).
|
|
102
|
+
return [f.name for f in entity.fields() if is_required(f) and not _is_auto_set(f)]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# --- #203 / ADR-0045: @autoSet stamping in the generated router (above the repo seam) ----------
|
|
106
|
+
|
|
107
|
+
_AUTO_SET_TEMPORAL_SUBTYPES = (
|
|
108
|
+
fc.FIELD_SUBTYPE_DATE,
|
|
109
|
+
fc.FIELD_SUBTYPE_TIME,
|
|
110
|
+
fc.FIELD_SUBTYPE_TIMESTAMP,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _is_auto_set(field: MetaField) -> bool:
|
|
115
|
+
"""True iff *field* is a server-owned ``@autoSet`` column (ADR-0039 resolving read)."""
|
|
116
|
+
return field.get_meta_attr(fc.FIELD_ATTR_AUTO_SET) in (
|
|
117
|
+
fc.AUTO_SET_ON_CREATE,
|
|
118
|
+
fc.AUTO_SET_ON_UPDATE,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _auto_set_split(entity: MetaObject) -> tuple[list[MetaField], list[MetaField]]:
|
|
123
|
+
"""The entity's ``@autoSet`` temporal fields split into ``(onCreate, onUpdate)``.
|
|
124
|
+
|
|
125
|
+
Reads the RESOLVING ``@autoSet`` (ADR-0039) so an inherited
|
|
126
|
+
``BaseEntity.createdAt/updatedAt`` is honored; a non-temporal field is skipped.
|
|
127
|
+
Both lists are empty for an entity that declares none, keeping its router
|
|
128
|
+
byte-identical to the pre-#203 output."""
|
|
129
|
+
on_create: list[MetaField] = []
|
|
130
|
+
on_update: list[MetaField] = []
|
|
131
|
+
for f in entity.fields():
|
|
132
|
+
if f.sub_type not in _AUTO_SET_TEMPORAL_SUBTYPES:
|
|
133
|
+
continue
|
|
134
|
+
mode = f.get_meta_attr(fc.FIELD_ATTR_AUTO_SET) # ADR-0039 resolving: may be inherited via extends
|
|
135
|
+
if mode == fc.AUTO_SET_ON_CREATE:
|
|
136
|
+
on_create.append(f)
|
|
137
|
+
elif mode == fc.AUTO_SET_ON_UPDATE:
|
|
138
|
+
on_update.append(f)
|
|
139
|
+
return on_create, on_update
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _auto_set_stamp_expr(field: MetaField, base_var: str) -> str:
|
|
143
|
+
"""The inline now()-expression for an ``@autoSet`` *field*, derived from one shared
|
|
144
|
+
tz-aware *base_var* datetime so every column stamped in one op is equal (a fresh
|
|
145
|
+
row's created == updated). Keyed off the COLUMN's temporal type: ``field.date`` →
|
|
146
|
+
``.date()``; ``field.time`` → ``.time()``; ``field.timestamp`` → the tz-aware base
|
|
147
|
+
(``@localTime`` → a naive wall-clock value). Mirrors ObjectManager._auto_set_stamp."""
|
|
148
|
+
sub = field.sub_type
|
|
149
|
+
if sub == fc.FIELD_SUBTYPE_DATE:
|
|
150
|
+
return f"{base_var}.date()"
|
|
151
|
+
if sub == fc.FIELD_SUBTYPE_TIME:
|
|
152
|
+
return f"{base_var}.time()"
|
|
153
|
+
is_tz = field.get_meta_attr(dbc.FIELD_ATTR_LOCAL_TIME) is not True # ADR-0039 resolving
|
|
154
|
+
return base_var if is_tz else f"{base_var}.replace(tzinfo=None)"
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _auto_set_stamp_lines(fields: list[MetaField], comment: str) -> list[str]:
|
|
158
|
+
"""Router-handler body lines stamping *fields* into ``dto`` from ONE captured base
|
|
159
|
+
instant (so all same-op columns are equal), led by *comment*. Empty for no fields
|
|
160
|
+
(so the call site spreads to nothing — a non-@autoSet router stays byte-identical)."""
|
|
161
|
+
if not fields:
|
|
162
|
+
return []
|
|
163
|
+
lines = [f" # {comment}", " _asnow = _dt.datetime.now(_dt.timezone.utc)"]
|
|
164
|
+
lines += [f' dto["{f.name}"] = {_auto_set_stamp_expr(f, "_asnow")}' for f in fields]
|
|
165
|
+
return lines
|
|
99
166
|
|
|
100
167
|
|
|
101
168
|
def _py_set_literal(names: list[str], *, frozen: bool = False) -> str:
|
|
@@ -259,6 +326,8 @@ class RouterGenerator:
|
|
|
259
326
|
ops_const: str,
|
|
260
327
|
model_name: str,
|
|
261
328
|
patch_model: str,
|
|
329
|
+
create_autoset: list[str] = (),
|
|
330
|
+
update_autoset: list[str] = (),
|
|
262
331
|
) -> list[str]:
|
|
263
332
|
"""One CRUD route handler block, dispatched by *name*
|
|
264
333
|
(``list`` / ``get`` / ``create`` / ``update`` / ``delete``). Override to
|
|
@@ -318,6 +387,10 @@ class RouterGenerator:
|
|
|
318
387
|
f" {model_name}(**dto)",
|
|
319
388
|
" except ValidationError:",
|
|
320
389
|
' return JSONResponse(status_code=400, content={"error": "validation"})',
|
|
390
|
+
# #203/ADR-0045: the generated router (the API surface) stamps @autoSet columns
|
|
391
|
+
# ABOVE the consumer repo seam — onCreate + onUpdate both stamped from one instant
|
|
392
|
+
# (a fresh row's createdAt == updatedAt), ignoring any caller-supplied value.
|
|
393
|
+
*create_autoset,
|
|
321
394
|
" return repo.create(dto)",
|
|
322
395
|
]
|
|
323
396
|
if name == "update":
|
|
@@ -341,6 +414,10 @@ class RouterGenerator:
|
|
|
341
414
|
f" {patch_model}(**dto)",
|
|
342
415
|
" except ValidationError:",
|
|
343
416
|
' return JSONResponse(status_code=400, content={"error": "validation"})',
|
|
417
|
+
# #203/ADR-0045: bump onUpdate @autoSet columns (server-owned) on EVERY patch,
|
|
418
|
+
# above the repo seam — a server-inserted present key (compatible with the PATCH
|
|
419
|
+
# present-key tristate); onCreate columns are never touched here.
|
|
420
|
+
*update_autoset,
|
|
344
421
|
f" saved = repo.update({pk_param}, dto)",
|
|
345
422
|
" if saved is None:",
|
|
346
423
|
' return JSONResponse(status_code=404, content={"error": "not_found"})',
|
|
@@ -417,6 +494,24 @@ class RouterGenerator:
|
|
|
417
494
|
ops_const = f"{upper}_FILTER_OPS_BY_FIELD"
|
|
418
495
|
allowlist_module = f"{snake}_filter_allowlist"
|
|
419
496
|
|
|
497
|
+
# #203/ADR-0045: @autoSet columns live on the BASE entity and are shared by every
|
|
498
|
+
# subtype (RESOLVING _auto_set_split(entity) picks up an inherited BaseEntity
|
|
499
|
+
# column too) — computed once here and threaded into each per-subtype handler
|
|
500
|
+
# below (empty for a non-@autoSet hierarchy → byte-identical output).
|
|
501
|
+
on_create_auto, on_update_auto = _auto_set_split(entity)
|
|
502
|
+
has_autoset = bool(on_create_auto or on_update_auto)
|
|
503
|
+
create_autoset = _auto_set_stamp_lines(
|
|
504
|
+
on_create_auto + on_update_auto,
|
|
505
|
+
"#203/ADR-0045: stamp @autoSet columns (server-owned; caller ignored).",
|
|
506
|
+
)
|
|
507
|
+
update_autoset = [
|
|
508
|
+
f' dto.pop("{f.name}", None) # onCreate @autoSet is write-once (server-owned)'
|
|
509
|
+
for f in on_create_auto
|
|
510
|
+
] + _auto_set_stamp_lines(
|
|
511
|
+
on_update_auto,
|
|
512
|
+
"#203/ADR-0045: bump onUpdate @autoSet column(s) (server-owned).",
|
|
513
|
+
)
|
|
514
|
+
|
|
420
515
|
# Sort allowlist = base scalar fields ∪ every subtype's own scalar fields, so a
|
|
421
516
|
# per-subtype list can sort on a subtype-only column too. Stable order.
|
|
422
517
|
sort_fields: list[str] = [f.name for f in _scalar_fields(entity)]
|
|
@@ -448,6 +543,10 @@ class RouterGenerator:
|
|
|
448
543
|
)
|
|
449
544
|
parts.append("from __future__ import annotations")
|
|
450
545
|
parts.append("")
|
|
546
|
+
if has_autoset:
|
|
547
|
+
# #203/ADR-0045: the router stamps @autoSet columns inline (no runtime dependency).
|
|
548
|
+
parts.append("import datetime as _dt")
|
|
549
|
+
parts.append("")
|
|
451
550
|
for import_line in sorted(pk.imports):
|
|
452
551
|
parts.append(import_line)
|
|
453
552
|
if pk.imports:
|
|
@@ -555,6 +654,9 @@ class RouterGenerator:
|
|
|
555
654
|
parts.append(f" {sub}Create(**dto)")
|
|
556
655
|
parts.append(" except ValidationError:")
|
|
557
656
|
parts.append(' return JSONResponse(status_code=400, content={"error": "validation"})')
|
|
657
|
+
# #203/ADR-0045: stamp @autoSet columns ABOVE the repo seam (empty for a
|
|
658
|
+
# non-@autoSet hierarchy — byte-identical output).
|
|
659
|
+
parts.extend(create_autoset)
|
|
558
660
|
parts.append(f' return repo.create("{val}", dto)')
|
|
559
661
|
parts.append("")
|
|
560
662
|
parts.append("")
|
|
@@ -585,6 +687,9 @@ class RouterGenerator:
|
|
|
585
687
|
parts.append(f" {sub}Patch(**dto)")
|
|
586
688
|
parts.append(" except ValidationError:")
|
|
587
689
|
parts.append(' return JSONResponse(status_code=400, content={"error": "validation"})')
|
|
690
|
+
# #203/ADR-0045: pop the write-once onCreate column(s), bump onUpdate — ABOVE
|
|
691
|
+
# the repo seam (empty for a non-@autoSet hierarchy — byte-identical output).
|
|
692
|
+
parts.extend(update_autoset)
|
|
588
693
|
parts.append(f' saved = repo.update("{val}", {pk_param}, dto)')
|
|
589
694
|
parts.append(" if saved is None:")
|
|
590
695
|
parts.append(' return JSONResponse(status_code=404, content={"error": "not_found"})')
|
|
@@ -684,6 +789,27 @@ class RouterGenerator:
|
|
|
684
789
|
# is a 400 — the update handler guards these before the repo call.
|
|
685
790
|
required_set_body = _py_set_literal(_required_field_names(entity), frozen=True)
|
|
686
791
|
|
|
792
|
+
# #203/ADR-0045: @autoSet stamp lines for the create/update handlers (empty for a
|
|
793
|
+
# non-@autoSet entity → byte-identical output). insert stamps onCreate+onUpdate from one
|
|
794
|
+
# instant; a patch bumps onUpdate only (createdAt stays immutable).
|
|
795
|
+
_on_create_auto, _on_update_auto = _auto_set_split(entity)
|
|
796
|
+
create_autoset = _auto_set_stamp_lines(
|
|
797
|
+
_on_create_auto + _on_update_auto,
|
|
798
|
+
"#203/ADR-0045: stamp @autoSet columns (server-owned; caller ignored).",
|
|
799
|
+
)
|
|
800
|
+
# #203/ADR-0045 (integrity): onCreate @autoSet columns are write-once — strip any
|
|
801
|
+
# caller-supplied value on PATCH before the repo call (a caller cannot mutate createdAt via
|
|
802
|
+
# the deployed API). Mirrors ObjectManager.update (`data.pop(...)`) + the Kotlin controller
|
|
803
|
+
# (which excludes @autoSet from its patch-settable set).
|
|
804
|
+
update_autoset = [
|
|
805
|
+
f' dto.pop("{f.name}", None) # onCreate @autoSet is write-once (server-owned)'
|
|
806
|
+
for f in _on_create_auto
|
|
807
|
+
] + _auto_set_stamp_lines(
|
|
808
|
+
_on_update_auto,
|
|
809
|
+
"#203/ADR-0045: bump onUpdate @autoSet column(s) (server-owned).",
|
|
810
|
+
)
|
|
811
|
+
has_autoset = bool(_on_create_auto or _on_update_auto)
|
|
812
|
+
|
|
687
813
|
parts: list[str] = []
|
|
688
814
|
parts.append(
|
|
689
815
|
generated_header(short_name, _effective_fqn(entity)).rstrip() + "\n"
|
|
@@ -691,6 +817,10 @@ class RouterGenerator:
|
|
|
691
817
|
)
|
|
692
818
|
parts.append("from __future__ import annotations")
|
|
693
819
|
parts.append("")
|
|
820
|
+
if has_autoset:
|
|
821
|
+
# #203/ADR-0045: the router stamps @autoSet columns inline (no runtime dependency).
|
|
822
|
+
parts.append("import datetime as _dt")
|
|
823
|
+
parts.append("")
|
|
694
824
|
for import_line in sorted(pk.imports):
|
|
695
825
|
parts.append(import_line)
|
|
696
826
|
if pk.imports:
|
|
@@ -762,6 +892,8 @@ class RouterGenerator:
|
|
|
762
892
|
ops_const=ops_const,
|
|
763
893
|
model_name=f"{short_name}Create",
|
|
764
894
|
patch_model=f"{short_name}Patch",
|
|
895
|
+
create_autoset=create_autoset,
|
|
896
|
+
update_autoset=update_autoset,
|
|
765
897
|
)
|
|
766
898
|
for i, hname in enumerate(("list", "get", "create", "update", "delete")):
|
|
767
899
|
if i > 0:
|
|
@@ -133,6 +133,9 @@ class ErrorCode(str, Enum):
|
|
|
133
133
|
ERR_PARTIAL_UNRESOLVED = "ERR_PARTIAL_UNRESOLVED"
|
|
134
134
|
ERR_REQUIRED_SLOT_UNUSED = "ERR_REQUIRED_SLOT_UNUSED"
|
|
135
135
|
ERR_VAR_NOT_ON_PAYLOAD = "ERR_VAR_NOT_ON_PAYLOAD"
|
|
136
|
+
# Codegen (ADR-0044): two value-object FQNs in one payload artifact derive the same
|
|
137
|
+
# emitted record name even after package-qualification. Peer of ERR_VAR_NOT_ON_PAYLOAD.
|
|
138
|
+
ERR_PAYLOAD_NAME_COLLISION = "ERR_PAYLOAD_NAME_COLLISION"
|
|
136
139
|
ERR_OUTPUT_TAG_MISSING = "ERR_OUTPUT_TAG_MISSING"
|
|
137
140
|
# SP-H Unit9 — @filterable: true on a field subtype with no filter-operator
|
|
138
141
|
# band (e.g. field.object). Would silently generate an empty-ops filter.
|