metaobjects 0.24.4__tar.gz → 0.24.5__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.24.4 → metaobjects-0.24.5}/PKG-INFO +1 -1
- {metaobjects-0.24.4 → metaobjects-0.24.5}/pyproject.toml +1 -1
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/agent_context/scaffold.py +62 -3
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/config.py +9 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/entity_model.py +14 -7
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/m2m_codegen.py +22 -11
- metaobjects-0.24.5/src/metaobjects/naming.py +90 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/runtime/object_manager.py +40 -23
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_entity_model.py +27 -14
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_agent_context_staleness.py +38 -0
- metaobjects-0.24.5/tests/unit/test_column_naming_strategy.py +78 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/uv.lock +1 -1
- {metaobjects-0.24.4 → metaobjects-0.24.5}/.gitignore +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/LICENSE +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/README.md +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/hatch_build.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/scripts/generate_embedded_library.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/agent_context/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/apidocs/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/apidocs/api_model.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/apidocs/builder.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/apidocs/naming.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/apidocs/paths.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/apidocs/renderer.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/attr_class_map.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/cli.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/collision_names.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/format.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generator_registry.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/find_inbound.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/payload_vo_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/router_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/template_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/instance_artifacts.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/overwrite_policy.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/project_config.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/runner.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/runtime/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/type_map.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/config/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/config/neutral_config.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/config/source_resolver.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/core_types.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/datatype.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/documentation/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/documentation/doc_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/documentation/doc_provider.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/documentation/doc_schema.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/errors.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/library/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/library/embedded_library.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/library/library_sources.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/merge.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/meta_data_loader.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/registered_validation.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/sources/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/sources/directory_source.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/sources/file_source.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/sources/uri_source.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validate_discriminator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validate_field_mutability.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validate_source_escapes.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validation_passes.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/attr/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/field/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/field/field_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/field/meta_field.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/identity/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/index/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/index/index_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/index/meta_index.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/meta_object.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/object_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/object_extract.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/value_object.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/validator/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/meta_data.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/meta_root.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/provider_extends.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/template/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/template/meta_template.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/template/prompt_provider.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/template/template_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/naming_refs.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/parser.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/parser_yaml.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/provider.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/py.typed +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/registry.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/registry_manifest.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/email_document.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/escapers.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/coerce.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/extract.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/extract_map.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/locate.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/normalize.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/strip.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/types.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/filesystem_provider.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/payload_accessors.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/prompt/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/prompt/prompt_field.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/prompt/prompt_style.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/renderer.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/verify.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/runtime/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/runtime/llm_recorder.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/runtime/n2m_resolver.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/runtime/tph.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/serializer_json.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/shared/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/shared/base_types.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/shared/separators.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/shared/structural.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/source/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/source/error_source.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/source/json_path.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/source/semantic_diff.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/source/yaml_positions.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/attr.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/db.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/documentation.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/field.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/identity.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/index.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/layout.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/object.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/origin.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/prompt.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/relationship.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/requirement.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/source.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/template.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/ui.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/validator.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/view.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/super_resolve.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/validation_types.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/yaml_desugar.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/extends/expected/Program.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/extends/meta.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/nested-array/meta.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/scalars/expected/Report.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/scalars/meta.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/vanilla/meta.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_abstract_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_api_docs_builder.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_api_docs_paths.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_config_gen.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_config_verify.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_providers.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_registry.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_staleness_nudge.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_verify_strict.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_verify_subverbs.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_constants_config.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_enum_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_extract_tier_collision.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_extractor_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_filter_allowlist_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_format.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_fr010_output_codegen.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_generator_extension_seams.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_golden.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_inheritance_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_instance_artifacts.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_m2m_codegen.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_origin_nullability.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_output_parser_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_overwrite_policy.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_overwrite_policy_hash.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_payload_vo_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_project_config.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_projection_compile.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_render_helper_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_render_helper_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_reverse_finders.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_router_autoset.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_router_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_runner.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_sourceless_projection.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_template_data.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_template_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_template_output_pattern.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_template_scope_helpers.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_template_scope_walk.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_template_spec.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_tph_codegen.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_trace_helper_generator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_type_map.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_validation_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_write_through.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/config/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/config/test_neutral_config.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/config/test_source_resolver.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/capabilities.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/conformance-expected-failures.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/conformance_adapter.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/corpus.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/expected_failures.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/fixture_discovery.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/navigator.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_extract_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_extract_object_verdict.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_fr010_loader_attrs.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_fr011_attrs.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_generator_registry_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_object_model_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_provider_composition_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_registry_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_runner_hardfail.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_source_resolution_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_spec_metamodel_embed.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_strict_attr_load.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_template_codegen_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_template_generator_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_yaml_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/api_contract_assertions.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/api_contract_jsonb_server.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/api_contract_m2m_server.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/api_contract_server.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/generated_jsonb_app.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/generated_m2m_app.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/generated_router_app.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/generated_tph_app.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/meta_ai_trace.yaml +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/normalization.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/postgres_container.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/query_runner.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/scenarios.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_api_contract.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_api_contract_generated.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_api_contract_jsonb.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_api_contract_m2m.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_api_contract_m2m_generated.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_api_contract_tph_generated.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_generated_router_uuid_pk.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_llm_call_trace.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_normalization.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_query_scenarios.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_runtime_return_types.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/loader/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/loader/test_enum_extends_values_conflict.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/loader/test_field_mutability_order.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/loader/test_shipped_library_ai.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/loader/test_template_payload_target_210.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/open_closed_proof_test.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_coerce.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_extract.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_extract_map.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_json_forgiving_reader.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_locate.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_model.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_normalize.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_strip.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/prompt/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/prompt/test_output_format_renderer.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_email_document.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_filesystem_provider.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_output_format_renderer_nested.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_output_prompt_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_render_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_render_max_chars.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_verify.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_verify_conformance.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/runtime/test_object_manager_enum_intvaluemap.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_fr5c_merge_attribution.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_fr5d_reference_resolution.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_fr5e_database_source_shape.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_json_path.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_semantic_diff.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_source_on_node.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_yaml_positions.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/test_api_docs_accuracy.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/__init__.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_capabilities.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_common_attrs.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_core_types.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_effective_package.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_errors.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_field_enum.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_field_enum_intvaluemap.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_field_map_validation.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_index_lookup.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_llm_recorder.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_loader.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_loader_bom.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_loader_class.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_merge.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_meta_attr.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_meta_data.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_meta_source.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_module_shortcuts.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_n2m_resolver.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_n2m_resolver_inherited.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_object_manager_write_through.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_one_primary_source.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_parser.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_parser_yaml.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_provider.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_provider_extension.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_registry.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_registry_completeness.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_registry_extend.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_registry_sealed.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_relationship_referential_actions.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_resolution_key.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_serializer.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_shared_constants.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_smoke.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_source_escapes.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_sources.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_strict_child_placement.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_super_resolve.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_template_toolcall.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_validation_attr_schema.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_validation_filter_values.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_validation_origin_195.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_validation_origin_paths.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_validation_sort_field.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_validation_warnings.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_write_coercion_arrays.py +0 -0
- {metaobjects-0.24.4 → metaobjects-0.24.5}/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.24.
|
|
3
|
+
Version: 0.24.5
|
|
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.24.
|
|
3
|
+
version = "0.24.5"
|
|
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"
|
|
@@ -10,6 +10,7 @@ installed MetaObjects version.
|
|
|
10
10
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
|
+
import re
|
|
13
14
|
from dataclasses import dataclass
|
|
14
15
|
from importlib.metadata import PackageNotFoundError, version as _pkg_version
|
|
15
16
|
|
|
@@ -76,6 +77,61 @@ class Manifest:
|
|
|
76
77
|
)
|
|
77
78
|
|
|
78
79
|
|
|
80
|
+
# The sentinel a port stamps when it cannot resolve its own installed version.
|
|
81
|
+
_UNRESOLVED_VERSION = "0.0.0"
|
|
82
|
+
|
|
83
|
+
_RELEASE_RE = re.compile(r"^(\d+)\.(\d+)\.(\d+)$")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _release_series(version: object) -> tuple[int, int] | None:
|
|
87
|
+
"""Ordered release coordinate ``(minor, patch)``, or ``None`` when not orderable.
|
|
88
|
+
|
|
89
|
+
The MAJOR is deliberately dropped. It is a per-registry constant, not information:
|
|
90
|
+
npm/PyPI/NuGet ship ``0.<m>.<p>`` and Maven Central the same ``<m>.<p>`` on its
|
|
91
|
+
historical major ``7``, so minor.patch IS the shared release coordinate across all
|
|
92
|
+
four ports.
|
|
93
|
+
|
|
94
|
+
``None`` means "not orderable, so nudge", and deliberately covers prereleases
|
|
95
|
+
(``0.24.5-rc.1``), build metadata (``0.24.5+abc``) and the ``0.0.0`` sentinel. Each
|
|
96
|
+
must keep nudging: an RC-scaffolded context against a final release is still worth
|
|
97
|
+
refreshing, and an unknown install must never assert "in sync".
|
|
98
|
+
"""
|
|
99
|
+
if not isinstance(version, str):
|
|
100
|
+
return None
|
|
101
|
+
v = version.strip()
|
|
102
|
+
if v == _UNRESOLVED_VERSION:
|
|
103
|
+
return None
|
|
104
|
+
m = _RELEASE_RE.match(v)
|
|
105
|
+
if m is None:
|
|
106
|
+
return None
|
|
107
|
+
return int(m.group(2)), int(m.group(3))
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _context_is_ahead_of_install(generated_by: object, current_version: str) -> bool:
|
|
111
|
+
"""True when the manifest was stamped by a release STRICTLY NEWER than the install.
|
|
112
|
+
|
|
113
|
+
The one exemption from "any drift nudges", and it exists because of the
|
|
114
|
+
publish-what-changed rule (docs/RELEASING.md): a registry publishes only when it has
|
|
115
|
+
a changed product file, so a port legitimately sits behind npm — while
|
|
116
|
+
``meta agent-docs``, the canonical scaffolder for EVERY port, stamps the npm version
|
|
117
|
+
it was run from. A Python install at ``0.24.4`` whose context was scaffolded by npm
|
|
118
|
+
``0.24.7`` is correct, and nudging it is issue #347 exactly: the remedy re-runs the
|
|
119
|
+
scaffolder, which re-stamps ``0.24.7``, so the advisory can never be satisfied and
|
|
120
|
+
fires on every build forever.
|
|
121
|
+
|
|
122
|
+
KNOWN BOUND, stated rather than hidden: ordering on minor.patch assumes both versions
|
|
123
|
+
sit in the same release SERIES. That holds for every release to date and after the
|
|
124
|
+
1.0/8.0 cut, but not ACROSS it — there a ``0.24.x`` context against a ``1.0.0``
|
|
125
|
+
install reads as "ahead" and the nudge is suppressed once. A missed advisory, never a
|
|
126
|
+
wrong action.
|
|
127
|
+
"""
|
|
128
|
+
stamped = _release_series(generated_by)
|
|
129
|
+
installed = _release_series(current_version)
|
|
130
|
+
if stamped is None or installed is None:
|
|
131
|
+
return False # not orderable → nudge
|
|
132
|
+
return stamped > installed
|
|
133
|
+
|
|
134
|
+
|
|
79
135
|
def agent_context_staleness(
|
|
80
136
|
manifest: dict[str, object] | None, current_version: str
|
|
81
137
|
) -> str | None:
|
|
@@ -85,15 +141,18 @@ def agent_context_staleness(
|
|
|
85
141
|
is in sync — and a one-line advisory message otherwise. Pure + advisory:
|
|
86
142
|
never raises, never blocks, never writes.
|
|
87
143
|
|
|
88
|
-
The comparison is **exact equality**
|
|
89
|
-
|
|
90
|
-
|
|
144
|
+
The comparison is **exact equality** first: ANY drift nudges (a re-scaffold is
|
|
145
|
+
cheap + idempotent), so this is not a semver compare — a prerelease or
|
|
146
|
+
build-metadata difference is still a reason to refresh. See
|
|
147
|
+
``_context_is_ahead_of_install`` for the ONE case that is exempt.
|
|
91
148
|
"""
|
|
92
149
|
if manifest is None:
|
|
93
150
|
return None # no agent context here → nothing to nudge
|
|
94
151
|
generated_by = manifest.get("generatedBy")
|
|
95
152
|
if generated_by == current_version:
|
|
96
153
|
return None # in sync
|
|
154
|
+
if _context_is_ahead_of_install(generated_by, current_version):
|
|
155
|
+
return None # scaffolded by a NEWER release than this install — see below
|
|
97
156
|
frm = generated_by if generated_by else "an older MetaObjects"
|
|
98
157
|
return (
|
|
99
158
|
f"MetaObjects agent context was generated by {frm}; "
|
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
|
|
6
|
+
from metaobjects.naming import DEFAULT_COLUMN_NAMING
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
@dataclass
|
|
8
10
|
class GenConfig:
|
|
@@ -23,5 +25,12 @@ class GenConfig:
|
|
|
23
25
|
# maps a declaring metadata package ("acme::shop") to the Python import module; with a
|
|
24
26
|
# single ``provided_enum_namespace`` fallback for the one-module case. A referenced
|
|
25
27
|
# @provided enum whose package resolves to no module is a codegen-time error.
|
|
28
|
+
# How a field with no explicit `@column` becomes a physical column name
|
|
29
|
+
# ("literal" | "snake_case" | "kebab-case"). Config, never metadata: the same model
|
|
30
|
+
# must be able to drive a snake_case schema and a literal-column one. Defaults to
|
|
31
|
+
# `literal`, this port's historical behaviour — but `meta migrate`, which owns
|
|
32
|
+
# schema for EVERY port (ADR-0015), defaults to `snake_case`, so a project whose
|
|
33
|
+
# tables it created wants `snake_case` here or an explicit `@column` per field.
|
|
34
|
+
column_naming: str = DEFAULT_COLUMN_NAMING
|
|
26
35
|
provided_enum_namespace: str | None = None
|
|
27
36
|
provided_enum_packages: dict[str, str] = field(default_factory=dict)
|
{metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/entity_model.py
RENAMED
|
@@ -339,13 +339,20 @@ def _field_line(field: MetaField, imports: set[str], config: GenConfig) -> tuple
|
|
|
339
339
|
else:
|
|
340
340
|
assignment = " = None"
|
|
341
341
|
|
|
342
|
-
# Pydantic field name =
|
|
343
|
-
#
|
|
344
|
-
#
|
|
345
|
-
#
|
|
346
|
-
#
|
|
347
|
-
|
|
348
|
-
|
|
342
|
+
# Pydantic field name = field.name, ALWAYS. `@column` is the physical column name,
|
|
343
|
+
# a different axis: it is what the persistence layer binds to, never what the model
|
|
344
|
+
# calls the field. Every other surface in this port already keyed by field.name —
|
|
345
|
+
# the FR-036 create/patch models, the generated router, and the runtime, whose
|
|
346
|
+
# ObjectManager maps {_column_of(f): f.name} on every read and RETURNING clause
|
|
347
|
+
# "for cross-port row-shape parity" — so keying the read model by @column made one
|
|
348
|
+
# generated module disagree with itself, and its stated reason (that the model field
|
|
349
|
+
# binds straight to the row) was never true.
|
|
350
|
+
#
|
|
351
|
+
# Idiomatic snake_case for a Python consumer is a real goal and this is not the
|
|
352
|
+
# lever for it: `columnNamingStrategy` applied to field.name is, because @column is
|
|
353
|
+
# free-form — `callPurpose` + `@column: purpose_code` used to emit a field
|
|
354
|
+
# `purpose_code`, which is neither the wire name nor derived from the field name.
|
|
355
|
+
return f" {field.name}: {annotation}{assignment}", uses_field
|
|
349
356
|
|
|
350
357
|
|
|
351
358
|
def _primary_identity_field_names(entity: MetaObject) -> list[str]:
|
|
@@ -26,6 +26,11 @@ from __future__ import annotations
|
|
|
26
26
|
from dataclasses import dataclass
|
|
27
27
|
|
|
28
28
|
from metaobjects.meta.core.field import field_constants as fc
|
|
29
|
+
from metaobjects.naming import (
|
|
30
|
+
DEFAULT_COLUMN_NAMING,
|
|
31
|
+
apply_column_naming_strategy,
|
|
32
|
+
resolve_column_name,
|
|
33
|
+
)
|
|
29
34
|
from metaobjects.meta.core.field.meta_field import MetaField
|
|
30
35
|
from metaobjects.meta.meta_data import MetaData
|
|
31
36
|
from metaobjects.meta.core.identity.identity_constants import (
|
|
@@ -92,15 +97,18 @@ def _physical_table(entity: MetaObject) -> str:
|
|
|
92
97
|
return entity.name
|
|
93
98
|
|
|
94
99
|
|
|
95
|
-
def _column_of(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
def _column_of(
|
|
101
|
+
field: MetaField | None, fallback: str, strategy: str = DEFAULT_COLUMN_NAMING
|
|
102
|
+
) -> str:
|
|
103
|
+
"""Physical column name for a junction FK. Delegates to the shared
|
|
104
|
+
:func:`metaobjects.naming.resolve_column_name` — the SAME resolver the runtime uses,
|
|
105
|
+
so generated junction SQL and runtime SQL cannot disagree about a column name.
|
|
106
|
+
|
|
107
|
+
*fallback* covers the case where the field could not be resolved at all; it is a
|
|
108
|
+
bare metadata name, so it goes through the strategy too."""
|
|
100
109
|
if field is None:
|
|
101
|
-
return fallback
|
|
102
|
-
|
|
103
|
-
return col if isinstance(col, str) and col else field.name
|
|
110
|
+
return apply_column_naming_strategy(fallback, strategy)
|
|
111
|
+
return resolve_column_name(field, strategy)
|
|
104
112
|
|
|
105
113
|
|
|
106
114
|
def _field_named(entity: MetaObject, field_name: str) -> MetaField | None:
|
|
@@ -144,7 +152,9 @@ def m2m_relationships(entity: MetaObject) -> list[MetaRelationship]:
|
|
|
144
152
|
|
|
145
153
|
|
|
146
154
|
def resolve_m2m_descriptors(
|
|
147
|
-
entity: MetaObject,
|
|
155
|
+
entity: MetaObject,
|
|
156
|
+
object_index: dict[str, MetaObject],
|
|
157
|
+
column_naming: str = DEFAULT_COLUMN_NAMING,
|
|
148
158
|
) -> list[M2mDescriptor]:
|
|
149
159
|
"""Resolve every M:N navigation on *entity* into a build-time descriptor.
|
|
150
160
|
|
|
@@ -181,11 +191,12 @@ def resolve_m2m_descriptors(
|
|
|
181
191
|
target_plural=plural_lowercase(target.name),
|
|
182
192
|
junction_table=_physical_table(junction),
|
|
183
193
|
target_table=_physical_table(target),
|
|
184
|
-
source_column=_column_of(source_fk, fields.source_field),
|
|
185
|
-
target_column=_column_of(target_fk, fields.target_field),
|
|
194
|
+
source_column=_column_of(source_fk, fields.source_field, column_naming),
|
|
195
|
+
target_column=_column_of(target_fk, fields.target_field, column_naming),
|
|
186
196
|
target_pk_column=_column_of(
|
|
187
197
|
_field_named(target, pk_field_name(target)),
|
|
188
198
|
pk_field_name(target),
|
|
199
|
+
column_naming,
|
|
189
200
|
),
|
|
190
201
|
symmetric=rel.symmetric(),
|
|
191
202
|
)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Physical naming: how a metadata name becomes a database identifier.
|
|
2
|
+
|
|
3
|
+
The column-naming strategy is CONFIG, not metadata (ADR-0023 does not apply). The same
|
|
4
|
+
model has to be able to drive a snake_case Postgres schema and a literal-column one —
|
|
5
|
+
which is exactly why it lives beside the persistence layer rather than in the metadata,
|
|
6
|
+
and why the byte-gated registry prose for ``@column`` describes the default as coming
|
|
7
|
+
"via columnNamingStrategy".
|
|
8
|
+
|
|
9
|
+
Cross-port siblings, sharing this vocabulary and this algorithm:
|
|
10
|
+
* TypeScript ``metadata/src/naming.ts`` (``applyColumnNamingStrategy``)
|
|
11
|
+
* C# ``MetaObjects.Codegen`` (``ColumnNamingStrategy``)
|
|
12
|
+
* Kotlin ``KotlinGenUtil`` (``applyColumnNamingStrategy``)
|
|
13
|
+
|
|
14
|
+
**This port's default is ``literal``** — ``@column`` or the field name verbatim — which
|
|
15
|
+
is what it has always done. Note that the ports deliberately differ here (TypeScript
|
|
16
|
+
defaults to ``snake_case``, the Postgres convention; C# to ``literal``, EF's
|
|
17
|
+
property=column convention), so a polyglot project either sets the strategy explicitly
|
|
18
|
+
or declares ``@column``.
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from metaobjects.meta.core.field import field_constants as fc
|
|
23
|
+
from metaobjects.meta.core.field.meta_field import MetaField
|
|
24
|
+
|
|
25
|
+
COLUMN_NAMING_SNAKE_CASE = "snake_case"
|
|
26
|
+
COLUMN_NAMING_LITERAL = "literal"
|
|
27
|
+
COLUMN_NAMING_KEBAB_CASE = "kebab-case"
|
|
28
|
+
|
|
29
|
+
COLUMN_NAMING_STRATEGIES = (
|
|
30
|
+
COLUMN_NAMING_SNAKE_CASE,
|
|
31
|
+
COLUMN_NAMING_LITERAL,
|
|
32
|
+
COLUMN_NAMING_KEBAB_CASE,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
#: This port's default. Not the same as TypeScript's — see the module docstring.
|
|
36
|
+
DEFAULT_COLUMN_NAMING = COLUMN_NAMING_LITERAL
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def to_snake_case(name: str) -> str:
|
|
40
|
+
"""``displayName`` → ``display_name``, ``URLPath`` → ``url_path``.
|
|
41
|
+
|
|
42
|
+
Byte-for-byte the algorithm the other ports use: insert ``_`` before an uppercase
|
|
43
|
+
letter preceded by a lowercase letter or digit, OR before an uppercase letter that
|
|
44
|
+
both follows another uppercase and precedes a lowercase (so an acronym splits once,
|
|
45
|
+
``URLPath`` → ``url_path``, not ``u_r_l_path``). A port-local approximation would put
|
|
46
|
+
the two halves of one schema out of step.
|
|
47
|
+
"""
|
|
48
|
+
if not name:
|
|
49
|
+
return name
|
|
50
|
+
out: list[str] = []
|
|
51
|
+
for i, c in enumerate(name):
|
|
52
|
+
if i > 0 and c.isupper():
|
|
53
|
+
prev = name[i - 1]
|
|
54
|
+
nxt = name[i + 1] if i + 1 < len(name) else None
|
|
55
|
+
if prev.islower() or prev.isdigit() or (
|
|
56
|
+
prev.isupper() and nxt is not None and nxt.islower()
|
|
57
|
+
):
|
|
58
|
+
out.append("_")
|
|
59
|
+
out.append(c.lower())
|
|
60
|
+
return "".join(out)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def apply_column_naming_strategy(name: str, strategy: str = DEFAULT_COLUMN_NAMING) -> str:
|
|
64
|
+
"""Apply a strategy to a bare name.
|
|
65
|
+
|
|
66
|
+
An unknown strategy RAISES rather than falling back to the default: a typo would
|
|
67
|
+
otherwise bind a whole schema to the wrong columns and report success.
|
|
68
|
+
"""
|
|
69
|
+
if strategy == COLUMN_NAMING_LITERAL:
|
|
70
|
+
return name
|
|
71
|
+
if strategy == COLUMN_NAMING_SNAKE_CASE:
|
|
72
|
+
return to_snake_case(name)
|
|
73
|
+
if strategy == COLUMN_NAMING_KEBAB_CASE:
|
|
74
|
+
return to_snake_case(name).replace("_", "-")
|
|
75
|
+
raise ValueError(
|
|
76
|
+
f"unknown column-naming strategy {strategy!r}; "
|
|
77
|
+
f"expected one of: {', '.join(COLUMN_NAMING_STRATEGIES)}"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def resolve_column_name(field: MetaField, strategy: str = DEFAULT_COLUMN_NAMING) -> str:
|
|
82
|
+
"""THE physical column name for a field: its explicit ``@column`` when present,
|
|
83
|
+
else ``field.name`` through the project's strategy.
|
|
84
|
+
|
|
85
|
+
ADR-0039: read RESOLVING — ``@column`` may be inherited through ``extends``.
|
|
86
|
+
"""
|
|
87
|
+
col = field.get_meta_attr(fc.FIELD_ATTR_COLUMN)
|
|
88
|
+
if isinstance(col, str) and col:
|
|
89
|
+
return col
|
|
90
|
+
return apply_column_naming_strategy(field.name, strategy)
|
|
@@ -36,6 +36,7 @@ from ..meta.meta_root import MetaRoot
|
|
|
36
36
|
from ..meta.core.object.meta_object import MetaObject
|
|
37
37
|
from ..meta.core.field.meta_field import MetaField
|
|
38
38
|
from ..meta.core.field import field_constants as fc
|
|
39
|
+
from ..naming import DEFAULT_COLUMN_NAMING, resolve_column_name
|
|
39
40
|
from ..meta.core.identity import identity_constants as ic
|
|
40
41
|
from ..meta.persistence.db import db_constants as dbc
|
|
41
42
|
from ..meta.persistence.source.meta_source import MetaSource
|
|
@@ -176,9 +177,21 @@ class PostgresDriver:
|
|
|
176
177
|
class ObjectManager:
|
|
177
178
|
"""Method-based read API. Translates Filter dicts → parameterized SQL."""
|
|
178
179
|
|
|
179
|
-
def __init__(
|
|
180
|
+
def __init__(
|
|
181
|
+
self,
|
|
182
|
+
root: MetaRoot,
|
|
183
|
+
driver: PostgresDriver,
|
|
184
|
+
column_naming: str = DEFAULT_COLUMN_NAMING,
|
|
185
|
+
) -> None:
|
|
180
186
|
self._root = root
|
|
181
187
|
self._driver = driver
|
|
188
|
+
# How a field with no explicit `@column` becomes a physical column name.
|
|
189
|
+
# Config, never metadata: the same model must be able to drive a snake_case
|
|
190
|
+
# schema and a literal-column one. Defaults to `literal`, this port's
|
|
191
|
+
# historical behaviour — but note `meta migrate`, which owns schema for EVERY
|
|
192
|
+
# port (ADR-0015), defaults to `snake_case`, so a project whose tables it
|
|
193
|
+
# created wants `snake_case` here or an explicit `@column` per field.
|
|
194
|
+
self._column_naming = column_naming
|
|
182
195
|
self._entity_by_name: dict[str, MetaObject] = {}
|
|
183
196
|
# ADR-0039 sanctioned own: top-level entity scan on the loader ROOT
|
|
184
197
|
# (metadata.root is never extended, so own == effective) — mirrors the TS
|
|
@@ -278,7 +291,7 @@ class ObjectManager:
|
|
|
278
291
|
# model, which carries derived fields) must not try to INSERT it; drop it here.
|
|
279
292
|
if f.is_derived():
|
|
280
293
|
continue
|
|
281
|
-
insert_cols.append(_column_of(f))
|
|
294
|
+
insert_cols.append(_column_of(f, self._column_naming))
|
|
282
295
|
params.append(_coerce_write_value(f, raw))
|
|
283
296
|
|
|
284
297
|
# RETURNING the physical column set so the inserted row — including any
|
|
@@ -287,8 +300,8 @@ class ObjectManager:
|
|
|
287
300
|
# column on the write table (it is computed by the replica view), so it is
|
|
288
301
|
# excluded from RETURNING; the write-through re-read below fetches it via the view.
|
|
289
302
|
returning_fields = [f for f in entity.fields() if not f.is_derived()]
|
|
290
|
-
all_cols = [_column_of(f) for f in returning_fields]
|
|
291
|
-
col_to_field = {_column_of(f): f.name for f in returning_fields}
|
|
303
|
+
all_cols = [_column_of(f, self._column_naming) for f in returning_fields]
|
|
304
|
+
col_to_field = {_column_of(f, self._column_naming): f.name for f in returning_fields}
|
|
292
305
|
|
|
293
306
|
if insert_cols:
|
|
294
307
|
col_list = ", ".join(_q(c) for c in insert_cols)
|
|
@@ -355,7 +368,7 @@ class ObjectManager:
|
|
|
355
368
|
entity = self._require_entity(entity_name)
|
|
356
369
|
table = self._table_name(entity)
|
|
357
370
|
pk_field = self._primary_pk_field(entity)
|
|
358
|
-
pk_col = _column_of(entity.find_field(pk_field))
|
|
371
|
+
pk_col = _column_of(entity.find_field(pk_field), self._column_naming)
|
|
359
372
|
|
|
360
373
|
# #203 — @autoSet: bump every onUpdate column to now(), and NEVER rewrite an
|
|
361
374
|
# onCreate column — strip it even if the caller supplied a (stale) value.
|
|
@@ -389,7 +402,7 @@ class ObjectManager:
|
|
|
389
402
|
# UPDATE it; drop it from the SET list.
|
|
390
403
|
if f.is_derived():
|
|
391
404
|
continue
|
|
392
|
-
set_cols.append(_column_of(f))
|
|
405
|
+
set_cols.append(_column_of(f, self._column_naming))
|
|
393
406
|
params.append(_coerce_write_value(f, raw))
|
|
394
407
|
if not set_cols:
|
|
395
408
|
# No columns to set → just read the (scoped) row back by PK (no-op update).
|
|
@@ -400,13 +413,13 @@ class ObjectManager:
|
|
|
400
413
|
# the write table (computed by the replica view); the write-through re-read below
|
|
401
414
|
# fetches them via the view.
|
|
402
415
|
returning_fields = [f for f in entity.fields() if not f.is_derived()]
|
|
403
|
-
all_cols = [_column_of(f) for f in returning_fields]
|
|
404
|
-
col_to_field = {_column_of(f): f.name for f in returning_fields}
|
|
416
|
+
all_cols = [_column_of(f, self._column_naming) for f in returning_fields]
|
|
417
|
+
col_to_field = {_column_of(f, self._column_naming): f.name for f in returning_fields}
|
|
405
418
|
assignments = ", ".join(f"{_q(c)} = %s" for c in set_cols)
|
|
406
419
|
params.append(_coerce_write_value(entity.find_field(pk_field), id_value))
|
|
407
420
|
where = f"{_q(pk_col)} = %s"
|
|
408
421
|
if tph is not None:
|
|
409
|
-
where += f" AND {_q(_column_of(entity.find_field(tph.field)))} = %s"
|
|
422
|
+
where += f" AND {_q(_column_of(entity.find_field(tph.field), self._column_naming))} = %s"
|
|
410
423
|
params.append(tph.value)
|
|
411
424
|
sql = (
|
|
412
425
|
f"UPDATE {_q(table)} SET {assignments} WHERE {where} "
|
|
@@ -456,14 +469,14 @@ class ObjectManager:
|
|
|
456
469
|
entity = self._require_entity(entity_name)
|
|
457
470
|
table = self._table_name(entity)
|
|
458
471
|
pk_field = self._primary_pk_field(entity)
|
|
459
|
-
pk_col = _column_of(entity.find_field(pk_field))
|
|
472
|
+
pk_col = _column_of(entity.find_field(pk_field), self._column_naming)
|
|
460
473
|
params: list[Any] = [_coerce_write_value(entity.find_field(pk_field), id_value)]
|
|
461
474
|
where = f"{_q(pk_col)} = %s"
|
|
462
475
|
# FR-017 TPH: a subtype delete is scoped to its discriminator (cross-subtype
|
|
463
476
|
# delete matches no row → False, mirroring the per-subtype route's 404).
|
|
464
477
|
tph = tph_subtype_of(entity)
|
|
465
478
|
if tph is not None:
|
|
466
|
-
where += f" AND {_q(_column_of(entity.find_field(tph.field)))} = %s"
|
|
479
|
+
where += f" AND {_q(_column_of(entity.find_field(tph.field), self._column_naming))} = %s"
|
|
467
480
|
params.append(tph.value)
|
|
468
481
|
sql = f"DELETE FROM {_q(table)} WHERE {where}"
|
|
469
482
|
return self._driver.execute_rowcount(sql, tuple(params)) > 0
|
|
@@ -482,14 +495,14 @@ class ObjectManager:
|
|
|
482
495
|
# derived origin.* columns), else the entity's own primary source. All effective
|
|
483
496
|
# fields (incl. derived) are selected — the view exposes them.
|
|
484
497
|
table = self._read_source_name(entity)
|
|
485
|
-
cols = [_column_of(f) for f in entity.fields()]
|
|
498
|
+
cols = [_column_of(f, self._column_naming) for f in entity.fields()]
|
|
486
499
|
sql = f'SELECT {", ".join(_q(c) for c in cols)} FROM {_q(table)}'
|
|
487
500
|
params: list[Any] = []
|
|
488
501
|
# FR-017 TPH: a subtype read is scoped to its discriminator value (a row of
|
|
489
502
|
# a different subtype is invisible); the base entity (no @discriminatorValue)
|
|
490
503
|
# reads polymorphically across the single table.
|
|
491
504
|
filter = self._scope_filter(filter, tph_subtype_of(entity))
|
|
492
|
-
where = _compile_filter(filter, entity) if filter else None
|
|
505
|
+
where = _compile_filter(filter, entity, self._column_naming) if filter else None
|
|
493
506
|
if where is not None:
|
|
494
507
|
sql += " WHERE " + where[0]
|
|
495
508
|
params.extend(where[1])
|
|
@@ -497,7 +510,7 @@ class ObjectManager:
|
|
|
497
510
|
order_parts = []
|
|
498
511
|
for field_name, direction in sort:
|
|
499
512
|
f = entity.find_field(field_name)
|
|
500
|
-
col = _column_of(f) if f is not None else field_name
|
|
513
|
+
col = _column_of(f, self._column_naming) if f is not None else field_name
|
|
501
514
|
d = "DESC" if direction.lower() == "desc" else "ASC"
|
|
502
515
|
order_parts.append(f"{_q(col)} {d}")
|
|
503
516
|
if order_parts:
|
|
@@ -509,7 +522,7 @@ class ObjectManager:
|
|
|
509
522
|
result = self._driver.select(sql, tuple(params))
|
|
510
523
|
# Map raw column → metadata field name for cross-port row-shape parity.
|
|
511
524
|
# Values stay native (ADR-0019); the boundary canonicalizes them.
|
|
512
|
-
col_to_field = {_column_of(f): f.name for f in entity.fields()}
|
|
525
|
+
col_to_field = {_column_of(f, self._column_naming): f.name for f in entity.fields()}
|
|
513
526
|
self.last_column_oids = {
|
|
514
527
|
col_to_field.get(c, c): oid for c, oid in result.column_oids.items()
|
|
515
528
|
}
|
|
@@ -528,7 +541,7 @@ class ObjectManager:
|
|
|
528
541
|
sql = f"SELECT COUNT(*) FROM {_q(table)}"
|
|
529
542
|
params: list[Any] = []
|
|
530
543
|
filter = self._scope_filter(filter, tph_subtype_of(entity)) # FR-017 TPH subtype scope
|
|
531
|
-
where = _compile_filter(filter, entity) if filter else None
|
|
544
|
+
where = _compile_filter(filter, entity, self._column_naming) if filter else None
|
|
532
545
|
if where is not None:
|
|
533
546
|
sql += " WHERE " + where[0]
|
|
534
547
|
params.extend(where[1])
|
|
@@ -670,7 +683,7 @@ class ObjectManager:
|
|
|
670
683
|
raise ValueError(
|
|
671
684
|
f"Junction '{junction.name}' has no field '{field_name}'"
|
|
672
685
|
)
|
|
673
|
-
return _column_of(f)
|
|
686
|
+
return _column_of(f, self._column_naming)
|
|
674
687
|
|
|
675
688
|
def primary_key_field(self, entity_name: str) -> str:
|
|
676
689
|
"""The single-field primary-key NAME for an entity, from its
|
|
@@ -695,7 +708,9 @@ class ObjectManager:
|
|
|
695
708
|
# ----------------------------------------------------------------------------
|
|
696
709
|
|
|
697
710
|
|
|
698
|
-
def _compile_filter(
|
|
711
|
+
def _compile_filter(
|
|
712
|
+
f: Filter | None, entity: MetaObject, column_naming: str = DEFAULT_COLUMN_NAMING
|
|
713
|
+
) -> tuple[str, list[Any]] | None:
|
|
699
714
|
if not f:
|
|
700
715
|
return None
|
|
701
716
|
# Top-level `and: [filter, filter, ...]` combinator.
|
|
@@ -703,7 +718,7 @@ def _compile_filter(f: Filter | None, entity: MetaObject) -> tuple[str, list[Any
|
|
|
703
718
|
parts: list[str] = []
|
|
704
719
|
params: list[Any] = []
|
|
705
720
|
for child in f["and"]:
|
|
706
|
-
compiled = _compile_filter(child, entity)
|
|
721
|
+
compiled = _compile_filter(child, entity, column_naming)
|
|
707
722
|
if compiled is None:
|
|
708
723
|
continue
|
|
709
724
|
parts.append("(" + compiled[0] + ")")
|
|
@@ -716,7 +731,7 @@ def _compile_filter(f: Filter | None, entity: MetaObject) -> tuple[str, list[Any
|
|
|
716
731
|
params = []
|
|
717
732
|
for field_name, ops in f.items():
|
|
718
733
|
mf = entity.find_field(field_name)
|
|
719
|
-
col = _column_of(mf) if mf is not None else field_name
|
|
734
|
+
col = _column_of(mf, column_naming) if mf is not None else field_name
|
|
720
735
|
if not isinstance(ops, dict):
|
|
721
736
|
# Shortcut: {field: value} → equality. Encoded like any other bound
|
|
722
737
|
# value (see _op_clause) so an int-backed enum reaches SQL as its int.
|
|
@@ -992,11 +1007,13 @@ def _parse_datetime(text: str, *, tz_aware: bool) -> _dt.datetime:
|
|
|
992
1007
|
return dt.replace(tzinfo=None)
|
|
993
1008
|
|
|
994
1009
|
|
|
995
|
-
def _column_of(field: MetaField | None) -> str:
|
|
1010
|
+
def _column_of(field: MetaField | None, strategy: str = DEFAULT_COLUMN_NAMING) -> str:
|
|
1011
|
+
"""Physical column for a field. Module-level shim over the shared
|
|
1012
|
+
:func:`metaobjects.naming.resolve_column_name` so the runtime and codegen cannot
|
|
1013
|
+
drift on what a column is called."""
|
|
996
1014
|
if field is None:
|
|
997
1015
|
return ""
|
|
998
|
-
|
|
999
|
-
return col if isinstance(col, str) and col else field.name
|
|
1016
|
+
return resolve_column_name(field, strategy)
|
|
1000
1017
|
|
|
1001
1018
|
|
|
1002
1019
|
def _q(ident: str) -> str:
|
|
@@ -128,22 +128,34 @@ def test_nested_object_array_imports_ref() -> None:
|
|
|
128
128
|
assert "posts: list[PostBrief] | None = None" in out
|
|
129
129
|
|
|
130
130
|
|
|
131
|
-
def
|
|
132
|
-
"""
|
|
133
|
-
name
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
131
|
+
def test_column_attr_does_not_rename_the_read_model_field() -> None:
|
|
132
|
+
"""``@column`` is the PHYSICAL column name. It must not become the Pydantic field
|
|
133
|
+
name — that is a different axis, and conflating them made one generated module
|
|
134
|
+
disagree with itself.
|
|
135
|
+
|
|
136
|
+
The read model used to key by ``@column``. Everything else in this port keys by
|
|
137
|
+
``field.name``: the FR-036 create/patch models, the generated router (it stamps
|
|
138
|
+
``dto["createdAt"]``), and the runtime — ``ObjectManager`` maps
|
|
139
|
+
``{_column_of(f): f.name}`` on every read and RETURNING clause, commented "for
|
|
140
|
+
cross-port row-shape parity". So the read model's stated reason ("the Python model
|
|
141
|
+
field IS the column, so it binds straight to the row") was false: the runtime never
|
|
142
|
+
hands out column-keyed rows.
|
|
143
|
+
|
|
144
|
+
It also leaked. ``@column`` is a free-form override, so a field ``callPurpose`` with
|
|
145
|
+
``@column: purpose_code`` produced a Pydantic field ``purpose_code`` — neither the
|
|
146
|
+
wire name nor anything derived from the field name, just the DB column surfacing in
|
|
147
|
+
the API shape. Idiomatic snake_case for Python is a real goal; the lever for it is
|
|
148
|
+
``columnNamingStrategy`` applied to ``field.name``, not the column override.
|
|
149
|
+
"""
|
|
139
150
|
f = _f("callPurpose", fc.FIELD_SUBTYPE_STRING, required=True)
|
|
140
|
-
|
|
151
|
+
# Deliberately NOT the snake_case of the field name — that coincidence is what made
|
|
152
|
+
# the old behaviour look right.
|
|
153
|
+
f.set_attr(fc.FIELD_ATTR_COLUMN, "purpose_code")
|
|
141
154
|
e = _entity("LlmCall", [f], package="app::telemetry")
|
|
142
155
|
out = render_entity_model(e)
|
|
143
|
-
# Scope to the read model (before the first validation model): it binds @column.
|
|
144
156
|
read_model = out.split("class LlmCallCreate")[0]
|
|
145
|
-
assert "
|
|
146
|
-
assert "
|
|
157
|
+
assert "callPurpose: str" in read_model
|
|
158
|
+
assert "purpose_code" not in read_model
|
|
147
159
|
|
|
148
160
|
|
|
149
161
|
def test_field_name_used_when_no_column_attr() -> None:
|
|
@@ -301,8 +313,9 @@ def test_create_model_validates_against_wire_name_not_column() -> None:
|
|
|
301
313
|
f.set_attr(fc.FIELD_ATTR_COLUMN, "full_name")
|
|
302
314
|
mod = _load_models(_entity("Person", [f], package="app::p"))
|
|
303
315
|
|
|
304
|
-
#
|
|
305
|
-
|
|
316
|
+
# BOTH key by the wire name now — the read model no longer renames itself to
|
|
317
|
+
# @column, so one module no longer disagrees with itself about what a field is called.
|
|
318
|
+
assert "fullName" in mod.Person.model_fields
|
|
306
319
|
assert "fullName" in mod.PersonCreate.model_fields
|
|
307
320
|
# An over-length WIRE value is now actually rejected (was silently dropped before).
|
|
308
321
|
with pytest.raises(ValidationError):
|
|
@@ -62,3 +62,41 @@ def test_installed_version_is_a_string() -> None:
|
|
|
62
62
|
v = installed_metaobjects_version()
|
|
63
63
|
assert isinstance(v, str)
|
|
64
64
|
assert v # non-empty
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# ── the context is AHEAD of the install (publish-what-changed, docs/RELEASING.md) ──
|
|
68
|
+
# A registry publishes only when it has a changed product file, so Python legitimately
|
|
69
|
+
# sits behind npm — and ``meta agent-docs`` (npm, canonical for every port) stamps the
|
|
70
|
+
# NEWER version. Nudging there is #347's shape: the remedy re-stamps the same newer
|
|
71
|
+
# version, so the advisory can never be satisfied and fires forever on a correct setup.
|
|
72
|
+
def test_context_from_a_newer_release_is_silent() -> None:
|
|
73
|
+
assert agent_context_staleness({"generatedBy": "0.24.7"}, "0.24.4") is None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_context_newer_only_in_the_patch_is_silent() -> None:
|
|
77
|
+
assert agent_context_staleness({"generatedBy": "0.24.5"}, "0.24.4") is None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_context_older_than_the_install_still_nudges() -> None:
|
|
81
|
+
msg = agent_context_staleness({"generatedBy": "0.24.4"}, "0.24.7")
|
|
82
|
+
assert msg is not None
|
|
83
|
+
assert "0.24.4" in msg
|
|
84
|
+
assert "0.24.7" in msg
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# The suppression is deliberately narrow: anything not orderable as a plain release
|
|
88
|
+
# still nudges, preserving the documented "ANY drift nudges" property.
|
|
89
|
+
def test_prerelease_context_still_nudges() -> None:
|
|
90
|
+
assert agent_context_staleness({"generatedBy": "0.24.5-rc.1"}, "0.24.4") is not None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_build_metadata_still_nudges() -> None:
|
|
94
|
+
assert agent_context_staleness({"generatedBy": "0.24.5+abc"}, "0.24.4") is not None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_unresolved_install_never_asserts_in_sync() -> None:
|
|
98
|
+
assert agent_context_staleness({"generatedBy": "0.24.7"}, "0.0.0") is not None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_non_numeric_version_still_nudges() -> None:
|
|
102
|
+
assert agent_context_staleness({"generatedBy": "dev"}, "0.24.4") is not None
|