metaobjects 0.15.12__tar.gz → 0.16.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {metaobjects-0.15.12 → metaobjects-0.16.0}/PKG-INFO +1 -1
- {metaobjects-0.15.12 → metaobjects-0.16.0}/pyproject.toml +1 -1
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/KNOWN_GAPS.md +8 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/entity_model.py +271 -27
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/m2m_codegen.py +3 -3
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/router_generator.py +158 -35
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/extract/extract.py +6 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/extract/types.py +31 -0
- metaobjects-0.16.0/tests/codegen/golden/extends/expected/BaseEntity.py +23 -0
- metaobjects-0.16.0/tests/codegen/golden/extends/expected/Program.py +27 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +2 -2
- metaobjects-0.16.0/tests/codegen/golden/vanilla/expected/Subscriber.py +26 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_entity_model.py +128 -9
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_extends_abstract_field_inheritance.py +6 -3
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_generator_extension_seams.py +2 -2
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_inherit_without_restate_gate.py +8 -3
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_inheritance_conformance.py +6 -2
- metaobjects-0.16.0/tests/codegen/test_router_generator.py +357 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/api_contract_server.py +29 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/generated_jsonb_app.py +3 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/generated_m2m_app.py +7 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/generated_router_app.py +6 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/generated_tph_app.py +7 -0
- metaobjects-0.16.0/tests/integration/test_generated_router_uuid_pk.py +224 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/uv.lock +1 -1
- metaobjects-0.15.12/tests/codegen/golden/extends/expected/BaseEntity.py +0 -11
- metaobjects-0.15.12/tests/codegen/golden/extends/expected/Program.py +0 -11
- metaobjects-0.15.12/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -12
- metaobjects-0.15.12/tests/codegen/test_router_generator.py +0 -160
- {metaobjects-0.15.12 → metaobjects-0.16.0}/.gitignore +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/LICENSE +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/README.md +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/hatch_build.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/agent_context/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/agent_context/scaffold.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/apidocs/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/apidocs/api_model.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/apidocs/builder.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/apidocs/naming.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/apidocs/paths.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/apidocs/renderer.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/attr_class_map.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/cli.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/config.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/format.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generator_registry.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/payload_vo_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/template_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/instance_artifacts.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/overwrite_policy.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/runner.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/runtime/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/type_map.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/core_types.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/datatype.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/documentation/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/documentation/doc_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/documentation/doc_provider.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/documentation/doc_schema.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/errors.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/merge.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/meta_data_loader.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/registered_validation.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/sources/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/sources/directory_source.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/sources/file_source.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/sources/uri_source.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/validate_discriminator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/validate_field_readonly.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/loader/validation_passes.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/attr/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/field/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/field/field_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/field/meta_field.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/identity/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/index/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/index/index_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/index/meta_index.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/object/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/object/meta_object.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/object/object_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/object/object_extract.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/object/value_object.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/validator/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/meta_data.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/meta_root.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/persistence/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/presentation/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/provider_extends.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/template/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/template/meta_template.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/template/prompt_provider.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/meta/template/template_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/naming_refs.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/parser.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/parser_yaml.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/provider.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/py.typed +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/registry.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/registry_manifest.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/email_document.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/escapers.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/extract/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/extract/coerce.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/extract/extract_map.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/extract/locate.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/extract/normalize.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/extract/strip.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/filesystem_provider.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/prompt/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/prompt/prompt_field.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/prompt/prompt_style.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/renderer.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/render/verify.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/runtime/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/runtime/llm_recorder.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/runtime/n2m_resolver.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/runtime/object_manager.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/runtime/tph.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/serializer_json.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/shared/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/shared/base_types.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/shared/separators.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/shared/structural.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/source/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/source/error_source.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/source/json_path.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/source/semantic_diff.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/source/yaml_positions.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/attr.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/db.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/documentation.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/field.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/identity.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/index.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/layout.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/object.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/origin.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/prompt.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/relationship.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/source.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/template.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/ui.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/validator.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/spec_metamodel/view.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/super_resolve.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/validation_types.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/yaml_desugar.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/golden/extends/meta.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/golden/nested-array/meta.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/golden/scalars/expected/Report.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/golden/scalars/meta.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/golden/vanilla/meta.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_abstract_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_api_docs_builder.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_api_docs_paths.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_cli.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_cli_providers.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_cli_registry.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_cli_staleness_nudge.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_cli_verify_strict.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_cli_verify_subverbs.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_constants_config.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_enum_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_extractor_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_filter_allowlist_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_format.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_fr010_output_codegen.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_golden.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_instance_artifacts.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_m2m_codegen.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_output_parser_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_overwrite_policy.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_payload_vo_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_projection_compile.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_render_helper_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_render_helper_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_reverse_finders.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_runner.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_template_data.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_template_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_template_output_pattern.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_template_scope_helpers.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_template_scope_walk.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_template_spec.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_tph_codegen.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_trace_helper_generator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_type_map.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/codegen/test_validation_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/capabilities.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/conformance-expected-failures.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/conformance_adapter.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/corpus.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/expected_failures.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/fixture_discovery.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/navigator.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_extract_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_extract_object_verdict.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_fr010_loader_attrs.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_fr011_attrs.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_generator_registry_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_object_model_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_provider_composition_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_registry_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_runner_hardfail.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_spec_metamodel_embed.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_strict_attr_load.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_template_codegen_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_template_generator_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/test_yaml_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/api_contract_assertions.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/api_contract_jsonb_server.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/api_contract_m2m_server.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/meta_ai_trace.yaml +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/normalization.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/postgres_container.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/query_runner.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/scenarios.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/test_api_contract.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/test_api_contract_generated.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/test_api_contract_jsonb.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/test_api_contract_m2m.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/test_api_contract_m2m_generated.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/test_api_contract_tph_generated.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/test_llm_call_trace.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/test_normalization.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/test_query_scenarios.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/integration/test_runtime_return_types.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/open_closed_proof_test.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/extract/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/extract/test_coerce.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/extract/test_extract.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/extract/test_extract_map.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/extract/test_json_forgiving_reader.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/extract/test_locate.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/extract/test_model.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/extract/test_normalize.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/extract/test_strip.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/prompt/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/prompt/test_output_format_renderer.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/test_email_document.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/test_filesystem_provider.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/test_output_format_renderer_nested.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/test_output_prompt_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/test_render_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/test_render_max_chars.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/test_verify.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/render/test_verify_conformance.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/source/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/source/test_fr5c_merge_attribution.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/source/test_fr5d_reference_resolution.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/source/test_fr5e_database_source_shape.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/source/test_json_path.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/source/test_semantic_diff.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/source/test_source_on_node.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/source/test_yaml_positions.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/test_api_docs_accuracy.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/__init__.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_agent_context_staleness.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_capabilities.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_common_attrs.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_core_types.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_effective_package.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_errors.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_field_enum.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_field_map_validation.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_index_lookup.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_llm_recorder.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_loader.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_loader_bom.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_loader_class.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_merge.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_meta_attr.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_meta_data.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_meta_source.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_module_shortcuts.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_n2m_resolver.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_n2m_resolver_inherited.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_one_primary_source.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_parser.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_parser_yaml.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_provider.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_provider_extension.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_registry.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_registry_completeness.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_registry_extend.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_registry_sealed.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_relationship_referential_actions.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_resolution_key.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_serializer.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_shared_constants.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_smoke.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_sources.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_strict_child_placement.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_super_resolve.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_template_toolcall.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_validation_attr_schema.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_validation_filter_values.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_validation_origin_paths.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_validation_sort_field.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_validation_warnings.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_write_coercion_arrays.py +0 -0
- {metaobjects-0.15.12 → metaobjects-0.16.0}/tests/unit/test_yaml_desugar.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metaobjects
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.0
|
|
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.
|
|
3
|
+
version = "0.16.0"
|
|
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"
|
|
@@ -32,6 +32,14 @@ The generated router takes `dto: dict[str, Any]` for `POST` / `PATCH` /
|
|
|
32
32
|
`PUT` request bodies and returns `Any` for responses. The repository
|
|
33
33
|
`Protocol` likewise uses `Any` for the row type.
|
|
34
34
|
|
|
35
|
+
**FR-036 update:** the router now DOES import the generated Pydantic models
|
|
36
|
+
(`from .<Entity> import <Entity>, <Entity>Patch`) and constructs them to enforce
|
|
37
|
+
field constraints over HTTP — POST validates `<Entity>(**dto)`, PATCH validates
|
|
38
|
+
the all-optional `<Entity>Patch(**dto)` (present values only) → `400 {"error":"validation"}`.
|
|
39
|
+
The repository seam still receives the original `dict` (preserving the FR-035
|
|
40
|
+
present-key tristate + wire values), so the strong-typing simplification below
|
|
41
|
+
remains for the repo/response types; only the validation import was added.
|
|
42
|
+
|
|
35
43
|
This keeps the router module decoupled from sibling generated files
|
|
36
44
|
(the entity-model generator emits one `@dataclass`/Pydantic model per
|
|
37
45
|
entity in a separate file — wiring router→entity-model would require
|
{metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/entity_model.py
RENAMED
|
@@ -5,7 +5,14 @@ import re
|
|
|
5
5
|
|
|
6
6
|
from metaobjects.meta.core.field.meta_field import MetaField
|
|
7
7
|
from metaobjects.meta.core.object.meta_object import MetaObject
|
|
8
|
+
from metaobjects.meta.core.object.object_constants import OBJECT_SUBTYPE_ENTITY
|
|
8
9
|
from metaobjects.meta.core.field import field_constants as fc
|
|
10
|
+
from metaobjects.meta.core.identity.identity_constants import (
|
|
11
|
+
GENERATION_INCREMENT,
|
|
12
|
+
GENERATION_UUID,
|
|
13
|
+
IDENTITY_ATTR_FIELDS,
|
|
14
|
+
IDENTITY_ATTR_GENERATION,
|
|
15
|
+
)
|
|
9
16
|
from metaobjects.meta.core.validator import validator_constants as vc
|
|
10
17
|
from metaobjects.shared.base_types import TYPE_VALIDATOR
|
|
11
18
|
from metaobjects.shared.separators import PACKAGE_SEP
|
|
@@ -98,7 +105,10 @@ def _validator_constraints(field: MetaField) -> dict[str, object]:
|
|
|
98
105
|
max_len = _first_attr(field, vc.VALIDATOR_SUBTYPE_LENGTH, vc.VALIDATOR_ATTR_MAX)
|
|
99
106
|
field_max = field.attrs().get(fc.FIELD_ATTR_MAX_LENGTH)
|
|
100
107
|
if _is_int(field_max):
|
|
101
|
-
|
|
108
|
+
# FR-036 A3 — strictest-wins: when BOTH a validator.length @max and a field
|
|
109
|
+
# @maxLength cap a string, the smaller bound governs (never the field attr
|
|
110
|
+
# unconditionally, which could loosen a tighter validator).
|
|
111
|
+
max_len = field_max if max_len is None else min(max_len, field_max)
|
|
102
112
|
if min_len is not None:
|
|
103
113
|
kwargs["min_length"] = min_len
|
|
104
114
|
if max_len is not None:
|
|
@@ -127,7 +137,11 @@ def _validator_constraints(field: MetaField) -> dict[str, object]:
|
|
|
127
137
|
# located via the resolving field.children() in _validators().
|
|
128
138
|
pattern = v.attr(vc.VALIDATOR_ATTR_PATTERN)
|
|
129
139
|
if isinstance(pattern, str):
|
|
130
|
-
|
|
140
|
+
# FR-036 Pin 2 — a validator.regex is a FULL match. Pydantic v2 `pattern=`
|
|
141
|
+
# is search/partial (un-anchored), so wrap the authored expression in an
|
|
142
|
+
# anchored non-capturing group so alternation still spans the whole value
|
|
143
|
+
# (a redundant anchor on an already-anchored pattern matches identically).
|
|
144
|
+
kwargs["pattern"] = f"^(?:{pattern})$"
|
|
131
145
|
break
|
|
132
146
|
|
|
133
147
|
# ADR-0036/0037 Wave 3 — @stringFormat: hostname -> a codegen-owned canonical
|
|
@@ -137,60 +151,87 @@ def _validator_constraints(field: MetaField) -> dict[str, object]:
|
|
|
137
151
|
if field.attrs().get(fc.FIELD_ATTR_STRING_FORMAT) == fc.STRING_FORMAT_HOSTNAME:
|
|
138
152
|
kwargs["pattern"] = _HOSTNAME_REGEX
|
|
139
153
|
|
|
154
|
+
# FR-036 Pin 1 — a @required non-array string is non-empty: reject null / "" but
|
|
155
|
+
# ACCEPT whitespace-only. Emit an implicit min_length of 1, keeping the stricter
|
|
156
|
+
# floor if a validator.length @min already set one.
|
|
157
|
+
if (
|
|
158
|
+
field.sub_type == fc.FIELD_SUBTYPE_STRING
|
|
159
|
+
and not field_is_array(field)
|
|
160
|
+
and field.attrs().get(fc.FIELD_ATTR_REQUIRED) is True
|
|
161
|
+
):
|
|
162
|
+
existing_min = kwargs.get("min_length")
|
|
163
|
+
kwargs["min_length"] = max(1, existing_min) if isinstance(existing_min, int) else 1
|
|
164
|
+
|
|
140
165
|
return kwargs
|
|
141
166
|
|
|
142
167
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
168
|
+
# Constraint kwargs are emitted in this fixed order so generated output is deterministic.
|
|
169
|
+
_CONSTRAINT_ORDER = ("pattern", "ge", "le", "min_length", "max_length")
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _constraint_parts(constraints: dict[str, object]) -> list[str]:
|
|
173
|
+
"""The ``Field(...)`` constraint kwargs rendered in the stable, deterministic order."""
|
|
174
|
+
return [f"{k}={constraints[k]!r}" for k in _CONSTRAINT_ORDER if k in constraints]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _type_expr_for_field(
|
|
178
|
+
field: MetaField, imports: set[str], config: GenConfig
|
|
179
|
+
) -> tuple[str, str | None]:
|
|
180
|
+
"""The Python annotation text for *field* (arrays wrapped in ``list[...]``) plus the
|
|
181
|
+
shared-enum class name when the field resolves to one (used to render an enum
|
|
182
|
+
default). Collects any required imports into *imports*. Shared by the create-model
|
|
183
|
+
and patch-model emitters so both carry byte-identical typing.
|
|
184
|
+
|
|
185
|
+
FR-019: a field resolving to a package-level shared enum is typed by the materialized
|
|
186
|
+
standalone class (imported from the shared ``enums`` module) or — when @provided — an
|
|
187
|
+
external module; inline enums keep their ``Literal[...]`` (py_type_for)."""
|
|
148
188
|
shared = (
|
|
149
189
|
fr019.shared_enum_for_field(field)
|
|
150
190
|
if field.sub_type == fc.FIELD_SUBTYPE_ENUM
|
|
151
191
|
else None
|
|
152
192
|
)
|
|
193
|
+
enum_type_name: str | None = None
|
|
153
194
|
if shared is not None:
|
|
154
195
|
type_name, import_line = fr019.enum_type_and_import(shared, config)
|
|
155
196
|
imports.add(import_line)
|
|
197
|
+
enum_type_name = type_name
|
|
156
198
|
type_expr = f"list[{type_name}]" if field_is_array(field) else type_name
|
|
157
199
|
else:
|
|
158
200
|
pt = py_type_for(field)
|
|
159
201
|
imports.update(pt.imports)
|
|
160
202
|
type_expr = pt.expr
|
|
161
|
-
# ADR-0036/0037 Wave 3 — @stringFormat: email narrows a plain string to a
|
|
162
|
-
#
|
|
163
|
-
#
|
|
164
|
-
# pattern= (handled in _validator_constraints). The field stays a string.
|
|
203
|
+
# ADR-0036/0037 Wave 3 — @stringFormat: email narrows a plain string to a validated
|
|
204
|
+
# email (Pydantic EmailStr, the Python analogue of Zod .email()); hostname stays a
|
|
205
|
+
# plain str with a codegen-owned canonical pattern= (in _validator_constraints).
|
|
165
206
|
if (
|
|
166
207
|
field.sub_type == fc.FIELD_SUBTYPE_STRING
|
|
167
208
|
and field.attrs().get(fc.FIELD_ATTR_STRING_FORMAT) == fc.STRING_FORMAT_EMAIL
|
|
168
209
|
):
|
|
169
|
-
base_expr = "EmailStr"
|
|
170
210
|
imports.add("from pydantic import EmailStr")
|
|
171
|
-
type_expr =
|
|
211
|
+
type_expr = "list[EmailStr]" if field_is_array(field) else "EmailStr"
|
|
172
212
|
if field.sub_type in (fc.FIELD_SUBTYPE_OBJECT, fc.FIELD_SUBTYPE_MAP):
|
|
173
|
-
# A field.object (-> VO) and a field.map with @objectRef (-> dict[str, VO])
|
|
174
|
-
#
|
|
175
|
-
#
|
|
213
|
+
# A field.object (-> VO) and a field.map with @objectRef (-> dict[str, VO]) both
|
|
214
|
+
# reference a value-object by name; import it so the emitted annotation resolves.
|
|
215
|
+
# @objectRef is FQN-expanded at load; the generated VOs live flat in one package,
|
|
216
|
+
# so import by the bare class name.
|
|
176
217
|
ref = field.attrs().get(fc.FIELD_ATTR_OBJECT_REF)
|
|
177
218
|
if ref:
|
|
178
|
-
# @objectRef is FQN-expanded at load time; the generated VOs live
|
|
179
|
-
# flat in one package, so import by the bare class name.
|
|
180
219
|
ref_name = str(ref).split("::")[-1]
|
|
181
220
|
imports.add(f"from .{ref_name} import {ref_name}")
|
|
221
|
+
return type_expr, enum_type_name
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _field_line(field: MetaField, imports: set[str], config: GenConfig) -> tuple[str, bool]:
|
|
225
|
+
"""Return (source line, uses_field). Collects required imports into *imports*."""
|
|
226
|
+
type_expr, enum_type_name = _type_expr_for_field(field, imports, config)
|
|
182
227
|
required = field.attrs().get(fc.FIELD_ATTR_REQUIRED) is True
|
|
183
228
|
default_raw = field.attrs().get(fc.FIELD_ATTR_DEFAULT)
|
|
184
229
|
# A server-side expression default (now(), gen_random_uuid(), CURRENT_TIMESTAMP)
|
|
185
230
|
# is filled by the DB — the Python model carries no default for it (the field keeps
|
|
186
231
|
# its required/optional shape). Only literal defaults become Pydantic defaults.
|
|
187
232
|
has_default = default_raw is not None and not _is_sql_expr_default(default_raw)
|
|
188
|
-
enum_type_name = type_name if shared is not None else None
|
|
189
233
|
|
|
190
|
-
|
|
191
|
-
# Emit kwargs in a stable order so generated output is deterministic.
|
|
192
|
-
_order = ["pattern", "ge", "le", "min_length", "max_length"]
|
|
193
|
-
parts = [f"{k}={constraints[k]!r}" for k in _order if k in constraints]
|
|
234
|
+
parts = _constraint_parts(_validator_constraints(field))
|
|
194
235
|
uses_field = bool(parts)
|
|
195
236
|
|
|
196
237
|
# @default — render an enum member (Type.MEMBER, UPPER_CASE) or a Python literal.
|
|
@@ -226,6 +267,106 @@ def _field_line(field: MetaField, imports: set[str], config: GenConfig) -> tuple
|
|
|
226
267
|
return f" {py_name}: {annotation}{assignment}", uses_field
|
|
227
268
|
|
|
228
269
|
|
|
270
|
+
def _primary_identity_field_names(entity: MetaObject) -> list[str]:
|
|
271
|
+
"""The field names in the entity's primary identity (``identity.primary @fields``),
|
|
272
|
+
normalized to a list. Empty when there is no primary identity. Mirrors the TS
|
|
273
|
+
``primaryIdentityFieldNames``."""
|
|
274
|
+
primary = entity.primary_identity()
|
|
275
|
+
if primary is None:
|
|
276
|
+
return []
|
|
277
|
+
# ADR-0039: resolving (identity attr) — an identity.primary may be inherited via extends.
|
|
278
|
+
fields = primary.get_meta_attr(IDENTITY_ATTR_FIELDS)
|
|
279
|
+
if isinstance(fields, (list, tuple)):
|
|
280
|
+
return [str(f) for f in fields]
|
|
281
|
+
if isinstance(fields, str) and fields:
|
|
282
|
+
return [s.strip() for s in fields.split(",") if s.strip()]
|
|
283
|
+
return []
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _auto_gen_pk_field_names(entity: MetaObject) -> set[str]:
|
|
287
|
+
"""Primary-key field names that the SERVER generates (``identity.primary
|
|
288
|
+
@generation: increment|uuid``) — excluded from the create-validation shape because
|
|
289
|
+
the caller never supplies them. An ``assigned`` (or ungenerated) PK is NOT excluded
|
|
290
|
+
(the caller provides it). Mirrors the TS ``autoGenPkFieldNames``."""
|
|
291
|
+
primary = entity.primary_identity()
|
|
292
|
+
if primary is None:
|
|
293
|
+
return set()
|
|
294
|
+
# ADR-0039: resolving (identity attr).
|
|
295
|
+
generation = primary.get_meta_attr(IDENTITY_ATTR_GENERATION)
|
|
296
|
+
if generation not in (GENERATION_INCREMENT, GENERATION_UUID):
|
|
297
|
+
return set()
|
|
298
|
+
return set(_primary_identity_field_names(entity))
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def _create_field_line(
|
|
302
|
+
field: MetaField, imports: set[str], config: GenConfig
|
|
303
|
+
) -> tuple[str, bool]:
|
|
304
|
+
"""A CREATE-model field line (FR-036): keyed by the WIRE name (``field.name``) and
|
|
305
|
+
carrying the same per-field constraints as the read model. A ``@required`` field
|
|
306
|
+
that is SERVER-FILLED — it has ANY ``@default`` (a literal OR a SQL expression such
|
|
307
|
+
as ``now()`` / ``gen_random_uuid()`` / ``CURRENT_TIMESTAMP``) or an ``@autoSet`` — is
|
|
308
|
+
emitted OPTIONAL, because the DB / trigger provides it and a POST that omits it must
|
|
309
|
+
not 400 (mirrors the TS InsertSchema ``fieldWillBeOptional``). A literal ``@default``
|
|
310
|
+
is preserved as the Python default; a SQL-expression default / ``@autoSet`` carries
|
|
311
|
+
no Python default (the server fills it). Returns (source line, uses_field)."""
|
|
312
|
+
type_expr, enum_type_name = _type_expr_for_field(field, imports, config)
|
|
313
|
+
required = field.attrs().get(fc.FIELD_ATTR_REQUIRED) is True
|
|
314
|
+
default_raw = field.attrs().get(fc.FIELD_ATTR_DEFAULT)
|
|
315
|
+
literal_default = default_raw is not None and not _is_sql_expr_default(default_raw)
|
|
316
|
+
auto_set = field.attrs().get(fc.FIELD_ATTR_AUTO_SET)
|
|
317
|
+
is_auto_set = auto_set in (fc.AUTO_SET_ON_CREATE, fc.AUTO_SET_ON_UPDATE)
|
|
318
|
+
# A field is required in the CREATE shape only when @required AND not server-filled:
|
|
319
|
+
# ANY @default (literal or SQL-expr) or @autoSet means the DB fills it, so the wire
|
|
320
|
+
# body may omit it (the FR-036 #1 regression fix).
|
|
321
|
+
server_filled = default_raw is not None or is_auto_set
|
|
322
|
+
create_required = required and not server_filled
|
|
323
|
+
|
|
324
|
+
parts = _constraint_parts(_validator_constraints(field))
|
|
325
|
+
uses_field = bool(parts)
|
|
326
|
+
|
|
327
|
+
py_name = field.name # FR-036 #3 — validation models key by the WIRE name (field.name)
|
|
328
|
+
|
|
329
|
+
if literal_default:
|
|
330
|
+
# Preserve the literal @default (enum member or Python literal) exactly as the
|
|
331
|
+
# read model does — the caller may omit the field and the model fills the default.
|
|
332
|
+
if enum_type_name is not None and not field_is_array(field):
|
|
333
|
+
default_expr = f"{enum_type_name}.{str(default_raw).upper()}"
|
|
334
|
+
else:
|
|
335
|
+
default_expr = repr(default_raw)
|
|
336
|
+
annotation = type_expr
|
|
337
|
+
assignment = (
|
|
338
|
+
f" = Field(default={default_expr}, {', '.join(parts)})"
|
|
339
|
+
if uses_field
|
|
340
|
+
else f" = {default_expr}"
|
|
341
|
+
)
|
|
342
|
+
elif create_required:
|
|
343
|
+
annotation = type_expr
|
|
344
|
+
assignment = f" = Field({', '.join(parts)})" if uses_field else ""
|
|
345
|
+
else:
|
|
346
|
+
annotation = f"{type_expr} | None"
|
|
347
|
+
assignment = (
|
|
348
|
+
f" = Field(default=None, {', '.join(parts)})" if uses_field else " = None"
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
return f" {py_name}: {annotation}{assignment}", uses_field
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _patch_field_line(
|
|
355
|
+
field: MetaField, imports: set[str], config: GenConfig
|
|
356
|
+
) -> tuple[str, bool]:
|
|
357
|
+
"""A PATCH-model field line: the field is made Optional (default ``None``) yet
|
|
358
|
+
carries the SAME per-field constraints as the create model, so a present, non-null
|
|
359
|
+
value is validated with the create rules (FR-036) while an absent field is left
|
|
360
|
+
untouched. A ``@default`` is never emitted (a patch does not default a column).
|
|
361
|
+
Returns (source line, uses_field)."""
|
|
362
|
+
type_expr, _enum = _type_expr_for_field(field, imports, config)
|
|
363
|
+
parts = _constraint_parts(_validator_constraints(field))
|
|
364
|
+
py_name = field.name # FR-036 #3 — validation models key by the WIRE name (field.name)
|
|
365
|
+
if parts:
|
|
366
|
+
return f" {py_name}: {type_expr} | None = Field(default=None, {', '.join(parts)})", True
|
|
367
|
+
return f" {py_name}: {type_expr} | None = None", False
|
|
368
|
+
|
|
369
|
+
|
|
229
370
|
def _effective_fqn(entity: MetaObject) -> str:
|
|
230
371
|
"""`package::name` via the canonical :meth:`MetaData.resolution_key` — own
|
|
231
372
|
package, else the file-default package (captured at parse), else the nearest
|
|
@@ -295,6 +436,76 @@ class EntityModelGenerator:
|
|
|
295
436
|
lines.append(f" {d.relation_name}: list[{element}] = []")
|
|
296
437
|
return lines, uses_field
|
|
297
438
|
|
|
439
|
+
def _emit_create_lines(
|
|
440
|
+
self,
|
|
441
|
+
entity: MetaObject,
|
|
442
|
+
imports: set[str],
|
|
443
|
+
config: GenConfig | None = None,
|
|
444
|
+
) -> tuple[list[str], bool]:
|
|
445
|
+
"""The ``<Name>Create`` body — the CREATE-validation shape the generated router
|
|
446
|
+
validates a POST body against (FR-036). Restates every EFFECTIVE field (own +
|
|
447
|
+
inherited via ``extends``) EXCEPT the ones the server owns: an auto-generated PK
|
|
448
|
+
(``identity.primary @generation``; FR-036 #2) and any ``@readOnly`` field
|
|
449
|
+
(FR-013) are omitted, and a ``@required`` server-filled field (``@default`` /
|
|
450
|
+
``@autoSet``; FR-036 #1) is made optional. Keyed by the wire name; a TPH
|
|
451
|
+
subtype's discriminator is pinned to its ``Literal`` value (the route injects it
|
|
452
|
+
from the URL, so it stays optional with a default). M:N navigations are omitted
|
|
453
|
+
(a create body targets columns, not relations). Returns ``(lines, uses_field)``.
|
|
454
|
+
Override to add/transform create-model lines."""
|
|
455
|
+
cfg = config if config is not None else GenConfig(out_dir="")
|
|
456
|
+
auto_gen_pk = _auto_gen_pk_field_names(entity)
|
|
457
|
+
binding = tph_subtype_binding(entity)
|
|
458
|
+
disc_field = binding[0] if binding is not None else None
|
|
459
|
+
uses_field = False
|
|
460
|
+
lines: list[str] = []
|
|
461
|
+
# RESOLVING (fields()): the flat Create model subclasses BaseModel (not the entity
|
|
462
|
+
# base), so it restates inherited fields too — unlike the read model's own_fields
|
|
463
|
+
# subclass-emit.
|
|
464
|
+
for f in entity.fields():
|
|
465
|
+
if disc_field is not None and f.name == disc_field:
|
|
466
|
+
continue # pinned below (prepended), never as a normal field line
|
|
467
|
+
if f.name in auto_gen_pk:
|
|
468
|
+
continue # FR-036 #2 — a server-generated PK is never in the create body
|
|
469
|
+
if f.attrs().get(fc.FIELD_ATTR_READ_ONLY) is True:
|
|
470
|
+
continue # FR-013 — a read-only column is DB/owner-written, not create input
|
|
471
|
+
line, used = _create_field_line(f, imports, cfg)
|
|
472
|
+
uses_field = uses_field or used
|
|
473
|
+
lines.append(line)
|
|
474
|
+
# FR-017 TPH: pin the inherited discriminator to this subtype's value (with a
|
|
475
|
+
# default so the URL-injected create body may omit it) — mirrors the read model.
|
|
476
|
+
if binding is not None:
|
|
477
|
+
disc_name, disc_value = binding
|
|
478
|
+
lines = [f' {disc_name}: Literal["{disc_value}"] = "{disc_value}"', *lines]
|
|
479
|
+
imports.add("from typing import Literal")
|
|
480
|
+
return lines, uses_field
|
|
481
|
+
|
|
482
|
+
def _emit_patch_lines(
|
|
483
|
+
self,
|
|
484
|
+
entity: MetaObject,
|
|
485
|
+
imports: set[str],
|
|
486
|
+
config: GenConfig | None = None,
|
|
487
|
+
) -> tuple[list[str], bool]:
|
|
488
|
+
"""The ``<Name>Patch`` body: every EFFECTIVE field (own + inherited via
|
|
489
|
+
``extends``) made Optional while retaining its create-model constraints, so the
|
|
490
|
+
generated PATCH handler can validate present, non-null values without
|
|
491
|
+
bean-validating absent ones (FR-036). The primary-key field(s) are excluded
|
|
492
|
+
(route-authoritative; FR-036 #4) and M:N navigations are omitted (a patch
|
|
493
|
+
targets columns, not relations). Returns ``(lines, uses_field)``. Override to
|
|
494
|
+
add/transform patch-model lines."""
|
|
495
|
+
cfg = config if config is not None else GenConfig(out_dir="")
|
|
496
|
+
pk_fields = set(_primary_identity_field_names(entity))
|
|
497
|
+
uses_field = False
|
|
498
|
+
lines: list[str] = []
|
|
499
|
+
# RESOLVING (fields()): the flat Patch model is self-contained (subclasses
|
|
500
|
+
# BaseModel, not the entity base), so it restates inherited fields too.
|
|
501
|
+
for f in entity.fields():
|
|
502
|
+
if f.name in pk_fields:
|
|
503
|
+
continue # FR-036 #4 — the PK is route-authoritative, never patched
|
|
504
|
+
line, used = _patch_field_line(f, imports, cfg)
|
|
505
|
+
uses_field = uses_field or used
|
|
506
|
+
lines.append(line)
|
|
507
|
+
return lines, uses_field
|
|
508
|
+
|
|
298
509
|
def render_entity_model(
|
|
299
510
|
self,
|
|
300
511
|
entity: MetaObject,
|
|
@@ -333,11 +544,29 @@ class EntityModelGenerator:
|
|
|
333
544
|
imports.add("from typing import Literal")
|
|
334
545
|
body = lines if lines else [" pass"]
|
|
335
546
|
|
|
336
|
-
#
|
|
547
|
+
# FR-036 — an object.entity also emits two flat validation models the generated
|
|
548
|
+
# router binds: a ``<Name>Create`` (POST-body shape: auto-gen PK / @readOnly
|
|
549
|
+
# omitted, @default/@autoSet optional, other @required required) and an
|
|
550
|
+
# all-optional ``<Name>Patch`` (PATCH-body shape: PK excluded). Both key by the
|
|
551
|
+
# WIRE name and carry the field constraints, so present values are validated with
|
|
552
|
+
# the create rules. Value objects / projections are never routed, so they emit
|
|
553
|
+
# neither (only the read model). See findings #1–#4.
|
|
554
|
+
emit_validation_models = entity.sub_type == OBJECT_SUBTYPE_ENTITY
|
|
555
|
+
create_lines: list[str] = []
|
|
556
|
+
create_uses_field = False
|
|
557
|
+
patch_lines: list[str] = []
|
|
558
|
+
patch_uses_field = False
|
|
559
|
+
if emit_validation_models:
|
|
560
|
+
create_lines, create_uses_field = self._emit_create_lines(entity, imports, config)
|
|
561
|
+
patch_lines, patch_uses_field = self._emit_patch_lines(entity, imports, config)
|
|
562
|
+
|
|
563
|
+
# Import only the pydantic names actually referenced. The main model imports
|
|
564
|
+
# BaseModel only when it has no super, but the flat Create/Patch models always
|
|
565
|
+
# subclass BaseModel, so their presence forces the import regardless.
|
|
337
566
|
pyd_names: list[str] = []
|
|
338
|
-
if entity.super_data is None:
|
|
567
|
+
if entity.super_data is None or emit_validation_models:
|
|
339
568
|
pyd_names.append("BaseModel")
|
|
340
|
-
if uses_field:
|
|
569
|
+
if uses_field or create_uses_field or patch_uses_field:
|
|
341
570
|
pyd_names.append("Field")
|
|
342
571
|
|
|
343
572
|
parts: list[str] = [
|
|
@@ -350,7 +579,22 @@ class EntityModelGenerator:
|
|
|
350
579
|
parts += [*extra_imports, ""]
|
|
351
580
|
if pyd_names:
|
|
352
581
|
parts += [f"from pydantic import {', '.join(pyd_names)}", ""]
|
|
353
|
-
parts += ["", self._emit_class_header(entity, base_class), *body
|
|
582
|
+
parts += ["", self._emit_class_header(entity, base_class), *body]
|
|
583
|
+
if emit_validation_models:
|
|
584
|
+
parts += [
|
|
585
|
+
"",
|
|
586
|
+
"",
|
|
587
|
+
f"class {entity.name}Create(BaseModel):",
|
|
588
|
+
' """GENERATED — CREATE input: auto-gen PK / @readOnly omitted; '
|
|
589
|
+
'@default/@autoSet optional; present values validated (FR-036)."""',
|
|
590
|
+
*create_lines,
|
|
591
|
+
"",
|
|
592
|
+
"",
|
|
593
|
+
f"class {entity.name}Patch(BaseModel):",
|
|
594
|
+
' """GENERATED — PATCH input: all fields optional (PK excluded); present values validated (FR-036)."""',
|
|
595
|
+
*patch_lines,
|
|
596
|
+
]
|
|
597
|
+
parts += [""]
|
|
354
598
|
return "\n".join(parts)
|
|
355
599
|
|
|
356
600
|
def _render_shared_enums_module(self, entities: list[MetaObject]) -> EmittedFile | None:
|
{metaobjects-0.15.12 → metaobjects-0.16.0}/src/metaobjects/codegen/generators/m2m_codegen.py
RENAMED
|
@@ -110,7 +110,7 @@ def _field_named(entity: MetaObject, field_name: str) -> MetaField | None:
|
|
|
110
110
|
return None
|
|
111
111
|
|
|
112
112
|
|
|
113
|
-
def
|
|
113
|
+
def pk_field_name(entity: MetaObject) -> str:
|
|
114
114
|
"""The single PK field name (``identity.primary @fields``), default ``id``."""
|
|
115
115
|
for c in entity.children():
|
|
116
116
|
if c.type == TYPE_IDENTITY and c.sub_type == IDENTITY_SUBTYPE_PRIMARY:
|
|
@@ -184,8 +184,8 @@ def resolve_m2m_descriptors(
|
|
|
184
184
|
source_column=_column_of(source_fk, fields.source_field),
|
|
185
185
|
target_column=_column_of(target_fk, fields.target_field),
|
|
186
186
|
target_pk_column=_column_of(
|
|
187
|
-
_field_named(target,
|
|
188
|
-
|
|
187
|
+
_field_named(target, pk_field_name(target)),
|
|
188
|
+
pk_field_name(target),
|
|
189
189
|
),
|
|
190
190
|
symmetric=rel.symmetric(),
|
|
191
191
|
)
|