metaobjects 0.23.1__tar.gz → 0.23.2__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.23.1 → metaobjects-0.23.2}/PKG-INFO +1 -1
- {metaobjects-0.23.1 → metaobjects-0.23.2}/pyproject.toml +1 -1
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +39 -4
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/core_types.py +13 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/errors.py +6 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/validation_passes.py +215 -14
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/attr/attr_constants.py +8 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/attr/meta_attr.py +17 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/field/field_constants.py +7 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/runtime/object_manager.py +94 -6
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/attr.json +6 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/field.json +2 -1
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/capabilities.py +7 -3
- metaobjects-0.23.2/tests/runtime/test_object_manager_enum_intvaluemap.py +192 -0
- metaobjects-0.23.2/tests/unit/test_field_enum_intvaluemap.py +185 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/uv.lock +1 -1
- {metaobjects-0.23.1 → metaobjects-0.23.2}/.gitignore +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/LICENSE +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/README.md +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/hatch_build.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/agent_context/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/agent_context/scaffold.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/apidocs/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/apidocs/api_model.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/apidocs/builder.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/apidocs/naming.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/apidocs/paths.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/apidocs/renderer.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/attr_class_map.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/cli.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/collision_names.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/config.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/format.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generator_registry.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/entity_model.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/payload_vo_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/router_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/template_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/instance_artifacts.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/overwrite_policy.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/project_config.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/runner.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/runtime/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/codegen/type_map.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/datatype.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/documentation/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/documentation/doc_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/documentation/doc_provider.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/documentation/doc_schema.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/merge.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/meta_data_loader.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/registered_validation.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/sources/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/sources/directory_source.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/sources/file_source.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/sources/uri_source.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/validate_discriminator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/validate_field_readonly.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/validate_source_escapes.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/attr/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/field/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/field/meta_field.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/identity/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/index/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/index/index_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/index/meta_index.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/meta_object.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/object_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/object_extract.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/value_object.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/validator/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/meta_data.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/meta_root.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/provider_extends.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/template/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/template/meta_template.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/template/prompt_provider.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/template/template_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/naming_refs.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/parser.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/parser_yaml.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/provider.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/py.typed +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/registry.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/registry_manifest.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/email_document.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/escapers.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/extract/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/extract/coerce.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/extract/extract.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/extract/extract_map.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/extract/locate.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/extract/normalize.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/extract/strip.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/extract/types.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/filesystem_provider.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/payload_accessors.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/prompt/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/prompt/prompt_field.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/prompt/prompt_style.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/renderer.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/render/verify.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/runtime/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/runtime/llm_recorder.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/runtime/n2m_resolver.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/runtime/tph.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/serializer_json.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/shared/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/shared/base_types.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/shared/separators.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/shared/structural.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/source/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/source/error_source.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/source/json_path.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/source/semantic_diff.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/source/yaml_positions.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/db.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/documentation.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/identity.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/index.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/layout.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/object.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/origin.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/prompt.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/relationship.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/requirement.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/source.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/template.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/ui.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/validator.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/view.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/super_resolve.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/validation_types.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/yaml_desugar.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/golden/extends/expected/Program.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/golden/extends/meta.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/golden/nested-array/meta.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/golden/scalars/expected/Report.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/golden/scalars/meta.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/golden/vanilla/meta.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_abstract_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_api_docs_builder.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_api_docs_paths.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_cli.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_cli_config_gen.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_cli_config_verify.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_cli_providers.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_cli_registry.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_cli_staleness_nudge.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_cli_verify_strict.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_cli_verify_subverbs.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_constants_config.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_entity_model.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_enum_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_extract_tier_collision.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_extractor_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_filter_allowlist_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_format.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_fr010_output_codegen.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_generator_extension_seams.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_golden.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_inheritance_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_instance_artifacts.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_m2m_codegen.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_origin_nullability.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_output_parser_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_overwrite_policy.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_payload_vo_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_project_config.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_projection_compile.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_render_helper_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_render_helper_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_reverse_finders.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_router_autoset.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_router_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_runner.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_sourceless_projection.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_template_data.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_template_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_template_output_pattern.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_template_scope_helpers.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_template_scope_walk.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_template_spec.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_tph_codegen.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_trace_helper_generator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_type_map.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_validation_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/codegen/test_write_through.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/conformance-expected-failures.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/conformance_adapter.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/corpus.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/expected_failures.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/fixture_discovery.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/navigator.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_extract_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_extract_object_verdict.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_fr010_loader_attrs.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_fr011_attrs.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_generator_registry_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_object_model_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_provider_composition_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_registry_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_runner_hardfail.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_spec_metamodel_embed.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_strict_attr_load.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_template_codegen_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_template_generator_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/test_yaml_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/api_contract_assertions.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/api_contract_jsonb_server.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/api_contract_m2m_server.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/api_contract_server.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/generated_jsonb_app.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/generated_m2m_app.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/generated_router_app.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/generated_tph_app.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/meta_ai_trace.yaml +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/normalization.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/postgres_container.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/query_runner.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/scenarios.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/test_api_contract.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/test_api_contract_generated.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/test_api_contract_jsonb.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/test_api_contract_m2m.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/test_api_contract_m2m_generated.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/test_api_contract_tph_generated.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/test_generated_router_uuid_pk.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/test_llm_call_trace.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/test_normalization.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/test_query_scenarios.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/integration/test_runtime_return_types.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/loader/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/loader/test_enum_extends_values_conflict.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/loader/test_template_payload_target_210.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/open_closed_proof_test.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/extract/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/extract/test_coerce.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/extract/test_extract.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/extract/test_extract_map.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/extract/test_json_forgiving_reader.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/extract/test_locate.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/extract/test_model.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/extract/test_normalize.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/extract/test_strip.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/prompt/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/prompt/test_output_format_renderer.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/test_email_document.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/test_filesystem_provider.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/test_output_format_renderer_nested.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/test_output_prompt_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/test_render_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/test_render_max_chars.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/test_verify.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/render/test_verify_conformance.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/source/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/source/test_fr5c_merge_attribution.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/source/test_fr5d_reference_resolution.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/source/test_fr5e_database_source_shape.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/source/test_json_path.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/source/test_semantic_diff.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/source/test_source_on_node.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/source/test_yaml_positions.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/test_api_docs_accuracy.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/__init__.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_agent_context_staleness.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_capabilities.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_common_attrs.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_core_types.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_effective_package.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_errors.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_field_enum.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_field_map_validation.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_index_lookup.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_llm_recorder.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_loader.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_loader_bom.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_loader_class.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_merge.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_meta_attr.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_meta_data.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_meta_source.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_module_shortcuts.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_n2m_resolver.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_n2m_resolver_inherited.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_object_manager_write_through.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_one_primary_source.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_parser.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_parser_yaml.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_provider.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_provider_extension.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_registry.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_registry_completeness.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_registry_extend.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_registry_sealed.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_relationship_referential_actions.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_resolution_key.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_serializer.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_shared_constants.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_smoke.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_source_escapes.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_sources.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_strict_child_placement.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_super_resolve.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_template_toolcall.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_validation_attr_schema.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_validation_filter_values.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_validation_origin_195.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_validation_origin_paths.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_validation_sort_field.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_validation_warnings.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_write_coercion_arrays.py +0 -0
- {metaobjects-0.23.1 → metaobjects-0.23.2}/tests/unit/test_yaml_desugar.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: metaobjects
|
|
3
|
-
Version: 0.23.
|
|
3
|
+
Version: 0.23.2
|
|
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.23.
|
|
3
|
+
version = "0.23.2"
|
|
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"
|
|
@@ -53,6 +53,11 @@ _OPS_STRING: tuple[str, ...] = ("eq", "ne", "in", "like", "isNull")
|
|
|
53
53
|
# uuid: identity-comparison only — no `like` (not a substring type), no ordering.
|
|
54
54
|
_OPS_UUID: tuple[str, ...] = ("eq", "ne", "in", "isNull")
|
|
55
55
|
_OPS_NUMERIC: tuple[str, ...] = ("eq", "ne", "gt", "gte", "lt", "lte", "in", "isNull")
|
|
56
|
+
# int-backed enum (@intValueMap, design D5): the enum band minus `like` — the column
|
|
57
|
+
# is an integer, and a substring match against an integer is meaningless. Distinct
|
|
58
|
+
# constant from _OPS_UUID despite the identical members: they narrow for different
|
|
59
|
+
# reasons and would diverge independently.
|
|
60
|
+
_OPS_ENUM_INT_BACKED: tuple[str, ...] = ("eq", "ne", "in", "isNull")
|
|
56
61
|
_OPS_BOOLEAN: tuple[str, ...] = ("eq", "isNull")
|
|
57
62
|
|
|
58
63
|
|
|
@@ -118,6 +123,36 @@ def ops_for_subtype_ordered(sub_type: str | None) -> tuple[str, ...]:
|
|
|
118
123
|
return ()
|
|
119
124
|
|
|
120
125
|
|
|
126
|
+
def ops_for_field_ordered(field: MetaField) -> tuple[str, ...]:
|
|
127
|
+
"""The operator tuple for a FIELD, in canonical operator order.
|
|
128
|
+
|
|
129
|
+
The ordered counterpart of ``validation_passes.ops_for_field``, and the entry
|
|
130
|
+
point for every consumer that has a field in hand: the codegen allowlist emit
|
|
131
|
+
and the cross-port ``field.filter-ops`` conformance capability.
|
|
132
|
+
|
|
133
|
+
Identical to :func:`ops_for_subtype_ordered` except for ONE case: an int-backed
|
|
134
|
+
``field.enum`` (one declaring ``@intValueMap``, design D5) persists as an INTEGER
|
|
135
|
+
column, so ``like`` -- a substring match -- is dropped. ``eq``/``ne``/``in``
|
|
136
|
+
survive because the member symbol encodes to its integer before it reaches SQL;
|
|
137
|
+
``like`` has no such encoding, and an unencoded ``LIKE 'DRAFT'`` against an integer
|
|
138
|
+
column is a request-time type error.
|
|
139
|
+
|
|
140
|
+
ADR-0039: the ``@intValueMap`` read is RESOLVING (``attrs()``, NOT ``attr()`` --
|
|
141
|
+
Python inverts the TS naming, ``attr()`` here is own-only). Post-#246 the map lives
|
|
142
|
+
on a shared root-level abstract declaration and consuming fields INHERIT it, so an
|
|
143
|
+
own-only read would see it absent on exactly the shape adopters are steered toward
|
|
144
|
+
and wrongly keep ``like``.
|
|
145
|
+
|
|
146
|
+
Cross-port: ``fixtures/conformance/filter-ops-matrix`` pins ``fEnum`` vs
|
|
147
|
+
``fEnumInt`` in all five ports.
|
|
148
|
+
"""
|
|
149
|
+
if field.sub_type == fc.FIELD_SUBTYPE_ENUM and isinstance(
|
|
150
|
+
field.attrs().get(fc.FIELD_ATTR_INT_VALUE_MAP), dict
|
|
151
|
+
):
|
|
152
|
+
return _OPS_ENUM_INT_BACKED
|
|
153
|
+
return ops_for_subtype_ordered(field.sub_type)
|
|
154
|
+
|
|
155
|
+
|
|
121
156
|
def _is_filterable(field: MetaField) -> bool:
|
|
122
157
|
"""True iff ``field`` carries ``@filterable: true`` as a metadata attribute.
|
|
123
158
|
|
|
@@ -166,10 +201,10 @@ class FilterAllowlistGenerator:
|
|
|
166
201
|
name = "filter-allowlist-generator"
|
|
167
202
|
|
|
168
203
|
def _ops_for_field(self, field: MetaField) -> tuple[str, ...]:
|
|
169
|
-
"""The operator tuple allowed for ``field`` (FR-009 §5
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return
|
|
204
|
+
"""The operator tuple allowed for ``field`` (FR-009 §5 matrix by default).
|
|
205
|
+
Override to customize the per-field operator vocabulary; returning an empty
|
|
206
|
+
tuple excludes the field from the allowlist."""
|
|
207
|
+
return ops_for_field_ordered(field)
|
|
173
208
|
|
|
174
209
|
def _compute_filterable_ops(
|
|
175
210
|
self, entity: MetaObject, object_index: dict[str, MetaObject] | None = None
|
|
@@ -9,6 +9,7 @@ from .meta.core.attr.attr_constants import (
|
|
|
9
9
|
ATTR_SUBTYPE_EXPRESSION,
|
|
10
10
|
ATTR_SUBTYPE_FILTER,
|
|
11
11
|
ATTR_SUBTYPE_INT,
|
|
12
|
+
ATTR_SUBTYPE_INT_MAP,
|
|
12
13
|
ATTR_SUBTYPE_STRING,
|
|
13
14
|
ATTR_SUBTYPES,
|
|
14
15
|
)
|
|
@@ -19,6 +20,7 @@ from .meta.core.field.field_constants import (
|
|
|
19
20
|
FIELD_ATTR_AUTO_SET,
|
|
20
21
|
FIELD_ATTR_CURRENCY,
|
|
21
22
|
FIELD_ATTR_DEFAULT,
|
|
23
|
+
FIELD_ATTR_INT_VALUE_MAP,
|
|
22
24
|
FIELD_ATTR_PROVIDED,
|
|
23
25
|
FIELD_ATTR_MAX_LENGTH,
|
|
24
26
|
FIELD_ATTR_OBJECT_REF,
|
|
@@ -472,6 +474,17 @@ core_provider.add(
|
|
|
472
474
|
value_type=ATTR_SUBTYPE_BOOLEAN,
|
|
473
475
|
required=False,
|
|
474
476
|
),
|
|
477
|
+
# int-backed-enum-values plan — @intValueMap: optional per-member int
|
|
478
|
+
# values ({member: int}) switching this enum field's DB persistence
|
|
479
|
+
# from string+CHECK to integer+CHECK. Keys must exactly match @values;
|
|
480
|
+
# values must be unique integers (enforced in _validate_enum_values,
|
|
481
|
+
# Rule 4). Structural (core), like @values / @provided — not a
|
|
482
|
+
# TS-web-only / prompt-domain overlay.
|
|
483
|
+
AttrSchema(
|
|
484
|
+
name=FIELD_ATTR_INT_VALUE_MAP,
|
|
485
|
+
value_type=ATTR_SUBTYPE_INT_MAP,
|
|
486
|
+
required=False,
|
|
487
|
+
),
|
|
475
488
|
# FR-033 — the field.enum tolerant-extract overlays (@enumAlias / @enumDoc /
|
|
476
489
|
# @coerceDefault / @normalize) are NO LONGER declared here; they are re-homed
|
|
477
490
|
# to the prompt domain provider (`prompt_provider`, metaobjects-prompt) via
|
|
@@ -194,6 +194,12 @@ class ErrorCode(str, Enum):
|
|
|
194
194
|
# own @values would be silently dropped in codegen. Remove the own @values
|
|
195
195
|
# to inherit the shared set, or extend a concrete (non-shared) enum instead.
|
|
196
196
|
ERR_ENUM_EXTENDS_VALUES_CONFLICT = "ERR_ENUM_EXTENDS_VALUES_CONFLICT"
|
|
197
|
+
# A field.enum carries @intValueMap together with isArray=true. Int-backing is
|
|
198
|
+
# a persistence-layer codec and no port implements it element-wise over an
|
|
199
|
+
# array column, so the combination would silently persist member SYMBOLS into
|
|
200
|
+
# an integer array. An array-of-enum stays string-backed: drop @intValueMap,
|
|
201
|
+
# or make the field scalar.
|
|
202
|
+
ERR_ENUM_INT_VALUE_MAP_ARRAY = "ERR_ENUM_INT_VALUE_MAP_ARRAY"
|
|
197
203
|
ERR_UNKNOWN = "ERR_UNKNOWN"
|
|
198
204
|
|
|
199
205
|
|
|
@@ -23,6 +23,7 @@ from ..meta.core.field.field_constants import (
|
|
|
23
23
|
ENUM_MEMBER_PATTERN,
|
|
24
24
|
FIELD_ATTR_COERCE_DEFAULT,
|
|
25
25
|
FIELD_ATTR_DEFAULT,
|
|
26
|
+
FIELD_ATTR_INT_VALUE_MAP,
|
|
26
27
|
FIELD_ATTR_OBJECT_REF,
|
|
27
28
|
FIELD_ATTR_REQUIRED,
|
|
28
29
|
FIELD_ATTR_STORAGE,
|
|
@@ -60,6 +61,7 @@ from ..meta.persistence.source.source_constants import (
|
|
|
60
61
|
SOURCE_ROLE_PRIMARY,
|
|
61
62
|
)
|
|
62
63
|
from ..meta.core.attr.attr_constants import (
|
|
64
|
+
ATTR_SUBTYPE_INT_MAP,
|
|
63
65
|
ATTR_SUBTYPE_PROPERTIES,
|
|
64
66
|
ATTR_SUBTYPE_STRINGARRAY,
|
|
65
67
|
)
|
|
@@ -281,6 +283,26 @@ def _type_ok(value: object, value_type: str) -> bool:
|
|
|
281
283
|
# fails here → ERR_BAD_ATTR_VALUE, matching TS + Java (fail-closed); an object
|
|
282
284
|
# @expr then flows to the closed-grammar check in the origin pass.
|
|
283
285
|
return isinstance(value, dict)
|
|
286
|
+
if value_type == ATTR_SUBTYPE_INT_MAP:
|
|
287
|
+
# attr.intMap (int-backed-enum-values plan): an object whose every member
|
|
288
|
+
# value is an integer (e.g. field.enum's @intValueMap). This port has no
|
|
289
|
+
# per-attr-class validateValue dispatch (that's TS's architecture); the
|
|
290
|
+
# generic shape check lives here, mirroring C#'s ValueMatchesType
|
|
291
|
+
# ATTR_SUBTYPE_INT_MAP case. field.enum's own key-set/uniqueness content
|
|
292
|
+
# rules run separately in _validate_enum_values (Rule 4), which skips
|
|
293
|
+
# re-reporting a non-integer member already caught here.
|
|
294
|
+
#
|
|
295
|
+
# Final-review fix: also bound every value to the 32-bit signed int range
|
|
296
|
+
# (inclusive) — the eventual DB column for an int-backed enum is a 32-bit
|
|
297
|
+
# Postgres/SQLite `integer` (design doc D5), matching Java's
|
|
298
|
+
# IntMapAttribute#setValueAsString bound check exactly. Python ints have
|
|
299
|
+
# no fixed width, so this is the only place that boundary is enforced.
|
|
300
|
+
return isinstance(value, dict) and all(
|
|
301
|
+
isinstance(v, int)
|
|
302
|
+
and not isinstance(v, bool)
|
|
303
|
+
and -2147483648 <= v <= 2147483647
|
|
304
|
+
for v in value.values()
|
|
305
|
+
)
|
|
284
306
|
# Unknown value types (e.g. "class") — allow anything.
|
|
285
307
|
return True
|
|
286
308
|
|
|
@@ -544,6 +566,32 @@ def _validate_attr_schema(
|
|
|
544
566
|
_ENUM_MEMBER_RE = re.compile(ENUM_MEMBER_PATTERN)
|
|
545
567
|
|
|
546
568
|
|
|
569
|
+
def _shared_enum_super(node: MetaData) -> MetaData | None:
|
|
570
|
+
"""The shared-enum super of ``node``, or ``None`` when it has none.
|
|
571
|
+
|
|
572
|
+
"Shared" (FR-019 / #246) means the immediate super is abstract AND declared at
|
|
573
|
+
metadata-root — its parent is the ``metadata.root`` node, not an object. Such a
|
|
574
|
+
declaration is materialized ONCE per port as a single named type, so anything a
|
|
575
|
+
consuming field re-declares that belongs to the shared TYPE's contract (its
|
|
576
|
+
``@values`` member set, or the ``@intValueMap`` integer backing of that set) is a
|
|
577
|
+
conflict. A concrete super, or a non-root abstract super (e.g. one nested inside
|
|
578
|
+
an object), is legal and not flagged.
|
|
579
|
+
|
|
580
|
+
Immediate-super-only, matching codegen's ``resolve_shared_enum_decl``
|
|
581
|
+
(``codegen/generators/fr019_shared_enum.py``) so the validator and the
|
|
582
|
+
shared-enum collapse agree on what "shared" means.
|
|
583
|
+
"""
|
|
584
|
+
sup = node.super_data
|
|
585
|
+
if (
|
|
586
|
+
sup is not None
|
|
587
|
+
and sup.is_abstract
|
|
588
|
+
and sup.parent is not None
|
|
589
|
+
and sup.parent.type == TYPE_METADATA
|
|
590
|
+
):
|
|
591
|
+
return sup
|
|
592
|
+
return None
|
|
593
|
+
|
|
594
|
+
|
|
547
595
|
def _validate_enum_values(
|
|
548
596
|
root: MetaData,
|
|
549
597
|
errors: list[MetaError],
|
|
@@ -556,6 +604,21 @@ def _validate_enum_values(
|
|
|
556
604
|
# @coerceDefault / @default / @normalize while inheriting @values).
|
|
557
605
|
_validate_enum_fr011_attrs(node, errors)
|
|
558
606
|
|
|
607
|
+
# Rule 4 (@intValueMap content rules) is independent of whether @values is
|
|
608
|
+
# own or inherited on THIS node — it must run whenever this node owns
|
|
609
|
+
# @intValueMap, using the EFFECTIVE @values (own-or-inherited) as the
|
|
610
|
+
# membership set. Mirrors TS/C#/Java, which all check this unconditionally
|
|
611
|
+
# (Java's `validateEnumIntValueMap` is a standalone call at the top of
|
|
612
|
+
# `validateEnumNode`). Deliberately called BEFORE the `own_values is None:
|
|
613
|
+
# continue` gate below so a concrete field.enum that inherits @values via
|
|
614
|
+
# `extends` but declares its own @intValueMap is still validated.
|
|
615
|
+
_validate_enum_int_value_map(node, errors)
|
|
616
|
+
|
|
617
|
+
# Design D7, narrowed: int-backing is scalar-only. Separate from the content
|
|
618
|
+
# rules above because it must fire on the node that combines the two halves,
|
|
619
|
+
# which is NOT necessarily the node that declares the map.
|
|
620
|
+
_validate_enum_int_value_map_not_array(node, errors)
|
|
621
|
+
|
|
559
622
|
# ADR-0039 sanctioned own: validates the AUTHORED @values membership on THIS
|
|
560
623
|
# node (mirrors the TS attr-schema-validate `node.ownAttrs()`); an inherited
|
|
561
624
|
# @values yields None here and is validated on its declaring node.
|
|
@@ -607,19 +670,9 @@ def _validate_enum_values(
|
|
|
607
670
|
|
|
608
671
|
# #246: own @values AND extends a shared package-level abstract enum —
|
|
609
672
|
# one shared enum type has one member set, so the own @values would be
|
|
610
|
-
# silently dropped by the shared-enum codegen collapse.
|
|
611
|
-
#
|
|
612
|
-
|
|
613
|
-
# concrete super, or a non-root abstract super (e.g. nested inside an
|
|
614
|
-
# object), is legal and not flagged. Mirrors the TS reference
|
|
615
|
-
# (attr-schema-validate.ts).
|
|
616
|
-
sup = node.super_data
|
|
617
|
-
if (
|
|
618
|
-
sup is not None
|
|
619
|
-
and sup.is_abstract
|
|
620
|
-
and sup.parent is not None
|
|
621
|
-
and sup.parent.type == TYPE_METADATA
|
|
622
|
-
):
|
|
673
|
+
# silently dropped by the shared-enum codegen collapse. Mirrors the TS
|
|
674
|
+
# reference (attr-schema-validate.ts).
|
|
675
|
+
if _shared_enum_super(node) is not None:
|
|
623
676
|
errors.append(
|
|
624
677
|
MetaError(
|
|
625
678
|
f"{label} declares its own '@{FIELD_ATTR_VALUES}' but extends "
|
|
@@ -633,6 +686,113 @@ def _validate_enum_values(
|
|
|
633
686
|
)
|
|
634
687
|
|
|
635
688
|
|
|
689
|
+
def _validate_enum_int_value_map_not_array(node: MetaData, errors: list[MetaError]) -> None:
|
|
690
|
+
"""``@intValueMap`` is scalar-only (design D7, narrowed).
|
|
691
|
+
|
|
692
|
+
Int-backing is a persistence-layer CODEC, and no port implements it
|
|
693
|
+
element-wise over an array column: this port's ``ObjectManager`` would bind the
|
|
694
|
+
symbol LIST straight into an ``integer[]``, OMDB's ``EnumCodec`` and Kotlin's
|
|
695
|
+
``customEnumeration`` are scalar by construction, and TypeScript's sqlite branch
|
|
696
|
+
serializes an array as JSON text before the enum case is reached. Two ports that
|
|
697
|
+
happen to compose (TS/Postgres, C#) are not a feature — shipping a claim four
|
|
698
|
+
ports silently get wrong is the ``field.byte``/``short``/``class`` mistake.
|
|
699
|
+
|
|
700
|
+
BOTH halves are read RESOLVING, unlike the content rules: the illegal thing is
|
|
701
|
+
the EFFECTIVE combination. Post-#246 the map must live on the shared abstract
|
|
702
|
+
declaration, so the field that inherits it is exactly where ``isArray`` gets
|
|
703
|
+
declared — an own-only read would see the two halves on different nodes and
|
|
704
|
+
never fire.
|
|
705
|
+
"""
|
|
706
|
+
if not isinstance(node.get_meta_attr(FIELD_ATTR_INT_VALUE_MAP), dict):
|
|
707
|
+
return
|
|
708
|
+
if not node.resolved_is_array():
|
|
709
|
+
return
|
|
710
|
+
errors.append(
|
|
711
|
+
MetaError(
|
|
712
|
+
f"{_node_label(node)} declares '@{FIELD_ATTR_INT_VALUE_MAP}' with isArray=true; "
|
|
713
|
+
f"int-backing is scalar-only — an array-of-enum persists its member symbols. "
|
|
714
|
+
f"Remove '@{FIELD_ATTR_INT_VALUE_MAP}', or make the field scalar.",
|
|
715
|
+
ErrorCode.ERR_ENUM_INT_VALUE_MAP_ARRAY,
|
|
716
|
+
envelope=node.source,
|
|
717
|
+
)
|
|
718
|
+
)
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
def _validate_enum_int_value_map(node: MetaData, errors: list[MetaError]) -> None:
|
|
722
|
+
"""``@intValueMap`` content rules (optional), independent of whether ``@values``
|
|
723
|
+
is own or inherited on this node. Mirrors TS/C#/Java, which all run this check
|
|
724
|
+
unconditionally against the node's EFFECTIVE ``@values`` — a concrete
|
|
725
|
+
``field.enum`` that inherits ``@values`` via ``extends`` but declares its own
|
|
726
|
+
``@intValueMap`` locally must still have that map validated.
|
|
727
|
+
|
|
728
|
+
a. Key set must exactly match the EFFECTIVE ``@values`` (own or inherited).
|
|
729
|
+
b. No two members may share the same int (protobuf's stance — no alias
|
|
730
|
+
opt-in). Every-value-is-an-integer is already enforced by ``_type_ok``'s
|
|
731
|
+
ATTR_SUBTYPE_INT_MAP case at parse time.
|
|
732
|
+
"""
|
|
733
|
+
int_value_map = node.attr(FIELD_ATTR_INT_VALUE_MAP)
|
|
734
|
+
if not isinstance(int_value_map, dict):
|
|
735
|
+
return
|
|
736
|
+
|
|
737
|
+
label = _node_label(node)
|
|
738
|
+
|
|
739
|
+
# #246 (int-backed twin): the symbol->int mapping is a property of the enum
|
|
740
|
+
# VOCABULARY, not of one column that uses it -- it is @values' numeric half. A
|
|
741
|
+
# shared enum is materialized once as a single type, so a per-field map would
|
|
742
|
+
# give one logical type N storage encodings (and, where a port emits per-TYPE
|
|
743
|
+
# codec artifacts, two same-named declarations). Same remedy as the @values
|
|
744
|
+
# half: declare it on the shared declaration and inherit it.
|
|
745
|
+
shared_super = _shared_enum_super(node)
|
|
746
|
+
if shared_super is not None:
|
|
747
|
+
errors.append(
|
|
748
|
+
MetaError(
|
|
749
|
+
f"{label} declares its own '@{FIELD_ATTR_INT_VALUE_MAP}' but extends "
|
|
750
|
+
f"a shared package-level abstract enum — a shared enum's integer "
|
|
751
|
+
f"backing is owned by the shared declaration. Move "
|
|
752
|
+
f"'@{FIELD_ATTR_INT_VALUE_MAP}' onto the shared declaration to "
|
|
753
|
+
f"inherit it, or extend a concrete (non-shared) enum instead",
|
|
754
|
+
ErrorCode.ERR_ENUM_EXTENDS_VALUES_CONFLICT,
|
|
755
|
+
envelope=node.source,
|
|
756
|
+
)
|
|
757
|
+
)
|
|
758
|
+
effective_values = _effective_enum_values(node)
|
|
759
|
+
member_set = set(effective_values)
|
|
760
|
+
key_set = set(int_value_map.keys())
|
|
761
|
+
missing = [m for m in effective_values if m not in key_set]
|
|
762
|
+
extra = [k for k in int_value_map if k not in member_set]
|
|
763
|
+
if missing or extra:
|
|
764
|
+
parts = []
|
|
765
|
+
if missing:
|
|
766
|
+
parts.append(f"missing: {', '.join(missing)}")
|
|
767
|
+
if extra:
|
|
768
|
+
parts.append(f"unknown: {', '.join(extra)}")
|
|
769
|
+
errors.append(
|
|
770
|
+
MetaError(
|
|
771
|
+
f"{label} attribute '@{FIELD_ATTR_INT_VALUE_MAP}' keys must exactly match "
|
|
772
|
+
f"'@{FIELD_ATTR_VALUES}' members ({'; '.join(parts)}).",
|
|
773
|
+
ErrorCode.ERR_BAD_ATTR_VALUE,
|
|
774
|
+
envelope=node.source,
|
|
775
|
+
)
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
seen_values: dict[int, str] = {}
|
|
779
|
+
for member, value in int_value_map.items():
|
|
780
|
+
if not isinstance(value, int) or isinstance(value, bool):
|
|
781
|
+
continue # _type_ok already reported this
|
|
782
|
+
owner = seen_values.get(value)
|
|
783
|
+
if owner is not None:
|
|
784
|
+
errors.append(
|
|
785
|
+
MetaError(
|
|
786
|
+
f"{label} attribute '@{FIELD_ATTR_INT_VALUE_MAP}' members {owner!r} and {member!r} "
|
|
787
|
+
f"share the same value {value}; every member must have a unique int.",
|
|
788
|
+
ErrorCode.ERR_BAD_ATTR_VALUE,
|
|
789
|
+
envelope=node.source,
|
|
790
|
+
)
|
|
791
|
+
)
|
|
792
|
+
else:
|
|
793
|
+
seen_values[value] = member
|
|
794
|
+
|
|
795
|
+
|
|
636
796
|
def _effective_enum_values(node: MetaData) -> list[str]:
|
|
637
797
|
"""The effective ``@values`` members of an enum node (own or inherited via
|
|
638
798
|
``extends:``). Empty list when absent. Mirrors Java ``effectiveEnumValues``."""
|
|
@@ -913,6 +1073,45 @@ def ops_for_subtype(field_subtype: str) -> frozenset[str]:
|
|
|
913
1073
|
return frozenset()
|
|
914
1074
|
|
|
915
1075
|
|
|
1076
|
+
# The int-backed-enum band: the enum band minus `like`. Named so the narrowing is
|
|
1077
|
+
# one constant rather than a set rebuilt at every call.
|
|
1078
|
+
_OPS_ENUM_INT_BACKED: frozenset[str] = frozenset({"eq", "ne", "in", "isNull"})
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
def ops_for_field(field: MetaData) -> frozenset[str]:
|
|
1082
|
+
"""The filter-operator band for a FIELD.
|
|
1083
|
+
|
|
1084
|
+
The entry point every consumer that has a field in hand must use (loader
|
|
1085
|
+
validation, the codegen filter-allowlist generator, the cross-port
|
|
1086
|
+
``field.filter-ops`` capability).
|
|
1087
|
+
|
|
1088
|
+
Identical to :func:`ops_for_subtype` except for ONE case: an int-backed
|
|
1089
|
+
``field.enum`` (one declaring ``@intValueMap``, design D5) persists as an
|
|
1090
|
+
INTEGER column, so ``like`` -- a substring match -- is dropped.
|
|
1091
|
+
``eq``/``ne``/``in`` survive because the member symbol encodes to its integer
|
|
1092
|
+
before it reaches SQL; ``like`` has no such encoding, and an unencoded
|
|
1093
|
+
``LIKE 'DRAFT'`` against an integer column is a request-time type error.
|
|
1094
|
+
|
|
1095
|
+
``ops_for_subtype`` cannot express this -- it only ever sees the subtype
|
|
1096
|
+
``"enum"`` -- and is deliberately left unchanged for the one caller that
|
|
1097
|
+
genuinely has no field: the expression grammar's declared operand type.
|
|
1098
|
+
|
|
1099
|
+
ADR-0039: the ``@intValueMap`` read is RESOLVING (``attrs()``, NOT ``attr()``
|
|
1100
|
+
-- Python inverts the TS naming, ``attr()`` here is own-only). Post-#246 the
|
|
1101
|
+
map lives on a shared root-level abstract declaration and consuming fields
|
|
1102
|
+
INHERIT it, so an own-only read would see it absent on exactly the shape
|
|
1103
|
+
adopters are steered toward and wrongly keep ``like``.
|
|
1104
|
+
|
|
1105
|
+
Cross-port: ``fixtures/conformance/filter-ops-matrix`` pins ``fEnum`` vs
|
|
1106
|
+
``fEnumInt`` in all five ports.
|
|
1107
|
+
"""
|
|
1108
|
+
if field.sub_type == FIELD_SUBTYPE_ENUM and isinstance(
|
|
1109
|
+
field.attrs().get(FIELD_ATTR_INT_VALUE_MAP), dict
|
|
1110
|
+
):
|
|
1111
|
+
return _OPS_ENUM_INT_BACKED
|
|
1112
|
+
return ops_for_subtype(field.sub_type)
|
|
1113
|
+
|
|
1114
|
+
|
|
916
1115
|
# ---------------------------------------------------------------------------
|
|
917
1116
|
# #195 — attr.expression closed grammar (validate + infer)
|
|
918
1117
|
# ---------------------------------------------------------------------------
|
|
@@ -1095,8 +1294,10 @@ def _validate_datagrid_filter_values(
|
|
|
1095
1294
|
continue
|
|
1096
1295
|
|
|
1097
1296
|
# Build filterable map: field_name → allowed ops set
|
|
1297
|
+
# ops_for_field, not ops_for_subtype — an int-backed field.enum
|
|
1298
|
+
# (@intValueMap) stores as an integer, so `like` is not in its band.
|
|
1098
1299
|
filterable: dict[str, frozenset[str]] = {
|
|
1099
|
-
f.name:
|
|
1300
|
+
f.name: ops_for_field(f)
|
|
1100
1301
|
for f in node.fields()
|
|
1101
1302
|
if f.attrs().get("filterable") is True
|
|
1102
1303
|
}
|
|
@@ -14,6 +14,13 @@ ATTR_SUBTYPE_CLASS = "class"
|
|
|
14
14
|
# ATTR_SUBTYPE_EXPRESSION / meta-attr-expression.ts.
|
|
15
15
|
ATTR_SUBTYPE_EXPRESSION = "expression"
|
|
16
16
|
|
|
17
|
+
# attr.intMap (int-backed-enum-values plan) — an object-shaped attribute whose
|
|
18
|
+
# values are all integers (e.g. field.enum's @intValueMap: {memberSymbol: int}).
|
|
19
|
+
# Generic shape check only; field.enum layers its own semantic rules (key-set
|
|
20
|
+
# membership, uniqueness) in its own content-rule validation pass. Mirrors TS
|
|
21
|
+
# ATTR_SUBTYPE_INT_MAP / C# AttrConstants.ATTR_SUBTYPE_INT_MAP.
|
|
22
|
+
ATTR_SUBTYPE_INT_MAP = "intMap"
|
|
23
|
+
|
|
17
24
|
# The retired "stringarray" array attr subtype. It is NO LONGER a registered
|
|
18
25
|
# (attr, sub_type) (not in ATTR_SUBTYPES) — array-ness is modeled as a "string"
|
|
19
26
|
# attr with the orthogonal AttrSchema.is_array flag (matching Java's
|
|
@@ -33,4 +40,5 @@ ATTR_SUBTYPES = (
|
|
|
33
40
|
ATTR_SUBTYPE_PROPERTIES,
|
|
34
41
|
ATTR_SUBTYPE_CLASS,
|
|
35
42
|
ATTR_SUBTYPE_EXPRESSION,
|
|
43
|
+
ATTR_SUBTYPE_INT_MAP,
|
|
36
44
|
)
|
|
@@ -12,6 +12,7 @@ from .attr_constants import (
|
|
|
12
12
|
ATTR_SUBTYPE_EXPRESSION,
|
|
13
13
|
ATTR_SUBTYPE_FILTER,
|
|
14
14
|
ATTR_SUBTYPE_INT,
|
|
15
|
+
ATTR_SUBTYPE_INT_MAP,
|
|
15
16
|
ATTR_SUBTYPE_LONG,
|
|
16
17
|
ATTR_SUBTYPE_PROPERTIES,
|
|
17
18
|
ATTR_SUBTYPE_STRING,
|
|
@@ -134,6 +135,21 @@ class PropertiesAttr(MetaAttr):
|
|
|
134
135
|
return DataType.OBJECT
|
|
135
136
|
|
|
136
137
|
|
|
138
|
+
class IntMapAttr(MetaAttr):
|
|
139
|
+
"""attr.intMap (int-backed-enum-values plan) — an object-shaped attribute
|
|
140
|
+
whose values are all integers (e.g. field.enum's @intValueMap). Generic
|
|
141
|
+
shape check only; the deeper "every value is an int" check is enforced by
|
|
142
|
+
`_type_ok`'s ATTR_SUBTYPE_INT_MAP case in validation_passes.py (this port
|
|
143
|
+
has no per-attr-class validate_value dispatch — TS's is the one port that
|
|
144
|
+
does; C# mirrors the same "static type-check function" architecture this
|
|
145
|
+
port uses). field.enum's own key-set/uniqueness content rules run in a
|
|
146
|
+
separate pass. Mirrors TS IntMapAttr / C# ATTR_SUBTYPE_INT_MAP shape."""
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def data_type(self) -> DataType:
|
|
150
|
+
return DataType.OBJECT
|
|
151
|
+
|
|
152
|
+
|
|
137
153
|
class ClassAttr(MetaAttr):
|
|
138
154
|
@property
|
|
139
155
|
def data_type(self) -> DataType:
|
|
@@ -145,4 +161,5 @@ register_attr_class(ATTR_SUBTYPE_STRINGARRAY, StringArrayAttr)
|
|
|
145
161
|
register_attr_class(ATTR_SUBTYPE_FILTER, FilterAttr)
|
|
146
162
|
register_attr_class(ATTR_SUBTYPE_PROPERTIES, PropertiesAttr)
|
|
147
163
|
register_attr_class(ATTR_SUBTYPE_EXPRESSION, ExpressionAttr)
|
|
164
|
+
register_attr_class(ATTR_SUBTYPE_INT_MAP, IntMapAttr)
|
|
148
165
|
register_attr_class(ATTR_SUBTYPE_CLASS, ClassAttr)
|
{metaobjects-0.23.1 → metaobjects-0.23.2}/src/metaobjects/meta/core/field/field_constants.py
RENAMED
|
@@ -150,3 +150,10 @@ SORT_ORDER_VALUES = (SORT_ORDER_ASC, SORT_ORDER_DESC)
|
|
|
150
150
|
# Regex pattern for enum member symbols — must be identifier-safe.
|
|
151
151
|
# Cross-language contract: every port enforces this pattern.
|
|
152
152
|
ENUM_MEMBER_PATTERN = r"^[A-Za-z_][A-Za-z0-9_]*$"
|
|
153
|
+
|
|
154
|
+
# int-backed-enum-values plan — @intValueMap (field.enum only): optional
|
|
155
|
+
# per-member int values ({member: int}) switching this enum field's DB
|
|
156
|
+
# persistence from string+CHECK to integer+CHECK. Keys must exactly match
|
|
157
|
+
# @values; values must be unique integers. The generated native type and wire
|
|
158
|
+
# format are unchanged in every language. Mirrors TS FIELD_ATTR_INT_VALUE_MAP.
|
|
159
|
+
FIELD_ATTR_INT_VALUE_MAP = "intValueMap"
|
|
@@ -311,6 +311,8 @@ class ObjectManager:
|
|
|
311
311
|
}
|
|
312
312
|
row = result.rows[0]
|
|
313
313
|
mapped = {col_to_field.get(k, k): v for k, v in row.items()}
|
|
314
|
+
# int-backed enums come back as integers; hand the caller the symbol.
|
|
315
|
+
mapped = _decode_read_row({f.name: f for f in returning_fields}, mapped)
|
|
314
316
|
# #214: a write-through entity's INSERT RETURNING covers only the table (non-derived)
|
|
315
317
|
# columns; re-read the persisted row through the replica VIEW by PK so the returned row
|
|
316
318
|
# carries the derived origin.* fields (read-your-writes). find_by_id routes to the view.
|
|
@@ -423,6 +425,8 @@ class ObjectManager:
|
|
|
423
425
|
}
|
|
424
426
|
row = result.rows[0]
|
|
425
427
|
mapped = {col_to_field.get(k, k): v for k, v in row.items()}
|
|
428
|
+
# int-backed enums come back as integers; hand the caller the symbol.
|
|
429
|
+
mapped = _decode_read_row({f.name: f for f in returning_fields}, mapped)
|
|
426
430
|
# #214: re-read the updated row through the replica VIEW by PK so the returned row
|
|
427
431
|
# carries the derived origin.* fields (write targeted the table, which lacks them).
|
|
428
432
|
if entity.is_write_through():
|
|
@@ -509,8 +513,11 @@ class ObjectManager:
|
|
|
509
513
|
self.last_column_oids = {
|
|
510
514
|
col_to_field.get(c, c): oid for c, oid in result.column_oids.items()
|
|
511
515
|
}
|
|
516
|
+
# int-backed enums come back as integers; hand the caller the symbol.
|
|
517
|
+
fields_by_name = {f.name: f for f in entity.fields()}
|
|
512
518
|
return [
|
|
513
|
-
{col_to_field.get(k, k): v for k, v in row.items()}
|
|
519
|
+
_decode_read_row(fields_by_name, {col_to_field.get(k, k): v for k, v in row.items()})
|
|
520
|
+
for row in result.rows
|
|
514
521
|
]
|
|
515
522
|
|
|
516
523
|
def count(self, entity_name: str, filter: Filter | None = None) -> int:
|
|
@@ -711,12 +718,13 @@ def _compile_filter(f: Filter | None, entity: MetaObject) -> tuple[str, list[Any
|
|
|
711
718
|
mf = entity.find_field(field_name)
|
|
712
719
|
col = _column_of(mf) if mf is not None else field_name
|
|
713
720
|
if not isinstance(ops, dict):
|
|
714
|
-
# Shortcut: {field: value} → equality
|
|
721
|
+
# Shortcut: {field: value} → equality. Encoded like any other bound
|
|
722
|
+
# value (see _op_clause) so an int-backed enum reaches SQL as its int.
|
|
715
723
|
parts.append(f"{_q(col)} = %s")
|
|
716
|
-
params.append(ops)
|
|
724
|
+
params.append(_coerce_write_value(mf, ops) if mf is not None else ops)
|
|
717
725
|
continue
|
|
718
726
|
for op, value in ops.items():
|
|
719
|
-
sql, p = _op_clause(col, op, value)
|
|
727
|
+
sql, p = _op_clause(col, op, value, mf)
|
|
720
728
|
parts.append(sql)
|
|
721
729
|
params.extend(p)
|
|
722
730
|
if not parts:
|
|
@@ -724,9 +732,21 @@ def _compile_filter(f: Filter | None, entity: MetaObject) -> tuple[str, list[Any
|
|
|
724
732
|
return " AND ".join(parts), params
|
|
725
733
|
|
|
726
734
|
|
|
727
|
-
def _op_clause(col: str, op: str, value: Any) -> tuple[str, list[Any]]:
|
|
728
|
-
"""Translate one operator → SQL + params. Mirrors TS/C#/Java semantics.
|
|
735
|
+
def _op_clause(col: str, op: str, value: Any, field: MetaField | None = None) -> tuple[str, list[Any]]:
|
|
736
|
+
"""Translate one operator → SQL + params. Mirrors TS/C#/Java semantics.
|
|
737
|
+
|
|
738
|
+
Bound values go through the WRITE codec, exactly as an INSERT's do: the four
|
|
739
|
+
sibling ports all encode on this path (TS through the Drizzle customType, Java
|
|
740
|
+
through GenericSQLDriver.setStatementValue → EnumCodec.write, Kotlin through
|
|
741
|
+
Exposed's toDb, C# through the EF converter). Without it an int-backed enum's
|
|
742
|
+
filter binds the member SYMBOL against an INTEGER column — the filter band
|
|
743
|
+
keeps eq/ne/in for int-backed enums precisely BECAUSE the symbol is supposed
|
|
744
|
+
to encode to its integer before reaching SQL.
|
|
745
|
+
"""
|
|
729
746
|
qc = _q(col)
|
|
747
|
+
if field is not None and op != "isNull":
|
|
748
|
+
value = ([_coerce_write_value(field, v) for v in value]
|
|
749
|
+
if op == "in" and value else _coerce_write_value(field, value))
|
|
730
750
|
if op == "eq": return f"{qc} = %s", [value]
|
|
731
751
|
if op == "ne": return f"{qc} <> %s", [value]
|
|
732
752
|
if op == "gt": return f"{qc} > %s", [value]
|
|
@@ -823,11 +843,79 @@ def _coerce_write_value(field: MetaField, value: Any) -> Any:
|
|
|
823
843
|
storage = field.get_meta_attr(fc.FIELD_ATTR_STORAGE) # ADR-0039 resolving
|
|
824
844
|
if storage != "flattened": # None / "jsonb" / "subdocument" → single jsonb column
|
|
825
845
|
return _json.dumps(value)
|
|
846
|
+
# field.enum carrying @intValueMap: the column is an INTEGER while the native
|
|
847
|
+
# and wire contract stays the member SYMBOL (int-backing is a persistence-layer
|
|
848
|
+
# concern, invisible above this codec), so encode symbol -> declared int here.
|
|
849
|
+
#
|
|
850
|
+
# An unmapped symbol is passed through untouched: membership is the column's
|
|
851
|
+
# CHECK constraint to enforce, and inventing a value here would hide the drift.
|
|
852
|
+
if sub == fc.FIELD_SUBTYPE_ENUM:
|
|
853
|
+
int_map = _int_value_map(field)
|
|
854
|
+
if int_map is not None and value in int_map:
|
|
855
|
+
return int_map[value]
|
|
856
|
+
|
|
826
857
|
# Everything else (string / int / long / double / float / boolean / enum)
|
|
827
858
|
# is already the native type pg8000 binds directly.
|
|
828
859
|
return value
|
|
829
860
|
|
|
830
861
|
|
|
862
|
+
def _int_value_map(field: MetaField) -> dict[Any, Any] | None:
|
|
863
|
+
"""The declared ``@intValueMap`` (symbol → int), or ``None`` when the enum is
|
|
864
|
+
string-backed.
|
|
865
|
+
|
|
866
|
+
ADR-0039 resolving: the map is ``@values``' numeric half — a logical property
|
|
867
|
+
of the enum vocabulary that inherits through ``extends`` — so it is read with
|
|
868
|
+
``get_meta_attr``, NOT the own-only accessor (contrast ``@dbColumnType`` in
|
|
869
|
+
:func:`_coerce_write_value`, the one field attribute that is deliberately
|
|
870
|
+
own-only). Shared by the write and read halves of the enum codec, mirroring
|
|
871
|
+
the dedicated int-map helper each sibling port's codec keeps (Java
|
|
872
|
+
``EnumCodec.intValueMap``, Kotlin ``readIntValueMap``, C# ``IntValueMapOf``).
|
|
873
|
+
"""
|
|
874
|
+
m = field.get_meta_attr(fc.FIELD_ATTR_INT_VALUE_MAP)
|
|
875
|
+
return m if isinstance(m, dict) else None
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
def _decode_read_value(field: MetaField, value: Any) -> Any:
|
|
879
|
+
"""Decode a stored value back to its authoring form on read.
|
|
880
|
+
|
|
881
|
+
The inverse of :func:`_coerce_write_value`'s int-backed-enum branch, and
|
|
882
|
+
today its only case: the column holds the member's integer, callers expect
|
|
883
|
+
the member SYMBOL. Every other field subtype is returned verbatim, keeping
|
|
884
|
+
ADR-0019's "runtime returns native in-process types" contract intact.
|
|
885
|
+
|
|
886
|
+
An int with no member RAISES. The database then holds a value the model says
|
|
887
|
+
is impossible — a hand-written INSERT, or a member removed without a
|
|
888
|
+
migration — and neither alternative is honest: returning the raw int hands
|
|
889
|
+
the caller a "member" that is not one (C#, Kotlin and TypeScript type this
|
|
890
|
+
property as a CLOSED enum, where ``7`` is not even representable), and
|
|
891
|
+
returning ``None`` hides the corruption behind a nullable column. Every port
|
|
892
|
+
throws here.
|
|
893
|
+
"""
|
|
894
|
+
if value is None:
|
|
895
|
+
return None
|
|
896
|
+
if field.sub_type != fc.FIELD_SUBTYPE_ENUM:
|
|
897
|
+
return value
|
|
898
|
+
int_map = _int_value_map(field)
|
|
899
|
+
if int_map is None or not isinstance(value, int) or isinstance(value, bool):
|
|
900
|
+
return value
|
|
901
|
+
for symbol, stored in int_map.items():
|
|
902
|
+
if stored == value:
|
|
903
|
+
return symbol
|
|
904
|
+
raise ValueError(
|
|
905
|
+
f"field.enum '{field.name}' read stored value {value} with no member in "
|
|
906
|
+
f"@{fc.FIELD_ATTR_INT_VALUE_MAP} (declared: {int_map}) — the database holds "
|
|
907
|
+
f"a value the model does not describe."
|
|
908
|
+
)
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
def _decode_read_row(fields_by_name: dict[str, MetaField], row: dict[str, Any]) -> dict[str, Any]:
|
|
912
|
+
"""Apply :func:`_decode_read_value` to every field-keyed value in a mapped row."""
|
|
913
|
+
return {
|
|
914
|
+
k: (_decode_read_value(fields_by_name[k], v) if k in fields_by_name else v)
|
|
915
|
+
for k, v in row.items()
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
|
|
831
919
|
# ----------------------------------------------------------------------------
|
|
832
920
|
# #203 — @autoSet CRUD stamping. A ``field.timestamp`` (or any temporal field)
|
|
833
921
|
# marked ``@autoSet: onCreate|onUpdate`` declares "the runtime owns this
|
|
@@ -19,6 +19,12 @@
|
|
|
19
19
|
"dataType": "int",
|
|
20
20
|
"description": "A 32-bit-integer-valued metadata attribute. Coerces to and validates as a number."
|
|
21
21
|
},
|
|
22
|
+
{
|
|
23
|
+
"type": "attr",
|
|
24
|
+
"subType": "intMap",
|
|
25
|
+
"dataType": "object",
|
|
26
|
+
"description": "An object-shaped attribute whose values are all integers (e.g. field.enum's @intValueMap: {memberSymbol: int}). Generic shape check only; a consumer field type layers its own semantic rules (key-set membership, uniqueness) in its own content-rule validation."
|
|
27
|
+
},
|
|
22
28
|
{
|
|
23
29
|
"type": "attr",
|
|
24
30
|
"subType": "long",
|