metaobjects 0.15.2__tar.gz → 0.15.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.15.2 → metaobjects-0.15.4}/PKG-INFO +1 -1
- {metaobjects-0.15.2 → metaobjects-0.15.4}/pyproject.toml +1 -1
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/runtime/filter_parser.py +13 -3
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/validation_passes.py +47 -12
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/registry_manifest.py +11 -1
- metaobjects-0.15.4/tests/conformance/test_provider_composition_conformance.py +150 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/postgres_container.py +78 -9
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_validation_origin_paths.py +64 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/.gitignore +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/LICENSE +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/README.md +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/hatch_build.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/agent_context/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/agent_context/scaffold.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/apidocs/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/apidocs/api_model.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/apidocs/builder.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/apidocs/naming.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/apidocs/paths.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/apidocs/renderer.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/attr_class_map.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/cli.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/config.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/format.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generator_registry.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/entity_model.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/payload_vo_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/router_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/template_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/instance_artifacts.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/overwrite_policy.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/runner.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/runtime/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/type_map.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/core_types.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/datatype.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/documentation/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/documentation/doc_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/documentation/doc_provider.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/documentation/doc_schema.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/errors.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/merge.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/meta_data_loader.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/registered_validation.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/sources/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/sources/directory_source.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/sources/file_source.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/sources/uri_source.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/validate_discriminator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/validate_field_readonly.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/attr/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/field/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/field/field_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/field/meta_field.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/identity/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/index/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/index/index_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/index/meta_index.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/object/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/object/meta_object.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/object/object_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/object/object_extract.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/object/value_object.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/validator/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/meta_data.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/meta_root.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/persistence/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/presentation/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/provider_extends.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/template/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/template/meta_template.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/template/prompt_provider.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/meta/template/template_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/naming_refs.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/parser.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/parser_yaml.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/provider.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/py.typed +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/registry.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/email_document.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/escapers.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/extract/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/extract/coerce.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/extract/extract.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/extract/extract_map.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/extract/locate.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/extract/normalize.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/extract/strip.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/extract/types.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/filesystem_provider.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/prompt/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/prompt/prompt_field.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/prompt/prompt_style.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/renderer.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/render/verify.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/runtime/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/runtime/llm_recorder.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/runtime/n2m_resolver.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/runtime/object_manager.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/runtime/tph.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/serializer_json.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/shared/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/shared/base_types.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/shared/separators.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/shared/structural.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/source/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/source/error_source.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/source/json_path.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/source/semantic_diff.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/source/yaml_positions.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/attr.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/db.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/documentation.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/field.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/identity.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/index.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/layout.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/object.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/origin.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/prompt.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/relationship.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/source.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/template.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/ui.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/validator.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/spec_metamodel/view.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/super_resolve.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/validation_types.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/yaml_desugar.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/golden/extends/expected/Program.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/golden/extends/meta.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/golden/nested-array/meta.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/golden/scalars/expected/Report.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/golden/scalars/meta.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/golden/vanilla/meta.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_abstract_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_api_docs_builder.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_api_docs_paths.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_cli.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_cli_registry.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_cli_staleness_nudge.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_cli_verify_strict.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_cli_verify_subverbs.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_constants_config.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_entity_model.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_enum_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_extractor_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_filter_allowlist_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_format.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_fr010_output_codegen.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_generator_extension_seams.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_golden.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_inheritance_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_instance_artifacts.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_m2m_codegen.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_output_parser_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_overwrite_policy.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_payload_vo_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_projection_compile.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_render_helper_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_render_helper_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_reverse_finders.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_router_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_runner.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_template_data.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_template_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_template_output_pattern.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_template_scope_helpers.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_template_scope_walk.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_template_spec.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_tph_codegen.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_trace_helper_generator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_type_map.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/codegen/test_validation_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/capabilities.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/conformance-expected-failures.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/conformance_adapter.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/corpus.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/expected_failures.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/fixture_discovery.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/navigator.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_extract_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_extract_object_verdict.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_fr010_loader_attrs.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_fr011_attrs.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_generator_registry_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_object_model_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_registry_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_runner_hardfail.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_spec_metamodel_embed.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_strict_attr_load.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_template_codegen_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_template_generator_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/test_yaml_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/api_contract_assertions.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/api_contract_jsonb_server.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/api_contract_m2m_server.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/api_contract_server.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/generated_jsonb_app.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/generated_m2m_app.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/generated_router_app.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/generated_tph_app.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/meta_ai_trace.yaml +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/normalization.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/query_runner.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/scenarios.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/test_api_contract.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/test_api_contract_generated.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/test_api_contract_jsonb.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/test_api_contract_m2m.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/test_api_contract_m2m_generated.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/test_api_contract_tph_generated.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/test_llm_call_trace.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/test_normalization.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/test_query_scenarios.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/integration/test_runtime_return_types.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/open_closed_proof_test.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/extract/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/extract/test_coerce.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/extract/test_extract.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/extract/test_extract_map.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/extract/test_json_forgiving_reader.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/extract/test_locate.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/extract/test_model.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/extract/test_normalize.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/extract/test_strip.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/prompt/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/prompt/test_output_format_renderer.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/test_email_document.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/test_filesystem_provider.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/test_output_format_renderer_nested.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/test_output_prompt_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/test_render_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/test_render_max_chars.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/test_verify.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/render/test_verify_conformance.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/source/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/source/test_fr5c_merge_attribution.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/source/test_fr5d_reference_resolution.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/source/test_fr5e_database_source_shape.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/source/test_json_path.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/source/test_semantic_diff.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/source/test_source_on_node.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/source/test_yaml_positions.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/test_api_docs_accuracy.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/__init__.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_agent_context_staleness.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_capabilities.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_common_attrs.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_core_types.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_effective_package.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_errors.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_field_enum.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_field_map_validation.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_index_lookup.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_llm_recorder.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_loader.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_loader_bom.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_loader_class.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_merge.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_meta_attr.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_meta_data.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_meta_source.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_module_shortcuts.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_n2m_resolver.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_n2m_resolver_inherited.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_one_primary_source.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_parser.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_parser_yaml.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_provider.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_provider_extension.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_registry.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_registry_completeness.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_registry_extend.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_registry_sealed.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_relationship_referential_actions.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_resolution_key.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_serializer.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_shared_constants.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_smoke.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_sources.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_strict_child_placement.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_super_resolve.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_template_toolcall.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_validation_attr_schema.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_validation_filter_values.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_validation_sort_field.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_validation_warnings.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_write_coercion_arrays.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/tests/unit/test_yaml_desugar.py +0 -0
- {metaobjects-0.15.2 → metaobjects-0.15.4}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metaobjects
|
|
3
|
-
Version: 0.15.
|
|
3
|
+
Version: 0.15.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.15.
|
|
3
|
+
version = "0.15.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"
|
|
@@ -14,8 +14,9 @@ Returned ``FilterParseResult`` is either:
|
|
|
14
14
|
* ``predicates`` populated + ``error_envelope`` ``None`` — success path; the
|
|
15
15
|
generated router passes ``predicates`` into the repository.
|
|
16
16
|
* ``error_envelope`` non-``None`` (one of ``invalid_filter_field`` /
|
|
17
|
-
``invalid_filter_op`` / ``invalid_filter_value``) —
|
|
18
|
-
|
|
17
|
+
``invalid_filter_op`` / ``invalid_filter_value`` / ``filter.in_too_large``) —
|
|
18
|
+
the generated router raises
|
|
19
|
+
``HTTPException(status_code=400, detail=result.error_envelope)``.
|
|
19
20
|
|
|
20
21
|
Mirror of the Java ``FilterParser`` / Kotlin ``KotlinFilterAllowlistGenerator`` /
|
|
21
22
|
C# ``FilterParser`` ports — same wire grammar, same error envelopes, same
|
|
@@ -35,6 +36,13 @@ _INVALID_VALUE = object()
|
|
|
35
36
|
_ERR_FIELD = "invalid_filter_field"
|
|
36
37
|
_ERR_OP = "invalid_filter_op"
|
|
37
38
|
_ERR_VALUE = "invalid_filter_value"
|
|
39
|
+
_ERR_IN_TOO_LARGE = "filter.in_too_large"
|
|
40
|
+
|
|
41
|
+
# Cross-port cap on the number of elements in an ``in``-list. A larger list is
|
|
42
|
+
# rejected with the ``filter.in_too_large`` envelope so a caller cannot force an
|
|
43
|
+
# unbounded ``IN (...)`` against the DB. Matches the TypeScript ``runtime-ts``
|
|
44
|
+
# filter parser's ``DEFAULT_MAX_IN_LIST``.
|
|
45
|
+
MAX_IN_LIST = 100
|
|
38
46
|
|
|
39
47
|
|
|
40
48
|
@dataclass(frozen=True)
|
|
@@ -85,7 +93,7 @@ def parse_filter(
|
|
|
85
93
|
validated + coerced filter list (preserving URL order); on failure,
|
|
86
94
|
``error_envelope`` is one of the cross-port envelopes
|
|
87
95
|
(``invalid_filter_field`` / ``invalid_filter_op`` /
|
|
88
|
-
``invalid_filter_value``).
|
|
96
|
+
``invalid_filter_value`` / ``filter.in_too_large``).
|
|
89
97
|
"""
|
|
90
98
|
allowed_set = set(allowed_fields)
|
|
91
99
|
ops_map: dict[str, frozenset[str]] = {
|
|
@@ -129,6 +137,8 @@ def parse_filter(
|
|
|
129
137
|
coerced = _coerce_value(value, op)
|
|
130
138
|
if coerced is _INVALID_VALUE:
|
|
131
139
|
return FilterParseResult(error_envelope={"error": _ERR_VALUE})
|
|
140
|
+
if op == "in" and isinstance(coerced, list) and len(coerced) > MAX_IN_LIST:
|
|
141
|
+
return FilterParseResult(error_envelope={"error": _ERR_IN_TOO_LARGE})
|
|
132
142
|
out.append(FilterPredicate(field=field_name, op=op, value=coerced))
|
|
133
143
|
|
|
134
144
|
return FilterParseResult(predicates=out)
|
|
@@ -962,6 +962,34 @@ def _relationships_by_name(obj: MetaObject) -> dict[str, MetaData]:
|
|
|
962
962
|
return result
|
|
963
963
|
|
|
964
964
|
|
|
965
|
+
def _find_reference(obj: MetaObject, name: str) -> MetaData | None:
|
|
966
|
+
"""Find an ``identity.reference`` (a forward FK) by name — the "reference hop"
|
|
967
|
+
FR-024 allows in a ``@via`` path. The reference IS the FK (single source of truth
|
|
968
|
+
for direction + join column), so naming it navigates its many-to-one edge without
|
|
969
|
+
a redundant ``relationship.*``. Effective (inherited via extends:/super:)."""
|
|
970
|
+
for child in obj.children():
|
|
971
|
+
if (
|
|
972
|
+
child.type == TYPE_IDENTITY
|
|
973
|
+
and child.sub_type == IDENTITY_SUBTYPE_REFERENCE
|
|
974
|
+
and child.name == name
|
|
975
|
+
):
|
|
976
|
+
return child
|
|
977
|
+
return None
|
|
978
|
+
|
|
979
|
+
|
|
980
|
+
def _is_reference_hop(hop: MetaData) -> bool:
|
|
981
|
+
"""True for an ``identity.reference`` node (a ``@via`` reference hop)."""
|
|
982
|
+
return hop.type == TYPE_IDENTITY and hop.sub_type == IDENTITY_SUBTYPE_REFERENCE
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
def _hop_target_name(hop: MetaData) -> object:
|
|
986
|
+
"""The target entity a ``@via`` hop points at: @objectRef (relationship) or
|
|
987
|
+
@references (reference hop)."""
|
|
988
|
+
if _is_reference_hop(hop):
|
|
989
|
+
return hop.get_meta_attr(IDENTITY_REFERENCE_ATTR_REFERENCES)
|
|
990
|
+
return hop.get_meta_attr(RELATIONSHIP_ATTR_OBJECT_REF)
|
|
991
|
+
|
|
992
|
+
|
|
965
993
|
def _validate_entity_field_ref(
|
|
966
994
|
ref: str,
|
|
967
995
|
attr_name: str,
|
|
@@ -1078,13 +1106,15 @@ def _validate_via_path(
|
|
|
1078
1106
|
hops: list[MetaData] = []
|
|
1079
1107
|
for rel_name in segments[1:]:
|
|
1080
1108
|
rels = _relationships_by_name(current_entity)
|
|
1081
|
-
|
|
1109
|
+
# FR-024: a hop may name a relationship OR a reference-only FK
|
|
1110
|
+
# (identity.reference) — the reference IS a navigable many-to-one edge.
|
|
1111
|
+
rel_node = rels.get(rel_name) or _find_reference(current_entity, rel_name)
|
|
1082
1112
|
if rel_node is None:
|
|
1083
1113
|
prefix = ".".join(valid_segments)
|
|
1084
1114
|
errors.append(
|
|
1085
1115
|
MetaError(
|
|
1086
1116
|
f"{context} @via='{via}' — entity '{current_entity.name}' has no "
|
|
1087
|
-
f"relationship '{rel_name}' (known relationships: {sorted(rels)}). "
|
|
1117
|
+
f"relationship or reference '{rel_name}' (known relationships: {sorted(rels)}). "
|
|
1088
1118
|
f'Deepest valid prefix was "{prefix}".',
|
|
1089
1119
|
ErrorCode.ERR_INVALID_ORIGIN,
|
|
1090
1120
|
envelope=resolved_source(origin_node.source, referrer, via),
|
|
@@ -1093,15 +1123,17 @@ def _validate_via_path(
|
|
|
1093
1123
|
return None
|
|
1094
1124
|
|
|
1095
1125
|
# Advance to the referenced entity.
|
|
1096
|
-
# ADR-0039: resolving — a relationship may inherit
|
|
1097
|
-
# (mirrors the TS _validateViaPath
|
|
1098
|
-
#
|
|
1099
|
-
obj_ref = rel_node
|
|
1126
|
+
# ADR-0039: resolving — a relationship/reference may inherit its target via
|
|
1127
|
+
# extends (mirrors the TS _validateViaPath which resolves). Target entity:
|
|
1128
|
+
# @objectRef (relationship) or @references (reference hop).
|
|
1129
|
+
obj_ref = _hop_target_name(rel_node)
|
|
1100
1130
|
if not isinstance(obj_ref, str):
|
|
1131
|
+
missing = "@references" if _is_reference_hop(rel_node) else "@objectRef"
|
|
1132
|
+
kind = "reference" if _is_reference_hop(rel_node) else "relationship"
|
|
1101
1133
|
errors.append(
|
|
1102
1134
|
MetaError(
|
|
1103
|
-
f"{context} @via='{via}' —
|
|
1104
|
-
f"'{current_entity.name}' has no
|
|
1135
|
+
f"{context} @via='{via}' — {kind} '{rel_name}' on entity "
|
|
1136
|
+
f"'{current_entity.name}' has no {missing}",
|
|
1105
1137
|
ErrorCode.ERR_INVALID_ORIGIN,
|
|
1106
1138
|
envelope=resolved_source(origin_node.source, referrer, via),
|
|
1107
1139
|
)
|
|
@@ -1110,11 +1142,11 @@ def _validate_via_path(
|
|
|
1110
1142
|
|
|
1111
1143
|
next_entity = object_index.get(obj_ref)
|
|
1112
1144
|
if next_entity is None:
|
|
1113
|
-
# FR5d —
|
|
1114
|
-
|
|
1145
|
+
# FR5d — the hop's target points at a missing entity.
|
|
1146
|
+
kind = "reference" if _is_reference_hop(rel_node) else "relationship"
|
|
1115
1147
|
errors.append(
|
|
1116
1148
|
MetaError(
|
|
1117
|
-
f"{context} @via='{via}' —
|
|
1149
|
+
f"{context} @via='{via}' — {kind} '{rel_name}' on entity "
|
|
1118
1150
|
f"'{current_entity.name}' references unknown entity '{obj_ref}'",
|
|
1119
1151
|
ErrorCode.ERR_INVALID_ORIGIN,
|
|
1120
1152
|
envelope=resolved_source(origin_node.source, referrer, obj_ref),
|
|
@@ -1137,7 +1169,10 @@ def _validate_via_path(
|
|
|
1137
1169
|
|
|
1138
1170
|
|
|
1139
1171
|
def _hop_cardinality(rel: MetaData) -> str | None:
|
|
1140
|
-
"""A hop
|
|
1172
|
+
"""A hop's effective @cardinality, or None when not declared. A reference hop
|
|
1173
|
+
(a forward FK) is inherently to-one — a child names the parent it points at."""
|
|
1174
|
+
if _is_reference_hop(rel):
|
|
1175
|
+
return CARDINALITY_ONE
|
|
1141
1176
|
# ADR-0039: resolving (@cardinality may be inherited via extends) — mirrors the
|
|
1142
1177
|
# TS _hopCardinality which reads `rel.attr()` (resolving), NOT ownAttr.
|
|
1143
1178
|
v = rel.get_meta_attr(RELATIONSHIP_ATTR_CARDINALITY)
|
|
@@ -255,6 +255,15 @@ def _sorted_children(definition: TypeDefinition) -> list[dict[str, object]]:
|
|
|
255
255
|
return children
|
|
256
256
|
|
|
257
257
|
|
|
258
|
+
METAMODEL_VERSION = "0.9"
|
|
259
|
+
"""Rolled-up spec-version for the cross-port registry manifest.
|
|
260
|
+
|
|
261
|
+
``"0"`` = pre-1.0 / unstable (semver major-0). Flips to ``"1.0"`` at the
|
|
262
|
+
1.0 vocabulary cut. Emitted as the first top-level key in the canonical
|
|
263
|
+
manifest so every port's byte-comparison gate sees it at position 0.
|
|
264
|
+
"""
|
|
265
|
+
|
|
266
|
+
|
|
258
267
|
def build_registry_manifest(registry: TypeRegistry) -> dict[str, object]:
|
|
259
268
|
"""Build the canonical registry-manifest object from an assembled registry.
|
|
260
269
|
|
|
@@ -306,8 +315,9 @@ def build_registry_manifest(registry: TypeRegistry) -> dict[str, object]:
|
|
|
306
315
|
if default_sub is not None:
|
|
307
316
|
default_sub_types[type_name] = default_sub
|
|
308
317
|
|
|
309
|
-
# Fixed top-level key order: types, commonAttrs, defaultSubTypes.
|
|
318
|
+
# Fixed top-level key order: metamodelVersion (C4), types, commonAttrs, defaultSubTypes.
|
|
310
319
|
return {
|
|
320
|
+
"metamodelVersion": METAMODEL_VERSION,
|
|
311
321
|
"types": types,
|
|
312
322
|
"commonAttrs": common_attrs,
|
|
313
323
|
"defaultSubTypes": default_sub_types,
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Provider-composition conformance runner (Python port).
|
|
2
|
+
|
|
3
|
+
Five registry/provider error codes are Tier-1 cross-port invariants that the
|
|
4
|
+
metadata-input -> error corpus cannot reach: they are triggered by HOW providers
|
|
5
|
+
are composed and sealed, not by any metadata document. This runner gates them
|
|
6
|
+
from the shared corpus at fixtures/provider-composition-conformance/.
|
|
7
|
+
|
|
8
|
+
Each port supplies the SAME canonical named-provider set (see the corpus
|
|
9
|
+
README). A manifest names providers by id; the runner maps names -> provider
|
|
10
|
+
objects, composes, and asserts the surfaced .code. The registry-sealed scenario
|
|
11
|
+
composes, seals, then runs a probe provider's register_types against the sealed
|
|
12
|
+
registry.
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
import pytest
|
|
20
|
+
|
|
21
|
+
from metaobjects.errors import ErrorCode, ParseError
|
|
22
|
+
from metaobjects.provider import Provider, compose_registry
|
|
23
|
+
from metaobjects.registry import AttrSchema, ChildRule, TypeDefinition, TypeRegistry
|
|
24
|
+
from metaobjects.meta.template.meta_template import MetaTemplate
|
|
25
|
+
from metaobjects.shared.base_types import TYPE_ATTR
|
|
26
|
+
|
|
27
|
+
# Fresh, otherwise-unused template subtype the attr-conflict / seal providers use.
|
|
28
|
+
_CONFLICT_SUBTYPE = "compositionprobe"
|
|
29
|
+
_CONFLICT_ATTR = "conflictAttr"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _corpus_root() -> Path:
|
|
33
|
+
here = Path(__file__).resolve()
|
|
34
|
+
for parent in [here, *here.parents]:
|
|
35
|
+
candidate = parent / "fixtures" / "provider-composition-conformance"
|
|
36
|
+
if candidate.is_dir():
|
|
37
|
+
return candidate
|
|
38
|
+
raise RuntimeError("could not locate fixtures/provider-composition-conformance from " + str(here))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _noop_provider(provider_id: str, *deps: str) -> Provider:
|
|
42
|
+
return Provider(provider_id, dependencies=tuple(deps))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _attr_conflict_base_provider() -> Provider:
|
|
46
|
+
"""Registers a fresh test-only type carrying a single string attr."""
|
|
47
|
+
p = Provider("attr-conflict-base")
|
|
48
|
+
p.add(
|
|
49
|
+
TypeDefinition(
|
|
50
|
+
type="template",
|
|
51
|
+
sub_type=_CONFLICT_SUBTYPE,
|
|
52
|
+
factory=lambda t, s, n: MetaTemplate(t, s, n),
|
|
53
|
+
attrs=[AttrSchema(_CONFLICT_ATTR, "string")],
|
|
54
|
+
child_rules=[ChildRule(TYPE_ATTR, "*")],
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
return p
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class _AttrConflictClashProvider(Provider):
|
|
61
|
+
"""Extends the base's type, redefining the same attr name -> attr conflict."""
|
|
62
|
+
|
|
63
|
+
def __init__(self) -> None:
|
|
64
|
+
super().__init__("attr-conflict-clash", dependencies=("attr-conflict-base",))
|
|
65
|
+
|
|
66
|
+
def register_types(self, registry: TypeRegistry) -> None: # noqa: D401
|
|
67
|
+
registry.extend(
|
|
68
|
+
"template",
|
|
69
|
+
_CONFLICT_SUBTYPE,
|
|
70
|
+
attributes=[AttrSchema(_CONFLICT_ATTR, "string")],
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class _SealProbeProvider(Provider):
|
|
75
|
+
"""Attempts a mutating registration — throws against a sealed registry."""
|
|
76
|
+
|
|
77
|
+
def __init__(self) -> None:
|
|
78
|
+
super().__init__("seal-probe")
|
|
79
|
+
|
|
80
|
+
def register_types(self, registry: TypeRegistry) -> None: # noqa: D401
|
|
81
|
+
registry.register(
|
|
82
|
+
TypeDefinition(
|
|
83
|
+
type="template",
|
|
84
|
+
sub_type="sealprobe",
|
|
85
|
+
factory=lambda t, s, n: MetaTemplate(t, s, n),
|
|
86
|
+
attrs=[],
|
|
87
|
+
child_rules=[],
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _providers() -> dict[str, Provider]:
|
|
93
|
+
return {
|
|
94
|
+
"duplicate-x": _noop_provider("duplicate-x"),
|
|
95
|
+
# Same `.id` as duplicate-x — surfaces ERR_PROVIDER_DUPLICATE_ID at compose time.
|
|
96
|
+
"duplicate-x-clone": _noop_provider("duplicate-x"),
|
|
97
|
+
"depends-on-missing": _noop_provider("depends-on-missing", "does-not-exist"),
|
|
98
|
+
"cycle-a": _noop_provider("cycle-a", "cycle-b"),
|
|
99
|
+
"cycle-b": _noop_provider("cycle-b", "cycle-a"),
|
|
100
|
+
"attr-conflict-base": _attr_conflict_base_provider(),
|
|
101
|
+
"attr-conflict-clash": _AttrConflictClashProvider(),
|
|
102
|
+
"seal-probe": _SealProbeProvider(),
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _resolve(providers: dict[str, Provider], pid: str) -> Provider:
|
|
107
|
+
p = providers.get(pid)
|
|
108
|
+
if p is None:
|
|
109
|
+
raise ValueError(f'Unknown named provider "{pid}" in provider-composition corpus')
|
|
110
|
+
return p
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _manifest_files() -> list[Path]:
|
|
114
|
+
return sorted(_corpus_root().glob("*.json"))
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _error_code(exc: BaseException) -> str:
|
|
118
|
+
code = getattr(exc, "code", None)
|
|
119
|
+
if isinstance(code, ErrorCode):
|
|
120
|
+
return code.value
|
|
121
|
+
if isinstance(code, str):
|
|
122
|
+
return code
|
|
123
|
+
return "ERR_UNKNOWN"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_corpus_non_empty() -> None:
|
|
127
|
+
assert len(_manifest_files()) > 0
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@pytest.mark.parametrize("manifest_path", _manifest_files(), ids=lambda p: p.name)
|
|
131
|
+
def test_provider_composition(manifest_path: Path) -> None:
|
|
132
|
+
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
|
133
|
+
providers = _providers()
|
|
134
|
+
expected = manifest["expectedError"]
|
|
135
|
+
resolved = [_resolve(providers, pid) for pid in manifest["providers"]]
|
|
136
|
+
|
|
137
|
+
if "sealThenRegister" in manifest:
|
|
138
|
+
# Compose (must succeed), seal, then run the probe against the sealed registry.
|
|
139
|
+
registry = compose_registry(resolved)
|
|
140
|
+
registry.seal()
|
|
141
|
+
probe = _resolve(providers, manifest["sealThenRegister"])
|
|
142
|
+
with pytest.raises(ParseError) as exc_info:
|
|
143
|
+
probe.register_types(registry)
|
|
144
|
+
assert _error_code(exc_info.value) == expected
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
# Ordinary scenario: the compose call itself throws.
|
|
148
|
+
with pytest.raises(ParseError) as exc_info:
|
|
149
|
+
compose_registry(resolved)
|
|
150
|
+
assert _error_code(exc_info.value) == expected
|
|
@@ -1,17 +1,31 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
"""Obtain a fresh, isolated Postgres database per scenario.
|
|
2
|
+
|
|
3
|
+
Two modes, mirroring the TS/Java/Kotlin/C# integration suites:
|
|
4
|
+
|
|
5
|
+
1. Shared sidecar (CI): if ``METAOBJECTS_TEST_PG_URL`` is set, connect to that
|
|
6
|
+
already-running Postgres and CREATE a uniquely-named database per instance
|
|
7
|
+
(dropping it on stop). No container boot / image pull on the hot path — the
|
|
8
|
+
point of the shared ``services: postgres`` CI sidecar. Each scenario still
|
|
9
|
+
gets a pristine empty database, so isolation is identical to the per-
|
|
10
|
+
container path.
|
|
11
|
+
2. Per-container (local dev): with no env var, ``docker run`` a fresh container,
|
|
12
|
+
exactly as before. Avoids the python-testcontainers package + its docker API
|
|
13
|
+
negotiation churn (the same kind of mismatch testcontainers-java hits
|
|
14
|
+
against Docker Engine 29+).
|
|
6
15
|
"""
|
|
7
16
|
from __future__ import annotations
|
|
8
17
|
|
|
18
|
+
import os
|
|
9
19
|
import socket
|
|
10
20
|
import subprocess
|
|
11
21
|
import time
|
|
12
22
|
import uuid
|
|
13
23
|
from contextlib import closing
|
|
14
24
|
from dataclasses import dataclass
|
|
25
|
+
from urllib.parse import urlsplit
|
|
26
|
+
|
|
27
|
+
# Env var naming the shared CI Postgres sidecar (admin URL). Unset = per-container.
|
|
28
|
+
SHARED_PG_URL_ENV = "METAOBJECTS_TEST_PG_URL"
|
|
15
29
|
|
|
16
30
|
|
|
17
31
|
@dataclass(frozen=True)
|
|
@@ -33,8 +47,21 @@ class PostgresContainer:
|
|
|
33
47
|
DATABASE = "postgres"
|
|
34
48
|
|
|
35
49
|
def __init__(self) -> None:
|
|
50
|
+
shared = os.environ.get(SHARED_PG_URL_ENV)
|
|
51
|
+
if shared:
|
|
52
|
+
self._shared = True
|
|
53
|
+
self._name = None
|
|
54
|
+
self._db_on_shared(shared)
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
self._shared = False
|
|
58
|
+
self._admin_url = None
|
|
36
59
|
self._name = f"metaobjects-test-{uuid.uuid4().hex[:8]}"
|
|
37
60
|
self._port = _pick_free_port()
|
|
61
|
+
self._info = PostgresInfo(
|
|
62
|
+
host="localhost", port=self._port, database=self.DATABASE,
|
|
63
|
+
user=self.USER, password=self.PASSWORD,
|
|
64
|
+
)
|
|
38
65
|
_docker(
|
|
39
66
|
"run", "-d", "--rm",
|
|
40
67
|
"--name", self._name,
|
|
@@ -44,13 +71,55 @@ class PostgresContainer:
|
|
|
44
71
|
)
|
|
45
72
|
self._wait_ready()
|
|
46
73
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
74
|
+
# -- Shared-sidecar mode -------------------------------------------------
|
|
75
|
+
# CREATE a fresh, uniquely-named database on the already-running Postgres
|
|
76
|
+
# named by the admin URL; a dedicated database per scenario preserves the
|
|
77
|
+
# per-container path's "pristine empty DB" isolation.
|
|
78
|
+
def _db_on_shared(self, admin_url: str) -> None:
|
|
79
|
+
import pg8000.dbapi # local import — pg8000 lives in the `integration` extra
|
|
80
|
+
|
|
81
|
+
parts = urlsplit(admin_url)
|
|
82
|
+
self._admin_url = admin_url
|
|
83
|
+
db_name = f"mo_test_{uuid.uuid4().hex}"
|
|
84
|
+
admin_db = parts.path.lstrip("/") or "postgres"
|
|
85
|
+
conn = pg8000.dbapi.connect(
|
|
86
|
+
host=parts.hostname, port=parts.port or 5432,
|
|
87
|
+
user=parts.username, password=parts.password, database=admin_db,
|
|
51
88
|
)
|
|
89
|
+
try:
|
|
90
|
+
conn.autocommit = True # CREATE DATABASE cannot run in a transaction
|
|
91
|
+
cur = conn.cursor()
|
|
92
|
+
cur.execute(f'CREATE DATABASE "{db_name}"') # generated name — no user input
|
|
93
|
+
finally:
|
|
94
|
+
conn.close()
|
|
95
|
+
self._info = PostgresInfo(
|
|
96
|
+
host=parts.hostname, port=parts.port or 5432, database=db_name,
|
|
97
|
+
user=parts.username, password=parts.password,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def info(self) -> PostgresInfo:
|
|
101
|
+
return self._info
|
|
52
102
|
|
|
53
103
|
def stop(self) -> None:
|
|
104
|
+
if self._shared:
|
|
105
|
+
import pg8000.dbapi
|
|
106
|
+
|
|
107
|
+
parts = urlsplit(self._admin_url)
|
|
108
|
+
admin_db = parts.path.lstrip("/") or "postgres"
|
|
109
|
+
try:
|
|
110
|
+
conn = pg8000.dbapi.connect(
|
|
111
|
+
host=parts.hostname, port=parts.port or 5432,
|
|
112
|
+
user=parts.username, password=parts.password, database=admin_db,
|
|
113
|
+
)
|
|
114
|
+
conn.autocommit = True
|
|
115
|
+
cur = conn.cursor()
|
|
116
|
+
cur.execute(
|
|
117
|
+
f'DROP DATABASE IF EXISTS "{self._info.database}" WITH (FORCE)'
|
|
118
|
+
)
|
|
119
|
+
conn.close()
|
|
120
|
+
except Exception: # noqa: BLE001 — best-effort cleanup
|
|
121
|
+
pass
|
|
122
|
+
return
|
|
54
123
|
try:
|
|
55
124
|
_docker("rm", "-f", self._name)
|
|
56
125
|
except subprocess.CalledProcessError:
|
|
@@ -12,6 +12,7 @@ from metaobjects.registry import TypeRegistry
|
|
|
12
12
|
from metaobjects.shared.base_types import (
|
|
13
13
|
SUBTYPE_ROOT,
|
|
14
14
|
TYPE_FIELD,
|
|
15
|
+
TYPE_IDENTITY,
|
|
15
16
|
TYPE_METADATA,
|
|
16
17
|
TYPE_OBJECT,
|
|
17
18
|
TYPE_ORIGIN,
|
|
@@ -119,6 +120,69 @@ def _build_passthrough_tree(from_ref: str) -> MetaData:
|
|
|
119
120
|
return root
|
|
120
121
|
|
|
121
122
|
|
|
123
|
+
def _build_reference_via_tree(via: str) -> MetaData:
|
|
124
|
+
"""Build a tree whose projection passthrough joins via an identity.reference
|
|
125
|
+
(a reference-only FK, no relationship) — FR-024 @via-over-reference.
|
|
126
|
+
- Program (id, title)
|
|
127
|
+
- Enrollment (id, programId, identity.reference ref_program → Program)
|
|
128
|
+
- EnrollmentView (extends Enrollment) passthrough Program.title @via *via*
|
|
129
|
+
"""
|
|
130
|
+
from metaobjects.meta.core.field.meta_field import MetaField
|
|
131
|
+
from metaobjects.meta.core.object.meta_object import MetaObject
|
|
132
|
+
|
|
133
|
+
root = MetaRoot(TYPE_METADATA, SUBTYPE_ROOT, "")
|
|
134
|
+
|
|
135
|
+
program = MetaObject(TYPE_OBJECT, "entity", "Program")
|
|
136
|
+
program.add_child(MetaField(TYPE_FIELD, "long", "id"))
|
|
137
|
+
program.add_child(MetaField(TYPE_FIELD, "string", "title"))
|
|
138
|
+
root.add_child(program)
|
|
139
|
+
|
|
140
|
+
enrollment = MetaObject(TYPE_OBJECT, "entity", "Enrollment")
|
|
141
|
+
enrollment.add_child(MetaField(TYPE_FIELD, "long", "id"))
|
|
142
|
+
enrollment.add_child(MetaField(TYPE_FIELD, "long", "programId"))
|
|
143
|
+
ref = MetaData(TYPE_IDENTITY, "reference", "ref_program")
|
|
144
|
+
ref.set_attr("fields", "programId", ATTR_SUBTYPE_STRING)
|
|
145
|
+
ref.set_attr("references", "Program", ATTR_SUBTYPE_STRING)
|
|
146
|
+
enrollment.add_child(ref)
|
|
147
|
+
root.add_child(enrollment)
|
|
148
|
+
|
|
149
|
+
view = MetaObject(TYPE_OBJECT, "entity", "EnrollmentView")
|
|
150
|
+
view.super_ref = "Enrollment"
|
|
151
|
+
view.super_data = enrollment
|
|
152
|
+
field = MetaField(TYPE_FIELD, "string", "program_title")
|
|
153
|
+
origin = MetaData(TYPE_ORIGIN, "passthrough", "")
|
|
154
|
+
origin.set_attr("from", "Program.title", ATTR_SUBTYPE_STRING)
|
|
155
|
+
origin.set_attr("via", via, ATTR_SUBTYPE_STRING)
|
|
156
|
+
field.add_child(origin)
|
|
157
|
+
view.add_child(field)
|
|
158
|
+
root.add_child(view)
|
|
159
|
+
|
|
160
|
+
return root
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _via_errors(root: MetaData) -> list[str]:
|
|
164
|
+
"""ERR_INVALID_ORIGIN messages that mention the @via path (ignores unrelated passes)."""
|
|
165
|
+
errors, _ = _errors_and_warnings(root)
|
|
166
|
+
return [
|
|
167
|
+
e.message
|
|
168
|
+
for e in errors
|
|
169
|
+
if e.code == ErrorCode.ERR_INVALID_ORIGIN and "@via" in e.message
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def test_valid_passthrough_via_reference_no_error() -> None:
|
|
174
|
+
"""@via naming an identity.reference (reference-only FK) resolves — no origin error."""
|
|
175
|
+
root = _build_reference_via_tree(via="Enrollment.ref_program")
|
|
176
|
+
assert _via_errors(root) == []
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def test_invalid_passthrough_via_bad_reference() -> None:
|
|
180
|
+
"""@via naming neither a relationship nor a reference → ERR_INVALID_ORIGIN."""
|
|
181
|
+
root = _build_reference_via_tree(via="Enrollment.bogus")
|
|
182
|
+
msgs = _via_errors(root)
|
|
183
|
+
assert any("bogus" in m and "no relationship or reference" in m for m in msgs), msgs
|
|
184
|
+
|
|
185
|
+
|
|
122
186
|
# ---------------------------------------------------------------------------
|
|
123
187
|
# Tests: origin.aggregate @via validation
|
|
124
188
|
# ---------------------------------------------------------------------------
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/extract_delegate_emitter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/entity_model.py
RENAMED
|
File without changes
|
{metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/extractor_generator.py
RENAMED
|
File without changes
|
|
File without changes
|
{metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/fr019_shared_enum.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/payload_vo_generator.py
RENAMED
|
File without changes
|
|
File without changes
|
{metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/router_generator.py
RENAMED
|
File without changes
|
{metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/generators/template_generator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{metaobjects-0.15.2 → metaobjects-0.15.4}/src/metaobjects/codegen/output_format_spec_emitter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|