metaobjects 0.15.11__tar.gz → 0.15.13__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.15.11 → metaobjects-0.15.13}/PKG-INFO +1 -1
- {metaobjects-0.15.11 → metaobjects-0.15.13}/pyproject.toml +1 -1
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/m2m_codegen.py +3 -3
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/payload_vo_generator.py +19 -3
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/render_helper_generator.py +43 -29
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/router_generator.py +64 -26
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/core_types.py +16 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/errors.py +7 -11
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/registered_validation.py +36 -12
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/validate_source_parameter_ref.py +7 -20
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/validation_passes.py +67 -128
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/persistence/origin/origin_constants.py +3 -2
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/naming_refs.py +79 -52
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/origin.json +1 -1
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_generator_extension_seams.py +2 -2
- metaobjects-0.15.13/tests/codegen/test_router_generator.py +357 -0
- metaobjects-0.15.13/tests/integration/test_generated_router_uuid_pk.py +221 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/uv.lock +1 -1
- metaobjects-0.15.11/tests/codegen/test_router_generator.py +0 -160
- {metaobjects-0.15.11 → metaobjects-0.15.13}/.gitignore +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/LICENSE +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/README.md +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/hatch_build.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/agent_context/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/agent_context/scaffold.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/apidocs/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/apidocs/api_model.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/apidocs/builder.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/apidocs/naming.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/apidocs/paths.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/apidocs/renderer.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/attr_class_map.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/cli.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/config.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/format.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generator_registry.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/entity_model.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/template_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/instance_artifacts.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/overwrite_policy.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/runner.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/runtime/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/type_map.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/datatype.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/documentation/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/documentation/doc_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/documentation/doc_provider.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/documentation/doc_schema.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/merge.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/meta_data_loader.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/sources/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/sources/directory_source.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/sources/file_source.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/sources/uri_source.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/validate_discriminator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/validate_field_readonly.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/attr/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/field/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/field/field_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/field/meta_field.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/identity/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/index/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/index/index_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/index/meta_index.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/object/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/object/meta_object.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/object/object_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/object/object_extract.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/object/value_object.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/validator/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/meta_data.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/meta_root.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/persistence/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/presentation/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/provider_extends.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/template/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/template/meta_template.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/template/prompt_provider.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/meta/template/template_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/parser.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/parser_yaml.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/provider.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/py.typed +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/registry.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/registry_manifest.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/email_document.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/escapers.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/extract/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/extract/coerce.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/extract/extract.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/extract/extract_map.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/extract/locate.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/extract/normalize.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/extract/strip.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/extract/types.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/filesystem_provider.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/prompt/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/prompt/prompt_field.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/prompt/prompt_style.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/renderer.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/render/verify.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/runtime/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/runtime/llm_recorder.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/runtime/n2m_resolver.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/runtime/object_manager.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/runtime/tph.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/serializer_json.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/shared/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/shared/base_types.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/shared/separators.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/shared/structural.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/source/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/source/error_source.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/source/json_path.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/source/semantic_diff.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/source/yaml_positions.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/attr.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/db.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/documentation.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/field.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/identity.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/index.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/layout.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/object.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/prompt.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/relationship.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/source.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/template.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/ui.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/validator.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/spec_metamodel/view.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/super_resolve.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/validation_types.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/yaml_desugar.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/golden/extends/expected/Program.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/golden/extends/meta.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/golden/nested-array/meta.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/golden/scalars/expected/Report.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/golden/scalars/meta.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/golden/vanilla/meta.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_abstract_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_api_docs_builder.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_api_docs_paths.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_cli.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_cli_providers.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_cli_registry.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_cli_staleness_nudge.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_cli_verify_strict.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_cli_verify_subverbs.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_constants_config.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_entity_model.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_enum_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_extractor_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_filter_allowlist_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_format.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_fr010_output_codegen.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_golden.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_inheritance_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_instance_artifacts.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_m2m_codegen.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_output_parser_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_overwrite_policy.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_payload_vo_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_projection_compile.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_render_helper_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_render_helper_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_reverse_finders.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_runner.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_template_data.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_template_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_template_output_pattern.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_template_scope_helpers.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_template_scope_walk.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_template_spec.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_tph_codegen.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_trace_helper_generator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_type_map.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/codegen/test_validation_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/capabilities.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/conformance-expected-failures.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/conformance_adapter.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/corpus.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/expected_failures.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/fixture_discovery.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/navigator.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_extract_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_extract_object_verdict.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_fr010_loader_attrs.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_fr011_attrs.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_generator_registry_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_object_model_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_provider_composition_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_registry_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_runner_hardfail.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_spec_metamodel_embed.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_strict_attr_load.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_template_codegen_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_template_generator_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/test_yaml_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/api_contract_assertions.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/api_contract_jsonb_server.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/api_contract_m2m_server.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/api_contract_server.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/generated_jsonb_app.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/generated_m2m_app.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/generated_router_app.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/generated_tph_app.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/meta_ai_trace.yaml +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/normalization.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/postgres_container.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/query_runner.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/scenarios.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/test_api_contract.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/test_api_contract_generated.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/test_api_contract_jsonb.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/test_api_contract_m2m.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/test_api_contract_m2m_generated.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/test_api_contract_tph_generated.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/test_llm_call_trace.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/test_normalization.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/test_query_scenarios.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/integration/test_runtime_return_types.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/open_closed_proof_test.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/extract/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/extract/test_coerce.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/extract/test_extract.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/extract/test_extract_map.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/extract/test_json_forgiving_reader.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/extract/test_locate.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/extract/test_model.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/extract/test_normalize.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/extract/test_strip.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/prompt/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/prompt/test_output_format_renderer.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/test_email_document.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/test_filesystem_provider.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/test_output_format_renderer_nested.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/test_output_prompt_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/test_render_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/test_render_max_chars.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/test_verify.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/render/test_verify_conformance.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/source/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/source/test_fr5c_merge_attribution.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/source/test_fr5d_reference_resolution.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/source/test_fr5e_database_source_shape.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/source/test_json_path.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/source/test_semantic_diff.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/source/test_source_on_node.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/source/test_yaml_positions.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/test_api_docs_accuracy.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/__init__.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_agent_context_staleness.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_capabilities.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_common_attrs.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_core_types.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_effective_package.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_errors.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_field_enum.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_field_map_validation.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_index_lookup.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_llm_recorder.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_loader.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_loader_bom.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_loader_class.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_merge.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_meta_attr.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_meta_data.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_meta_source.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_module_shortcuts.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_n2m_resolver.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_n2m_resolver_inherited.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_one_primary_source.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_parser.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_parser_yaml.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_provider.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_provider_extension.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_registry.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_registry_completeness.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_registry_extend.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_registry_sealed.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_relationship_referential_actions.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_resolution_key.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_serializer.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_shared_constants.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_smoke.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_sources.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_strict_child_placement.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_super_resolve.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_template_toolcall.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_validation_attr_schema.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_validation_filter_values.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_validation_origin_paths.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_validation_sort_field.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_validation_warnings.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_write_coercion_arrays.py +0 -0
- {metaobjects-0.15.11 → metaobjects-0.15.13}/tests/unit/test_yaml_desugar.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metaobjects
|
|
3
|
-
Version: 0.15.
|
|
3
|
+
Version: 0.15.13
|
|
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.15.
|
|
3
|
+
version = "0.15.13"
|
|
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"
|
{metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/m2m_codegen.py
RENAMED
|
@@ -110,7 +110,7 @@ def _field_named(entity: MetaObject, field_name: str) -> MetaField | None:
|
|
|
110
110
|
return None
|
|
111
111
|
|
|
112
112
|
|
|
113
|
-
def
|
|
113
|
+
def pk_field_name(entity: MetaObject) -> str:
|
|
114
114
|
"""The single PK field name (``identity.primary @fields``), default ``id``."""
|
|
115
115
|
for c in entity.children():
|
|
116
116
|
if c.type == TYPE_IDENTITY and c.sub_type == IDENTITY_SUBTYPE_PRIMARY:
|
|
@@ -184,8 +184,8 @@ def resolve_m2m_descriptors(
|
|
|
184
184
|
source_column=_column_of(source_fk, fields.source_field),
|
|
185
185
|
target_column=_column_of(target_fk, fields.target_field),
|
|
186
186
|
target_pk_column=_column_of(
|
|
187
|
-
_field_named(target,
|
|
188
|
-
|
|
187
|
+
_field_named(target, pk_field_name(target)),
|
|
188
|
+
pk_field_name(target),
|
|
189
189
|
),
|
|
190
190
|
symmetric=rel.symmetric(),
|
|
191
191
|
)
|
|
@@ -63,6 +63,7 @@ from metaobjects.meta.persistence.origin.origin_constants import (
|
|
|
63
63
|
)
|
|
64
64
|
from metaobjects.meta.template import template_constants as tc
|
|
65
65
|
from metaobjects.meta.template.meta_template import MetaTemplate
|
|
66
|
+
from metaobjects.naming_refs import resolve_object_ref
|
|
66
67
|
from metaobjects.shared.base_types import TYPE_OBJECT, TYPE_TEMPLATE
|
|
67
68
|
from metaobjects.shared.separators import PACKAGE_SEP
|
|
68
69
|
|
|
@@ -104,6 +105,16 @@ def payload_module_name(template_name: str) -> str:
|
|
|
104
105
|
# ---------------------------------------------------------------------------
|
|
105
106
|
|
|
106
107
|
|
|
108
|
+
def _pkg_of(node: MetaData) -> str:
|
|
109
|
+
"""The effective package of an object — its ``resolution_key()`` minus the
|
|
110
|
+
trailing ``::<name>`` ("" for a root-level object). Derived from the resolution
|
|
111
|
+
key so it is correct for BOTH loaded trees (file_default_package) and
|
|
112
|
+
programmatically-built trees (package only on the root)."""
|
|
113
|
+
key = node.resolution_key()
|
|
114
|
+
i = key.rfind(PACKAGE_SEP)
|
|
115
|
+
return "" if i == -1 else key[:i]
|
|
116
|
+
|
|
117
|
+
|
|
107
118
|
def _resolve_object_by_short_or_fqn(root: MetaData, ref: str) -> MetaObject | None:
|
|
108
119
|
"""Find a ``MetaObject`` child satisfying an (already-expanded) object ref.
|
|
109
120
|
|
|
@@ -192,9 +203,14 @@ def _resolve_object_field_type(
|
|
|
192
203
|
ref = field.attrs().get(fc.FIELD_ATTR_OBJECT_REF)
|
|
193
204
|
if not isinstance(ref, str) or not ref:
|
|
194
205
|
return _fallback_type(field)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
206
|
+
# ADR-0042 — a nested @objectRef resolves in the DECLARING field's package
|
|
207
|
+
# (correct for a field.object inherited via extends across packages); an FQN
|
|
208
|
+
# resolves exactly. NO bare-tail short-name fallback that would bind a same-named
|
|
209
|
+
# VO in the wrong package on a cross-package collision (#191). The declaring
|
|
210
|
+
# package is taken from the parent object's resolution key so it is correct for
|
|
211
|
+
# both loaded trees (file_default_package) and programmatic trees (root package).
|
|
212
|
+
referrer_pkg = _pkg_of(field.parent) if field.parent is not None else ""
|
|
213
|
+
target = resolve_object_ref(root, ref, referrer_pkg)
|
|
198
214
|
if target is None:
|
|
199
215
|
return _fallback_type(field)
|
|
200
216
|
nested_class = payload_class_name(target.name)
|
|
@@ -62,7 +62,8 @@ from metaobjects.render.verify import (
|
|
|
62
62
|
PayloadField,
|
|
63
63
|
verify,
|
|
64
64
|
)
|
|
65
|
-
from metaobjects.
|
|
65
|
+
from metaobjects.naming_refs import resolve_object_ref
|
|
66
|
+
from metaobjects.shared.base_types import TYPE_FIELD, TYPE_TEMPLATE
|
|
66
67
|
from metaobjects.shared.separators import PACKAGE_SEP
|
|
67
68
|
|
|
68
69
|
_GENERATOR_NAME = "render-helper-generator"
|
|
@@ -81,30 +82,34 @@ def _py_str(s: str) -> str:
|
|
|
81
82
|
# ---------------------------------------------------------------------------
|
|
82
83
|
|
|
83
84
|
|
|
84
|
-
def
|
|
85
|
+
def _pkg_of(node: MetaData) -> str:
|
|
86
|
+
"""The effective package of an object — its ``resolution_key()`` minus the
|
|
87
|
+
trailing ``::<name>`` ("" for a root-level object). Derived from the resolution
|
|
88
|
+
key so it is correct for BOTH loaded trees (file_default_package) and
|
|
89
|
+
programmatically-built trees (package only on the root, folded via the ancestor
|
|
90
|
+
walk in ``resolution_key()``)."""
|
|
91
|
+
key = node.resolution_key()
|
|
92
|
+
i = key.rfind(PACKAGE_SEP)
|
|
93
|
+
return "" if i == -1 else key[:i]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _resolve_nested_object_ref(
|
|
97
|
+
root: MetaData, reference: str, referrer_pkg: str
|
|
98
|
+
) -> MetaObject | None:
|
|
85
99
|
"""Resolve a ``field.object``'s ``@objectRef`` to its target ``object.value``.
|
|
86
100
|
|
|
87
|
-
ADR-
|
|
88
|
-
package-qualified name
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
(
|
|
92
|
-
``
|
|
101
|
+
ADR-0042: package-local — an FQN ref (contains ``::``) resolves EXACTLY on the
|
|
102
|
+
package-qualified name; a bare ref resolves in the referrer's package FIRST
|
|
103
|
+
(else a root-level object), never a same-named ``object.value`` in another
|
|
104
|
+
package via a bare-tail fallback. *referrer_pkg* is the DECLARING field's
|
|
105
|
+
package (which differs from the VO's when the field is inherited via extends
|
|
106
|
+
from an abstract VO in another package). Shares the single ``resolve_object_ref``
|
|
107
|
+
matcher. Mirrors the TS ``findObject`` in payload-field-tree.ts."""
|
|
93
108
|
if not reference:
|
|
94
109
|
return None
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
for child in root.own_children():
|
|
99
|
-
if child.type != TYPE_OBJECT or not isinstance(child, MetaObject):
|
|
100
|
-
continue
|
|
101
|
-
if child.sub_type != OBJECT_SUBTYPE_VALUE:
|
|
102
|
-
continue
|
|
103
|
-
if fqn:
|
|
104
|
-
if child.resolution_key() == reference or child.fqn() == reference:
|
|
105
|
-
return child
|
|
106
|
-
elif child.name.rsplit(PACKAGE_SEP, 1)[-1] == ref_short:
|
|
107
|
-
return child
|
|
110
|
+
target = resolve_object_ref(root, reference, referrer_pkg)
|
|
111
|
+
if target is not None and target.sub_type == OBJECT_SUBTYPE_VALUE:
|
|
112
|
+
return target # type: ignore[return-value]
|
|
108
113
|
return None
|
|
109
114
|
|
|
110
115
|
|
|
@@ -118,6 +123,10 @@ def _derive_payload_field_tree(
|
|
|
118
123
|
if vo is None or vo.resolution_key() in seen:
|
|
119
124
|
return []
|
|
120
125
|
next_seen = seen | {vo.resolution_key()}
|
|
126
|
+
# A nested @objectRef resolves in the FIELD's own declaring package (below),
|
|
127
|
+
# which differs from this VO's when the field is inherited via extends from an
|
|
128
|
+
# abstract VO in another package (the bare ref was authored there).
|
|
129
|
+
vo_pkg = _pkg_of(vo)
|
|
121
130
|
fields: list[PayloadField] = []
|
|
122
131
|
for f in vo.children():
|
|
123
132
|
if f.type != TYPE_FIELD or not isinstance(f, MetaField):
|
|
@@ -125,7 +134,8 @@ def _derive_payload_field_tree(
|
|
|
125
134
|
if f.sub_type == fc.FIELD_SUBTYPE_OBJECT:
|
|
126
135
|
ref = f.attrs().get(fc.FIELD_ATTR_OBJECT_REF)
|
|
127
136
|
if isinstance(ref, str) and ref:
|
|
128
|
-
|
|
137
|
+
field_pkg = _pkg_of(f.parent) if f.parent is not None else vo_pkg
|
|
138
|
+
target = _resolve_nested_object_ref(root, ref, field_pkg)
|
|
129
139
|
if target is not None and target.sub_type == OBJECT_SUBTYPE_VALUE:
|
|
130
140
|
children = _derive_payload_field_tree(root, target, next_seen)
|
|
131
141
|
fields.append(PayloadField(f.name, children))
|
|
@@ -152,16 +162,20 @@ def _field_tree_literal(fields: list[PayloadField]) -> str:
|
|
|
152
162
|
|
|
153
163
|
|
|
154
164
|
def _resolve_payload_vo(root: MetaData, payload_ref: str) -> MetaObject | None:
|
|
155
|
-
"""``@payloadRef`` must resolve to an ``object.value
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
165
|
+
"""``@payloadRef`` must resolve to an ``object.value``. Package-local (ADR-0042):
|
|
166
|
+
the referrer's own package first (else a root-level object), FQN exact. The
|
|
167
|
+
referrer package is derived from the resolved match's own resolution key, so this
|
|
168
|
+
keeps the same behavior for the single-package + FQN codegen fixtures while never
|
|
169
|
+
binding a same-named VO in the wrong package (the nested @objectRef path is the
|
|
170
|
+
one #191 named — see _resolve_nested_object_ref). Matches a value-object child by
|
|
171
|
+
the package-folded resolution key OR the bare short name (FR-026 expands refs to
|
|
172
|
+
FQN, while the child node still carries the short ``name``)."""
|
|
173
|
+
ref_short = payload_ref.rsplit(PACKAGE_SEP, 1)[-1]
|
|
160
174
|
# ADR-0039 sanctioned own: top-level scan on the loader ROOT (never extended, own == effective)
|
|
161
175
|
for child in root.own_children():
|
|
162
|
-
if
|
|
176
|
+
if not isinstance(child, MetaObject) or child.sub_type != OBJECT_SUBTYPE_VALUE:
|
|
163
177
|
continue
|
|
164
|
-
if child.
|
|
178
|
+
if child.resolution_key() == payload_ref or child.name == ref_short:
|
|
165
179
|
return child
|
|
166
180
|
return None
|
|
167
181
|
|
{metaobjects-0.15.11 → metaobjects-0.15.13}/src/metaobjects/codegen/generators/router_generator.py
RENAMED
|
@@ -43,10 +43,12 @@ from metaobjects.codegen.generator import EmittedFile, GenContext, Generator, pe
|
|
|
43
43
|
from metaobjects.codegen.generators.m2m_codegen import (
|
|
44
44
|
M2mDescriptor,
|
|
45
45
|
build_object_index,
|
|
46
|
+
pk_field_name,
|
|
46
47
|
resolve_m2m_descriptors,
|
|
47
48
|
)
|
|
48
49
|
from metaobjects.codegen.generators.tph_plan import TphPlan, is_tph_subtype, tph_plan_for
|
|
49
50
|
from metaobjects.codegen.instance_artifacts import emits_instance_artifacts
|
|
51
|
+
from metaobjects.codegen.type_map import PyType, py_type_for
|
|
50
52
|
from metaobjects.meta.core.field import field_constants as fc
|
|
51
53
|
from metaobjects.meta.core.field.meta_field import MetaField
|
|
52
54
|
from metaobjects.meta.core.identity.identity_constants import (
|
|
@@ -87,6 +89,23 @@ def _scalar_fields(entity: MetaObject) -> list[MetaField]:
|
|
|
87
89
|
return [f for f in entity.fields() if f.sub_type != fc.FIELD_SUBTYPE_OBJECT]
|
|
88
90
|
|
|
89
91
|
|
|
92
|
+
def _pk_py_type(entity: MetaObject) -> PyType:
|
|
93
|
+
"""The Python type of the entity's primary-key path/id parameter, derived
|
|
94
|
+
from the PK field's declared subtype via ``type_map.py_type_for`` — the same
|
|
95
|
+
mapper the Pydantic entity model uses, so ``field.uuid`` binds ``uuid.UUID``
|
|
96
|
+
on the route exactly as it does on the model (mirrors the C#
|
|
97
|
+
RoutesGenerator's ``CSharpNaming.ScalarFor(pkField.SubType)``).
|
|
98
|
+
|
|
99
|
+
Composite PK → ``@fields[0]`` (the TS ``getPkInfo`` behavior); no primary
|
|
100
|
+
identity / unresolvable field → ``int`` (the ``field.long`` default).
|
|
101
|
+
"""
|
|
102
|
+
name = pk_field_name(entity)
|
|
103
|
+
pk_field = next((f for f in entity.fields() if f.name == name), None)
|
|
104
|
+
if pk_field is None:
|
|
105
|
+
return PyType("int")
|
|
106
|
+
return py_type_for(pk_field)
|
|
107
|
+
|
|
108
|
+
|
|
90
109
|
@dataclass(frozen=True)
|
|
91
110
|
class ReverseFk:
|
|
92
111
|
"""One FK an entity ``E`` holds (ADR-0038): the FK FIELD name on ``E`` and the
|
|
@@ -140,13 +159,15 @@ class RouterGenerator:
|
|
|
140
159
|
|
|
141
160
|
Override points:
|
|
142
161
|
|
|
143
|
-
* ``_emit_repository_protocol(repo_class, m2m)`` — the consumer-
|
|
144
|
-
``Repository`` ``Protocol`` block (CRUD finders + M:N
|
|
162
|
+
* ``_emit_repository_protocol(repo_class, m2m, pk_type)`` — the consumer-
|
|
163
|
+
implemented ``Repository`` ``Protocol`` block (CRUD finders + M:N
|
|
164
|
+
``find_related_*``); ``pk_type`` is the PK's Python annotation text.
|
|
145
165
|
* ``_emit_reverse_finders(entity)`` — the ADR-0038 reverse-FK finder pair
|
|
146
166
|
(``find_<e_plural>_by_<fk_segment>`` + ``…_in``) appended to the ``Protocol``.
|
|
147
167
|
* ``_emit_route_handler(name, ...)`` — the CRUD route handlers (list / get /
|
|
148
168
|
create / update / delete), keyed by ``name``.
|
|
149
|
-
* ``_emit_m2m_route(d, snake, pk_param, repo_class)`` — one M:N
|
|
169
|
+
* ``_emit_m2m_route(d, snake, pk_param, pk_type, repo_class)`` — one M:N
|
|
170
|
+
traversal route.
|
|
150
171
|
* ``render_router(entity, object_index)`` — the whole module (last resort).
|
|
151
172
|
|
|
152
173
|
Skips entities without a ``source.rdb`` child and read-only kinds
|
|
@@ -156,11 +177,12 @@ class RouterGenerator:
|
|
|
156
177
|
name = "router-generator"
|
|
157
178
|
|
|
158
179
|
def _emit_repository_protocol(
|
|
159
|
-
self, repo_class: str, m2m: list[M2mDescriptor]
|
|
180
|
+
self, repo_class: str, m2m: list[M2mDescriptor], pk_type: str
|
|
160
181
|
) -> list[str]:
|
|
161
182
|
"""The repository ``Protocol`` block. Returns/accepts ``Any`` so this module
|
|
162
|
-
stays decoupled from the entity-model import
|
|
163
|
-
|
|
183
|
+
stays decoupled from the entity-model import; *pk_type* is the PK's Python
|
|
184
|
+
annotation text (metadata-derived — e.g. ``uuid.UUID`` / ``int`` / ``str``).
|
|
185
|
+
Override to add custom finder signatures or change the seam shape."""
|
|
164
186
|
lines: list[str] = [
|
|
165
187
|
f"class {repo_class}(Protocol):",
|
|
166
188
|
' """GENERATED — consumer implements with their preferred persistence layer."""',
|
|
@@ -172,14 +194,14 @@ class RouterGenerator:
|
|
|
172
194
|
" filters: list[FilterPredicate],",
|
|
173
195
|
" ) -> list[Any]: ...",
|
|
174
196
|
" def count(self, filters: list[FilterPredicate]) -> int: ...",
|
|
175
|
-
" def find_by_id(self, id:
|
|
197
|
+
f" def find_by_id(self, id: {pk_type}) -> Any | None: ...",
|
|
176
198
|
" def create(self, dto: Any) -> Any: ...",
|
|
177
|
-
" def update(self, id:
|
|
178
|
-
" def delete(self, id:
|
|
199
|
+
f" def update(self, id: {pk_type}, dto: Any) -> Any | None: ...",
|
|
200
|
+
f" def delete(self, id: {pk_type}) -> bool: ...",
|
|
179
201
|
]
|
|
180
202
|
for d in m2m:
|
|
181
203
|
lines.append(
|
|
182
|
-
f" def find_related_{d.relation_name}(self, id:
|
|
204
|
+
f" def find_related_{d.relation_name}(self, id: {pk_type}) -> list[Any]: ..."
|
|
183
205
|
)
|
|
184
206
|
return lines
|
|
185
207
|
|
|
@@ -212,6 +234,7 @@ class RouterGenerator:
|
|
|
212
234
|
snake: str,
|
|
213
235
|
plural: str,
|
|
214
236
|
pk_param: str,
|
|
237
|
+
pk_type: str,
|
|
215
238
|
repo_class: str,
|
|
216
239
|
fields_const: str,
|
|
217
240
|
ops_const: str,
|
|
@@ -251,7 +274,7 @@ class RouterGenerator:
|
|
|
251
274
|
return [
|
|
252
275
|
f'@router.get("/{{{pk_param}}}")',
|
|
253
276
|
f"def get_{snake}(",
|
|
254
|
-
f" {pk_param}:
|
|
277
|
+
f" {pk_param}: {pk_type},",
|
|
255
278
|
f" repo: Annotated[{repo_class}, Depends(get_repository)],",
|
|
256
279
|
") -> Any:",
|
|
257
280
|
f" row = repo.find_by_id({pk_param})",
|
|
@@ -273,7 +296,7 @@ class RouterGenerator:
|
|
|
273
296
|
f'@router.patch("/{{{pk_param}}}")',
|
|
274
297
|
f'@router.put("/{{{pk_param}}}")',
|
|
275
298
|
f"def update_{snake}(",
|
|
276
|
-
f" {pk_param}:
|
|
299
|
+
f" {pk_param}: {pk_type},",
|
|
277
300
|
" dto: dict[str, Any],",
|
|
278
301
|
f" repo: Annotated[{repo_class}, Depends(get_repository)],",
|
|
279
302
|
") -> Any:",
|
|
@@ -286,7 +309,7 @@ class RouterGenerator:
|
|
|
286
309
|
return [
|
|
287
310
|
f'@router.delete("/{{{pk_param}}}", status_code=status.HTTP_204_NO_CONTENT)',
|
|
288
311
|
f"def delete_{snake}(",
|
|
289
|
-
f" {pk_param}:
|
|
312
|
+
f" {pk_param}: {pk_type},",
|
|
290
313
|
f" repo: Annotated[{repo_class}, Depends(get_repository)],",
|
|
291
314
|
") -> None:",
|
|
292
315
|
f" if not repo.delete({pk_param}):",
|
|
@@ -295,7 +318,7 @@ class RouterGenerator:
|
|
|
295
318
|
raise ValueError(f"unknown route handler '{name}'")
|
|
296
319
|
|
|
297
320
|
def _emit_m2m_route(
|
|
298
|
-
self, d: M2mDescriptor, snake: str, pk_param: str, repo_class: str
|
|
321
|
+
self, d: M2mDescriptor, snake: str, pk_param: str, pk_type: str, repo_class: str
|
|
299
322
|
) -> list[str]:
|
|
300
323
|
"""One M:N traversal route ``GET /{id}/<relationName>`` — a thin pass-through
|
|
301
324
|
to the repository's ``find_related_*`` finder. Override to add filtering /
|
|
@@ -303,7 +326,7 @@ class RouterGenerator:
|
|
|
303
326
|
return [
|
|
304
327
|
f'@router.get("/{{{pk_param}}}/{d.relation_name}")',
|
|
305
328
|
f"def list_{snake}_{d.relation_name}(",
|
|
306
|
-
f" {pk_param}:
|
|
329
|
+
f" {pk_param}: {pk_type},",
|
|
307
330
|
f" repo: Annotated[{repo_class}, Depends(get_repository)],",
|
|
308
331
|
") -> list[Any]:",
|
|
309
332
|
f" return repo.find_related_{d.relation_name}({pk_param})",
|
|
@@ -343,6 +366,10 @@ class RouterGenerator:
|
|
|
343
366
|
snake = _snake_case(short_name)
|
|
344
367
|
plural = _plural_lowercase(short_name)
|
|
345
368
|
pk_param = f"{snake}_id"
|
|
369
|
+
# PK type from the BASE's declared primary key (subtypes share the
|
|
370
|
+
# base's single table — mirrors the C# TPH pkType threading).
|
|
371
|
+
pk = _pk_py_type(entity)
|
|
372
|
+
pk_type = pk.expr
|
|
346
373
|
repo_class = f"{short_name}Repository"
|
|
347
374
|
upper = short_name.upper()
|
|
348
375
|
fields_const = f"{upper}_FILTER_FIELDS"
|
|
@@ -371,6 +398,10 @@ class RouterGenerator:
|
|
|
371
398
|
)
|
|
372
399
|
parts.append("from __future__ import annotations")
|
|
373
400
|
parts.append("")
|
|
401
|
+
for import_line in sorted(pk.imports):
|
|
402
|
+
parts.append(import_line)
|
|
403
|
+
if pk.imports:
|
|
404
|
+
parts.append("")
|
|
374
405
|
parts.append("from typing import Annotated, Any, Protocol")
|
|
375
406
|
parts.append("")
|
|
376
407
|
parts.append("from fastapi import APIRouter, Depends, Query, Request, status")
|
|
@@ -420,10 +451,10 @@ class RouterGenerator:
|
|
|
420
451
|
parts.append(" filters: list[FilterPredicate],")
|
|
421
452
|
parts.append(" ) -> list[Any]: ...")
|
|
422
453
|
parts.append(" def count(self, subtype: str | None, filters: list[FilterPredicate]) -> int: ...")
|
|
423
|
-
parts.append(" def find_by_id(self, subtype: str | None, id:
|
|
454
|
+
parts.append(f" def find_by_id(self, subtype: str | None, id: {pk_type}) -> Any | None: ...")
|
|
424
455
|
parts.append(" def create(self, subtype: str, dto: Any) -> Any: ...")
|
|
425
|
-
parts.append(" def update(self, subtype: str, id:
|
|
426
|
-
parts.append(" def delete(self, subtype: str, id:
|
|
456
|
+
parts.append(f" def update(self, subtype: str, id: {pk_type}, dto: Any) -> Any | None: ...")
|
|
457
|
+
parts.append(f" def delete(self, subtype: str, id: {pk_type}) -> bool: ...")
|
|
427
458
|
parts.append("")
|
|
428
459
|
parts.append("")
|
|
429
460
|
parts.append(f"def get_repository() -> {repo_class}:")
|
|
@@ -445,7 +476,7 @@ class RouterGenerator:
|
|
|
445
476
|
") -> Any:",
|
|
446
477
|
]
|
|
447
478
|
|
|
448
|
-
# --- Per-subtype routes FIRST (literal segments match before /{id
|
|
479
|
+
# --- Per-subtype routes FIRST (literal segments match before /{id}). ---
|
|
449
480
|
for st in plan.subtypes:
|
|
450
481
|
seg = st.route_segment
|
|
451
482
|
val = st.value
|
|
@@ -464,7 +495,7 @@ class RouterGenerator:
|
|
|
464
495
|
parts.append("")
|
|
465
496
|
parts.append(f'@router.get("/{seg}/{{{pk_param}}}")')
|
|
466
497
|
parts.append(f"def get_{plural}_{sfx}(")
|
|
467
|
-
parts.append(f" {pk_param}:
|
|
498
|
+
parts.append(f" {pk_param}: {pk_type},")
|
|
468
499
|
parts.append(f" repo: Annotated[{repo_class}, Depends(get_repository)],")
|
|
469
500
|
parts.append(") -> Any:")
|
|
470
501
|
parts.append(f' row = repo.find_by_id("{val}", {pk_param})')
|
|
@@ -476,7 +507,7 @@ class RouterGenerator:
|
|
|
476
507
|
parts.append(f'@router.patch("/{seg}/{{{pk_param}}}")')
|
|
477
508
|
parts.append(f'@router.put("/{seg}/{{{pk_param}}}")')
|
|
478
509
|
parts.append(f"def update_{plural}_{sfx}(")
|
|
479
|
-
parts.append(f" {pk_param}:
|
|
510
|
+
parts.append(f" {pk_param}: {pk_type},")
|
|
480
511
|
parts.append(" dto: dict[str, Any],")
|
|
481
512
|
parts.append(f" repo: Annotated[{repo_class}, Depends(get_repository)],")
|
|
482
513
|
parts.append(") -> Any:")
|
|
@@ -488,7 +519,7 @@ class RouterGenerator:
|
|
|
488
519
|
parts.append("")
|
|
489
520
|
parts.append(f'@router.delete("/{seg}/{{{pk_param}}}", status_code=status.HTTP_204_NO_CONTENT)')
|
|
490
521
|
parts.append(f"def delete_{plural}_{sfx}(")
|
|
491
|
-
parts.append(f" {pk_param}:
|
|
522
|
+
parts.append(f" {pk_param}: {pk_type},")
|
|
492
523
|
parts.append(f" repo: Annotated[{repo_class}, Depends(get_repository)],")
|
|
493
524
|
parts.append(") -> None:")
|
|
494
525
|
parts.append(f' if not repo.delete("{val}", {pk_param}):')
|
|
@@ -496,14 +527,14 @@ class RouterGenerator:
|
|
|
496
527
|
parts.append("")
|
|
497
528
|
parts.append("")
|
|
498
529
|
|
|
499
|
-
# --- Polymorphic base routes LAST (so /{id
|
|
530
|
+
# --- Polymorphic base routes LAST (so /{id} doesn't shadow /<segment>). ---
|
|
500
531
|
parts.extend(list_sig(f"list_{plural}", ""))
|
|
501
532
|
parts.extend(self._emit_tph_list_body("None", fields_const, ops_const))
|
|
502
533
|
parts.append("")
|
|
503
534
|
parts.append("")
|
|
504
535
|
parts.append(f'@router.get("/{{{pk_param}}}")')
|
|
505
536
|
parts.append(f"def get_{snake}(")
|
|
506
|
-
parts.append(f" {pk_param}:
|
|
537
|
+
parts.append(f" {pk_param}: {pk_type},")
|
|
507
538
|
parts.append(f" repo: Annotated[{repo_class}, Depends(get_repository)],")
|
|
508
539
|
parts.append(") -> Any:")
|
|
509
540
|
parts.append(f" row = repo.find_by_id(None, {pk_param})")
|
|
@@ -560,6 +591,8 @@ class RouterGenerator:
|
|
|
560
591
|
snake = _snake_case(short_name)
|
|
561
592
|
plural = _plural_lowercase(short_name)
|
|
562
593
|
pk_param = f"{snake}_id"
|
|
594
|
+
pk = _pk_py_type(entity)
|
|
595
|
+
pk_type = pk.expr
|
|
563
596
|
repo_class = f"{short_name}Repository"
|
|
564
597
|
sort_fields = [f.name for f in _scalar_fields(entity)]
|
|
565
598
|
upper = short_name.upper()
|
|
@@ -578,6 +611,10 @@ class RouterGenerator:
|
|
|
578
611
|
)
|
|
579
612
|
parts.append("from __future__ import annotations")
|
|
580
613
|
parts.append("")
|
|
614
|
+
for import_line in sorted(pk.imports):
|
|
615
|
+
parts.append(import_line)
|
|
616
|
+
if pk.imports:
|
|
617
|
+
parts.append("")
|
|
581
618
|
parts.append("from typing import Annotated, Any, Protocol")
|
|
582
619
|
parts.append("")
|
|
583
620
|
parts.append("from fastapi import APIRouter, Depends, Query, Request, status")
|
|
@@ -616,7 +653,7 @@ class RouterGenerator:
|
|
|
616
653
|
parts.append(" return _SortClause(field=parts[0], direction=direction)")
|
|
617
654
|
parts.append("")
|
|
618
655
|
parts.append("")
|
|
619
|
-
proto_lines = self._emit_repository_protocol(repo_class, m2m)
|
|
656
|
+
proto_lines = self._emit_repository_protocol(repo_class, m2m, pk_type)
|
|
620
657
|
proto_lines.extend(self._emit_reverse_finders(entity))
|
|
621
658
|
parts.extend(proto_lines)
|
|
622
659
|
parts.append("")
|
|
@@ -631,6 +668,7 @@ class RouterGenerator:
|
|
|
631
668
|
snake=snake,
|
|
632
669
|
plural=plural,
|
|
633
670
|
pk_param=pk_param,
|
|
671
|
+
pk_type=pk_type,
|
|
634
672
|
repo_class=repo_class,
|
|
635
673
|
fields_const=fields_const,
|
|
636
674
|
ops_const=ops_const,
|
|
@@ -649,7 +687,7 @@ class RouterGenerator:
|
|
|
649
687
|
# array for an orphan source — never a 404).
|
|
650
688
|
for d in m2m:
|
|
651
689
|
parts.append("")
|
|
652
|
-
parts.extend(self._emit_m2m_route(d, snake, pk_param, repo_class))
|
|
690
|
+
parts.extend(self._emit_m2m_route(d, snake, pk_param, pk_type, repo_class))
|
|
653
691
|
parts.append("")
|
|
654
692
|
|
|
655
693
|
return "\n".join(parts)
|
|
@@ -374,6 +374,22 @@ for _def in core_provider._defs: # noqa: SLF001 (provider build-time enrichment
|
|
|
374
374
|
)
|
|
375
375
|
break
|
|
376
376
|
|
|
377
|
+
# ADR-0042 — a field.object / field.map @objectRef must RESOLVE (a dangling target
|
|
378
|
+
# fails the load, closing the gap #191 surfaced as a misleading downstream error).
|
|
379
|
+
# The required-attr pass owns absence (ERR_OBJECT_FIELD_WITHOUT_OBJECT_REF); this
|
|
380
|
+
# reference descriptor fires only when @objectRef is present but resolves to nothing
|
|
381
|
+
# → ERR_UNRESOLVED_OBJECT_REF. Mirrors the TS core-types.ts registerCoreTypeDefs.
|
|
382
|
+
for _def in core_provider._defs: # noqa: SLF001 (provider build-time enrichment)
|
|
383
|
+
if _def.type == TYPE_FIELD and _def.sub_type in (
|
|
384
|
+
fc.FIELD_SUBTYPE_OBJECT,
|
|
385
|
+
fc.FIELD_SUBTYPE_MAP,
|
|
386
|
+
):
|
|
387
|
+
_def.references.append(
|
|
388
|
+
ReferenceDescriptor(
|
|
389
|
+
FIELD_ATTR_OBJECT_REF, TYPE_OBJECT, None, False, "ERR_UNRESOLVED_OBJECT_REF"
|
|
390
|
+
)
|
|
391
|
+
)
|
|
392
|
+
|
|
377
393
|
# field.enum — dedicated registration with required @values attr.
|
|
378
394
|
# Inherits every common field attr (column / required / unique / default /
|
|
379
395
|
# maxLength / filterable / sortable / etc.) so the D2 type-coercion guard
|
|
@@ -138,17 +138,13 @@ class ErrorCode(str, Enum):
|
|
|
138
138
|
# emit this yet (the T6 guard is deferred — like TS, it belongs in the parser);
|
|
139
139
|
# the enum tracks the shared corpus code so resolution/desugar stay aligned.
|
|
140
140
|
ERR_RELATIVE_REF_IN_CANONICAL = "ERR_RELATIVE_REF_IN_CANONICAL"
|
|
141
|
-
# ADR-
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
#
|
|
147
|
-
|
|
148
|
-
# package anywhere, resolves fine. ``extends`` is intentionally NOT covered
|
|
149
|
-
# (its same-package/root-strict super-resolver yields ERR_UNRESOLVED_SUPER on a
|
|
150
|
-
# bare cross-package miss, not ambiguity).
|
|
151
|
-
ERR_AMBIGUOUS_REF = "ERR_AMBIGUOUS_REF"
|
|
141
|
+
# ADR-0042 — a field.object / field.map @objectRef does not resolve to any
|
|
142
|
+
# object in the loaded tree (a dangling target). Bare refs resolve
|
|
143
|
+
# package-locally (referrer's package, else root-level); FQN refs resolve
|
|
144
|
+
# exactly — a bare cross-package ref no longer binds elsewhere. Supersedes the
|
|
145
|
+
# retired ADR-0041 ERR_AMBIGUOUS_REF (bare = package-local ⇒ ambiguity is
|
|
146
|
+
# unreachable, so every unresolved ref fails closed with its per-attr code).
|
|
147
|
+
ERR_UNRESOLVED_OBJECT_REF = "ERR_UNRESOLVED_OBJECT_REF"
|
|
152
148
|
# FR-033 — strict structural-placement vocabulary. ERR_CHILD_NOT_ALLOWED: a
|
|
153
149
|
# structural child (field/identity/source/validator/… — not an attr) is placed
|
|
154
150
|
# under a parent whose registered childRules do not admit it (the structural
|
|
@@ -12,8 +12,10 @@ from ..errors import ErrorCode, MetaError
|
|
|
12
12
|
from ..meta.core.object.meta_object import MetaObject
|
|
13
13
|
from ..meta.meta_data import MetaData
|
|
14
14
|
from ..meta.meta_root import MetaRoot
|
|
15
|
+
from ..naming_refs import did_you_mean_hint
|
|
15
16
|
from ..registry import TypeRegistry
|
|
16
17
|
from ..shared.base_types import TYPE_OBJECT
|
|
18
|
+
from ..shared.separators import PACKAGE_SEP
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
class SymbolTable:
|
|
@@ -29,19 +31,29 @@ class SymbolTable:
|
|
|
29
31
|
# extended, own == effective) — mirrors the TS validation-registry.
|
|
30
32
|
for child in root.own_children():
|
|
31
33
|
if child.type == TYPE_OBJECT and isinstance(child, MetaObject):
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
# ADR-0042: key by the canonical resolution key ONLY (the FQN, or
|
|
35
|
+
# the bare name for a root-level/empty-package object) — NO bare-name
|
|
36
|
+
# fallback, so a bare ref never binds a same-named object in another
|
|
37
|
+
# package. Mirrors the TS validation-registry symbol table.
|
|
35
38
|
t._index[child.resolution_key()] = child
|
|
36
39
|
return t
|
|
37
40
|
|
|
38
|
-
def resolve_object(self, reference: str) -> MetaData | None:
|
|
39
|
-
|
|
41
|
+
def resolve_object(self, reference: str, referrer_pkg: str) -> MetaData | None:
|
|
42
|
+
"""ADR-0042 package-local resolution: FQN → exact resolution-key match;
|
|
43
|
+
bare → the referrer's own package (``<referrer_pkg>::<ref>``), else a
|
|
44
|
+
root-level object. Mirrors the TS ``resolveObject``."""
|
|
45
|
+
if PACKAGE_SEP in reference:
|
|
46
|
+
return self._index.get(reference)
|
|
47
|
+
local_key = (
|
|
48
|
+
f"{referrer_pkg}{PACKAGE_SEP}{reference}" if referrer_pkg else reference
|
|
49
|
+
)
|
|
50
|
+
return self._index.get(local_key) or self._index.get(reference)
|
|
40
51
|
|
|
41
52
|
|
|
42
53
|
class ValidationContext:
|
|
43
|
-
def __init__(self, symbols: SymbolTable) -> None:
|
|
54
|
+
def __init__(self, symbols: SymbolTable, root: MetaData) -> None:
|
|
44
55
|
self.symbols = symbols
|
|
56
|
+
self.root = root
|
|
45
57
|
self.errors: list[MetaError] = []
|
|
46
58
|
|
|
47
59
|
def error(self, code: str, node: MetaData, message: str) -> None:
|
|
@@ -55,12 +67,23 @@ class ValidationContext:
|
|
|
55
67
|
|
|
56
68
|
|
|
57
69
|
def run(root: MetaRoot, registry: TypeRegistry) -> list[MetaError]:
|
|
58
|
-
ctx = ValidationContext(SymbolTable.build(root))
|
|
59
|
-
_walk(root, registry, ctx)
|
|
70
|
+
ctx = ValidationContext(SymbolTable.build(root), root)
|
|
71
|
+
_walk(root, registry, ctx, "")
|
|
60
72
|
return ctx.errors
|
|
61
73
|
|
|
62
74
|
|
|
63
|
-
def _walk(
|
|
75
|
+
def _walk(
|
|
76
|
+
node: MetaData, registry: TypeRegistry, ctx: ValidationContext, referrer_pkg: str
|
|
77
|
+
) -> None:
|
|
78
|
+
# ADR-0042: a top-level object establishes the package context for its subtree;
|
|
79
|
+
# nested ref-bearing nodes (relationship/field.object/identity.reference) resolve
|
|
80
|
+
# BARE refs against it. Nested nodes carry no `package`, so they inherit the
|
|
81
|
+
# enclosing object's (via file_default_package, else the threaded context).
|
|
82
|
+
pkg = (
|
|
83
|
+
(node.package or node.file_default_package or referrer_pkg)
|
|
84
|
+
if node.type == TYPE_OBJECT
|
|
85
|
+
else referrer_pkg
|
|
86
|
+
)
|
|
64
87
|
type_def = registry.find(node.type, node.sub_type)
|
|
65
88
|
if type_def is not None:
|
|
66
89
|
for desc in type_def.references:
|
|
@@ -72,7 +95,8 @@ def _walk(node: MetaData, registry: TypeRegistry, ctx: ValidationContext) -> Non
|
|
|
72
95
|
if not isinstance(raw, str) or raw == "":
|
|
73
96
|
continue # absence is the required-attr pass's job
|
|
74
97
|
entity_ref = raw.split(".", 1)[0] if desc.dotted_field_path else raw
|
|
75
|
-
|
|
98
|
+
# ADR-0042: bare refs resolve package-local against the enclosing object.
|
|
99
|
+
target = ctx.symbols.resolve_object(entity_ref, pkg)
|
|
76
100
|
# Qualify the node name with its owning entity (e.g. "Order.items") so the error
|
|
77
101
|
# is locatable from the message alone, not just the source envelope.
|
|
78
102
|
qname = f"{node.parent.name}.{node.name}" if node.parent and node.parent.name else node.name
|
|
@@ -80,7 +104,7 @@ def _walk(node: MetaData, registry: TypeRegistry, ctx: ValidationContext) -> Non
|
|
|
80
104
|
ctx.error(
|
|
81
105
|
desc.error_code, node,
|
|
82
106
|
f'{node.type}.{node.sub_type} "{qname}" @{desc.attr} "{raw}" '
|
|
83
|
-
f"does not resolve to an object.",
|
|
107
|
+
f"does not resolve to an object.{did_you_mean_hint(ctx.root, entity_ref)}",
|
|
84
108
|
)
|
|
85
109
|
elif target.type != desc.target_type or (
|
|
86
110
|
desc.target_sub_type is not None and target.sub_type != desc.target_sub_type
|
|
@@ -101,4 +125,4 @@ def _walk(node: MetaData, registry: TypeRegistry, ctx: ValidationContext) -> Non
|
|
|
101
125
|
# node once at its declaration site (own children); inherited nodes are
|
|
102
126
|
# validated where they are declared. Mirrors the TS ``node.ownChildren()`` walk.
|
|
103
127
|
for child in node.own_children():
|
|
104
|
-
_walk(child, registry, ctx)
|
|
128
|
+
_walk(child, registry, ctx, pkg)
|