metaobjects 0.25.0__tar.gz → 1.0.0rc5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/PKG-INFO +1 -1
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/pyproject.toml +1 -1
- metaobjects-1.0.0rc5/src/metaobjects/codegen/format.py +72 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/names_generator.py +20 -16
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/router_generator.py +46 -4
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/registry_manifest.py +1 -1
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/source_resolution.py +26 -6
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/ui.json +2 -2
- metaobjects-1.0.0rc5/tests/codegen/test_format.py +85 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_names_extends_chain.py +42 -10
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/api_contract_server.py +15 -1
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/uv.lock +1 -1
- metaobjects-0.25.0/src/metaobjects/codegen/format.py +0 -42
- metaobjects-0.25.0/tests/codegen/test_format.py +0 -30
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/.gitignore +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/LICENSE +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/README.md +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/hatch_build.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/scripts/generate_embedded_library.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/agent_context/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/agent_context/scaffold.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/apidocs/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/apidocs/api_model.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/apidocs/builder.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/apidocs/naming.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/apidocs/paths.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/apidocs/renderer.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/attr_class_map.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/cli.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/collision_names.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/config.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generator_registry.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/entity_model.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/find_inbound.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/payload_vo_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/template_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/instance_artifacts.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/overwrite_policy.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/project_config.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/runner.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/runtime/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/type_map.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/config/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/config/neutral_config.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/config/source_resolver.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/core_types.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/datatype.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/documentation/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/documentation/doc_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/documentation/doc_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/documentation/doc_schema.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/errors.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/library/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/library/embedded_library.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/library/library_sources.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/merge.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/meta_data_loader.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/registered_validation.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/sources/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/sources/directory_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/sources/file_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/sources/uri_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validate_discriminator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validate_field_mutability.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validate_source_escapes.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validation_passes.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/attr/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/field/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/field/field_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/field/meta_field.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/identity/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/index/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/index/index_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/index/meta_index.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/meta_object.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/object_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/object_extract.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/value_object.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/validator/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/meta_data.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/meta_root.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/provider_extends.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/template/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/template/meta_template.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/template/prompt_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/template/template_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/naming.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/naming_refs.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/parser.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/parser_yaml.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/py.typed +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/registry.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/email_document.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/escapers.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/coerce.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/extract.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/extract_map.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/locate.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/normalize.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/strip.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/types.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/filesystem_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/payload_accessors.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/prompt/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/prompt/prompt_field.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/prompt/prompt_style.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/renderer.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/verify.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/runtime/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/runtime/llm_recorder.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/runtime/n2m_resolver.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/runtime/object_manager.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/runtime/tph.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/serializer_json.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/shared/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/shared/base_types.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/shared/separators.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/shared/structural.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/source/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/source/error_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/source/json_path.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/source/semantic_diff.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/source/yaml_positions.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/attr.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/db.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/documentation.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/field.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/identity.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/index.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/layout.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/object.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/origin.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/prompt.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/relationship.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/requirement.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/source.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/template.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/validator.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/view.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/super_resolve.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/validation_types.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/yaml_desugar.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/extends/expected/Program.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/extends/meta.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/nested-array/meta.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/scalars/expected/Report.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/scalars/meta.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/vanilla/meta.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_abstract_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_api_docs_builder.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_api_docs_paths.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_config_gen.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_config_verify.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_providers.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_registry.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_staleness_nudge.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_verify_strict.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_verify_subverbs.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_constants_config.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_entity_model.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_enum_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_extract_tier_collision.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_extractor_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_filter_allowlist_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_fr010_output_codegen.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_generator_extension_seams.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_golden.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_inheritance_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_instance_artifacts.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_m2m_codegen.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_names_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_no_magic_physical_names.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_origin_nullability.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_output_parser_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_overwrite_policy.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_overwrite_policy_hash.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_payload_vo_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_project_config.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_projection_compile.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_render_helper_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_render_helper_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_reverse_finders.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_router_autoset.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_router_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_runner.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_source_resolution.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_sourceless_projection.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_template_data.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_template_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_template_output_pattern.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_template_scope_helpers.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_template_scope_walk.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_template_spec.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_tph_codegen.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_trace_helper_generator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_type_map.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_validation_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_write_through.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/config/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/config/test_neutral_config.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/config/test_source_resolver.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/capabilities.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/conformance-expected-failures.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/conformance_adapter.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/corpus.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/expected_failures.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/fixture_discovery.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/navigator.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_extract_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_extract_object_verdict.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_fr010_loader_attrs.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_fr011_attrs.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_generator_registry_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_object_model_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_provider_composition_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_registry_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_runner_hardfail.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_source_resolution_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_spec_metamodel_embed.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_strict_attr_load.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_template_codegen_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_template_generator_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_yaml_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/api_contract_assertions.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/api_contract_jsonb_server.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/api_contract_m2m_server.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/generated_jsonb_app.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/generated_m2m_app.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/generated_router_app.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/generated_tph_app.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/meta_ai_trace.yaml +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/normalization.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/postgres_container.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/query_runner.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/scenarios.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_api_contract.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_api_contract_generated.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_api_contract_jsonb.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_api_contract_m2m.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_api_contract_m2m_generated.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_api_contract_tph_generated.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_generated_router_uuid_pk.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_llm_call_trace.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_normalization.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_query_scenarios.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_runtime_return_types.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/loader/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/loader/test_abstract_subtype_authored.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/loader/test_enum_extends_values_conflict.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/loader/test_field_mutability_order.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/loader/test_shipped_library_ai.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/loader/test_template_payload_target_210.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/open_closed_proof_test.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_coerce.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_extract.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_extract_map.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_json_forgiving_reader.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_locate.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_model.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_normalize.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_strip.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/prompt/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/prompt/test_output_format_renderer.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_email_document.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_filesystem_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_output_format_renderer_nested.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_output_prompt_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_render_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_render_max_chars.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_verify.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_verify_conformance.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/runtime/test_object_manager_enum_intvaluemap.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/runtime/test_object_manager_table_name.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_fr5c_merge_attribution.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_fr5d_reference_resolution.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_fr5e_database_source_shape.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_json_path.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_semantic_diff.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_source_on_node.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_yaml_positions.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/test_api_docs_accuracy.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/__init__.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_agent_context_staleness.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_capabilities.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_column_naming_strategy.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_common_attrs.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_core_types.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_effective_children_sibling_shadowing.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_effective_package.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_errors.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_field_enum.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_field_enum_intvaluemap.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_field_map_validation.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_index_lookup.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_llm_recorder.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_loader.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_loader_bom.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_loader_class.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_merge.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_meta_attr.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_meta_data.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_meta_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_module_shortcuts.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_n2m_resolver.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_n2m_resolver_inherited.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_no_dead_config_fields.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_object_manager_write_through.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_one_primary_source.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_parser.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_parser_yaml.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_provider.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_provider_extension.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_registry.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_registry_completeness.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_registry_extend.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_registry_sealed.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_relationship_referential_actions.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_resolution_key.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_serializer.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_shared_constants.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_smoke.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_source_escapes.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_sources.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_strict_child_placement.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_super_resolve.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_template_toolcall.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_validation_attr_schema.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_validation_filter_values.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_validation_origin_195.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_validation_origin_paths.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_validation_sort_field.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_validation_warnings.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_write_coercion_arrays.py +0 -0
- {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_yaml_desugar.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: metaobjects
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0rc5
|
|
4
4
|
Summary: Cross-language metadata standard: declare typed entities once, generate idiomatic drift-checked code across languages — Python port.
|
|
5
5
|
Project-URL: Homepage, https://metaobjects.dev
|
|
6
6
|
Project-URL: Repository, https://github.com/metaobjectsdev/metaobjects
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "metaobjects"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "1.0.0rc5"
|
|
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"
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Canonicalize emitted source via ruff: sort imports (isort), then format.
|
|
2
|
+
|
|
3
|
+
Both passes read stdin / write stdout, so generated code is import-sorted AND
|
|
4
|
+
formatted — i.e. `ruff check`- and `ruff format`-clean for downstream consumers."""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import importlib.util
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
_STDIN_NAME = "generated.py"
|
|
12
|
+
|
|
13
|
+
#: ruff is a codegen-time convenience (import-sort + format), not a runtime requirement
|
|
14
|
+
#: of the emitted code. When it's absent we emit valid-but-unformatted Python rather
|
|
15
|
+
#: than hard-failing the whole ``gen``.
|
|
16
|
+
_RUFF_AVAILABLE = importlib.util.find_spec("ruff") is not None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _run_ruff(args: list[str], source: str) -> str:
|
|
20
|
+
proc = subprocess.run(
|
|
21
|
+
[sys.executable, "-m", "ruff", *args],
|
|
22
|
+
input=source,
|
|
23
|
+
capture_output=True,
|
|
24
|
+
text=True,
|
|
25
|
+
)
|
|
26
|
+
if proc.returncode != 0:
|
|
27
|
+
# A non-zero exit is read by the caller as "ruff rejected the source" — a
|
|
28
|
+
# generator bug. Two things make that reading unsafe, so record what actually
|
|
29
|
+
# happened instead of asserting a cause.
|
|
30
|
+
#
|
|
31
|
+
# First, ruff reports a source it cannot parse as exit 2 WITH stderr (measured,
|
|
32
|
+
# ruff 0.15.14: `error: Failed to parse at 1:7: ...`). So an EMPTY stderr is not
|
|
33
|
+
# a source rejection — the process did not get far enough to say anything.
|
|
34
|
+
# Second, a NEGATIVE returncode is death by signal, which is not a verdict on
|
|
35
|
+
# the source at all.
|
|
36
|
+
#
|
|
37
|
+
# This branch used to raise `ruff format failed:` — trailing off after the colon
|
|
38
|
+
# whenever stderr was empty, naming neither the exit status nor the fact that
|
|
39
|
+
# ruff never looked at the source, and sending a reader hunting a syntax error
|
|
40
|
+
# that did not exist. Always carry the status; never claim a source error for a
|
|
41
|
+
# process that did not finish, and do not guess at WHY it did not finish.
|
|
42
|
+
detail = proc.stderr.strip()
|
|
43
|
+
if proc.returncode < 0:
|
|
44
|
+
raise RuntimeError(
|
|
45
|
+
f"ruff {args[0]} was killed by signal {-proc.returncode} before it could "
|
|
46
|
+
f"format the source — this is not a source error; the formatter never ran "
|
|
47
|
+
f"to completion" + (f": {detail}" if detail else "")
|
|
48
|
+
)
|
|
49
|
+
raise RuntimeError(
|
|
50
|
+
f"ruff {args[0]} failed (exit {proc.returncode})"
|
|
51
|
+
+ (
|
|
52
|
+
f": {detail}"
|
|
53
|
+
if detail
|
|
54
|
+
else " and wrote nothing to stderr — ruff reports an unparseable source"
|
|
55
|
+
" WITH stderr, so this is not a source error"
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
return proc.stdout
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def ruff_format(source: str) -> str:
|
|
62
|
+
"""Sort imports then format *source*; return the canonical text.
|
|
63
|
+
|
|
64
|
+
A no-op (returns *source* unchanged) when ruff is not installed — the emitted
|
|
65
|
+
code is still valid Python, just unformatted. Still raises RuntimeError if ruff
|
|
66
|
+
IS present but fails (e.g. a syntax error in emitted code — that's a generator bug)."""
|
|
67
|
+
if not _RUFF_AVAILABLE:
|
|
68
|
+
return source
|
|
69
|
+
sorted_src = _run_ruff(
|
|
70
|
+
["check", "--select", "I", "--fix", "--stdin-filename", _STDIN_NAME, "-"], source
|
|
71
|
+
)
|
|
72
|
+
return _run_ruff(["format", "-"], sorted_src)
|
{metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/names_generator.py
RENAMED
|
@@ -286,24 +286,28 @@ def _sources_by_role(entity: MetaObject) -> dict[str, MetaSource]:
|
|
|
286
286
|
ADR-0039: ``children()`` RESOLVES — a source inherited via ``extends`` (the TPH
|
|
287
287
|
pattern) is seen; ``own_children()`` would miss it.
|
|
288
288
|
|
|
289
|
-
The refusal is about DISAGREEMENT, not about the count —
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
it exists to serve.
|
|
289
|
+
The refusal is about DISAGREEMENT, not about the count — the SAME rule
|
|
290
|
+
:func:`primary_rdb_source` enforces, which now compares the whole ADDRESS
|
|
291
|
+
(:func:`source_address_key`: kind, schema, physical name) rather than the bare
|
|
292
|
+
name. An abstract base and the child that extends it may each declare a
|
|
293
|
+
``@role: primary`` source naming the same relation; that is legal, and refusing it
|
|
294
|
+
would make this module stricter than the invariant it exists to serve.
|
|
295
295
|
|
|
296
296
|
Two sources in one role that resolve DIFFERENTLY is the real problem, and silently
|
|
297
297
|
keeping one is the failure mode this artifact makes impossible: the second name is
|
|
298
298
|
carried nowhere, read by nobody, and the binding quietly takes the first's.
|
|
299
299
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
agreeing on the name and differing on
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
300
|
+
This docstring used to claim the two were "deliberately the SAME rule" while
|
|
301
|
+
describing, two paragraphs later, exactly how they differed — that function
|
|
302
|
+
compared physical NAMES, so two primaries agreeing on the name and differing on
|
|
303
|
+
``@schema`` got past it and landed on one role key here. They are the same rule
|
|
304
|
+
now. What remains for this loop is every NON-primary role: the authority knows only
|
|
305
|
+
about ``@role: primary``, so two disagreeing REPLICAs still land here.
|
|
306
|
+
|
|
307
|
+
(Two sources reach one role key only when both are OWN children or both carry an
|
|
308
|
+
explicit structural ``name``: effective-children shadowing matches on
|
|
309
|
+
``(type, name)``, so two UNNAMED sources across an ``extends`` boundary collapse
|
|
310
|
+
into one before this ever runs.)
|
|
307
311
|
"""
|
|
308
312
|
out: dict[str, MetaSource] = {}
|
|
309
313
|
for child in entity.children():
|
|
@@ -329,9 +333,9 @@ def _sources_by_role(entity: MetaObject) -> dict[str, MetaSource]:
|
|
|
329
333
|
)
|
|
330
334
|
raise ValueError(
|
|
331
335
|
f'{entity.name} declares more than one source.rdb with @role: "{role}", '
|
|
332
|
-
f
|
|
333
|
-
f'"{child.physical_name()}" ({detail}).
|
|
334
|
-
f"by role, so the second has nowhere to go."
|
|
336
|
+
f"and they disagree on the object's physical address — "
|
|
337
|
+
f'"{existing.physical_name()}" vs "{child.physical_name()}" ({detail}). '
|
|
338
|
+
f"The names module keys sources by role, so the second has nowhere to go."
|
|
335
339
|
)
|
|
336
340
|
return out
|
|
337
341
|
|
{metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/router_generator.py
RENAMED
|
@@ -201,6 +201,27 @@ def _py_set_literal(names: list[str], *, frozen: bool = False) -> str:
|
|
|
201
201
|
return f"frozenset({body})" if frozen else body
|
|
202
202
|
|
|
203
203
|
|
|
204
|
+
def _py_sort_default_order_literal(fields: list[MetaField]) -> str:
|
|
205
|
+
"""A ``dict[str, str]`` literal of each field's DECLARED ``@sortableDefaultOrder``.
|
|
206
|
+
|
|
207
|
+
Declared orders only — a field with no ``@sortableDefaultOrder`` is absent and the
|
|
208
|
+
generated ``_parse_sort`` supplies ``"asc"``. That split matches the other four
|
|
209
|
+
ports: one place per port spells the fallback, so no port can drift by baking a
|
|
210
|
+
different default into its map.
|
|
211
|
+
|
|
212
|
+
ADR-0039: ``attrs()`` is the RESOLVING accessor in Python (``attr()`` is own-only),
|
|
213
|
+
so an ``@sortableDefaultOrder`` inherited via ``extends`` is honoured.
|
|
214
|
+
"""
|
|
215
|
+
rows = []
|
|
216
|
+
for f in fields:
|
|
217
|
+
v = f.attrs().get(fc.FIELD_ATTR_SORTABLE_DEFAULT_ORDER)
|
|
218
|
+
if v in ("asc", "desc"):
|
|
219
|
+
rows.append(f' "{f.name}": "{v}",\n')
|
|
220
|
+
if not rows:
|
|
221
|
+
return "{}"
|
|
222
|
+
return "{\n" + "".join(rows) + "}"
|
|
223
|
+
|
|
224
|
+
|
|
204
225
|
def _pk_py_type(entity: MetaObject) -> PyType:
|
|
205
226
|
"""The Python type of the entity's primary-key path/id parameter, derived
|
|
206
227
|
from the PK field's declared subtype via ``type_map.py_type_for`` — the same
|
|
@@ -542,14 +563,17 @@ class RouterGenerator:
|
|
|
542
563
|
|
|
543
564
|
# Sort allowlist = base scalar fields ∪ every subtype's own scalar fields, so a
|
|
544
565
|
# per-subtype list can sort on a subtype-only column too. Stable order.
|
|
545
|
-
|
|
566
|
+
sort_field_nodes = list(_scalar_fields(entity))
|
|
567
|
+
sort_fields: list[str] = [f.name for f in sort_field_nodes]
|
|
546
568
|
seen = set(sort_fields)
|
|
547
569
|
for st in plan.subtypes:
|
|
548
570
|
for f in _scalar_fields(st.entity):
|
|
549
571
|
if f.name not in seen:
|
|
550
572
|
seen.add(f.name)
|
|
551
573
|
sort_fields.append(f.name)
|
|
574
|
+
sort_field_nodes.append(f)
|
|
552
575
|
sort_set_body = _py_set_literal(sort_fields)
|
|
576
|
+
sort_default_order_body = _py_sort_default_order_literal(sort_field_nodes)
|
|
553
577
|
# FR-035 PATCH-2: @required fields across the base AND every subtype — an
|
|
554
578
|
# explicit null on any of these is a 400 (the per-subtype update handlers
|
|
555
579
|
# guard against it before the repo call). Union, stable order.
|
|
@@ -632,6 +656,9 @@ class RouterGenerator:
|
|
|
632
656
|
parts.append(f"_SORT_ALLOWLIST: set[str] = {sort_set_body}")
|
|
633
657
|
parts.append("")
|
|
634
658
|
parts.append("")
|
|
659
|
+
parts.append(f"_SORT_DEFAULT_ORDER: dict[str, str] = {sort_default_order_body}")
|
|
660
|
+
parts.append("")
|
|
661
|
+
parts.append("")
|
|
635
662
|
parts.append(f"_REQUIRED_FIELDS: frozenset[str] = {required_set_body}")
|
|
636
663
|
parts.append("")
|
|
637
664
|
parts.append("")
|
|
@@ -646,7 +673,12 @@ class RouterGenerator:
|
|
|
646
673
|
parts.append(' parts = raw.split(":", 1)')
|
|
647
674
|
parts.append(" if not parts or parts[0] not in _SORT_ALLOWLIST:")
|
|
648
675
|
parts.append(" return None")
|
|
649
|
-
|
|
676
|
+
# `?sort=field` with no `:order` takes the field's DECLARED @sortableDefaultOrder.
|
|
677
|
+
# The "asc" fallback stays at the READ, one place per port.
|
|
678
|
+
parts.append(' direction = (')
|
|
679
|
+
parts.append(' parts[1].lower() if len(parts) == 2')
|
|
680
|
+
parts.append(' else _SORT_DEFAULT_ORDER.get(parts[0], "asc")')
|
|
681
|
+
parts.append(' )')
|
|
650
682
|
parts.append(' if direction not in ("asc", "desc"):')
|
|
651
683
|
parts.append(" return None")
|
|
652
684
|
parts.append(" return _SortClause(field=parts[0], direction=direction)")
|
|
@@ -847,13 +879,15 @@ class RouterGenerator:
|
|
|
847
879
|
pk = _pk_py_type(entity)
|
|
848
880
|
pk_type = pk.expr
|
|
849
881
|
repo_class = f"{short_name}Repository"
|
|
850
|
-
|
|
882
|
+
sort_field_nodes = list(_scalar_fields(entity))
|
|
883
|
+
sort_fields = [f.name for f in sort_field_nodes]
|
|
851
884
|
upper = short_name.upper()
|
|
852
885
|
fields_const = f"{upper}_FILTER_FIELDS"
|
|
853
886
|
ops_const = f"{upper}_FILTER_OPS_BY_FIELD"
|
|
854
887
|
allowlist_module = f"{snake}_filter_allowlist"
|
|
855
888
|
|
|
856
889
|
sort_set_body = _py_set_literal(sort_fields)
|
|
890
|
+
sort_default_order_body = _py_sort_default_order_literal(sort_field_nodes)
|
|
857
891
|
# FR-035 PATCH-2: an explicit null on a @required field (scalar or jsonb)
|
|
858
892
|
# is a 400 — the update handler guards these before the repo call.
|
|
859
893
|
required_set_body = _py_set_literal(_required_field_names(entity), frozen=True)
|
|
@@ -928,6 +962,9 @@ class RouterGenerator:
|
|
|
928
962
|
parts.append(f"_SORT_ALLOWLIST: set[str] = {sort_set_body}")
|
|
929
963
|
parts.append("")
|
|
930
964
|
parts.append("")
|
|
965
|
+
parts.append(f"_SORT_DEFAULT_ORDER: dict[str, str] = {sort_default_order_body}")
|
|
966
|
+
parts.append("")
|
|
967
|
+
parts.append("")
|
|
931
968
|
parts.append(f"_REQUIRED_FIELDS: frozenset[str] = {required_set_body}")
|
|
932
969
|
parts.append("")
|
|
933
970
|
parts.append("")
|
|
@@ -942,7 +979,12 @@ class RouterGenerator:
|
|
|
942
979
|
parts.append(' parts = raw.split(":", 1)')
|
|
943
980
|
parts.append(" if not parts or parts[0] not in _SORT_ALLOWLIST:")
|
|
944
981
|
parts.append(" return None")
|
|
945
|
-
|
|
982
|
+
# `?sort=field` with no `:order` takes the field's DECLARED @sortableDefaultOrder.
|
|
983
|
+
# The "asc" fallback stays at the READ, one place per port.
|
|
984
|
+
parts.append(' direction = (')
|
|
985
|
+
parts.append(' parts[1].lower() if len(parts) == 2')
|
|
986
|
+
parts.append(' else _SORT_DEFAULT_ORDER.get(parts[0], "asc")')
|
|
987
|
+
parts.append(' )')
|
|
946
988
|
parts.append(' if direction not in ("asc", "desc"):')
|
|
947
989
|
parts.append(" return None")
|
|
948
990
|
parts.append(" return _SortClause(field=parts[0], direction=direction)")
|
|
@@ -255,7 +255,7 @@ def _sorted_children(definition: TypeDefinition) -> list[dict[str, object]]:
|
|
|
255
255
|
return children
|
|
256
256
|
|
|
257
257
|
|
|
258
|
-
METAMODEL_VERSION = "0
|
|
258
|
+
METAMODEL_VERSION = "1.0"
|
|
259
259
|
"""Rolled-up spec-version for the cross-port registry manifest.
|
|
260
260
|
|
|
261
261
|
``"0"`` = pre-1.0 / unstable (semver major-0). Flips to ``"1.0"`` at the
|
|
@@ -45,6 +45,24 @@ from metaobjects.meta.persistence.source.meta_source import MetaSource
|
|
|
45
45
|
from metaobjects.meta.persistence.source.source_constants import SOURCE_ROLE_PRIMARY
|
|
46
46
|
|
|
47
47
|
|
|
48
|
+
def source_address_key(source: MetaSource) -> str:
|
|
49
|
+
"""The RESOLVED address of *source* — the same three parts the names artifact
|
|
50
|
+
compares, so the shared authority and the generated artifact cannot answer
|
|
51
|
+
"is this one object?" differently. Rendered rather than structural because
|
|
52
|
+
every port must produce a byte-identical message from it.
|
|
53
|
+
|
|
54
|
+
RAW, deliberately: an absent ``@schema`` is NOT folded into a dialect default.
|
|
55
|
+
On Postgres absent and ``"public"`` address the same relation, but on
|
|
56
|
+
SQLite/D1 they do not — the expected-schema builder rejects ANY declared
|
|
57
|
+
schema, ``"public"`` included, while an absent one is fine. Deciding what
|
|
58
|
+
"absent" means belongs to the caller's dialect, not to this layer, so
|
|
59
|
+
normalizing here would import one dialect's rule into a dialect-free tier.
|
|
60
|
+
"""
|
|
61
|
+
schema = source.schema()
|
|
62
|
+
qualifier = f'"{schema}".' if schema else ""
|
|
63
|
+
return f'{qualifier}"{source.physical_name()}" ({source.effective_kind()})'
|
|
64
|
+
|
|
65
|
+
|
|
48
66
|
def primary_rdb_source(entity: MetaObject) -> MetaSource | None:
|
|
49
67
|
"""THE primary ``source.rdb`` for *entity*, or ``None``.
|
|
50
68
|
|
|
@@ -61,7 +79,8 @@ def primary_rdb_source(entity: MetaObject) -> MetaSource | None:
|
|
|
61
79
|
|
|
62
80
|
Raises :class:`ValueError` — mirroring the other four ports' wording exactly —
|
|
63
81
|
when the resolving children carry MORE THAN ONE ``@role: primary`` source and
|
|
64
|
-
they do not agree on a physical
|
|
82
|
+
they do not agree on a physical ADDRESS (kind, schema, physical name; see
|
|
83
|
+
:func:`source_address_key`). Direction-blind: it compares every
|
|
65
84
|
primary against every other, so it does not matter which of them is writable,
|
|
66
85
|
nor which was declared first. See the module docstring for why that matters.
|
|
67
86
|
No downstream consumer re-checks this; the refusal lives here, once, so every
|
|
@@ -75,13 +94,14 @@ def primary_rdb_source(entity: MetaObject) -> MetaSource | None:
|
|
|
75
94
|
if not primaries:
|
|
76
95
|
return None
|
|
77
96
|
|
|
78
|
-
|
|
79
|
-
if len(
|
|
80
|
-
joined = "
|
|
97
|
+
addresses = sorted({source_address_key(s) for s in primaries})
|
|
98
|
+
if len(addresses) > 1:
|
|
99
|
+
joined = " vs ".join(addresses)
|
|
81
100
|
raise ValueError(
|
|
82
101
|
f"{entity.name}: role=primary sources disagree on the object's physical "
|
|
83
|
-
f"
|
|
84
|
-
f"physical
|
|
102
|
+
f"address — {joined}. Every consumer binds ONE address. Give them a "
|
|
103
|
+
f"matching @kind, @schema and physical name, or drop the extra "
|
|
104
|
+
f"role=primary declaration."
|
|
85
105
|
)
|
|
86
106
|
return primaries[0]
|
|
87
107
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"children": [
|
|
8
8
|
{ "type": "attr", "subType": "boolean", "name": "filterable", "min": 0, "max": 1, "description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)." },
|
|
9
9
|
{ "type": "attr", "subType": "boolean", "name": "sortable", "min": 0, "max": 1, "description": "When true, the field is exposed in generated CRUD sort allowlists. Inherits from @filterable by default; set false to opt out." },
|
|
10
|
-
{ "type": "attr", "subType": "string", "name": "sortableDefaultOrder", "min": 0, "max": 1, "allowedValues": ["asc", "desc"], "description": "
|
|
10
|
+
{ "type": "attr", "subType": "string", "name": "sortableDefaultOrder", "min": 0, "max": 1, "allowedValues": ["asc", "desc"], "description": "Direction a sort takes when it names this field but omits the order: a ?sort=<field> with no :order, and a layout.dataGrid whose @defaultSortField names it with no @defaultSortOrder. Defaults to 'asc'." },
|
|
11
11
|
{ "type": "attr", "subType": "boolean", "name": "formExclude", "min": 0, "max": 1, "description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)." }
|
|
12
12
|
]
|
|
13
13
|
},
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"children": [
|
|
25
25
|
{ "type": "attr", "subType": "int", "name": "pageSize", "min": 0, "max": 1, "description": "Number of rows per page in the generated data grid." },
|
|
26
26
|
{ "type": "attr", "subType": "string", "name": "defaultSortField", "min": 0, "max": 1, "description": "Field name the grid is sorted by on initial render. Must reference an actual field on the entity." },
|
|
27
|
-
{ "type": "attr", "subType": "string", "name": "defaultSortOrder", "min": 0, "max": 1, "allowedValues": ["asc", "desc"], "description": "Initial sort direction for the default sort field: 'asc' or 'desc'." },
|
|
27
|
+
{ "type": "attr", "subType": "string", "name": "defaultSortOrder", "min": 0, "max": 1, "allowedValues": ["asc", "desc"], "description": "Initial sort direction for the default sort field: 'asc' or 'desc'. When omitted, the named field's @sortableDefaultOrder applies." },
|
|
28
28
|
{ "type": "attr", "subType": "boolean", "name": "filterable", "min": 0, "max": 1, "description": "When true, the generated grid exposes column filtering UI." },
|
|
29
29
|
{ "type": "attr", "subType": "filter", "name": "filter", "min": 0, "max": 1, "description": "Structured preset filter object applied to the grid at the metadata level. Desugared to canonical { field: { op: value } } form at parse time." },
|
|
30
30
|
{ "type": "attr", "subType": "string", "name": "columns", "isArray": true, "min": 0, "max": 1, "description": "Flat ordered list of field names to display as grid columns." }
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from metaobjects.codegen.format import ruff_format
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_ruff_format_canonicalizes() -> None:
|
|
5
|
+
messy = "x={'a':1,'b':2}\n"
|
|
6
|
+
out = ruff_format(messy)
|
|
7
|
+
assert out == 'x = {"a": 1, "b": 2}\n'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_ruff_format_is_idempotent() -> None:
|
|
11
|
+
src = "y = [1, 2, 3]\n"
|
|
12
|
+
assert ruff_format(ruff_format(src)) == ruff_format(src)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_ruff_format_sorts_imports() -> None:
|
|
16
|
+
# stdlib before third-party before first-party-relative (PEP 8 / isort groups).
|
|
17
|
+
src = "from .local import L\nimport os\n\nfrom pydantic import BaseModel\n"
|
|
18
|
+
out = ruff_format(src)
|
|
19
|
+
assert out.index("import os") < out.index("from pydantic") < out.index("from .local import L")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_ruff_format_no_op_when_ruff_absent(monkeypatch) -> None:
|
|
23
|
+
"""ruff is a codegen-time convenience, not a runtime requirement — when it's not
|
|
24
|
+
installed, ruff_format returns the source unformatted (still valid Python) rather
|
|
25
|
+
than crashing the whole gen run."""
|
|
26
|
+
import metaobjects.codegen.format as fmt
|
|
27
|
+
|
|
28
|
+
monkeypatch.setattr(fmt, "_RUFF_AVAILABLE", False)
|
|
29
|
+
messy = "x={'a':1}\n"
|
|
30
|
+
assert fmt.ruff_format(messy) == messy
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_killed_ruff_says_it_was_killed_and_names_the_signal(monkeypatch) -> None:
|
|
34
|
+
"""A ruff process killed by a signal must not be reported as a source error.
|
|
35
|
+
|
|
36
|
+
`_run_ruff` treats a non-zero exit as "ruff rejected the source", which is the
|
|
37
|
+
generator bug `ruff_format`'s docstring describes. But a process killed by a
|
|
38
|
+
signal returns a NEGATIVE code and writes no stderr, so that path produced
|
|
39
|
+
`ruff format failed:` — a message naming neither the cause nor the fact that
|
|
40
|
+
ruff never ran. Observed on a CI box running five lanes at once.
|
|
41
|
+
"""
|
|
42
|
+
import subprocess
|
|
43
|
+
|
|
44
|
+
import metaobjects.codegen.format as fmt
|
|
45
|
+
|
|
46
|
+
def killed(*_a, **_k):
|
|
47
|
+
return subprocess.CompletedProcess(args=[], returncode=-9, stdout="", stderr="")
|
|
48
|
+
|
|
49
|
+
monkeypatch.setattr(fmt.subprocess, "run", killed)
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
fmt.ruff_format("x = 1\n")
|
|
53
|
+
except RuntimeError as e:
|
|
54
|
+
msg = str(e)
|
|
55
|
+
else:
|
|
56
|
+
raise AssertionError("expected RuntimeError")
|
|
57
|
+
|
|
58
|
+
# It must say the process was killed, and by which signal, so the reader is not
|
|
59
|
+
# left hunting a syntax error in emitted code that ruff never looked at.
|
|
60
|
+
assert "killed" in msg
|
|
61
|
+
assert "9" in msg
|
|
62
|
+
assert msg.rstrip().endswith(")") or "signal" in msg
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_nonzero_ruff_with_no_stderr_still_names_the_exit_code(monkeypatch) -> None:
|
|
66
|
+
"""The other half: a genuine non-zero exit that happens to print nothing must
|
|
67
|
+
still carry its exit code, rather than trailing off after the colon."""
|
|
68
|
+
import subprocess
|
|
69
|
+
|
|
70
|
+
import metaobjects.codegen.format as fmt
|
|
71
|
+
|
|
72
|
+
def quiet_failure(*_a, **_k):
|
|
73
|
+
return subprocess.CompletedProcess(args=[], returncode=2, stdout="", stderr="")
|
|
74
|
+
|
|
75
|
+
monkeypatch.setattr(fmt.subprocess, "run", quiet_failure)
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
fmt.ruff_format("x = 1\n")
|
|
79
|
+
except RuntimeError as e:
|
|
80
|
+
msg = str(e)
|
|
81
|
+
else:
|
|
82
|
+
raise AssertionError("expected RuntimeError")
|
|
83
|
+
|
|
84
|
+
assert "2" in msg
|
|
85
|
+
assert not msg.rstrip().endswith(":")
|
|
@@ -389,18 +389,22 @@ def test_two_sources_in_one_role_that_AGREE_are_legal() -> None:
|
|
|
389
389
|
assert src.count("ROLECHILD_SOURCE_PRIMARY_TABLE: Final") == 1
|
|
390
390
|
|
|
391
391
|
|
|
392
|
-
def
|
|
392
|
+
def test_a_schema_disagreement_in_the_primary_role_is_refused_by_the_AUTHORITY() -> None:
|
|
393
393
|
"""...and the disagreement is the real problem, because keeping one silently is the
|
|
394
394
|
failure this artifact makes impossible: the second name would be carried nowhere,
|
|
395
395
|
read by nobody, while the binding quietly took the first's.
|
|
396
396
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
397
|
+
This test used to assert the message came from THIS module, and documented why:
|
|
398
|
+
``primary_rdb_source`` compared physical NAMES only, so two primaries agreeing on
|
|
399
|
+
the name and differing on which SCHEMA it lives in got past it and landed on one
|
|
400
|
+
role key here. That gap is closed — the authority now compares the whole ADDRESS
|
|
401
|
+
(kind, schema, physical name), so it refuses one level down and this module never
|
|
402
|
+
sees the shape.
|
|
403
|
+
|
|
404
|
+
Why it was closed rather than left: the weaker key did not merely accept the model,
|
|
405
|
+
it made the accepted answer PORT-DEPENDENT. ``primaries[0]`` is the inherited source
|
|
406
|
+
in Python/TS/C# (``children()`` puts the super's entries first) and the own source
|
|
407
|
+
on the JVM, so this exact model bound one schema in three ports and the other in two.
|
|
404
408
|
"""
|
|
405
409
|
model = _role_model(
|
|
406
410
|
{"source.rdb": {"name": "child_src", "@table": "zz_shared", "@schema": "zz_other"}}
|
|
@@ -408,8 +412,36 @@ def test_two_sources_in_one_role_that_DISAGREE_are_refused_naming_both() -> None
|
|
|
408
412
|
with pytest.raises(ValueError) as exc:
|
|
409
413
|
_render(model, "RoleChild")
|
|
410
414
|
message = str(exc.value)
|
|
411
|
-
assert '
|
|
412
|
-
|
|
415
|
+
assert "disagree on the object's physical address" in message
|
|
416
|
+
# The ADDRESS, not the bare name: the names agree here, so a message naming only
|
|
417
|
+
# "zz_shared" would describe two identical things as different.
|
|
418
|
+
assert '"zz_other"."zz_shared"' in message
|
|
419
|
+
assert '"zz_shared" (table)' in message
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def test_two_REPLICAS_that_disagree_are_still_refused_by_this_module() -> None:
|
|
423
|
+
"""The per-role check here is not redundant with the authority: the authority only
|
|
424
|
+
knows about ``@role: primary``. Two sources sharing any OTHER role key still land
|
|
425
|
+
here, and the second still has nowhere to go in a map keyed by role.
|
|
426
|
+
|
|
427
|
+
Without this case, closing the primary-role gap would leave the whole per-role loop
|
|
428
|
+
unexercised — a check nothing reaches is a check that can rot.
|
|
429
|
+
"""
|
|
430
|
+
# The child keeps a primary that AGREES with the base's — `validate_source_roles` is
|
|
431
|
+
# own-only, so a child declaring replicas alone fails the load with
|
|
432
|
+
# ERR_SOURCE_NO_PRIMARY before this module is ever reached.
|
|
433
|
+
model = _role_model({"source.rdb": {"name": "child_src", "@table": "zz_shared"}})
|
|
434
|
+
model["metadata.root"]["children"][1]["object.entity"]["children"].extend(
|
|
435
|
+
[
|
|
436
|
+
{"source.rdb": {"name": "r1", "@table": "zz_replica", "@role": "replica"}},
|
|
437
|
+
{"source.rdb": {"name": "r2", "@table": "zz_elsewhere", "@role": "replica"}},
|
|
438
|
+
]
|
|
439
|
+
)
|
|
440
|
+
with pytest.raises(ValueError) as exc:
|
|
441
|
+
_render(model, "RoleChild")
|
|
442
|
+
message = str(exc.value)
|
|
443
|
+
assert '@role: "replica"' in message
|
|
444
|
+
assert "disagree on the object's physical address" in message
|
|
413
445
|
|
|
414
446
|
|
|
415
447
|
TPH_MODEL = {
|
|
@@ -40,6 +40,14 @@ from .postgres_container import PostgresInfo
|
|
|
40
40
|
# fields outside it elicit the cross-port 400 invalid_sort envelope.
|
|
41
41
|
_SORT_ALLOWLIST: frozenset[str] = frozenset({"id", "name", "createdAt"})
|
|
42
42
|
|
|
43
|
+
# Cross-port contract: each field's DECLARED @sortableDefaultOrder — the direction a
|
|
44
|
+
# `?sort=<field>` carrying no `:dir` takes. Hardcoded from meta.json for the same reason
|
|
45
|
+
# the allowlist above is: this is the hand-rolled fixed point the generated routers are
|
|
46
|
+
# measured against, so it must not reach the generator's code to agree with it. A field
|
|
47
|
+
# absent here declares nothing and takes the "asc" fallback at the read — one place per
|
|
48
|
+
# port spells the default.
|
|
49
|
+
_SORT_DEFAULT_ORDER: dict[str, str] = {"createdAt": "desc"}
|
|
50
|
+
|
|
43
51
|
# Per-entity FR-009 filter allowlist for Author. Mirror of what
|
|
44
52
|
# `filter_allowlist_generator` would emit for the Author entity (the
|
|
45
53
|
# integration test is hand-wired so we duplicate the constants here; the
|
|
@@ -446,7 +454,13 @@ def make_app(repo: AuthorRepository) -> FastAPI:
|
|
|
446
454
|
field = parts[0]
|
|
447
455
|
if field not in _SORT_ALLOWLIST:
|
|
448
456
|
return JSONResponse(status_code=400, content={"error": "invalid_sort"})
|
|
449
|
-
|
|
457
|
+
# No `:dir` supplied -> the named field's declared @sortableDefaultOrder, and
|
|
458
|
+
# "asc" when it declares none. The explicit branch is untouched, so a
|
|
459
|
+
# caller-supplied order always beats the declaration.
|
|
460
|
+
direction = (
|
|
461
|
+
parts[1].lower() if len(parts) == 2
|
|
462
|
+
else _SORT_DEFAULT_ORDER.get(field, "asc")
|
|
463
|
+
)
|
|
450
464
|
if direction not in ("asc", "desc"):
|
|
451
465
|
return JSONResponse(status_code=400, content={"error": "invalid_sort"})
|
|
452
466
|
sort_field, sort_dir = field, direction.upper()
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
"""Canonicalize emitted source via ruff: sort imports (isort), then format.
|
|
2
|
-
|
|
3
|
-
Both passes read stdin / write stdout, so generated code is import-sorted AND
|
|
4
|
-
formatted — i.e. `ruff check`- and `ruff format`-clean for downstream consumers."""
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
import importlib.util
|
|
8
|
-
import subprocess
|
|
9
|
-
import sys
|
|
10
|
-
|
|
11
|
-
_STDIN_NAME = "generated.py"
|
|
12
|
-
|
|
13
|
-
#: ruff is a codegen-time convenience (import-sort + format), not a runtime requirement
|
|
14
|
-
#: of the emitted code. When it's absent we emit valid-but-unformatted Python rather
|
|
15
|
-
#: than hard-failing the whole ``gen``.
|
|
16
|
-
_RUFF_AVAILABLE = importlib.util.find_spec("ruff") is not None
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def _run_ruff(args: list[str], source: str) -> str:
|
|
20
|
-
proc = subprocess.run(
|
|
21
|
-
[sys.executable, "-m", "ruff", *args],
|
|
22
|
-
input=source,
|
|
23
|
-
capture_output=True,
|
|
24
|
-
text=True,
|
|
25
|
-
)
|
|
26
|
-
if proc.returncode != 0:
|
|
27
|
-
raise RuntimeError(f"ruff {args[0]} failed: {proc.stderr.strip()}")
|
|
28
|
-
return proc.stdout
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def ruff_format(source: str) -> str:
|
|
32
|
-
"""Sort imports then format *source*; return the canonical text.
|
|
33
|
-
|
|
34
|
-
A no-op (returns *source* unchanged) when ruff is not installed — the emitted
|
|
35
|
-
code is still valid Python, just unformatted. Still raises RuntimeError if ruff
|
|
36
|
-
IS present but fails (e.g. a syntax error in emitted code — that's a generator bug)."""
|
|
37
|
-
if not _RUFF_AVAILABLE:
|
|
38
|
-
return source
|
|
39
|
-
sorted_src = _run_ruff(
|
|
40
|
-
["check", "--select", "I", "--fix", "--stdin-filename", _STDIN_NAME, "-"], source
|
|
41
|
-
)
|
|
42
|
-
return _run_ruff(["format", "-"], sorted_src)
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
from metaobjects.codegen.format import ruff_format
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def test_ruff_format_canonicalizes() -> None:
|
|
5
|
-
messy = "x={'a':1,'b':2}\n"
|
|
6
|
-
out = ruff_format(messy)
|
|
7
|
-
assert out == 'x = {"a": 1, "b": 2}\n'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def test_ruff_format_is_idempotent() -> None:
|
|
11
|
-
src = "y = [1, 2, 3]\n"
|
|
12
|
-
assert ruff_format(ruff_format(src)) == ruff_format(src)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def test_ruff_format_sorts_imports() -> None:
|
|
16
|
-
# stdlib before third-party before first-party-relative (PEP 8 / isort groups).
|
|
17
|
-
src = "from .local import L\nimport os\n\nfrom pydantic import BaseModel\n"
|
|
18
|
-
out = ruff_format(src)
|
|
19
|
-
assert out.index("import os") < out.index("from pydantic") < out.index("from .local import L")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def test_ruff_format_no_op_when_ruff_absent(monkeypatch) -> None:
|
|
23
|
-
"""ruff is a codegen-time convenience, not a runtime requirement — when it's not
|
|
24
|
-
installed, ruff_format returns the source unformatted (still valid Python) rather
|
|
25
|
-
than crashing the whole gen run."""
|
|
26
|
-
import metaobjects.codegen.format as fmt
|
|
27
|
-
|
|
28
|
-
monkeypatch.setattr(fmt, "_RUFF_AVAILABLE", False)
|
|
29
|
-
messy = "x={'a':1}\n"
|
|
30
|
-
assert fmt.ruff_format(messy) == messy
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|