metaobjects 1.0.8__tar.gz → 1.0.9__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-1.0.8 → metaobjects-1.0.9}/PKG-INFO +1 -1
- {metaobjects-1.0.8 → metaobjects-1.0.9}/pyproject.toml +1 -1
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/cli.py +78 -10
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/eject.py +76 -3
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generator_registry.py +14 -3
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/extractor_generator.py +14 -7
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/router_generator.py +66 -7
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/trace_helper_generator.py +11 -6
- metaobjects-1.0.9/src/metaobjects/codegen/model_walk.py +101 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/runner.py +5 -1
- metaobjects-1.0.9/src/metaobjects/codegen/runtime/__init__.py +9 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/object/object_extract.py +25 -10
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/extract/extract.py +16 -6
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/extract/json_forgiving_reader.py +39 -3
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/extract/locate.py +14 -2
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/extract/types.py +18 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/prompt/output_format_renderer.py +14 -2
- metaobjects-1.0.9/tests/codegen/test_cli_gen_unknown_attr.py +70 -0
- metaobjects-1.0.9/tests/codegen/test_eject_runtime.py +331 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_extractor_generator.py +29 -1
- metaobjects-1.0.9/tests/codegen/test_recipe_generators.py +105 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_trace_helper_generator.py +3 -1
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_extract_conformance.py +6 -1
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/test_output_prompt_conformance.py +1 -1
- {metaobjects-1.0.8 → metaobjects-1.0.9}/uv.lock +1 -1
- metaobjects-1.0.8/src/metaobjects/codegen/runtime/__init__.py +0 -6
- {metaobjects-1.0.8 → metaobjects-1.0.9}/.gitignore +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/LICENSE +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/README.md +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/hatch_build.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/scripts/generate_embedded_library.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/agent_context/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/agent_context/scaffold.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/apidocs/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/apidocs/api_model.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/apidocs/builder.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/apidocs/naming.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/apidocs/paths.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/apidocs/renderer.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/attr_class_map.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/collision_names.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/config.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/format.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/entity_model.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/find_inbound.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/names_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/template_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/instance_artifacts.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/overwrite_policy.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/project_config.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/runtime/constraint_errors.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/type_map.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/value_objects.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/config/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/config/dependencies.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/config/neutral_config.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/config/source_resolver.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/core_types.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/datatype.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/documentation/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/documentation/doc_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/documentation/doc_provider.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/documentation/doc_schema.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/errors.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/library/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/library/embedded_library.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/library/library_sources.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/merge.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/meta_data_loader.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/registered_validation.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/sources/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/sources/directory_source.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/sources/file_source.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/sources/uri_source.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/validate_discriminator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/validate_field_mutability.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/validate_source_escapes.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/loader/validation_passes.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/attr/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/field/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/field/field_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/field/meta_field.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/identity/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/index/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/index/index_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/index/meta_index.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/object/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/object/meta_object.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/object/object_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/object/value_object.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/relationship/relationship_references.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/validator/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/meta_data.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/meta_root.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/persistence/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/presentation/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/provider_extends.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/template/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/template/meta_template.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/template/prompt_provider.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta/template/template_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/meta_endpoint.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/naming.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/naming_refs.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/parser.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/parser_yaml.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/provider.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/py.typed +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/registry.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/registry_manifest.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/email_document.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/escapers.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/extract/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/extract/coerce.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/extract/extract_map.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/extract/normalize.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/extract/strip.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/filesystem_provider.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/payload_accessors.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/prompt/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/prompt/prompt_field.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/prompt/prompt_style.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/renderer.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/render/verify.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/runtime/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/runtime/llm_recorder.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/runtime/n2m_resolver.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/runtime/object_manager.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/runtime/tph.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/scope.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/serializer_json.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/shared/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/shared/base_types.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/shared/separators.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/shared/structural.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/source/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/source/error_source.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/source/json_path.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/source/semantic_diff.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/source/yaml_positions.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/source_resolution.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/attr.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/db.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/documentation.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/field.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/identity.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/index.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/layout.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/object.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/origin.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/prompt.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/relationship.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/requirement.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/source.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/template.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/ui.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/validator.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/spec_metamodel/view.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/super_resolve.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/validation_types.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/yaml_desugar.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/gen_suite.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/golden/extends/expected/Program.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/golden/extends/meta.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/golden/nested-array/meta.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/golden/scalars/expected/Report.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/golden/scalars/meta.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/golden/vanilla/meta.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_abstract_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_api_docs_builder.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_api_docs_paths.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_cli.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_cli_config_gen.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_cli_config_verify.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_cli_dependencies.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_cli_providers.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_cli_registry.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_cli_render_helper_template_root.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_cli_staleness_nudge.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_cli_verify_strict.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_cli_verify_subverbs.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_codegen_compile_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_constants_config.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_eject.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_entity_model.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_enum_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_extract_tier_collision.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_filter_allowlist_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_format.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_fr010_output_codegen.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_gen_state_keying.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_generator_extension_seams.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_golden.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_inheritance_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_instance_artifacts.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_m2m_codegen.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_names_extends_chain.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_names_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_no_magic_physical_names.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_origin_nullability.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_output_parser_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_overwrite_policy.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_overwrite_policy_hash.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_project_config.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_projection_compile.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_render_helper_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_render_helper_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_reverse_finders.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_route_path_naming.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_router_autoset.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_router_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_router_generator_m2m_target_tph.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_router_generator_tph_m2m.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_router_generator_tph_m2m_shadowed.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_runner.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_source_resolution.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_sourceless_projection.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_template_data.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_template_generator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_template_output_pattern.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_template_scope_helpers.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_template_scope_walk.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_template_spec.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_tph_codegen.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_type_map.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_validation_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_value_objects.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/codegen/test_write_through.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/config/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/config/test_dependencies.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/config/test_library_package_guard.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/config/test_neutral_config.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/config/test_source_resolver.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/capabilities.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/conformance-expected-failures.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/conformance_adapter.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/corpus.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/expected_failures.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/fixture_discovery.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/navigator.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_dependency_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_extract_object_verdict.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_fr010_loader_attrs.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_fr011_attrs.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_generator_registry_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_object_model_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_provider_composition_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_registry_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_runner_hardfail.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_scope_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_source_resolution_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_spec_metamodel_embed.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_strict_attr_load.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_template_codegen_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_template_generator_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/test_yaml_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/api_contract_assertions.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/api_contract_jsonb_server.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/api_contract_m2m_server.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/api_contract_server.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/generated_jsonb_app.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/generated_m2m_app.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/generated_projection_app.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/generated_router_app.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/generated_tph_app.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/meta_ai_trace.yaml +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/normalization.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/postgres_container.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/query_runner.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/scenarios.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_api_contract.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_api_contract_generated.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_api_contract_jsonb.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_api_contract_m2m.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_api_contract_m2m_generated.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_api_contract_projection.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_api_contract_tph_generated.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_generated_router_uuid_pk.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_llm_call_trace.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_m2m_target_tph_generated.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_normalization.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_query_scenarios.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_runtime_return_types.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_tph_m2m_generated.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/integration/test_tph_m2m_shadowed_generated.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/loader/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/loader/test_abstract_subtype_authored.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/loader/test_child_wrapper_body_shape.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/loader/test_enum_extends_values_conflict.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/loader/test_field_mutability_order.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/loader/test_shipped_library_ai.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/loader/test_template_payload_target_210.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/open_closed_proof_test.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/extract/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/extract/test_coerce.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/extract/test_extract.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/extract/test_extract_map.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/extract/test_json_forgiving_reader.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/extract/test_locate.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/extract/test_model.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/extract/test_normalize.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/extract/test_strip.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/prompt/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/prompt/test_output_format_renderer.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/test_email_document.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/test_filesystem_provider.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/test_output_format_renderer_nested.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/test_render_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/test_render_max_chars.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/test_render_model_payload.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/test_verify.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/render/test_verify_conformance.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/runtime/test_constraint_errors.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/runtime/test_object_manager_currency_read.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/runtime/test_object_manager_enum_intvaluemap.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/runtime/test_object_manager_table_name.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/source/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/source/test_fr5c_merge_attribution.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/source/test_fr5d_reference_resolution.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/source/test_fr5e_database_source_shape.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/source/test_json_path.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/source/test_semantic_diff.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/source/test_source_on_node.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/source/test_yaml_positions.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/test_api_docs_accuracy.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/test_meta_endpoint.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/__init__.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_agent_context_staleness.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_capabilities.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_column_naming_strategy.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_common_attrs.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_core_types.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_derive_m2m_declaring_entity.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_effective_children_sibling_shadowing.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_effective_package.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_errors.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_field_enum.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_field_enum_intvaluemap.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_field_map_validation.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_file_source_id.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_index_lookup.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_llm_recorder.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_loader.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_loader_bom.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_loader_class.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_merge.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_meta_attr.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_meta_data.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_meta_source.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_module_shortcuts.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_n2m_resolver.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_n2m_resolver_inherited.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_no_dead_config_fields.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_object_manager_write_through.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_one_primary_source.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_parser.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_parser_yaml.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_provider.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_provider_extension.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_registry.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_registry_completeness.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_registry_extend.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_registry_sealed.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_relationship_m2m_validation.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_relationship_references.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_relationship_referential_actions.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_resolution_key.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_serializer.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_serializer_shared_document.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_shared_constants.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_smoke.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_source_escapes.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_sources.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_strict_child_placement.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_super_resolve.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_template_toolcall.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_validation_attr_schema.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_validation_filter_values.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_validation_origin_195.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_validation_origin_paths.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_validation_sort_field.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_validation_warnings.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_write_coercion_arrays.py +0 -0
- {metaobjects-1.0.8 → metaobjects-1.0.9}/tests/unit/test_yaml_desugar.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: metaobjects
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.9
|
|
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 = "1.0.
|
|
3
|
+
version = "1.0.9"
|
|
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"
|
|
@@ -57,7 +57,7 @@ from pathlib import Path
|
|
|
57
57
|
from typing import Callable
|
|
58
58
|
|
|
59
59
|
from metaobjects import MetaDataLoader
|
|
60
|
-
from metaobjects.errors import ParseError
|
|
60
|
+
from metaobjects.errors import ErrorCode, MetaError, ParseError
|
|
61
61
|
from metaobjects.config.dependencies import (
|
|
62
62
|
Collection,
|
|
63
63
|
imported_from,
|
|
@@ -276,9 +276,14 @@ def _load_root(
|
|
|
276
276
|
strict: bool = False,
|
|
277
277
|
providers: list[object] | None = None,
|
|
278
278
|
libraries: list[str] | None = None,
|
|
279
|
+
unknown_attr_out: list[str] | None = None,
|
|
279
280
|
) -> tuple[MetaData | None, list[str]]:
|
|
280
281
|
"""Load metadata; return ``(root, error_messages)``. ``root`` is None on error.
|
|
281
282
|
|
|
283
|
+
``unknown_attr_out`` — when given on a LENIENT load, a second strict load of the
|
|
284
|
+
same metadata is run and its ``ERR_UNKNOWN_ATTR`` findings are appended, formatted,
|
|
285
|
+
so ``gen`` can warn about what ``verify`` would reject instead of staying silent.
|
|
286
|
+
|
|
282
287
|
``strict`` (ADR-0023, #96) — when True, an undeclared own ``@attr`` →
|
|
283
288
|
``ERR_UNKNOWN_ATTR``. Defaults False so ``gen`` / ``docs`` keep the legacy
|
|
284
289
|
open-attr load; only ``verify`` opts in (strict-by-default with a ``--lax``
|
|
@@ -312,20 +317,24 @@ def _load_root(
|
|
|
312
317
|
return None, [f"{exc.code}: {exc}"]
|
|
313
318
|
all_libraries = _merge_libraries(neutral.libraries if neutral is not None else None, libraries)
|
|
314
319
|
|
|
315
|
-
|
|
320
|
+
def load(strict_load: bool) -> LoadResult:
|
|
316
321
|
if providers:
|
|
317
322
|
from metaobjects.core_types import core_providers
|
|
318
323
|
|
|
319
|
-
|
|
324
|
+
return MetaDataLoader.from_directory(
|
|
320
325
|
metadata_dir,
|
|
321
326
|
providers=[*core_providers, *providers],
|
|
322
|
-
strict=
|
|
327
|
+
strict=strict_load,
|
|
323
328
|
libraries=all_libraries,
|
|
324
329
|
)
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
330
|
+
return MetaDataLoader.from_directory(
|
|
331
|
+
metadata_dir, strict=strict_load, libraries=all_libraries
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
try:
|
|
335
|
+
result = load(strict)
|
|
336
|
+
if unknown_attr_out is not None and not strict and not result.errors:
|
|
337
|
+
unknown_attr_out.extend(_unknown_attr_findings(load(True)))
|
|
329
338
|
except OSError as e:
|
|
330
339
|
# `DirectorySource.expand()` walks via `iterdir()` (not `rglob()`, so it
|
|
331
340
|
# can follow a symlinked subdirectory — the I1 fix) and raises a plain
|
|
@@ -416,6 +425,7 @@ def _load_root_from_collection(
|
|
|
416
425
|
strict: bool = False,
|
|
417
426
|
providers: list[object] | None = None,
|
|
418
427
|
libraries: list[str] | None = None,
|
|
428
|
+
unknown_attr_out: list[str] | None = None,
|
|
419
429
|
) -> tuple[MetaData | None, list[str]]:
|
|
420
430
|
"""Load a resolved `Collection` — the source-resolution ladder's
|
|
421
431
|
``.metaobjects/config.json`` rung (:func:`resolve_metadata_location`), which
|
|
@@ -432,9 +442,58 @@ def _load_root_from_collection(
|
|
|
432
442
|
if result.errors:
|
|
433
443
|
msgs = [f"{e.code}: {e.message}" for e in result.errors]
|
|
434
444
|
return None, msgs
|
|
445
|
+
if unknown_attr_out is not None and not strict:
|
|
446
|
+
# See `_load_root`: what a strict load (`verify`) would reject, for `gen` to warn.
|
|
447
|
+
try:
|
|
448
|
+
strict_result = _load_collection_result(
|
|
449
|
+
collection, strict=True, providers=providers, libraries=libraries
|
|
450
|
+
)
|
|
451
|
+
except ParseError:
|
|
452
|
+
strict_result = None
|
|
453
|
+
if strict_result is not None:
|
|
454
|
+
unknown_attr_out.extend(_unknown_attr_findings(strict_result))
|
|
435
455
|
return result.root, []
|
|
436
456
|
|
|
437
457
|
|
|
458
|
+
#: Trailing advice after ``gen``'s unknown-attribute warnings. ``gen`` has no strict
|
|
459
|
+
#: flag of its own; ``verify`` is the strict door (ADR-0023), so that is what it names.
|
|
460
|
+
UNKNOWN_ATTR_GEN_ADVICE = (
|
|
461
|
+
"metaobjects gen loads leniently and generated anyway, but `metaobjects verify` "
|
|
462
|
+
"rejects this metadata (ADR-0023): fix or remove the attribute - a typo'd one "
|
|
463
|
+
"(`isAbstrakt`, `requird`) silently changes what is generated."
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
def _format_unknown_attr(err: MetaError) -> str:
|
|
468
|
+
"""One ``gen`` warning: code + message (naming attribute and node), then the file."""
|
|
469
|
+
env = getattr(err, "envelope", None)
|
|
470
|
+
files = [f for f in (getattr(env, "files", None) or ()) if f]
|
|
471
|
+
json_path = getattr(env, "json_path", None)
|
|
472
|
+
where = " ".join(
|
|
473
|
+
p for p in (", ".join(files) if files else None, f"at {json_path}" if json_path else None) if p
|
|
474
|
+
)
|
|
475
|
+
head = f"{err.code.value if hasattr(err.code, 'value') else err.code}: {err.message}"
|
|
476
|
+
return f"{head}\n in {where}" if where else head
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def _unknown_attr_findings(result: LoadResult) -> list[str]:
|
|
480
|
+
"""The ERR_UNKNOWN_ATTR findings of a STRICT load, formatted for ``gen``."""
|
|
481
|
+
return [
|
|
482
|
+
_format_unknown_attr(e) for e in result.errors
|
|
483
|
+
if (e.code.value if hasattr(e.code, "value") else e.code) == ErrorCode.ERR_UNKNOWN_ATTR.value
|
|
484
|
+
]
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
def _print_unknown_attr_warnings(findings: list[str]) -> None:
|
|
488
|
+
"""``gen`` loads leniently; an unknown attribute ``verify`` would reject is named here
|
|
489
|
+
as a warning (attribute, node, file). Advisory only: the exit code is unchanged."""
|
|
490
|
+
if not findings:
|
|
491
|
+
return
|
|
492
|
+
for f in findings:
|
|
493
|
+
print(f"warning: {f}", file=sys.stderr)
|
|
494
|
+
print(f"warning: {UNKNOWN_ATTR_GEN_ADVICE}", file=sys.stderr)
|
|
495
|
+
|
|
496
|
+
|
|
438
497
|
def _strict_load_hint() -> str:
|
|
439
498
|
"""Actionable next-steps when strict verify rejects an undeclared @attr."""
|
|
440
499
|
return (
|
|
@@ -1005,6 +1064,8 @@ def _cmd_list(_args: argparse.Namespace) -> int:
|
|
|
1005
1064
|
status = owned.owned_status(root, entry)
|
|
1006
1065
|
mark = f" [owned — {status}]" if status is not None else ""
|
|
1007
1066
|
print(f"{entry.name} — {entry.description}{requires}{mark}")
|
|
1067
|
+
for path, status in owned.runtime_status(root):
|
|
1068
|
+
print(f"runtime {path.as_posix()} [owned — {status}]")
|
|
1008
1069
|
return 0
|
|
1009
1070
|
|
|
1010
1071
|
|
|
@@ -1097,12 +1158,16 @@ def _cmd_gen(args: argparse.Namespace) -> int:
|
|
|
1097
1158
|
return 1
|
|
1098
1159
|
# Load the metadata ONCE; both the default suite and the (optional)
|
|
1099
1160
|
# --template-spec pass run against this single loaded root.
|
|
1100
|
-
|
|
1161
|
+
unknown_attrs: list[str] = []
|
|
1162
|
+
root, load_errors = _load_root(
|
|
1163
|
+
args.metadata_dir, providers=providers, unknown_attr_out=unknown_attrs
|
|
1164
|
+
)
|
|
1101
1165
|
if root is None:
|
|
1102
1166
|
print("error: failed to load metadata:", file=sys.stderr)
|
|
1103
1167
|
for msg in load_errors:
|
|
1104
1168
|
print(f" {msg}", file=sys.stderr)
|
|
1105
1169
|
return 1
|
|
1170
|
+
_print_unknown_attr_warnings(unknown_attrs)
|
|
1106
1171
|
gen_state = gen_state_dir_for(args.metadata_dir)
|
|
1107
1172
|
# Same anchor the manifest itself uses. Both passes below key against it, so a
|
|
1108
1173
|
# `--template-spec` artifact and a default-suite artifact land in one key space.
|
|
@@ -1366,14 +1431,17 @@ def _cmd_gen_config(args: argparse.Namespace) -> int:
|
|
|
1366
1431
|
if collection is None:
|
|
1367
1432
|
return 1
|
|
1368
1433
|
|
|
1434
|
+
unknown_attrs: list[str] = []
|
|
1369
1435
|
root, load_errors = _load_root_from_collection(
|
|
1370
|
-
collection, providers=providers, libraries=config.libraries
|
|
1436
|
+
collection, providers=providers, libraries=config.libraries,
|
|
1437
|
+
unknown_attr_out=unknown_attrs,
|
|
1371
1438
|
)
|
|
1372
1439
|
if root is None:
|
|
1373
1440
|
print("error: failed to load metadata:", file=sys.stderr)
|
|
1374
1441
|
for msg in load_errors:
|
|
1375
1442
|
print(f" {msg}", file=sys.stderr)
|
|
1376
1443
|
return 1
|
|
1444
|
+
_print_unknown_attr_warnings(unknown_attrs)
|
|
1377
1445
|
|
|
1378
1446
|
for t in targets:
|
|
1379
1447
|
imported_refusal = _refuse_imported_entities(t.entities, root, collection)
|
|
@@ -9,6 +9,14 @@ to wire instead.
|
|
|
9
9
|
|
|
10
10
|
A copy imports the same ``metaobjects.codegen.*`` module paths the packaged generator
|
|
11
11
|
does. Those module paths are the documented surface an owned generator builds on.
|
|
12
|
+
|
|
13
|
+
What the copy's OUTPUT imports is a different question. A generator whose generated code
|
|
14
|
+
imports helper runtime (``routes``: ``filter_parser``, ``constraint_errors``) lists it on
|
|
15
|
+
its registry entry, and eject hands that over too: the runtime source lands in
|
|
16
|
+
``codegen/runtime/`` and the copy's ``OWNED_RUNTIME`` switch is flipped, so the owned
|
|
17
|
+
generator emits that source into the generated package and its output imports the local
|
|
18
|
+
copy. Core modules (loader, registry, render, extract, ``ObjectManager``) stay package
|
|
19
|
+
imports. An existing runtime copy is never overwritten, even with ``--force``.
|
|
12
20
|
"""
|
|
13
21
|
from __future__ import annotations
|
|
14
22
|
|
|
@@ -30,6 +38,14 @@ from metaobjects.codegen.generator_registry import (
|
|
|
30
38
|
#: Where an owned copy lands, relative to the project root. Mirrors the TS layout.
|
|
31
39
|
OWNED_DIR = Path("codegen") / "generators"
|
|
32
40
|
|
|
41
|
+
#: Where the helper runtime an owned generator's output depends on lands. A sibling of
|
|
42
|
+
#: :data:`OWNED_DIR`, which is where the owned router reads it from.
|
|
43
|
+
RUNTIME_DIR = Path("codegen") / "runtime"
|
|
44
|
+
|
|
45
|
+
#: The switch an owned copy flips to emit and import its runtime locally.
|
|
46
|
+
_RUNTIME_SWITCH_OFF = "OWNED_RUNTIME = False"
|
|
47
|
+
_RUNTIME_SWITCH_ON = "OWNED_RUNTIME = True"
|
|
48
|
+
|
|
33
49
|
|
|
34
50
|
def owned_stem(name: str) -> str:
|
|
35
51
|
"""The module name of an owned copy: the stable name with ``-`` as ``_``."""
|
|
@@ -52,6 +68,32 @@ def packaged_source(entry: GeneratorEntry) -> str:
|
|
|
52
68
|
return Path(module.__file__).read_text(encoding="utf-8")
|
|
53
69
|
|
|
54
70
|
|
|
71
|
+
def ejected_source(entry: GeneratorEntry) -> str:
|
|
72
|
+
"""What ``eject`` writes for *entry*: the packaged source, with the runtime switch on
|
|
73
|
+
when its output imports helper runtime. This is the reference an owned copy is
|
|
74
|
+
compared against."""
|
|
75
|
+
source = packaged_source(entry)
|
|
76
|
+
if not entry.runtime:
|
|
77
|
+
return source
|
|
78
|
+
if source.count(_RUNTIME_SWITCH_OFF) != 1:
|
|
79
|
+
raise RuntimeError(
|
|
80
|
+
f"{entry.source_module} must carry exactly one {_RUNTIME_SWITCH_OFF!r} line "
|
|
81
|
+
"for eject to hand its runtime over"
|
|
82
|
+
)
|
|
83
|
+
return source.replace(_RUNTIME_SWITCH_OFF, _RUNTIME_SWITCH_ON)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def packaged_runtime_path(module: str) -> Path:
|
|
87
|
+
"""The installed source of helper runtime *module*."""
|
|
88
|
+
package = importlib.import_module("metaobjects.codegen.runtime")
|
|
89
|
+
assert package.__file__ is not None
|
|
90
|
+
return Path(package.__file__).parent / f"{module}.py"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def runtime_path(root: Path, module: str) -> Path:
|
|
94
|
+
return root / RUNTIME_DIR / f"{module}.py"
|
|
95
|
+
|
|
96
|
+
|
|
55
97
|
def ejectable() -> list[GeneratorEntry]:
|
|
56
98
|
return [e for e in GENERATOR_REGISTRY.values() if e.source is not None]
|
|
57
99
|
|
|
@@ -88,9 +130,19 @@ def eject(names: list[str], root: Path, *, force: bool = False) -> EjectResult:
|
|
|
88
130
|
for n in names:
|
|
89
131
|
entry = known[n]
|
|
90
132
|
target = owned_path(root, n)
|
|
91
|
-
target.write_text(
|
|
133
|
+
target.write_text(ejected_source(entry), encoding="utf-8")
|
|
92
134
|
out.append(f"ejected {n} -> {target.relative_to(root)}")
|
|
93
135
|
out.append(f" wire it: replace \"{n}\" in `generators` with {owned_token(entry)}")
|
|
136
|
+
for module in entry.runtime:
|
|
137
|
+
rt = runtime_path(root, module)
|
|
138
|
+
rel = rt.relative_to(root)
|
|
139
|
+
if rt.exists():
|
|
140
|
+
out.append(f" runtime {rel}: kept your copy (eject never overwrites runtime)")
|
|
141
|
+
continue
|
|
142
|
+
rt.parent.mkdir(parents=True, exist_ok=True)
|
|
143
|
+
rt.write_text(packaged_runtime_path(module).read_text(encoding="utf-8"),
|
|
144
|
+
encoding="utf-8")
|
|
145
|
+
out.append(f" runtime {rel}: copied — its generated output imports this copy")
|
|
94
146
|
out.append("")
|
|
95
147
|
out.append(
|
|
96
148
|
"The copies are yours: edit them freely. Keep only one of the packaged name and your "
|
|
@@ -112,8 +164,12 @@ def owned_status(root: Path, entry: GeneratorEntry) -> str | None:
|
|
|
112
164
|
path = owned_path(root, entry.name)
|
|
113
165
|
if entry.source is None or not path.exists():
|
|
114
166
|
return None
|
|
115
|
-
|
|
116
|
-
|
|
167
|
+
return _compare(path.read_text(encoding="utf-8"), ejected_source(entry))
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _compare(mine_text: str, ref_text: str) -> str:
|
|
171
|
+
mine = _normalised(mine_text)
|
|
172
|
+
ref = _normalised(ref_text)
|
|
117
173
|
behind = sum((ref - mine).values())
|
|
118
174
|
own = sum((mine - ref).values())
|
|
119
175
|
if behind == 0 and own == 0:
|
|
@@ -121,6 +177,23 @@ def owned_status(root: Path, entry: GeneratorEntry) -> str | None:
|
|
|
121
177
|
return f"DIFFERS: {behind} behind, {own} of your own"
|
|
122
178
|
|
|
123
179
|
|
|
180
|
+
def runtime_status(root: Path) -> list[tuple[Path, str]]:
|
|
181
|
+
"""``(relative path, status)`` for each owned runtime copy, against the installed one.
|
|
182
|
+
|
|
183
|
+
Same verdict shape as :func:`owned_status`, so ``--list`` can say when an upgrade
|
|
184
|
+
changed runtime you own."""
|
|
185
|
+
modules = sorted({m for e in ejectable() for m in e.runtime})
|
|
186
|
+
rows: list[tuple[Path, str]] = []
|
|
187
|
+
for module in modules:
|
|
188
|
+
path = runtime_path(root, module)
|
|
189
|
+
if path.exists():
|
|
190
|
+
rows.append((path.relative_to(root), _compare(
|
|
191
|
+
path.read_text(encoding="utf-8"),
|
|
192
|
+
packaged_runtime_path(module).read_text(encoding="utf-8"),
|
|
193
|
+
)))
|
|
194
|
+
return rows
|
|
195
|
+
|
|
196
|
+
|
|
124
197
|
def build_owned(spec: str, root: Path, ctx: GeneratorBuildContext) -> tuple[Generator | None, str | None]:
|
|
125
198
|
"""Resolve a ``module:symbol`` generator entry against the project at *root*.
|
|
126
199
|
|
|
@@ -40,7 +40,10 @@ from metaobjects.codegen.generators.output_prompt_generator import (
|
|
|
40
40
|
from metaobjects.codegen.generators.render_helper_generator import (
|
|
41
41
|
render_helper_generator,
|
|
42
42
|
)
|
|
43
|
-
from metaobjects.codegen.generators.router_generator import
|
|
43
|
+
from metaobjects.codegen.generators.router_generator import (
|
|
44
|
+
RUNTIME_MODULES as _ROUTER_RUNTIME,
|
|
45
|
+
router_generator,
|
|
46
|
+
)
|
|
44
47
|
from metaobjects.codegen.generators.template_generator import template_generator
|
|
45
48
|
from metaobjects.codegen.generators.trace_helper_generator import trace_helper_generator
|
|
46
49
|
from metaobjects.render.verify import InMemoryProvider
|
|
@@ -113,6 +116,13 @@ class GeneratorEntry:
|
|
|
113
116
|
#: symbol the copy is wired by. ``None`` = not ejectable (the ``template`` primitive
|
|
114
117
|
#: has no emit logic of its own to own).
|
|
115
118
|
source: Callable[..., Generator] | None = None
|
|
119
|
+
#: Helper runtime modules (under ``metaobjects.codegen.runtime``) the generator's
|
|
120
|
+
#: OUTPUT imports. ``metaobjects eject`` copies their source into the adopter's
|
|
121
|
+
#: ``codegen/runtime/`` beside the owned generator, and the owned copy's output imports
|
|
122
|
+
#: that copy instead of the installed package (ADR-0034 Amendment 3: the adopter owns
|
|
123
|
+
#: every helper line its generated code depends on). Core modules — loader, registry,
|
|
124
|
+
#: render, extract, ``ObjectManager`` — are never listed here: they stay package imports.
|
|
125
|
+
runtime: tuple[str, ...] = ()
|
|
116
126
|
|
|
117
127
|
@property
|
|
118
128
|
def source_module(self) -> str | None:
|
|
@@ -186,10 +196,11 @@ GENERATOR_REGISTRY: dict[str, GeneratorEntry] = {
|
|
|
186
196
|
# generated package fails at import (ModuleNotFoundError).
|
|
187
197
|
requires=("entity", "filter-allowlist"),
|
|
188
198
|
source=router_generator,
|
|
199
|
+
runtime=_ROUTER_RUNTIME,
|
|
189
200
|
),
|
|
190
201
|
"output-parser": GeneratorEntry(
|
|
191
202
|
name="output-parser",
|
|
192
|
-
description="Per-template
|
|
203
|
+
description="Per-template response parser: a strict parse that rejects a reply not matching the @responseRef shape, plus a tolerant, never-raising extract_lenient.",
|
|
193
204
|
tier="native",
|
|
194
205
|
layer="capability",
|
|
195
206
|
factory=lambda _ctx: output_parser_generator(),
|
|
@@ -215,7 +226,7 @@ GENERATOR_REGISTRY: dict[str, GeneratorEntry] = {
|
|
|
215
226
|
),
|
|
216
227
|
"extractor": GeneratorEntry(
|
|
217
228
|
name="extractor",
|
|
218
|
-
description="Per-template
|
|
229
|
+
description="Per-template typed extract<Name> helper: tolerant recovery of the typed response from dirty model text; raises only when a @required field is lost.",
|
|
219
230
|
tier="native",
|
|
220
231
|
layer="capability",
|
|
221
232
|
factory=lambda _ctx: extractor_generator(),
|
{metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/extractor_generator.py
RENAMED
|
@@ -9,7 +9,7 @@ arrays-of-objects populated) in ONE call:
|
|
|
9
9
|
|
|
10
10
|
extract_<snake>(root, text, opts=None) -> <Vo>
|
|
11
11
|
r = extract_lenient_<snake>_with_loader(root, text, opts) # nested-capable extract
|
|
12
|
-
if r.report.has_lost_required(): raise ValueError(...)
|
|
12
|
+
if r.report.has_lost_required() or r.report.has_malformed_required(): raise ValueError(...)
|
|
13
13
|
return _to_strict_<vo>(r.data) # mirror -> strict mapper
|
|
14
14
|
|
|
15
15
|
Why the loaded ``root``: the SELF-CONTAINED ``extract_<snake>(text)`` leaves nested
|
|
@@ -173,16 +173,23 @@ def render_extractor(
|
|
|
173
173
|
lines.append(" value-object). Runs the tolerant nested-capable extract, then maps the")
|
|
174
174
|
lines.append(" extracted mirror graph onto the strict Pydantic payload graph.")
|
|
175
175
|
lines.append("")
|
|
176
|
-
lines.append(" :raises ValueError: iff a ``@required`` field was lost
|
|
176
|
+
lines.append(" :raises ValueError: iff a ``@required`` field was lost, or present but")
|
|
177
|
+
lines.append(" unusable (MALFORMED: an undeclared enum member, text for a number).")
|
|
177
178
|
lines.append(' """')
|
|
178
179
|
lines.append(f" r = {extract_lenient_with_fn}(root, text, opts)")
|
|
179
|
-
lines.append(" if r.report.has_lost_required():")
|
|
180
|
-
lines.append("
|
|
180
|
+
lines.append(" if r.report.has_lost_required() or r.report.has_malformed_required():")
|
|
181
|
+
lines.append(" unusable = []")
|
|
182
|
+
lines.append(" if r.report.has_lost_required():")
|
|
181
183
|
lines.append(
|
|
182
|
-
|
|
184
|
+
' unusable.append("lost required field(s): "'
|
|
185
|
+
' + ", ".join(r.report.lost_required()))'
|
|
183
186
|
)
|
|
184
|
-
lines.append(
|
|
185
|
-
lines.append(
|
|
187
|
+
lines.append(" if r.report.has_malformed_required():")
|
|
188
|
+
lines.append(
|
|
189
|
+
' unusable.append("malformed required field(s): "'
|
|
190
|
+
' + ", ".join(r.report.malformed_required()))'
|
|
191
|
+
)
|
|
192
|
+
lines.append(f' raise ValueError("{extract_fn}: " + "; ".join(unusable))')
|
|
186
193
|
lines.append(f" return {root_mapper}(r.data)")
|
|
187
194
|
lines.append("")
|
|
188
195
|
lines.append("")
|
{metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/router_generator.py
RENAMED
|
@@ -39,11 +39,12 @@ pick their preferred persistence layer.
|
|
|
39
39
|
from __future__ import annotations
|
|
40
40
|
|
|
41
41
|
from dataclasses import dataclass
|
|
42
|
+
from pathlib import Path
|
|
42
43
|
|
|
43
44
|
from metaobjects.apidocs.naming import route_path as _route_path
|
|
44
45
|
from metaobjects.apidocs.naming import reverse_finder_fn, reverse_finder_in_fn
|
|
45
46
|
from metaobjects.apidocs.naming import snake_case as _snake_case
|
|
46
|
-
from metaobjects.codegen.constants import generated_header
|
|
47
|
+
from metaobjects.codegen.constants import GENERATED_MARKER, generated_header
|
|
47
48
|
from metaobjects.codegen.format import ruff_format
|
|
48
49
|
from metaobjects.codegen.fr010_field_mapping import is_required
|
|
49
50
|
from metaobjects.codegen.generator import EmittedFile, GenContext, Generator, per_entity
|
|
@@ -81,6 +82,61 @@ from metaobjects.naming import DEFAULT_COLUMN_NAMING
|
|
|
81
82
|
from metaobjects.shared.base_types import TYPE_IDENTITY
|
|
82
83
|
from metaobjects.shared.separators import PACKAGE_SEP
|
|
83
84
|
|
|
85
|
+
#: Where the emitted router imports its helper runtime (``filter_parser``,
|
|
86
|
+
#: ``constraint_errors``) from. ``False`` — the packaged generator — imports the copy
|
|
87
|
+
#: installed with ``metaobjects``: ``from metaobjects.codegen.runtime.<m> import ...``.
|
|
88
|
+
#: ``metaobjects eject routes`` flips this line to ``True`` in the owned copy, which then
|
|
89
|
+
#: EMITS that runtime's source from ``codegen/runtime/`` (the directory beside the owned
|
|
90
|
+
#: generators, :data:`RUNTIME_SOURCE_DIR`) into the generated package as ``_runtime/`` and
|
|
91
|
+
#: imports it package-relatively. The runtime is then code the adopter owns: edit
|
|
92
|
+
#: ``codegen/runtime/<m>.py``, regenerate, and the generated package carries the change.
|
|
93
|
+
OWNED_RUNTIME = False
|
|
94
|
+
|
|
95
|
+
#: The helper runtime modules the emitted router imports (ADR-0034 Amendment 3: helper
|
|
96
|
+
#: tier, not core). Listed on the registry entry too, which is what ``eject`` copies.
|
|
97
|
+
RUNTIME_MODULES: tuple[str, ...] = ("constraint_errors", "filter_parser")
|
|
98
|
+
|
|
99
|
+
#: The generated subpackage an owned router emits the runtime into.
|
|
100
|
+
RUNTIME_SUBPACKAGE = "_runtime"
|
|
101
|
+
|
|
102
|
+
#: Where an owned router reads the runtime source it emits. The packaged generator and an
|
|
103
|
+
#: ejected copy sit at the same depth relative to their ``runtime/`` sibling
|
|
104
|
+
#: (``metaobjects/codegen/generators`` vs ``codegen/generators``), so one expression
|
|
105
|
+
#: serves both.
|
|
106
|
+
RUNTIME_SOURCE_DIR = Path(__file__).resolve().parent.parent / "runtime"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _runtime_module(module: str) -> str:
|
|
110
|
+
"""The module path an emitted router imports runtime *module* from."""
|
|
111
|
+
if OWNED_RUNTIME:
|
|
112
|
+
return f".{RUNTIME_SUBPACKAGE}.{module}"
|
|
113
|
+
return f"metaobjects.codegen.runtime.{module}"
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _owned_runtime_files() -> list[EmittedFile]:
|
|
117
|
+
"""The runtime source an owned router emits beside itself, marked as generated."""
|
|
118
|
+
files = [EmittedFile(
|
|
119
|
+
path=f"{RUNTIME_SUBPACKAGE}/__init__.py",
|
|
120
|
+
content=f"# {GENERATED_MARKER} — DO NOT EDIT.\n"
|
|
121
|
+
f"# Helper runtime for the generated routers. Its source is codegen/runtime/.\n",
|
|
122
|
+
)]
|
|
123
|
+
for module in RUNTIME_MODULES:
|
|
124
|
+
src = RUNTIME_SOURCE_DIR / f"{module}.py"
|
|
125
|
+
if not src.is_file():
|
|
126
|
+
raise FileNotFoundError(
|
|
127
|
+
f"the owned routes generator emits its runtime from {src}, which does not "
|
|
128
|
+
f"exist. Copy {module}.py back from the installed package's "
|
|
129
|
+
"metaobjects/codegen/runtime/ directory (`python -c \"import "
|
|
130
|
+
"metaobjects.codegen.runtime as r; print(r.__path__[0])\"` prints it)."
|
|
131
|
+
)
|
|
132
|
+
files.append(EmittedFile(
|
|
133
|
+
path=f"{RUNTIME_SUBPACKAGE}/{module}.py",
|
|
134
|
+
content=f"# {GENERATED_MARKER} — DO NOT EDIT. Copied from "
|
|
135
|
+
f"codegen/runtime/{module}.py: edit that file and regenerate.\n"
|
|
136
|
+
+ src.read_text(encoding="utf-8"),
|
|
137
|
+
))
|
|
138
|
+
return files
|
|
139
|
+
|
|
84
140
|
|
|
85
141
|
def _effective_fqn(entity: MetaObject) -> str:
|
|
86
142
|
"""``package::name`` via the canonical :meth:`MetaData.resolution_key` (own
|
|
@@ -928,10 +984,10 @@ class RouterGenerator:
|
|
|
928
984
|
parts.append("from fastapi.responses import JSONResponse")
|
|
929
985
|
parts.append("from pydantic import BaseModel, ValidationError")
|
|
930
986
|
parts.append("")
|
|
931
|
-
parts.append("from
|
|
987
|
+
parts.append(f"from {_runtime_module('constraint_errors')} import (")
|
|
932
988
|
parts.append(" classify_constraint_error,")
|
|
933
989
|
parts.append(")")
|
|
934
|
-
parts.append("from
|
|
990
|
+
parts.append(f"from {_runtime_module('filter_parser')} import (")
|
|
935
991
|
parts.append(" FilterPredicate,")
|
|
936
992
|
parts.append(" parse_filter,")
|
|
937
993
|
parts.append(")")
|
|
@@ -1280,10 +1336,10 @@ class RouterGenerator:
|
|
|
1280
1336
|
parts.append("from fastapi.responses import JSONResponse")
|
|
1281
1337
|
parts.append("from pydantic import BaseModel, ValidationError")
|
|
1282
1338
|
parts.append("")
|
|
1283
|
-
parts.append("from
|
|
1339
|
+
parts.append(f"from {_runtime_module('constraint_errors')} import (")
|
|
1284
1340
|
parts.append(" classify_constraint_error,")
|
|
1285
1341
|
parts.append(")")
|
|
1286
|
-
parts.append("from
|
|
1342
|
+
parts.append(f"from {_runtime_module('filter_parser')} import (")
|
|
1287
1343
|
parts.append(" FilterPredicate,")
|
|
1288
1344
|
parts.append(" parse_filter,")
|
|
1289
1345
|
parts.append(")")
|
|
@@ -1447,7 +1503,7 @@ class RouterGenerator:
|
|
|
1447
1503
|
parts.append("from fastapi.responses import JSONResponse")
|
|
1448
1504
|
parts.append("from pydantic import BaseModel")
|
|
1449
1505
|
parts.append("")
|
|
1450
|
-
parts.append("from
|
|
1506
|
+
parts.append(f"from {_runtime_module('filter_parser')} import (")
|
|
1451
1507
|
parts.append(" FilterPredicate,")
|
|
1452
1508
|
parts.append(" parse_filter,")
|
|
1453
1509
|
parts.append(")")
|
|
@@ -1528,7 +1584,10 @@ class RouterGenerator:
|
|
|
1528
1584
|
)
|
|
1529
1585
|
]
|
|
1530
1586
|
|
|
1531
|
-
|
|
1587
|
+
files = per_entity(emit)(ctx)
|
|
1588
|
+
if OWNED_RUNTIME and files:
|
|
1589
|
+
files.extend(_owned_runtime_files())
|
|
1590
|
+
return files
|
|
1532
1591
|
|
|
1533
1592
|
|
|
1534
1593
|
def render_router(
|
{metaobjects-1.0.8 → metaobjects-1.0.9}/src/metaobjects/codegen/generators/trace_helper_generator.py
RENAMED
|
@@ -282,13 +282,18 @@ def render_trace_helper(entity: MetaObject, root: MetaData) -> str | None:
|
|
|
282
282
|
" :param redact: optional row redaction applied before the single record.",
|
|
283
283
|
' """',
|
|
284
284
|
" outcome = extract(input.llm_response_text, _RESPONSE_SCHEMA)",
|
|
285
|
-
"
|
|
285
|
+
" # A required field lost OR malformed (present but unusable) has no value,",
|
|
286
|
+
" # so either fails the call.",
|
|
287
|
+
" unusable = []",
|
|
288
|
+
" if outcome.report.has_lost_required():",
|
|
289
|
+
' unusable.append("lost required: " + ", ".join(outcome.report.lost_required()))',
|
|
290
|
+
" if outcome.report.has_malformed_required():",
|
|
291
|
+
" unusable.append(",
|
|
292
|
+
' "malformed required: " + ", ".join(outcome.report.malformed_required())',
|
|
293
|
+
" )",
|
|
294
|
+
" failed = bool(unusable)",
|
|
286
295
|
" status = STATUS_ERROR if failed else STATUS_OK",
|
|
287
|
-
|
|
288
|
-
' "lost required: " + ", ".join(outcome.report.lost_required())',
|
|
289
|
-
" if failed",
|
|
290
|
-
" else None",
|
|
291
|
-
" )",
|
|
296
|
+
' error_detail = "; ".join(unusable) if failed else None',
|
|
292
297
|
" # Extraction owns the derived status/error_detail — fold them into the input",
|
|
293
298
|
" # before building the base row (dataclasses.replace, leaving the original",
|
|
294
299
|
" # input untouched).",
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Everything a generator written from scratch needs, in one import (ADR-0034 Amendment 4).
|
|
2
|
+
|
|
3
|
+
MetaObjects' product is the core; the outputs an application needs beyond the reference
|
|
4
|
+
generators — OpenAPI, JSON Schema, a client, docs — are generators the adopter writes. A
|
|
5
|
+
generator is any object with a ``name`` and a ``generate(ctx) -> list[EmittedFile]``; wire it
|
|
6
|
+
as ``module:symbol`` in ``--generators`` or in ``metaobjects.config.yaml``'s
|
|
7
|
+
``targets.<name>.generators`` and ``metaobjects gen`` runs it and ``metaobjects verify
|
|
8
|
+
--codegen`` drift-gates it. See ``docs/recipes/write-your-own-generator.md``.
|
|
9
|
+
|
|
10
|
+
These helpers answer the questions whose right answer is a rule the engine already owns.
|
|
11
|
+
Before this module they were spread over five internal modules, one of them private, and the
|
|
12
|
+
obvious spelling of several was wrong:
|
|
13
|
+
|
|
14
|
+
* **Python's ``attr(name)`` is OWN-ONLY** (ADR-0039's naming inversion). A field that inherits
|
|
15
|
+
``@maxLength`` or ``@required`` through ``extends`` reads ``None`` through it. Read effective
|
|
16
|
+
values with ``node.attrs().get(name)`` — or the helpers below, which do.
|
|
17
|
+
* ``field.is_array`` is the raw own flag; :func:`field_is_array` resolves.
|
|
18
|
+
* An ``@objectRef`` is resolved package-locally (ADR-0042), never by short name.
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
from metaobjects.apidocs.naming import route_path
|
|
25
|
+
from metaobjects.codegen.generator import (
|
|
26
|
+
EmittedFile,
|
|
27
|
+
GenContext,
|
|
28
|
+
Generator,
|
|
29
|
+
once_per_run,
|
|
30
|
+
per_entity,
|
|
31
|
+
per_model,
|
|
32
|
+
per_package,
|
|
33
|
+
)
|
|
34
|
+
from metaobjects.codegen.instance_artifacts import is_abstract
|
|
35
|
+
from metaobjects.codegen.template_codegen.template_data import package_of
|
|
36
|
+
from metaobjects.codegen.type_map import effective_enum_values, field_is_array
|
|
37
|
+
from metaobjects.codegen.value_objects import object_ref_target
|
|
38
|
+
from metaobjects.meta.core.field.field_constants import FIELD_ATTR_MAX_LENGTH, FIELD_ATTR_REQUIRED
|
|
39
|
+
from metaobjects.naming import to_snake_case
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"EmittedFile",
|
|
43
|
+
"GenContext",
|
|
44
|
+
"Generator",
|
|
45
|
+
"description",
|
|
46
|
+
"enum_values",
|
|
47
|
+
"field_is_array",
|
|
48
|
+
"is_abstract",
|
|
49
|
+
"is_required",
|
|
50
|
+
"max_length",
|
|
51
|
+
"object_ref_target",
|
|
52
|
+
"once_per_run",
|
|
53
|
+
"package_of",
|
|
54
|
+
"per_entity",
|
|
55
|
+
"per_model",
|
|
56
|
+
"per_package",
|
|
57
|
+
"primary_key_fields",
|
|
58
|
+
"route_path",
|
|
59
|
+
"to_snake_case",
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
_TYPE_VALIDATOR = "validator"
|
|
63
|
+
_VALIDATOR_REQUIRED = "required"
|
|
64
|
+
_DOC_DESCRIPTION = "description"
|
|
65
|
+
_IDENTITY_FIELDS = "fields"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def is_required(field: Any) -> bool:
|
|
69
|
+
"""Effective required-ness: ``@required: true`` or a ``validator.required`` child, own or
|
|
70
|
+
inherited through ``extends`` — the same rule the neutral template data uses."""
|
|
71
|
+
if field.attrs().get(FIELD_ATTR_REQUIRED) is True:
|
|
72
|
+
return True
|
|
73
|
+
return any(c.type == _TYPE_VALIDATOR and c.sub_type == _VALIDATOR_REQUIRED for c in field.children())
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def max_length(field: Any) -> int | None:
|
|
77
|
+
"""Effective ``@maxLength``, or ``None``."""
|
|
78
|
+
v = field.attrs().get(FIELD_ATTR_MAX_LENGTH)
|
|
79
|
+
return int(v) if isinstance(v, (int, float)) and not isinstance(v, bool) else None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def enum_values(field: Any) -> list[str]:
|
|
83
|
+
"""A ``field.enum``'s effective ``@values`` (empty when absent)."""
|
|
84
|
+
return effective_enum_values(field)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def description(node: Any) -> str | None:
|
|
88
|
+
"""The node's effective ``@description``, or ``None``."""
|
|
89
|
+
v = node.attrs().get(_DOC_DESCRIPTION)
|
|
90
|
+
return v if isinstance(v, str) else None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def primary_key_fields(obj: Any) -> list[str]:
|
|
94
|
+
"""The primary identity's field names, own or inherited (empty when none)."""
|
|
95
|
+
identity = obj.primary_identity()
|
|
96
|
+
if identity is None:
|
|
97
|
+
return []
|
|
98
|
+
v = identity.attrs().get(_IDENTITY_FIELDS)
|
|
99
|
+
if isinstance(v, str):
|
|
100
|
+
return [s.strip() for s in v.split(",") if s.strip()]
|
|
101
|
+
return [str(x) for x in v] if isinstance(v, (list, tuple)) else []
|
|
@@ -130,9 +130,13 @@ def run_gen(
|
|
|
130
130
|
# to out_dir). The generated modules use package-relative imports, so without
|
|
131
131
|
# this a consumer can't import them. A generator-emitted __init__.py wins; a
|
|
132
132
|
# hand-authored one is left untouched by the overwrite policy below.
|
|
133
|
+
#
|
|
134
|
+
# Only directories that hold a generated PYTHON module: an adopter's own generator
|
|
135
|
+
# emitting JSON Schema or OpenAPI into `schemas/` is not writing a package, and an
|
|
136
|
+
# `__init__.py` there is litter that makes the tree look importable.
|
|
133
137
|
if config.emit_package_init:
|
|
134
138
|
pkg_rel_dirs: set[str] = set()
|
|
135
|
-
for full in
|
|
139
|
+
for full in [p for p in emitted if p.endswith(".py")]:
|
|
136
140
|
d = os.path.dirname(os.path.relpath(full, config.out_dir))
|
|
137
141
|
while True:
|
|
138
142
|
pkg_rel_dirs.add(d)
|