metaobjects 1.0.5rc10__tar.gz → 1.0.7__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.5rc10 → metaobjects-1.0.7}/PKG-INFO +3 -2
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/README.md +2 -1
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/pyproject.toml +1 -1
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/cli.py +55 -4
- metaobjects-1.0.7/src/metaobjects/codegen/eject.py +168 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generator_registry.py +30 -1
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/router_generator.py +35 -3
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/runner.py +15 -1
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/extract/extract.py +29 -2
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/extract/locate.py +24 -1
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/extract/strip.py +8 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/extract/xml_forgiving_reader.py +62 -6
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_cli_registry.py +3 -0
- metaobjects-1.0.7/tests/codegen/test_eject.py +145 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_gen_state_keying.py +34 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_extract_conformance.py +2 -2
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/uv.lock +1 -1
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/.gitignore +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/LICENSE +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/hatch_build.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/scripts/generate_embedded_library.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/agent_context/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/agent_context/scaffold.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/apidocs/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/apidocs/api_model.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/apidocs/builder.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/apidocs/naming.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/apidocs/paths.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/apidocs/renderer.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/attr_class_map.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/collision_names.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/config.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/format.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/entity_model.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/find_inbound.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/names_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/template_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/instance_artifacts.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/overwrite_policy.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/project_config.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/runtime/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/runtime/constraint_errors.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/type_map.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/value_objects.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/config/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/config/dependencies.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/config/neutral_config.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/config/source_resolver.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/core_types.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/datatype.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/documentation/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/documentation/doc_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/documentation/doc_provider.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/documentation/doc_schema.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/errors.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/library/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/library/embedded_library.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/library/library_sources.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/merge.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/meta_data_loader.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/registered_validation.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/sources/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/sources/directory_source.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/sources/file_source.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/sources/uri_source.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/validate_discriminator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/validate_field_mutability.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/validate_source_escapes.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/loader/validation_passes.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/attr/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/field/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/field/field_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/field/meta_field.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/identity/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/index/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/index/index_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/index/meta_index.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/object/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/object/meta_object.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/object/object_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/object/object_extract.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/object/value_object.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/relationship/relationship_references.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/validator/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/meta_data.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/meta_root.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/persistence/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/presentation/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/provider_extends.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/template/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/template/meta_template.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/template/prompt_provider.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta/template/template_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/meta_endpoint.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/naming.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/naming_refs.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/parser.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/parser_yaml.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/provider.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/py.typed +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/registry.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/registry_manifest.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/email_document.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/escapers.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/extract/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/extract/coerce.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/extract/extract_map.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/extract/normalize.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/extract/types.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/filesystem_provider.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/payload_accessors.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/prompt/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/prompt/prompt_field.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/prompt/prompt_style.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/renderer.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/render/verify.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/runtime/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/runtime/llm_recorder.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/runtime/n2m_resolver.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/runtime/object_manager.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/runtime/tph.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/scope.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/serializer_json.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/shared/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/shared/base_types.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/shared/separators.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/shared/structural.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/source/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/source/error_source.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/source/json_path.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/source/semantic_diff.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/source/yaml_positions.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/source_resolution.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/attr.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/db.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/documentation.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/field.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/identity.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/index.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/layout.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/object.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/origin.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/prompt.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/relationship.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/requirement.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/source.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/template.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/ui.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/validator.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/spec_metamodel/view.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/super_resolve.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/validation_types.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/yaml_desugar.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/gen_suite.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/golden/extends/expected/Program.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/golden/extends/meta.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/golden/nested-array/meta.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/golden/scalars/expected/Report.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/golden/scalars/meta.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/golden/vanilla/meta.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_abstract_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_api_docs_builder.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_api_docs_paths.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_cli.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_cli_config_gen.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_cli_config_verify.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_cli_dependencies.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_cli_providers.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_cli_render_helper_template_root.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_cli_staleness_nudge.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_cli_verify_strict.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_cli_verify_subverbs.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_codegen_compile_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_constants_config.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_entity_model.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_enum_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_extract_tier_collision.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_extractor_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_filter_allowlist_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_format.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_fr010_output_codegen.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_generator_extension_seams.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_golden.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_inheritance_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_instance_artifacts.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_m2m_codegen.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_names_extends_chain.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_names_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_no_magic_physical_names.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_origin_nullability.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_output_parser_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_overwrite_policy.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_overwrite_policy_hash.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_project_config.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_projection_compile.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_render_helper_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_render_helper_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_reverse_finders.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_route_path_naming.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_router_autoset.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_router_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_router_generator_m2m_target_tph.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_router_generator_tph_m2m.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_router_generator_tph_m2m_shadowed.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_runner.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_source_resolution.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_sourceless_projection.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_template_data.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_template_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_template_output_pattern.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_template_scope_helpers.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_template_scope_walk.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_template_spec.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_tph_codegen.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_trace_helper_generator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_type_map.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_validation_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_value_objects.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/codegen/test_write_through.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/config/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/config/test_dependencies.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/config/test_library_package_guard.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/config/test_neutral_config.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/config/test_source_resolver.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/capabilities.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/conformance-expected-failures.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/conformance_adapter.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/corpus.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/expected_failures.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/fixture_discovery.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/navigator.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_dependency_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_extract_object_verdict.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_fr010_loader_attrs.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_fr011_attrs.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_generator_registry_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_object_model_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_provider_composition_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_registry_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_runner_hardfail.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_scope_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_source_resolution_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_spec_metamodel_embed.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_strict_attr_load.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_template_codegen_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_template_generator_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/test_yaml_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/api_contract_assertions.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/api_contract_jsonb_server.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/api_contract_m2m_server.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/api_contract_server.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/generated_jsonb_app.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/generated_m2m_app.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/generated_projection_app.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/generated_router_app.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/generated_tph_app.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/meta_ai_trace.yaml +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/normalization.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/postgres_container.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/query_runner.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/scenarios.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_api_contract.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_api_contract_generated.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_api_contract_jsonb.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_api_contract_m2m.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_api_contract_m2m_generated.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_api_contract_projection.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_api_contract_tph_generated.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_generated_router_uuid_pk.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_llm_call_trace.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_m2m_target_tph_generated.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_normalization.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_query_scenarios.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_runtime_return_types.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_tph_m2m_generated.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/integration/test_tph_m2m_shadowed_generated.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/loader/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/loader/test_abstract_subtype_authored.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/loader/test_child_wrapper_body_shape.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/loader/test_enum_extends_values_conflict.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/loader/test_field_mutability_order.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/loader/test_shipped_library_ai.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/loader/test_template_payload_target_210.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/open_closed_proof_test.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/extract/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/extract/test_coerce.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/extract/test_extract.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/extract/test_extract_map.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/extract/test_json_forgiving_reader.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/extract/test_locate.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/extract/test_model.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/extract/test_normalize.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/extract/test_strip.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/prompt/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/prompt/test_output_format_renderer.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/test_email_document.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/test_filesystem_provider.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/test_output_format_renderer_nested.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/test_output_prompt_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/test_render_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/test_render_max_chars.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/test_render_model_payload.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/test_verify.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/render/test_verify_conformance.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/runtime/test_constraint_errors.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/runtime/test_object_manager_currency_read.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/runtime/test_object_manager_enum_intvaluemap.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/runtime/test_object_manager_table_name.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/source/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/source/test_fr5c_merge_attribution.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/source/test_fr5d_reference_resolution.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/source/test_fr5e_database_source_shape.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/source/test_json_path.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/source/test_semantic_diff.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/source/test_source_on_node.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/source/test_yaml_positions.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/test_api_docs_accuracy.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/test_meta_endpoint.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/__init__.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_agent_context_staleness.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_capabilities.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_column_naming_strategy.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_common_attrs.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_core_types.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_derive_m2m_declaring_entity.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_effective_children_sibling_shadowing.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_effective_package.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_errors.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_field_enum.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_field_enum_intvaluemap.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_field_map_validation.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_file_source_id.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_index_lookup.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_llm_recorder.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_loader.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_loader_bom.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_loader_class.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_merge.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_meta_attr.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_meta_data.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_meta_source.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_module_shortcuts.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_n2m_resolver.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_n2m_resolver_inherited.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_no_dead_config_fields.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_object_manager_write_through.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_one_primary_source.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_parser.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_parser_yaml.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_provider.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_provider_extension.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_registry.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_registry_completeness.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_registry_extend.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_registry_sealed.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_relationship_m2m_validation.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_relationship_references.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_relationship_referential_actions.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_resolution_key.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_serializer.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_serializer_shared_document.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_shared_constants.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_smoke.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_source_escapes.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_sources.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_strict_child_placement.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_super_resolve.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_template_toolcall.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_validation_attr_schema.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_validation_filter_values.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_validation_origin_195.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_validation_origin_paths.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_validation_sort_field.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_validation_warnings.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/tests/unit/test_write_coercion_arrays.py +0 -0
- {metaobjects-1.0.5rc10 → metaobjects-1.0.7}/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.7
|
|
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
|
|
@@ -78,7 +78,8 @@ else:
|
|
|
78
78
|
The primary public API is the **loader** (`load_directory` / `load_uris` /
|
|
79
79
|
`load_string`, `MetaDataLoader`, `LoadResult`, `ErrorCode`, `MetaError`). The
|
|
80
80
|
distribution also ships the Python implementations of the other pillars used by the CLI
|
|
81
|
-
and tooling: `codegen` (Pydantic + FastAPI emit
|
|
81
|
+
and tooling: `codegen` (Pydantic + FastAPI emit — reference generators you own:
|
|
82
|
+
`metaobjects eject <name>` copies one into your repo), `render` (Mustache + payload-VO +
|
|
82
83
|
verify), and `runtime` (a DB-API 2 `ObjectManager` — pg8000 / psycopg — no SQLAlchemy).
|
|
83
84
|
Schema migrations are owned by the TypeScript `meta` CLI (ADR-0015); there is
|
|
84
85
|
**no `migrate` module** in this distribution.
|
|
@@ -43,7 +43,8 @@ else:
|
|
|
43
43
|
The primary public API is the **loader** (`load_directory` / `load_uris` /
|
|
44
44
|
`load_string`, `MetaDataLoader`, `LoadResult`, `ErrorCode`, `MetaError`). The
|
|
45
45
|
distribution also ships the Python implementations of the other pillars used by the CLI
|
|
46
|
-
and tooling: `codegen` (Pydantic + FastAPI emit
|
|
46
|
+
and tooling: `codegen` (Pydantic + FastAPI emit — reference generators you own:
|
|
47
|
+
`metaobjects eject <name>` copies one into your repo), `render` (Mustache + payload-VO +
|
|
47
48
|
verify), and `runtime` (a DB-API 2 `ObjectManager` — pg8000 / psycopg — no SQLAlchemy).
|
|
48
49
|
Schema migrations are owned by the TypeScript `meta` CLI (ADR-0015); there is
|
|
49
50
|
**no `migrate` module** in this distribution.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "metaobjects"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.7"
|
|
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"
|
|
@@ -105,6 +105,7 @@ from metaobjects.codegen.generator_registry import (
|
|
|
105
105
|
unsatisfied_requires,
|
|
106
106
|
)
|
|
107
107
|
from metaobjects.codegen.runner import run_gen
|
|
108
|
+
from metaobjects.codegen import eject as owned
|
|
108
109
|
from metaobjects.codegen.generators.render_helper_generator import (
|
|
109
110
|
_derive_payload_field_tree,
|
|
110
111
|
)
|
|
@@ -501,10 +502,14 @@ def _template_root_for(args: argparse.Namespace) -> str:
|
|
|
501
502
|
|
|
502
503
|
|
|
503
504
|
def _resolve_generators(
|
|
504
|
-
names: str, ctx: GeneratorBuildContext | None = None,
|
|
505
|
+
names: str, ctx: GeneratorBuildContext | None = None, owned_root: Path | None = None,
|
|
505
506
|
) -> tuple[list[Generator], list[str]]:
|
|
506
507
|
"""Resolve a comma-separated list of STABLE generator names via the registry.
|
|
507
508
|
|
|
509
|
+
An entry of the form ``module:symbol`` is an adopter-owned copy (``metaobjects
|
|
510
|
+
eject``), imported with *owned_root* (default: the working directory) on ``sys.path``
|
|
511
|
+
— the config directory in config mode, so a copy beside the config resolves.
|
|
512
|
+
|
|
508
513
|
Returns ``(generators, errors)``. An unknown name produces a clear error and
|
|
509
514
|
no generators (so the caller can fail with exit code != 0).
|
|
510
515
|
|
|
@@ -519,17 +524,27 @@ def _resolve_generators(
|
|
|
519
524
|
requested = [n.strip() for n in names.split(",") if n.strip()]
|
|
520
525
|
gens: list[Generator] = []
|
|
521
526
|
errors: list[str] = []
|
|
527
|
+
selected: list[str] = []
|
|
522
528
|
for n in requested:
|
|
523
529
|
entry = get_generator(n)
|
|
530
|
+
if entry is None and (":" in n or "." in n):
|
|
531
|
+
gen, err = owned.build_owned(n, owned_root or Path.cwd(), ctx)
|
|
532
|
+
if err is not None:
|
|
533
|
+
errors.append(err)
|
|
534
|
+
continue
|
|
535
|
+
gens.append(gen)
|
|
536
|
+
selected.append(gen.name)
|
|
537
|
+
continue
|
|
524
538
|
if entry is None:
|
|
525
539
|
known = ", ".join(sorted(GENERATOR_REGISTRY))
|
|
526
540
|
errors.append(f"unknown generator {n!r}; known: {known}")
|
|
527
541
|
continue
|
|
528
542
|
gens.append(entry.factory(ctx))
|
|
543
|
+
selected.append(n)
|
|
529
544
|
if not errors and not gens:
|
|
530
545
|
errors.append("no generators selected (empty --generators list)")
|
|
531
546
|
if not errors:
|
|
532
|
-
for warning in unsatisfied_requires(
|
|
547
|
+
for warning in unsatisfied_requires(selected):
|
|
533
548
|
print(f"warning: {warning}", file=sys.stderr)
|
|
534
549
|
return gens, errors
|
|
535
550
|
|
|
@@ -968,17 +983,42 @@ def _cmd_docs(args: argparse.Namespace) -> int:
|
|
|
968
983
|
return 0
|
|
969
984
|
|
|
970
985
|
|
|
986
|
+
#: ADR-0034 Amendment 3: generators are reference helpers you own with ``metaobjects
|
|
987
|
+
#: eject``. Printed above the ``--list`` entries.
|
|
988
|
+
LIST_HEADER = (
|
|
989
|
+
"Reference generators — each is a helper, not a guarantee: `metaobjects eject <name>`\n"
|
|
990
|
+
"copies it into codegen/generators/ and the copy is yours to change. What MetaObjects\n"
|
|
991
|
+
"guarantees (verify, render) is not a generator and is not listed.\n"
|
|
992
|
+
"Select with --generators <name,...>:"
|
|
993
|
+
)
|
|
994
|
+
|
|
995
|
+
|
|
971
996
|
def _cmd_list(_args: argparse.Namespace) -> int:
|
|
972
997
|
"""Print each registered generator ``<stable-name> — <description>`` and exit 0.
|
|
973
998
|
|
|
974
999
|
Does NOT run codegen — pure discoverability (ADR-0021 D3).
|
|
975
1000
|
"""
|
|
1001
|
+
print(LIST_HEADER)
|
|
1002
|
+
root = Path.cwd()
|
|
976
1003
|
for entry in list_generators():
|
|
977
1004
|
requires = f" (requires: {', '.join(entry.requires)})" if entry.requires else ""
|
|
978
|
-
|
|
1005
|
+
status = owned.owned_status(root, entry)
|
|
1006
|
+
mark = f" [owned — {status}]" if status is not None else ""
|
|
1007
|
+
print(f"{entry.name} — {entry.description}{requires}{mark}")
|
|
979
1008
|
return 0
|
|
980
1009
|
|
|
981
1010
|
|
|
1011
|
+
def _cmd_eject(args: argparse.Namespace) -> int:
|
|
1012
|
+
"""Copy reference generators into ``codegen/generators/`` to own (ADR-0034 Am. 3)."""
|
|
1013
|
+
root = Path(args.root) if args.root else Path.cwd()
|
|
1014
|
+
result = owned.eject(args.names, root, force=args.force)
|
|
1015
|
+
for line in result.out:
|
|
1016
|
+
print(line)
|
|
1017
|
+
for line in result.err:
|
|
1018
|
+
print(f"error: {line}", file=sys.stderr)
|
|
1019
|
+
return result.code
|
|
1020
|
+
|
|
1021
|
+
|
|
982
1022
|
def _warn_if_agent_context_stale() -> None:
|
|
983
1023
|
"""Print ONE advisory line to stderr if the scaffolded agent context is stale.
|
|
984
1024
|
|
|
@@ -1161,7 +1201,8 @@ def _run_gen_targets(
|
|
|
1161
1201
|
gens: list[Generator] | None = None
|
|
1162
1202
|
if t.generators is not None:
|
|
1163
1203
|
gens, gen_errors = _resolve_generators(
|
|
1164
|
-
",".join(t.generators), build_ctx or GeneratorBuildContext()
|
|
1204
|
+
",".join(t.generators), build_ctx or GeneratorBuildContext(),
|
|
1205
|
+
owned_root=config.config_dir)
|
|
1165
1206
|
if gen_errors:
|
|
1166
1207
|
errors.extend(f"target '{t.name}': {m}" for m in gen_errors)
|
|
1167
1208
|
continue
|
|
@@ -2365,6 +2406,16 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
2365
2406
|
)
|
|
2366
2407
|
verify.set_defaults(func=_cmd_verify)
|
|
2367
2408
|
|
|
2409
|
+
eject_p = sub.add_parser(
|
|
2410
|
+
"eject",
|
|
2411
|
+
help="copy reference generators into codegen/generators/ to own and edit",
|
|
2412
|
+
)
|
|
2413
|
+
eject_p.add_argument("names", nargs="+", metavar="NAME", help="stable generator names")
|
|
2414
|
+
eject_p.add_argument("--force", action="store_true",
|
|
2415
|
+
help="replace an existing owned copy with the reference")
|
|
2416
|
+
eject_p.add_argument("--root", default=None, help="project root (default: cwd)")
|
|
2417
|
+
eject_p.set_defaults(func=_cmd_eject)
|
|
2418
|
+
|
|
2368
2419
|
agent_docs = sub.add_parser(
|
|
2369
2420
|
"agent-docs",
|
|
2370
2421
|
help=(
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""`metaobjects eject` — copy a reference generator into the adopter's repo to own.
|
|
2
|
+
|
|
3
|
+
ADR-0034 Amendment 3: a generator is a reference helper, not a guarantee. The adopter
|
|
4
|
+
copies it with ``eject``, wires the copy into ``generators`` as ``module:symbol`` (the
|
|
5
|
+
syntax ``providers`` already accepts), and ``gen`` / ``verify --codegen`` run the copy.
|
|
6
|
+
Mirrors the TypeScript ``meta eject``: the copy is verbatim, an existing copy is never
|
|
7
|
+
overwritten without ``--force``, and the config is never edited — eject prints the entry
|
|
8
|
+
to wire instead.
|
|
9
|
+
|
|
10
|
+
A copy imports the same ``metaobjects.codegen.*`` module paths the packaged generator
|
|
11
|
+
does. Those module paths are the documented surface an owned generator builds on.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import importlib
|
|
16
|
+
import inspect
|
|
17
|
+
import sys
|
|
18
|
+
import tempfile
|
|
19
|
+
from collections import Counter
|
|
20
|
+
from dataclasses import dataclass
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
from metaobjects.codegen.generator import Generator
|
|
24
|
+
from metaobjects.codegen.generator_registry import (
|
|
25
|
+
GENERATOR_REGISTRY,
|
|
26
|
+
GeneratorBuildContext,
|
|
27
|
+
GeneratorEntry,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
#: Where an owned copy lands, relative to the project root. Mirrors the TS layout.
|
|
31
|
+
OWNED_DIR = Path("codegen") / "generators"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def owned_stem(name: str) -> str:
|
|
35
|
+
"""The module name of an owned copy: the stable name with ``-`` as ``_``."""
|
|
36
|
+
return name.replace("-", "_")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def owned_path(root: Path, name: str) -> Path:
|
|
40
|
+
return root / OWNED_DIR / f"{owned_stem(name)}.py"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def owned_token(entry: GeneratorEntry) -> str:
|
|
44
|
+
"""The ``module:symbol`` entry that wires an owned copy of *entry*."""
|
|
45
|
+
return f"codegen.generators.{owned_stem(entry.name)}:{entry.symbol}"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def packaged_source(entry: GeneratorEntry) -> str:
|
|
49
|
+
assert entry.source_module is not None
|
|
50
|
+
module = importlib.import_module(entry.source_module)
|
|
51
|
+
assert module.__file__ is not None
|
|
52
|
+
return Path(module.__file__).read_text(encoding="utf-8")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def ejectable() -> list[GeneratorEntry]:
|
|
56
|
+
return [e for e in GENERATOR_REGISTRY.values() if e.source is not None]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class EjectResult:
|
|
61
|
+
code: int
|
|
62
|
+
out: list[str]
|
|
63
|
+
err: list[str]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def eject(names: list[str], root: Path, *, force: bool = False) -> EjectResult:
|
|
67
|
+
"""Copy each named generator. Every name is checked before any file is written."""
|
|
68
|
+
known = {e.name: e for e in ejectable()}
|
|
69
|
+
unknown = [n for n in names if n not in known]
|
|
70
|
+
if unknown:
|
|
71
|
+
return EjectResult(2, [], [
|
|
72
|
+
f"unknown or non-ejectable generator(s): {', '.join(unknown)}; "
|
|
73
|
+
f"ejectable: {', '.join(sorted(known))}",
|
|
74
|
+
])
|
|
75
|
+
existing = [n for n in names if owned_path(root, n).exists()]
|
|
76
|
+
if existing and not force:
|
|
77
|
+
return EjectResult(1, [], [
|
|
78
|
+
f"already owned: {', '.join(str(owned_path(root, n).relative_to(root)) for n in existing)}. "
|
|
79
|
+
"Eject never overwrites your copy; pass --force to replace it with the reference.",
|
|
80
|
+
])
|
|
81
|
+
|
|
82
|
+
(root / OWNED_DIR).mkdir(parents=True, exist_ok=True)
|
|
83
|
+
for init in (root / "codegen" / "__init__.py", root / OWNED_DIR / "__init__.py"):
|
|
84
|
+
if not init.exists():
|
|
85
|
+
init.write_text("", encoding="utf-8")
|
|
86
|
+
|
|
87
|
+
out: list[str] = []
|
|
88
|
+
for n in names:
|
|
89
|
+
entry = known[n]
|
|
90
|
+
target = owned_path(root, n)
|
|
91
|
+
target.write_text(packaged_source(entry), encoding="utf-8")
|
|
92
|
+
out.append(f"ejected {n} -> {target.relative_to(root)}")
|
|
93
|
+
out.append(f" wire it: replace \"{n}\" in `generators` with {owned_token(entry)}")
|
|
94
|
+
out.append("")
|
|
95
|
+
out.append(
|
|
96
|
+
"The copies are yours: edit them freely. Keep only one of the packaged name and your "
|
|
97
|
+
"copy in `generators` — wiring both runs both, and they write the same files."
|
|
98
|
+
)
|
|
99
|
+
return EjectResult(0, out, [])
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _normalised(text: str) -> Counter[str]:
|
|
103
|
+
return Counter(line.rstrip() for line in text.splitlines() if line.strip())
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def owned_status(root: Path, entry: GeneratorEntry) -> str | None:
|
|
107
|
+
"""``identical`` / ``DIFFERS: N behind, M of your own``, or ``None`` if not owned.
|
|
108
|
+
|
|
109
|
+
Line-multiset comparison, the same shape as TS ``owned-copy.ts``: *behind* counts
|
|
110
|
+
reference lines the copy lacks, *of your own* counts copy lines the reference lacks.
|
|
111
|
+
"""
|
|
112
|
+
path = owned_path(root, entry.name)
|
|
113
|
+
if entry.source is None or not path.exists():
|
|
114
|
+
return None
|
|
115
|
+
mine = _normalised(path.read_text(encoding="utf-8"))
|
|
116
|
+
ref = _normalised(packaged_source(entry))
|
|
117
|
+
behind = sum((ref - mine).values())
|
|
118
|
+
own = sum((mine - ref).values())
|
|
119
|
+
if behind == 0 and own == 0:
|
|
120
|
+
return "identical"
|
|
121
|
+
return f"DIFFERS: {behind} behind, {own} of your own"
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def build_owned(spec: str, root: Path, ctx: GeneratorBuildContext) -> tuple[Generator | None, str | None]:
|
|
125
|
+
"""Resolve a ``module:symbol`` generator entry against the project at *root*.
|
|
126
|
+
|
|
127
|
+
The symbol may be a Generator, or a factory: one taking ``template_root`` (the
|
|
128
|
+
render-helper shape) gets the build context's template root; one taking a single
|
|
129
|
+
positional argument gets the build context; otherwise it is called with none.
|
|
130
|
+
"""
|
|
131
|
+
module_name, sep, symbol = spec.partition(":")
|
|
132
|
+
if not sep or not module_name or not symbol:
|
|
133
|
+
return None, (f"generator {spec!r} is neither a registered name nor a "
|
|
134
|
+
"'module:symbol' reference to an owned copy")
|
|
135
|
+
root_str = str(root.resolve())
|
|
136
|
+
if root_str not in sys.path:
|
|
137
|
+
sys.path.insert(0, root_str)
|
|
138
|
+
# A module of the same name imported from another project (or an earlier copy) would
|
|
139
|
+
# be reused from the cache; drop any entry that does not live under this root.
|
|
140
|
+
top = module_name.split(".")[0]
|
|
141
|
+
for key in [k for k in sys.modules if k == top or k.startswith(top + ".")]:
|
|
142
|
+
file = getattr(sys.modules[key], "__file__", None)
|
|
143
|
+
if file is None or not str(Path(file).resolve()).startswith(root_str):
|
|
144
|
+
del sys.modules[key]
|
|
145
|
+
try:
|
|
146
|
+
module = importlib.import_module(module_name)
|
|
147
|
+
except Exception as exc: # ImportError and anything raised at import time
|
|
148
|
+
return None, f"generator {spec!r}: cannot import {module_name!r}: {exc}"
|
|
149
|
+
obj = getattr(module, symbol, None)
|
|
150
|
+
if obj is None:
|
|
151
|
+
return None, f"generator {spec!r}: {module_name!r} has no attribute {symbol!r}"
|
|
152
|
+
if not hasattr(obj, "generate") and callable(obj):
|
|
153
|
+
params = inspect.signature(obj).parameters
|
|
154
|
+
required = [p for p in params.values()
|
|
155
|
+
if p.default is inspect.Parameter.empty
|
|
156
|
+
and p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD)]
|
|
157
|
+
try:
|
|
158
|
+
if "template_root" in params:
|
|
159
|
+
obj = obj(template_root=ctx.template_root or tempfile.gettempdir())
|
|
160
|
+
elif len(required) == 1:
|
|
161
|
+
obj = obj(ctx)
|
|
162
|
+
else:
|
|
163
|
+
obj = obj()
|
|
164
|
+
except Exception as exc:
|
|
165
|
+
return None, f"generator {spec!r}: factory {symbol}() raised: {exc}"
|
|
166
|
+
if not hasattr(obj, "generate") or not hasattr(obj, "name"):
|
|
167
|
+
return None, f"generator {spec!r}: {symbol!r} is not a generator (needs name and generate)"
|
|
168
|
+
return obj, None
|
|
@@ -108,6 +108,21 @@ class GeneratorEntry:
|
|
|
108
108
|
#: Not gated cross-port (the manifest carries no such column); surfaced by ``--list``
|
|
109
109
|
#: and warned about by :func:`unsatisfied_requires`.
|
|
110
110
|
requires: tuple[str, ...] = ()
|
|
111
|
+
#: The packaged factory an adopter copies with ``metaobjects eject`` (ADR-0034
|
|
112
|
+
#: Amendment 3). Its module is the file copied; its name is the ``module:symbol``
|
|
113
|
+
#: symbol the copy is wired by. ``None`` = not ejectable (the ``template`` primitive
|
|
114
|
+
#: has no emit logic of its own to own).
|
|
115
|
+
source: Callable[..., Generator] | None = None
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def source_module(self) -> str | None:
|
|
119
|
+
"""Dotted module path of the file ``eject`` copies, or ``None``."""
|
|
120
|
+
return self.source.__module__ if self.source is not None else None
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
def symbol(self) -> str | None:
|
|
124
|
+
"""The factory name an owned copy exports, or ``None``."""
|
|
125
|
+
return self.source.__name__ if self.source is not None else None
|
|
111
126
|
|
|
112
127
|
|
|
113
128
|
def _template_primitive(_ctx: GeneratorBuildContext) -> Generator:
|
|
@@ -149,10 +164,16 @@ def _render_helper_default(ctx: GeneratorBuildContext) -> Generator:
|
|
|
149
164
|
GENERATOR_REGISTRY: dict[str, GeneratorEntry] = {
|
|
150
165
|
"entity": GeneratorEntry(
|
|
151
166
|
name="entity",
|
|
152
|
-
description=
|
|
167
|
+
description=(
|
|
168
|
+
"Per-entity model/class — the entity module (table-backed or value object). "
|
|
169
|
+
"[A field with @stringFormat email is typed pydantic EmailStr, which imports "
|
|
170
|
+
"email-validator when the class is defined, so the consuming project needs "
|
|
171
|
+
"`pydantic[email]` — without it the generated module fails at import.]"
|
|
172
|
+
),
|
|
153
173
|
tier="native",
|
|
154
174
|
layer="model",
|
|
155
175
|
factory=lambda _ctx: entity_model(),
|
|
176
|
+
source=entity_model,
|
|
156
177
|
),
|
|
157
178
|
"routes": GeneratorEntry(
|
|
158
179
|
name="routes",
|
|
@@ -160,6 +181,7 @@ GENERATOR_REGISTRY: dict[str, GeneratorEntry] = {
|
|
|
160
181
|
tier="native",
|
|
161
182
|
layer="api",
|
|
162
183
|
factory=lambda _ctx: router_generator(),
|
|
184
|
+
source=router_generator,
|
|
163
185
|
),
|
|
164
186
|
"output-parser": GeneratorEntry(
|
|
165
187
|
name="output-parser",
|
|
@@ -168,6 +190,7 @@ GENERATOR_REGISTRY: dict[str, GeneratorEntry] = {
|
|
|
168
190
|
layer="capability",
|
|
169
191
|
factory=lambda _ctx: output_parser_generator(),
|
|
170
192
|
requires=("entity",),
|
|
193
|
+
source=output_parser_generator,
|
|
171
194
|
),
|
|
172
195
|
"output-prompt": GeneratorEntry(
|
|
173
196
|
name="output-prompt",
|
|
@@ -175,6 +198,7 @@ GENERATOR_REGISTRY: dict[str, GeneratorEntry] = {
|
|
|
175
198
|
tier="native",
|
|
176
199
|
layer="capability",
|
|
177
200
|
factory=lambda _ctx: output_prompt_generator(),
|
|
201
|
+
source=output_prompt_generator,
|
|
178
202
|
),
|
|
179
203
|
"render-helper": GeneratorEntry(
|
|
180
204
|
name="render-helper",
|
|
@@ -183,6 +207,7 @@ GENERATOR_REGISTRY: dict[str, GeneratorEntry] = {
|
|
|
183
207
|
layer="capability",
|
|
184
208
|
factory=_render_helper_default,
|
|
185
209
|
requires=("entity",),
|
|
210
|
+
source=render_helper_generator,
|
|
186
211
|
),
|
|
187
212
|
"extractor": GeneratorEntry(
|
|
188
213
|
name="extractor",
|
|
@@ -191,6 +216,7 @@ GENERATOR_REGISTRY: dict[str, GeneratorEntry] = {
|
|
|
191
216
|
layer="capability",
|
|
192
217
|
factory=lambda _ctx: extractor_generator(),
|
|
193
218
|
requires=("entity",),
|
|
219
|
+
source=extractor_generator,
|
|
194
220
|
),
|
|
195
221
|
"template": GeneratorEntry(
|
|
196
222
|
name="template",
|
|
@@ -205,6 +231,7 @@ GENERATOR_REGISTRY: dict[str, GeneratorEntry] = {
|
|
|
205
231
|
tier="native",
|
|
206
232
|
layer="api",
|
|
207
233
|
factory=lambda _ctx: filter_allowlist_generator(),
|
|
234
|
+
source=filter_allowlist_generator,
|
|
208
235
|
),
|
|
209
236
|
"names": GeneratorEntry(
|
|
210
237
|
name="names",
|
|
@@ -212,6 +239,7 @@ GENERATOR_REGISTRY: dict[str, GeneratorEntry] = {
|
|
|
212
239
|
tier="native",
|
|
213
240
|
layer="model",
|
|
214
241
|
factory=lambda _ctx: names_generator(),
|
|
242
|
+
source=names_generator,
|
|
215
243
|
),
|
|
216
244
|
"trace-helper": GeneratorEntry(
|
|
217
245
|
name="trace-helper",
|
|
@@ -219,6 +247,7 @@ GENERATOR_REGISTRY: dict[str, GeneratorEntry] = {
|
|
|
219
247
|
tier="native",
|
|
220
248
|
layer="capability",
|
|
221
249
|
factory=lambda _ctx: trace_helper_generator(),
|
|
250
|
+
source=trace_helper_generator,
|
|
222
251
|
),
|
|
223
252
|
}
|
|
224
253
|
|
{metaobjects-1.0.5rc10 → metaobjects-1.0.7}/src/metaobjects/codegen/generators/router_generator.py
RENAMED
|
@@ -431,6 +431,32 @@ def _sort_parse_fn_lines() -> list[str]:
|
|
|
431
431
|
]
|
|
432
432
|
|
|
433
433
|
|
|
434
|
+
def _auth_docstring_paragraph(*, read_only: bool) -> str:
|
|
435
|
+
"""The auth-seam paragraph appended to every generated router's module docstring
|
|
436
|
+
(#367). A generated router is unauthenticated by construction — the consumer wires
|
|
437
|
+
a dependency onto `app.include_router` — and until this, nothing in the emitted
|
|
438
|
+
module said so, mirroring the gap the TS route generators closed for #367 with a
|
|
439
|
+
doc-comment above the register function. Python has no `expose` option to narrow a
|
|
440
|
+
generated router down to a safe subset (non-TS REST templates are frozen for
|
|
441
|
+
features), so the escape hatch for anything a dependency cannot express — a
|
|
442
|
+
row-ownership rule — is `metaobjects eject`, not a narrowing flag.
|
|
443
|
+
|
|
444
|
+
*read_only* only swaps "these endpoints" for "these read endpoints" on a
|
|
445
|
+
projection's GET-only surface; the guidance is otherwise identical. Returned text
|
|
446
|
+
starts and ends with a newline so a caller can splice it directly between the
|
|
447
|
+
docstring's summary line and the closing `\"\"\"`."""
|
|
448
|
+
verbs = "read endpoints" if read_only else "endpoints"
|
|
449
|
+
return (
|
|
450
|
+
"\n"
|
|
451
|
+
f"Auth: these {verbs} are unauthenticated. To guard them, include the router with a\n"
|
|
452
|
+
"dependency, e.g. `app.include_router(router, dependencies=[Depends(require_auth)])`.\n"
|
|
453
|
+
"\n"
|
|
454
|
+
'A row-ownership rule ("only the owner may read this row") cannot be expressed as a\n'
|
|
455
|
+
"router dependency: eject this generator with `metaobjects eject` and hand-write\n"
|
|
456
|
+
"those endpoints.\n"
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
|
|
434
460
|
class RouterGenerator:
|
|
435
461
|
"""One ``<entity_snake>_router.py`` per routed object (FastAPI ``APIRouter``):
|
|
436
462
|
full CRUD for a writable source, read-only for a view-backed one.
|
|
@@ -882,7 +908,9 @@ class RouterGenerator:
|
|
|
882
908
|
parts.append(
|
|
883
909
|
h + "\n"
|
|
884
910
|
+ f'"""GENERATED — TPH polymorphic REST router for the {short_name} hierarchy '
|
|
885
|
-
+ '(single-table inheritance: polymorphic base + per-subtype CRUD)
|
|
911
|
+
+ '(single-table inheritance: polymorphic base + per-subtype CRUD).\n'
|
|
912
|
+
+ _auth_docstring_paragraph(read_only=False)
|
|
913
|
+
+ '"""\n'
|
|
886
914
|
)
|
|
887
915
|
parts.append("from __future__ import annotations")
|
|
888
916
|
parts.append("")
|
|
@@ -1232,7 +1260,9 @@ class RouterGenerator:
|
|
|
1232
1260
|
parts: list[str] = []
|
|
1233
1261
|
parts.append(
|
|
1234
1262
|
generated_header(short_name, _effective_fqn(entity)).rstrip() + "\n"
|
|
1235
|
-
+ f'"""GENERATED — REST router for {short_name} entity. Implements the cross-port API contract
|
|
1263
|
+
+ f'"""GENERATED — REST router for {short_name} entity. Implements the cross-port API contract.\n'
|
|
1264
|
+
+ _auth_docstring_paragraph(read_only=False)
|
|
1265
|
+
+ '"""\n'
|
|
1236
1266
|
)
|
|
1237
1267
|
parts.append("from __future__ import annotations")
|
|
1238
1268
|
parts.append("")
|
|
@@ -1401,7 +1431,9 @@ class RouterGenerator:
|
|
|
1401
1431
|
generated_header(short_name, _effective_fqn(entity)).rstrip() + "\n"
|
|
1402
1432
|
+ f'"""GENERATED — read-only REST router for the {short_name} projection.\n\n'
|
|
1403
1433
|
+ "Implements the cross-port API contract: GET list + GET by id; every write\n"
|
|
1404
|
-
+ 'verb answers 405 {"error": "method_not_allowed"}
|
|
1434
|
+
+ 'verb answers 405 {"error": "method_not_allowed"}.\n'
|
|
1435
|
+
+ _auth_docstring_paragraph(read_only=True)
|
|
1436
|
+
+ '"""\n'
|
|
1405
1437
|
)
|
|
1406
1438
|
parts.append("from __future__ import annotations")
|
|
1407
1439
|
parts.append("")
|
|
@@ -151,6 +151,7 @@ def run_gen(
|
|
|
151
151
|
|
|
152
152
|
refused: list[str] = []
|
|
153
153
|
adopted: list[str] = []
|
|
154
|
+
untracked = 0
|
|
154
155
|
for full, (content, _by) in emitted.items():
|
|
155
156
|
# The out-dir-relative name: what the manifest used to be keyed by, and still
|
|
156
157
|
# what a refusal is REPORTED as (it is the name the reader sees in `--out`).
|
|
@@ -173,11 +174,17 @@ def run_gen(
|
|
|
173
174
|
if config.project_root
|
|
174
175
|
else rel
|
|
175
176
|
)
|
|
177
|
+
# A file written OUTSIDE the project has no place in the project's manifest: its
|
|
178
|
+
# key would be `../`-relative and committed into `.hashes.json`. It gets the
|
|
179
|
+
# manifest-less rule a run with no project gets — written, never recorded.
|
|
180
|
+
outside = bool(config.project_root) and (key.startswith("..") or os.path.isabs(key))
|
|
181
|
+
if outside:
|
|
182
|
+
untracked += 1
|
|
176
183
|
status = decide_and_write(
|
|
177
184
|
full,
|
|
178
185
|
content,
|
|
179
186
|
merge_strategy,
|
|
180
|
-
gen_state_dir=config.gen_state_dir,
|
|
187
|
+
gen_state_dir=None if outside else config.gen_state_dir,
|
|
181
188
|
rel_path=key,
|
|
182
189
|
legacy_rel_path=rel if key != rel else None,
|
|
183
190
|
baseline=config.baseline,
|
|
@@ -188,6 +195,13 @@ def run_gen(
|
|
|
188
195
|
elif status == "adopted":
|
|
189
196
|
adopted.append(rel)
|
|
190
197
|
|
|
198
|
+
if untracked:
|
|
199
|
+
result.warnings.append(
|
|
200
|
+
f"{untracked} generated file(s) were written outside the project root and are "
|
|
201
|
+
f"not recorded in .metaobjects/.gen-state/.hashes.json, so hand-edit protection "
|
|
202
|
+
f"does not apply to them beyond the @generated header rule."
|
|
203
|
+
)
|
|
204
|
+
|
|
191
205
|
if refused:
|
|
192
206
|
if not tracking_hashes:
|
|
193
207
|
# No state to reason from, so decide_and_write can only have refused for
|
|
@@ -45,7 +45,7 @@ def extract(
|
|
|
45
45
|
span: str | None
|
|
46
46
|
raw: dict[str, object]
|
|
47
47
|
if schema.format == Format.JSON:
|
|
48
|
-
span =
|
|
48
|
+
span = _select_json(text, stripped, schema.fields, ci)
|
|
49
49
|
raw = {} if span is None else JsonForgivingReader().read(span)
|
|
50
50
|
elif o.rootless:
|
|
51
51
|
span = None if stripped == "" else stripped
|
|
@@ -199,12 +199,39 @@ def _extract_value(
|
|
|
199
199
|
# A text element that also carried XML attributes is represented by XmlForgivingReader
|
|
200
200
|
# as a dict with the body under TEXT_KEY. A scalar field reads that text (attributes
|
|
201
201
|
# ignored for scalars — preserving pre-attribute-support behaviour).
|
|
202
|
-
if isinstance(present, dict)
|
|
202
|
+
if isinstance(present, dict):
|
|
203
|
+
# An element with no text of its own (only child elements) is not a scalar value.
|
|
204
|
+
# Never stringify the dict: that delivered "{'child': ...}" as the field's text.
|
|
205
|
+
if TEXT_KEY not in present:
|
|
206
|
+
return MALFORMED
|
|
203
207
|
present = present[TEXT_KEY]
|
|
204
208
|
raw_str = present if isinstance(present, str) else str(present)
|
|
205
209
|
return _coerce.value(raw_str, f, o, path, report)
|
|
206
210
|
|
|
207
211
|
|
|
212
|
+
def _select_json(
|
|
213
|
+
text: str | None, stripped: str, fields: list[FieldSpec], ci: bool
|
|
214
|
+
) -> str | None:
|
|
215
|
+
"""Pick the JSON object that answers the schema. Fenced blocks are searched first, then
|
|
216
|
+
the whole reply, and the first object carrying at least one declared field wins, so a
|
|
217
|
+
draft object, an echoed format example or a brace in prose no longer shadows the real
|
|
218
|
+
answer (#363). A fenced object with none of the declared fields falls through the same
|
|
219
|
+
way. When nothing carries a declared field, the first-object rule (``locate.json``)
|
|
220
|
+
decides."""
|
|
221
|
+
for region in [*_strip.fenced_bodies(text), stripped]:
|
|
222
|
+
for candidate in _locate.json_candidates(region):
|
|
223
|
+
parsed = JsonForgivingReader().read(candidate)
|
|
224
|
+
if any(_carries(parsed, f.name, ci) for f in fields):
|
|
225
|
+
return candidate
|
|
226
|
+
return _locate.json(stripped)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _carries(raw: dict[str, object], name: str, ci: bool) -> bool:
|
|
230
|
+
if name in raw:
|
|
231
|
+
return True
|
|
232
|
+
return ci and any(k.lower() == name.lower() for k in raw)
|
|
233
|
+
|
|
234
|
+
|
|
208
235
|
def _lookup(raw: dict[str, object], name: str, ci: bool) -> object | None:
|
|
209
236
|
"""Case-folding lookup honoring tolerance."""
|
|
210
237
|
if name in raw:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Stages 2-3: isolate and select the payload root span.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
JSON: extract picks among json_candidates by the schema (fenced first, first object carrying a
|
|
4
|
+
declared field); json() (first-closed-else-first-open) is its fallback.
|
|
4
5
|
"""
|
|
5
6
|
from __future__ import annotations
|
|
6
7
|
|
|
@@ -22,6 +23,28 @@ def json(text: str | None) -> str | None:
|
|
|
22
23
|
return None if first_open < 0 else text[first_open:]
|
|
23
24
|
|
|
24
25
|
|
|
26
|
+
def json_candidates(text: str | None) -> list[str]:
|
|
27
|
+
"""Every top-level object span in ``text``, in order: each balanced {...} (nested objects
|
|
28
|
+
are part of their parent, not separate spans), and, for a '{' that never closes, the text
|
|
29
|
+
from it to the end."""
|
|
30
|
+
out: list[str] = []
|
|
31
|
+
if text is None:
|
|
32
|
+
return out
|
|
33
|
+
tail_added = False
|
|
34
|
+
i = 0
|
|
35
|
+
while i < len(text):
|
|
36
|
+
if text[i] == "{":
|
|
37
|
+
end = _scan_balanced(text, i)
|
|
38
|
+
if end >= 0:
|
|
39
|
+
out.append(text[i : end + 1])
|
|
40
|
+
i = end
|
|
41
|
+
elif not tail_added:
|
|
42
|
+
out.append(text[i:])
|
|
43
|
+
tail_added = True
|
|
44
|
+
i += 1
|
|
45
|
+
return out
|
|
46
|
+
|
|
47
|
+
|
|
25
48
|
def _scan_balanced(s: str, open_idx: int) -> int:
|
|
26
49
|
"""Return index of the matching ``}``, or -1 if unterminated. String-aware."""
|
|
27
50
|
depth = 0
|
|
@@ -18,3 +18,11 @@ def strip(raw: str | None) -> str:
|
|
|
18
18
|
if m:
|
|
19
19
|
return (raw[: m.start()] + m.group(1) + raw[m.end():]).strip()
|
|
20
20
|
return raw.strip()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def fenced_bodies(raw: str | None) -> list[str]:
|
|
24
|
+
"""The body of every fenced block, in order. Locate searches these before the whole
|
|
25
|
+
text, because a model told to fence its answer puts the answer there."""
|
|
26
|
+
if raw is None:
|
|
27
|
+
return []
|
|
28
|
+
return [m.group(1) for m in _FENCE.finditer(raw)]
|