metaobjects 1.0.11__tar.gz → 1.0.13__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.
Files changed (485) hide show
  1. {metaobjects-1.0.11 → metaobjects-1.0.13}/PKG-INFO +1 -1
  2. {metaobjects-1.0.11 → metaobjects-1.0.13}/pyproject.toml +1 -1
  3. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/apidocs/naming.py +56 -7
  4. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/cli.py +151 -0
  5. metaobjects-1.0.13/src/metaobjects/codegen/collection_name_collision.py +58 -0
  6. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/runner.py +5 -0
  7. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/errors.py +6 -0
  8. metaobjects-1.0.13/src/metaobjects/fmt.py +214 -0
  9. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/persistence/source/meta_source.py +13 -2
  10. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/extract/__init__.py +2 -0
  11. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/extract/extract.py +34 -2
  12. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/extract/types.py +28 -1
  13. metaobjects-1.0.13/tests/codegen/test_cli_fmt.py +137 -0
  14. metaobjects-1.0.13/tests/codegen/test_collection_name_collision.py +109 -0
  15. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_extractor_generator.py +41 -0
  16. metaobjects-1.0.13/tests/codegen/test_fmt_format_file.py +45 -0
  17. metaobjects-1.0.13/tests/codegen/test_route_path_naming.py +149 -0
  18. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_runner.py +21 -0
  19. metaobjects-1.0.13/tests/conformance/test_fmt_conformance.py +54 -0
  20. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/extract/test_extract.py +100 -0
  21. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_fr016_source_name_and_kind_aliases.py +33 -0
  22. {metaobjects-1.0.11 → metaobjects-1.0.13}/uv.lock +1 -1
  23. metaobjects-1.0.11/tests/codegen/test_route_path_naming.py +0 -67
  24. {metaobjects-1.0.11 → metaobjects-1.0.13}/.gitignore +0 -0
  25. {metaobjects-1.0.11 → metaobjects-1.0.13}/LICENSE +0 -0
  26. {metaobjects-1.0.11 → metaobjects-1.0.13}/README.md +0 -0
  27. {metaobjects-1.0.11 → metaobjects-1.0.13}/hatch_build.py +0 -0
  28. {metaobjects-1.0.11 → metaobjects-1.0.13}/scripts/generate_embedded_library.py +0 -0
  29. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/__init__.py +0 -0
  30. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/agent_context/__init__.py +0 -0
  31. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/agent_context/scaffold.py +0 -0
  32. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/apidocs/__init__.py +0 -0
  33. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/apidocs/api_model.py +0 -0
  34. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/apidocs/builder.py +0 -0
  35. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/apidocs/paths.py +0 -0
  36. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/apidocs/renderer.py +0 -0
  37. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/attr_class_map.py +0 -0
  38. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
  39. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/__init__.py +0 -0
  40. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/collision_names.py +0 -0
  41. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/config.py +0 -0
  42. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/constants.py +0 -0
  43. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/eject.py +0 -0
  44. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
  45. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
  46. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/format.py +0 -0
  47. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
  48. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generator.py +0 -0
  49. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generator_registry.py +0 -0
  50. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/__init__.py +0 -0
  51. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/entity_model.py +0 -0
  52. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
  53. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
  54. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/find_inbound.py +0 -0
  55. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
  56. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
  57. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/names_generator.py +0 -0
  58. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
  59. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
  60. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
  61. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/router_generator.py +0 -0
  62. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/template_generator.py +0 -0
  63. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
  64. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
  65. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/instance_artifacts.py +0 -0
  66. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
  67. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/model_walk.py +0 -0
  68. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
  69. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/overwrite_policy.py +0 -0
  70. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/project_config.py +0 -0
  71. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/runtime/__init__.py +0 -0
  72. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/runtime/constraint_errors.py +0 -0
  73. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
  74. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
  75. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
  76. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
  77. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
  78. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/type_map.py +0 -0
  79. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/codegen/value_objects.py +0 -0
  80. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/config/__init__.py +0 -0
  81. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/config/dependencies.py +0 -0
  82. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/config/neutral_config.py +0 -0
  83. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/config/source_resolver.py +0 -0
  84. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/core_types.py +0 -0
  85. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/datatype.py +0 -0
  86. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/documentation/__init__.py +0 -0
  87. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/documentation/doc_constants.py +0 -0
  88. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/documentation/doc_provider.py +0 -0
  89. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/documentation/doc_schema.py +0 -0
  90. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/library/__init__.py +0 -0
  91. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/library/embedded_library.py +0 -0
  92. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/library/library_sources.py +0 -0
  93. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/__init__.py +0 -0
  94. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/merge.py +0 -0
  95. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/meta_data_loader.py +0 -0
  96. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/registered_validation.py +0 -0
  97. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/sources/__init__.py +0 -0
  98. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/sources/directory_source.py +0 -0
  99. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/sources/file_source.py +0 -0
  100. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
  101. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/sources/uri_source.py +0 -0
  102. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/validate_discriminator.py +0 -0
  103. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
  104. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/validate_field_mutability.py +0 -0
  105. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/validate_source_escapes.py +0 -0
  106. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
  107. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
  108. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/loader/validation_passes.py +0 -0
  109. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/__init__.py +0 -0
  110. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/__init__.py +0 -0
  111. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/attr/__init__.py +0 -0
  112. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
  113. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
  114. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/field/__init__.py +0 -0
  115. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/field/field_constants.py +0 -0
  116. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/field/meta_field.py +0 -0
  117. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/identity/__init__.py +0 -0
  118. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
  119. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
  120. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/index/__init__.py +0 -0
  121. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/index/index_constants.py +0 -0
  122. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/index/meta_index.py +0 -0
  123. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/object/__init__.py +0 -0
  124. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/object/meta_object.py +0 -0
  125. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
  126. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
  127. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/object/object_constants.py +0 -0
  128. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/object/object_extract.py +0 -0
  129. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/object/value_object.py +0 -0
  130. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
  131. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
  132. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
  133. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
  134. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/relationship/relationship_references.py +0 -0
  135. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
  136. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
  137. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
  138. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/validator/__init__.py +0 -0
  139. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
  140. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/meta_data.py +0 -0
  141. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/meta_root.py +0 -0
  142. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/persistence/__init__.py +0 -0
  143. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
  144. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
  145. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
  146. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
  147. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
  148. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
  149. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
  150. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
  151. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/presentation/__init__.py +0 -0
  152. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
  153. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
  154. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
  155. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
  156. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
  157. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
  158. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
  159. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
  160. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/provider_extends.py +0 -0
  161. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/template/__init__.py +0 -0
  162. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/template/meta_template.py +0 -0
  163. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/template/prompt_provider.py +0 -0
  164. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta/template/template_constants.py +0 -0
  165. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/meta_endpoint.py +0 -0
  166. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/naming.py +0 -0
  167. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/naming_refs.py +0 -0
  168. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/parser.py +0 -0
  169. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/parser_yaml.py +0 -0
  170. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/provider.py +0 -0
  171. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/py.typed +0 -0
  172. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/registry.py +0 -0
  173. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/registry_manifest.py +0 -0
  174. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/__init__.py +0 -0
  175. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/email_document.py +0 -0
  176. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/escapers.py +0 -0
  177. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
  178. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/extract/coerce.py +0 -0
  179. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/extract/extract_map.py +0 -0
  180. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
  181. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/extract/locate.py +0 -0
  182. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/extract/normalize.py +0 -0
  183. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/extract/strip.py +0 -0
  184. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
  185. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/filesystem_provider.py +0 -0
  186. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/payload_accessors.py +0 -0
  187. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/prompt/__init__.py +0 -0
  188. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
  189. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
  190. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/prompt/prompt_field.py +0 -0
  191. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
  192. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/prompt/prompt_style.py +0 -0
  193. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/renderer.py +0 -0
  194. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/render/verify.py +0 -0
  195. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/runtime/__init__.py +0 -0
  196. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/runtime/llm_recorder.py +0 -0
  197. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/runtime/n2m_resolver.py +0 -0
  198. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/runtime/object_manager.py +0 -0
  199. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/runtime/tph.py +0 -0
  200. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/scope.py +0 -0
  201. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/serializer_json.py +0 -0
  202. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/shared/__init__.py +0 -0
  203. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/shared/base_types.py +0 -0
  204. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/shared/separators.py +0 -0
  205. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/shared/structural.py +0 -0
  206. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/source/__init__.py +0 -0
  207. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/source/error_source.py +0 -0
  208. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/source/json_path.py +0 -0
  209. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/source/semantic_diff.py +0 -0
  210. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/source/yaml_positions.py +0 -0
  211. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/source_resolution.py +0 -0
  212. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/__init__.py +0 -0
  213. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/attr.json +0 -0
  214. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/db.json +0 -0
  215. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/documentation.json +0 -0
  216. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/field.json +0 -0
  217. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/identity.json +0 -0
  218. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/index.json +0 -0
  219. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/layout.json +0 -0
  220. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/object.json +0 -0
  221. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/origin.json +0 -0
  222. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/prompt.json +0 -0
  223. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/relationship.json +0 -0
  224. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/requirement.json +0 -0
  225. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/source.json +0 -0
  226. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/template.json +0 -0
  227. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
  228. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/ui.json +0 -0
  229. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/validator.json +0 -0
  230. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/spec_metamodel/view.json +0 -0
  231. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/super_resolve.py +0 -0
  232. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/validation_types.py +0 -0
  233. {metaobjects-1.0.11 → metaobjects-1.0.13}/src/metaobjects/yaml_desugar.py +0 -0
  234. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/__init__.py +0 -0
  235. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/__init__.py +0 -0
  236. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/gen_suite.py +0 -0
  237. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
  238. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/golden/extends/expected/Program.py +0 -0
  239. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/golden/extends/meta.json +0 -0
  240. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
  241. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
  242. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/golden/nested-array/meta.json +0 -0
  243. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
  244. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/golden/scalars/expected/Report.py +0 -0
  245. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/golden/scalars/meta.json +0 -0
  246. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
  247. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/golden/vanilla/meta.json +0 -0
  248. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_abstract_conformance.py +0 -0
  249. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_api_docs_builder.py +0 -0
  250. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_api_docs_paths.py +0 -0
  251. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_cli.py +0 -0
  252. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_cli_config_gen.py +0 -0
  253. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_cli_config_verify.py +0 -0
  254. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_cli_dependencies.py +0 -0
  255. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_cli_gen_unknown_attr.py +0 -0
  256. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_cli_providers.py +0 -0
  257. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_cli_registry.py +0 -0
  258. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_cli_render_helper_template_root.py +0 -0
  259. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_cli_staleness_nudge.py +0 -0
  260. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_cli_verify_strict.py +0 -0
  261. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_cli_verify_subverbs.py +0 -0
  262. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_codegen_compile_conformance.py +0 -0
  263. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_constants_config.py +0 -0
  264. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_eject.py +0 -0
  265. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_eject_runtime.py +0 -0
  266. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_entity_model.py +0 -0
  267. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_enum_conformance.py +0 -0
  268. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
  269. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_extract_tier_collision.py +0 -0
  270. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_filter_allowlist_generator.py +0 -0
  271. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_format.py +0 -0
  272. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
  273. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_fr010_output_codegen.py +0 -0
  274. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
  275. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_gen_state_keying.py +0 -0
  276. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_generator.py +0 -0
  277. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_generator_extension_seams.py +0 -0
  278. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_golden.py +0 -0
  279. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
  280. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_inheritance_conformance.py +0 -0
  281. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_instance_artifacts.py +0 -0
  282. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_m2m_codegen.py +0 -0
  283. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_names_extends_chain.py +0 -0
  284. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_names_generator.py +0 -0
  285. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_no_magic_physical_names.py +0 -0
  286. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_origin_nullability.py +0 -0
  287. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_output_parser_generator.py +0 -0
  288. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_overwrite_policy.py +0 -0
  289. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_overwrite_policy_hash.py +0 -0
  290. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_project_config.py +0 -0
  291. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_projection_compile.py +0 -0
  292. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_recipe_generators.py +0 -0
  293. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_render_helper_conformance.py +0 -0
  294. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_render_helper_generator.py +0 -0
  295. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_reverse_finders.py +0 -0
  296. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_router_autoset.py +0 -0
  297. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_router_generator.py +0 -0
  298. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_router_generator_m2m_target_tph.py +0 -0
  299. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_router_generator_tph_m2m.py +0 -0
  300. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_router_generator_tph_m2m_shadowed.py +0 -0
  301. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_source_resolution.py +0 -0
  302. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_sourceless_entity_surface.py +0 -0
  303. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_sourceless_projection.py +0 -0
  304. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_template_data.py +0 -0
  305. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_template_generator.py +0 -0
  306. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_template_output_pattern.py +0 -0
  307. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_template_scope_helpers.py +0 -0
  308. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_template_scope_walk.py +0 -0
  309. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_template_spec.py +0 -0
  310. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_tph_codegen.py +0 -0
  311. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_trace_helper_generator.py +0 -0
  312. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_type_map.py +0 -0
  313. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_validation_conformance.py +0 -0
  314. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_value_objects.py +0 -0
  315. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/codegen/test_write_through.py +0 -0
  316. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/config/__init__.py +0 -0
  317. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/config/test_dependencies.py +0 -0
  318. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/config/test_library_package_guard.py +0 -0
  319. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/config/test_neutral_config.py +0 -0
  320. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/config/test_source_resolver.py +0 -0
  321. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/__init__.py +0 -0
  322. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/capabilities.py +0 -0
  323. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/conformance-expected-failures.json +0 -0
  324. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/conformance_adapter.py +0 -0
  325. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/corpus.py +0 -0
  326. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/expected_failures.py +0 -0
  327. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/fixture_discovery.py +0 -0
  328. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/navigator.py +0 -0
  329. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
  330. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_conformance.py +0 -0
  331. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_dependency_conformance.py +0 -0
  332. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_extract_conformance.py +0 -0
  333. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_extract_object_array_bounds.py +0 -0
  334. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_extract_object_verdict.py +0 -0
  335. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_fr010_loader_attrs.py +0 -0
  336. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_fr011_attrs.py +0 -0
  337. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_generator_registry_conformance.py +0 -0
  338. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_object_model_conformance.py +0 -0
  339. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_provider_composition_conformance.py +0 -0
  340. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_registry_conformance.py +0 -0
  341. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_runner_hardfail.py +0 -0
  342. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_scope_conformance.py +0 -0
  343. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_source_resolution_conformance.py +0 -0
  344. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_spec_metamodel_embed.py +0 -0
  345. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_strict_attr_load.py +0 -0
  346. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_template_codegen_conformance.py +0 -0
  347. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_template_generator_conformance.py +0 -0
  348. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/test_yaml_conformance.py +0 -0
  349. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
  350. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/__init__.py +0 -0
  351. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/api_contract_assertions.py +0 -0
  352. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/api_contract_jsonb_server.py +0 -0
  353. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/api_contract_m2m_server.py +0 -0
  354. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/api_contract_server.py +0 -0
  355. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/generated_jsonb_app.py +0 -0
  356. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/generated_m2m_app.py +0 -0
  357. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/generated_projection_app.py +0 -0
  358. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/generated_router_app.py +0 -0
  359. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/generated_tph_app.py +0 -0
  360. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/meta_ai_trace.yaml +0 -0
  361. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/normalization.py +0 -0
  362. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/postgres_container.py +0 -0
  363. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/query_runner.py +0 -0
  364. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/scenarios.py +0 -0
  365. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_api_contract.py +0 -0
  366. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_api_contract_generated.py +0 -0
  367. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_api_contract_jsonb.py +0 -0
  368. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_api_contract_m2m.py +0 -0
  369. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_api_contract_m2m_generated.py +0 -0
  370. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_api_contract_projection.py +0 -0
  371. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_api_contract_tph_generated.py +0 -0
  372. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_generated_router_uuid_pk.py +0 -0
  373. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_llm_call_trace.py +0 -0
  374. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_m2m_target_tph_generated.py +0 -0
  375. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_normalization.py +0 -0
  376. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_query_scenarios.py +0 -0
  377. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_runtime_return_types.py +0 -0
  378. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_tph_m2m_generated.py +0 -0
  379. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/integration/test_tph_m2m_shadowed_generated.py +0 -0
  380. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/loader/__init__.py +0 -0
  381. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/loader/test_abstract_subtype_authored.py +0 -0
  382. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/loader/test_child_wrapper_body_shape.py +0 -0
  383. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/loader/test_enum_extends_values_conflict.py +0 -0
  384. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/loader/test_field_mutability_order.py +0 -0
  385. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/loader/test_shipped_library_ai.py +0 -0
  386. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/loader/test_template_payload_target_210.py +0 -0
  387. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/open_closed_proof_test.py +0 -0
  388. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/__init__.py +0 -0
  389. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/extract/__init__.py +0 -0
  390. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/extract/test_coerce.py +0 -0
  391. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/extract/test_extract_map.py +0 -0
  392. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/extract/test_json_forgiving_reader.py +0 -0
  393. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/extract/test_locate.py +0 -0
  394. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/extract/test_model.py +0 -0
  395. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/extract/test_normalize.py +0 -0
  396. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/extract/test_strip.py +0 -0
  397. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
  398. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/prompt/__init__.py +0 -0
  399. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/prompt/test_output_format_renderer.py +0 -0
  400. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/test_email_document.py +0 -0
  401. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/test_filesystem_provider.py +0 -0
  402. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/test_output_format_renderer_nested.py +0 -0
  403. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/test_output_prompt_conformance.py +0 -0
  404. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/test_render_conformance.py +0 -0
  405. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/test_render_max_chars.py +0 -0
  406. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/test_render_model_payload.py +0 -0
  407. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/test_verify.py +0 -0
  408. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/render/test_verify_conformance.py +0 -0
  409. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/runtime/test_constraint_errors.py +0 -0
  410. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/runtime/test_object_manager_currency_read.py +0 -0
  411. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/runtime/test_object_manager_enum_intvaluemap.py +0 -0
  412. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/runtime/test_object_manager_table_name.py +0 -0
  413. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/source/__init__.py +0 -0
  414. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/source/test_fr5c_merge_attribution.py +0 -0
  415. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/source/test_fr5d_reference_resolution.py +0 -0
  416. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/source/test_fr5e_database_source_shape.py +0 -0
  417. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/source/test_json_path.py +0 -0
  418. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/source/test_semantic_diff.py +0 -0
  419. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/source/test_source_on_node.py +0 -0
  420. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/source/test_yaml_positions.py +0 -0
  421. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/test_api_docs_accuracy.py +0 -0
  422. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/test_meta_endpoint.py +0 -0
  423. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/__init__.py +0 -0
  424. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_agent_context_staleness.py +0 -0
  425. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_capabilities.py +0 -0
  426. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_column_naming_strategy.py +0 -0
  427. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_common_attrs.py +0 -0
  428. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_core_types.py +0 -0
  429. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_derive_m2m_declaring_entity.py +0 -0
  430. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_effective_children_sibling_shadowing.py +0 -0
  431. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_effective_package.py +0 -0
  432. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_errors.py +0 -0
  433. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_field_enum.py +0 -0
  434. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_field_enum_intvaluemap.py +0 -0
  435. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_field_map_validation.py +0 -0
  436. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
  437. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_file_source_id.py +0 -0
  438. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_index_lookup.py +0 -0
  439. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_llm_recorder.py +0 -0
  440. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_loader.py +0 -0
  441. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_loader_bom.py +0 -0
  442. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_loader_class.py +0 -0
  443. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_merge.py +0 -0
  444. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_meta_attr.py +0 -0
  445. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_meta_data.py +0 -0
  446. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_meta_source.py +0 -0
  447. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_module_shortcuts.py +0 -0
  448. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_n2m_resolver.py +0 -0
  449. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_n2m_resolver_inherited.py +0 -0
  450. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_no_dead_config_fields.py +0 -0
  451. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
  452. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
  453. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_object_manager_write_through.py +0 -0
  454. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_one_primary_source.py +0 -0
  455. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_parser.py +0 -0
  456. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_parser_yaml.py +0 -0
  457. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_provider.py +0 -0
  458. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_provider_extension.py +0 -0
  459. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_registry.py +0 -0
  460. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_registry_completeness.py +0 -0
  461. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_registry_extend.py +0 -0
  462. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_registry_sealed.py +0 -0
  463. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_relationship_m2m_validation.py +0 -0
  464. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_relationship_references.py +0 -0
  465. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_relationship_referential_actions.py +0 -0
  466. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_resolution_key.py +0 -0
  467. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
  468. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_serializer.py +0 -0
  469. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_serializer_shared_document.py +0 -0
  470. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_shared_constants.py +0 -0
  471. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_smoke.py +0 -0
  472. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_source_escapes.py +0 -0
  473. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_sources.py +0 -0
  474. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_strict_child_placement.py +0 -0
  475. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_super_resolve.py +0 -0
  476. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_template_toolcall.py +0 -0
  477. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
  478. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_validation_attr_schema.py +0 -0
  479. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_validation_filter_values.py +0 -0
  480. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_validation_origin_195.py +0 -0
  481. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_validation_origin_paths.py +0 -0
  482. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_validation_sort_field.py +0 -0
  483. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_validation_warnings.py +0 -0
  484. {metaobjects-1.0.11 → metaobjects-1.0.13}/tests/unit/test_write_coercion_arrays.py +0 -0
  485. {metaobjects-1.0.11 → metaobjects-1.0.13}/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.11
3
+ Version: 1.0.13
4
4
  Summary: Cross-language metadata standard: declare typed entities once, generate idiomatic drift-checked code across languages — Python port.
5
5
  Project-URL: Homepage, https://metaobjects.dev
6
6
  Project-URL: Repository, https://github.com/metaobjectsdev/metaobjects
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "metaobjects"
3
- version = "1.0.11"
3
+ version = "1.0.13"
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"
@@ -74,6 +74,52 @@ def _route_snake_case(name: str) -> str:
74
74
  return to_snake_case(name)
75
75
 
76
76
 
77
+ _ALREADY_PLURAL_EXCLUDED_PRECEDING_CHARS = "suia"
78
+ """The four letters that precede a genuinely SINGULAR "...s" ending in the common
79
+ patterns this codebase's entity names hit — status, address, bonus, alias, gas,
80
+ analysis. Anything else before a final "s" reads as already-plural."""
81
+
82
+
83
+ def _is_already_plural(word: str) -> bool:
84
+ """True when ``word`` already reads as a plural noun, so running it through
85
+ the ordinary suffix rule would double it — the real defect this exists to
86
+ fix: ``program_purchase_stats`` -> ``program_purchase_statses`` shipped as a
87
+ REST collection path in an adopter's app.
88
+
89
+ Heuristic, not a dictionary: a word ending in ``s`` is already-plural UNLESS
90
+ the character immediately before that final ``s`` is one of s/u/i/a
91
+ (case-insensitive). Covers stats, settings, details, news, analytics,
92
+ series, photos; leaves status, address, bonus, alias, gas, analysis on the
93
+ ordinary suffix path (unchanged).
94
+
95
+ Known miss, deliberately not fixed here: a genuinely singular word ending in
96
+ "...s" with none of those four letters before it reads as already-plural too
97
+ — ``lens`` -> ``lens`` (correct plural ``lenses``). Fixing that needs a real
98
+ dictionary, which this is not; the heuristic optimizes for the shape the
99
+ doubling defect actually hits (entity names that are already a plural
100
+ concept)."""
101
+ if len(word) < 2:
102
+ return False
103
+ lowered = word.lower()
104
+ if lowered[-1] != "s":
105
+ return False
106
+ return lowered[-2] not in _ALREADY_PLURAL_EXCLUDED_PRECEDING_CHARS
107
+
108
+
109
+ def _pluralize_legacy_suffix_only(name: str) -> str:
110
+ """FROZEN — byte-for-byte the pre-fix suffix-only pluralization rule, with no
111
+ already-plural detection. Exposed only so :func:`pluralize` can fall back to
112
+ it. The DEFAULT PHYSICAL name fallback lives in a completely separate,
113
+ independently-frozen implementation (``meta_source._pluralize``) — this is
114
+ NOT that one, and the two must never be merged into a single call site."""
115
+ lowered = name.lower()
116
+ if lowered.endswith(("s", "x", "z", "ch", "sh")):
117
+ return name + "es"
118
+ if len(name) >= 2 and lowered[-1] == "y" and lowered[-2] not in "aeiou":
119
+ return name[:-1] + "ies"
120
+ return name + "s"
121
+
122
+
77
123
  def pluralize(name: str) -> str:
78
124
  """``post_category`` → ``post_categories``; ``address`` → ``addresses``.
79
125
 
@@ -82,13 +128,16 @@ def pluralize(name: str) -> str:
82
128
  ``y`` becomes ``ies``; anything else takes ``s``. The cross-port
83
129
  byte-identity covers the already-lowercased word :func:`route_path` feeds
84
130
  in — suffix tests here run on a lowercased copy, unlike the JVM port's
85
- case-sensitive ones, so mixed-case input may diverge."""
86
- lowered = name.lower()
87
- if lowered.endswith(("s", "x", "z", "ch", "sh")):
88
- return name + "es"
89
- if len(name) >= 2 and lowered[-1] == "y" and lowered[-2] not in "aeiou":
90
- return name[:-1] + "ies"
91
- return name + "s"
131
+ case-sensitive ones, so mixed-case input may diverge.
132
+
133
+ Adds already-plural detection (:func:`_is_already_plural`) on top of that
134
+ historical suffix rule (:func:`_pluralize_legacy_suffix_only`) — API/code-
135
+ surface pluralization only; the DEFAULT PHYSICAL table name fallback is
136
+ frozen separately (``meta_source._pluralize``), so an existing adopter
137
+ database never sees a proposed rename."""
138
+ if _is_already_plural(name):
139
+ return name
140
+ return _pluralize_legacy_suffix_only(name)
92
141
 
93
142
 
94
143
  def model_class_name(obj: MetaData) -> str:
@@ -1069,6 +1069,132 @@ def _cmd_list(_args: argparse.Namespace) -> int:
1069
1069
  return 0
1070
1070
 
1071
1071
 
1072
+ def _describe_fmt_report(report: "object", cwd: Path) -> str:
1073
+ from metaobjects import fmt
1074
+
1075
+ try:
1076
+ rel = report.path.relative_to(cwd)
1077
+ except ValueError:
1078
+ rel = report.path
1079
+ if report.status == fmt.STATUS_FORMATTED:
1080
+ return f" reformatted {rel}"
1081
+ if report.status == fmt.STATUS_WOULD_FORMAT:
1082
+ return f" not canonical {rel}"
1083
+ if report.status == fmt.STATUS_UNCHANGED:
1084
+ return f" ok {rel}"
1085
+ if report.status == fmt.STATUS_SKIPPED_YAML:
1086
+ return f" skipped (yaml) {rel} — {report.detail}"
1087
+ if report.status == fmt.STATUS_SKIPPED_OVERLAY:
1088
+ return (
1089
+ f" skipped (overlay) {rel} — this file declares an overlay fmt "
1090
+ "cannot resolve standalone"
1091
+ )
1092
+ if report.status == fmt.STATUS_ERROR:
1093
+ return f" error {rel} — {report.detail}"
1094
+ return f" {report.status} {rel}" # pragma: no cover — exhaustive in practice
1095
+
1096
+
1097
+ def _cmd_fmt(args: argparse.Namespace) -> int:
1098
+ """``fmt`` (#304) — rewrite metadata files into canonical form; ``--check``
1099
+ lists non-canonical files and exits non-zero without changing anything.
1100
+
1101
+ Mirrors the TS reference surface exactly: no ``metadata_dir`` positional —
1102
+ files come from the neutral ``.metaobjects/config.json`` ladder
1103
+ (:func:`resolve_metadata_location`, rungs 3-4; this command does not read
1104
+ this port's own ``metaobjects.config.yaml`` rung 2, matching the scope the
1105
+ C# and Java ports also keep for `fmt`), optionally narrowed by explicit
1106
+ file arguments.
1107
+ """
1108
+ from metaobjects import fmt
1109
+ from metaobjects.core_types import core_providers
1110
+ from metaobjects.library import library_sources
1111
+ from metaobjects.provider import compose_registry
1112
+
1113
+ providers_extra, providers_ok = _providers_from_args(args)
1114
+ if not providers_ok:
1115
+ return 1
1116
+ providers = [*core_providers, *providers_extra]
1117
+ registry = compose_registry(providers)
1118
+
1119
+ cwd = Path.cwd()
1120
+ collection = _resolve_metadata_location_or_print_error(None, cwd)
1121
+ if collection is None:
1122
+ return 1
1123
+
1124
+ all_files = list(collection.files)
1125
+ own_files = list(collection.own_files)
1126
+
1127
+ if args.files:
1128
+ wanted = [Path(f).resolve() for f in args.files]
1129
+ owned_set = {p.resolve() for p in own_files}
1130
+ missing = [str(p) for p in wanted if p not in owned_set]
1131
+ if missing:
1132
+ print(
1133
+ "error: not among this project's resolved metadata sources: "
1134
+ + ", ".join(missing),
1135
+ file=sys.stderr,
1136
+ )
1137
+ print(
1138
+ "metaobjects fmt only formats files the metadata-location ladder "
1139
+ "already resolves — pass no arguments to format every one of them.",
1140
+ file=sys.stderr,
1141
+ )
1142
+ return 1
1143
+ wanted_set = {p for p in wanted}
1144
+ targets = [p for p in own_files if p.resolve() in wanted_set]
1145
+ else:
1146
+ targets = own_files
1147
+
1148
+ lib_sources = library_sources(list(collection.libraries)) if collection.libraries else []
1149
+
1150
+ result = fmt.run(
1151
+ all_files=all_files,
1152
+ target_files=targets,
1153
+ file_ids=dict(collection.file_ids),
1154
+ registry=registry,
1155
+ lib_sources=lib_sources,
1156
+ check=bool(args.check),
1157
+ providers=providers,
1158
+ )
1159
+
1160
+ if result.fatal is not None:
1161
+ print(f"error: {result.fatal}", file=sys.stderr)
1162
+ return 1
1163
+
1164
+ if not result.files:
1165
+ print("metaobjects fmt — no metadata files to format.")
1166
+ return 0
1167
+
1168
+ for report in result.files:
1169
+ print(_describe_fmt_report(report, cwd))
1170
+
1171
+ errored = sum(1 for r in result.files if r.status == fmt.STATUS_ERROR)
1172
+ needs_format = sum(1 for r in result.files if r.status == fmt.STATUS_WOULD_FORMAT)
1173
+ reformatted = sum(1 for r in result.files if r.status == fmt.STATUS_FORMATTED)
1174
+
1175
+ if args.check:
1176
+ if needs_format or errored:
1177
+ suffix = f", {errored} error(s)" if errored else ""
1178
+ print(
1179
+ f"metaobjects fmt --check — {needs_format} file(s) not canonical{suffix}. "
1180
+ "Run `metaobjects fmt` to fix.",
1181
+ file=sys.stderr,
1182
+ )
1183
+ return 1
1184
+ print("metaobjects fmt --check — every file is already canonical.")
1185
+ return 0
1186
+
1187
+ if errored:
1188
+ print(
1189
+ f"metaobjects fmt — {errored} file(s) could not be formatted safely (left unchanged).",
1190
+ file=sys.stderr,
1191
+ )
1192
+ return 1
1193
+
1194
+ print(f"metaobjects fmt — {reformatted} file(s) reformatted.")
1195
+ return 0
1196
+
1197
+
1072
1198
  def _cmd_eject(args: argparse.Namespace) -> int:
1073
1199
  """Copy reference generators into ``codegen/generators/`` to own (ADR-0034 Am. 3)."""
1074
1200
  root = Path(args.root) if args.root else Path.cwd()
@@ -2493,6 +2619,31 @@ def _build_parser() -> argparse.ArgumentParser:
2493
2619
  )
2494
2620
  verify.set_defaults(func=_cmd_verify)
2495
2621
 
2622
+ fmt_p = sub.add_parser(
2623
+ "fmt",
2624
+ help="rewrite metadata files into canonical form (#304)",
2625
+ )
2626
+ fmt_p.add_argument(
2627
+ "files",
2628
+ nargs="*",
2629
+ metavar="FILE",
2630
+ help="optional explicit file(s) to format — must be members of this "
2631
+ "project's resolved metadata sources; omit to format every one of them",
2632
+ )
2633
+ fmt_p.add_argument(
2634
+ "--check",
2635
+ action="store_true",
2636
+ help="list files that are not canonical and exit non-zero; changes nothing",
2637
+ )
2638
+ fmt_p.add_argument(
2639
+ "--provider",
2640
+ action="append",
2641
+ default=None,
2642
+ metavar="MODULE:SYMBOL",
2643
+ help="consumer-registered Provider(s), repeatable (module:symbol)",
2644
+ )
2645
+ fmt_p.set_defaults(func=_cmd_fmt)
2646
+
2496
2647
  eject_p = sub.add_parser(
2497
2648
  "eject",
2498
2649
  help="copy reference generators into codegen/generators/ to own and edit",
@@ -0,0 +1,58 @@
1
+ """Collection-name collision refusal — the single choke point every route/router/
2
+ finder generator path goes through (called once, in ``run_gen``, over the full
3
+ entity set BEFORE any generator runs).
4
+
5
+ Two DISTINCT entities/projections pluralizing to the SAME API-surface collection
6
+ name (REST path, generated router module/finder names) is reachable from stock
7
+ metadata now that :func:`metaobjects.apidocs.naming.pluralize` no longer doubles an
8
+ already-plural word: ``Address`` (not already-plural: legacy-pluralizes to
9
+ ``Addresses``) and ``Addresses`` (already-plural: left unchanged, ALSO
10
+ ``Addresses``) collide, where before the fix they did not (``Addresses`` legacy-
11
+ pluralized to ``Addresseses``). Silently letting two entities share one collection
12
+ name would mean whichever generator runs second silently wins, or a straight
13
+ duplicate-module/route registration two files downstream of the real cause. This
14
+ refuses at the one place that can see the WHOLE set, with a message naming both
15
+ entities and the colliding name.
16
+ """
17
+ from __future__ import annotations
18
+
19
+ from metaobjects.apidocs.naming import pluralize
20
+ from metaobjects.errors import ErrorCode
21
+ from metaobjects.meta.core.object.meta_object import MetaObject
22
+ from metaobjects.meta.core.object.object_constants import OBJECT_SUBTYPE_VALUE
23
+
24
+ ERR_COLLECTION_NAME_COLLISION = ErrorCode.ERR_COLLECTION_NAME_COLLISION.value
25
+
26
+
27
+ def assert_no_collection_name_collisions(entities: list[MetaObject]) -> None:
28
+ """Refuse a generation run in which two DISTINCT entities/projections pluralize
29
+ to the same API-surface collection name.
30
+
31
+ Scope: every object EXCEPT ``object.value`` (a value object never gets a route,
32
+ router module, or finder name — it is pure shape, so it cannot collide on any of
33
+ those). A TPH subtype IS included: it gets its own generated names against the
34
+ shared base table, so two subtypes (or a subtype and an unrelated top-level
35
+ entity) sharing a pluralized name collide on those generated symbols exactly as
36
+ two top-level entities would.
37
+
38
+ A PURE function of the entity set — never of traversal order: the reported pair
39
+ is deterministic (first-seen-by-input-order "owner" of a plural; raised as soon
40
+ as a second, different entity claims the same plural).
41
+ """
42
+ owner_of_plural: dict[str, MetaObject] = {}
43
+ for obj in entities:
44
+ if obj.sub_type == OBJECT_SUBTYPE_VALUE:
45
+ continue
46
+ plural = pluralize(obj.name)
47
+ existing = owner_of_plural.get(plural)
48
+ if existing is not None:
49
+ if existing.resolution_key() != obj.resolution_key():
50
+ raise ValueError(
51
+ f"{ERR_COLLECTION_NAME_COLLISION}: \"{existing.name}\" and \"{obj.name}\" both "
52
+ f'pluralize to the API-surface collection name "{plural}" (REST path, generated '
53
+ "router module/finder names) — rename one entity so its pluralized name is "
54
+ "distinct. Default PHYSICAL table names are unaffected by this rule and are not "
55
+ "involved in the collision."
56
+ )
57
+ else:
58
+ owner_of_plural[plural] = obj
@@ -10,6 +10,7 @@ from metaobjects.meta.meta_root import MetaRoot
10
10
  from metaobjects.meta.meta_data import MetaData
11
11
  from metaobjects.meta.core.object.meta_object import MetaObject
12
12
  from metaobjects.shared.base_types import TYPE_OBJECT
13
+ from .collection_name_collision import assert_no_collection_name_collisions
13
14
  from .config import GenConfig
14
15
  from .constants import generated_package_init
15
16
  from .generator import GenContext, Generator
@@ -107,6 +108,10 @@ def run_gen(
107
108
  if not safe:
108
109
  return result
109
110
 
111
+ # Refuse before any generator runs — the one choke point that sees the WHOLE
112
+ # entity set every route/router-emitting generator below reads from.
113
+ assert_no_collection_name_collisions(safe)
114
+
110
115
  emitted: dict[str, tuple[str, str]] = {} # full_path -> (content, generated_by)
111
116
  for gen in generators:
112
117
  ctx = GenContext(
@@ -200,6 +200,12 @@ class ErrorCode(str, Enum):
200
200
  # Codegen (ADR-0044): two value-object FQNs in one payload artifact derive the same
201
201
  # emitted record name even after package-qualification. Peer of ERR_VAR_NOT_ON_PAYLOAD.
202
202
  ERR_PAYLOAD_NAME_COLLISION = "ERR_PAYLOAD_NAME_COLLISION"
203
+ # Codegen: two DISTINCT entities/projections in one generation run pluralize to the
204
+ # SAME API-surface collection name (route path, generated router/finder names) —
205
+ # e.g. "Address" and "Addresses" both resolving to "Addresses". A codegen-time (not
206
+ # loader) error, peer of ERR_PAYLOAD_NAME_COLLISION: refused rather than silently
207
+ # letting one entity's route win.
208
+ ERR_COLLECTION_NAME_COLLISION = "ERR_COLLECTION_NAME_COLLISION"
203
209
  ERR_OUTPUT_TAG_MISSING = "ERR_OUTPUT_TAG_MISSING"
204
210
  # SP-H Unit9 — @filterable: true on a field subtype with no filter-operator
205
211
  # band (e.g. field.object). Would silently generate an empty-ops filter.
@@ -0,0 +1,214 @@
1
+ """``metaobjects fmt`` (#304) — rewrite metadata files into the canonical form
2
+ the cross-port canonical serializer already produces. ``--check`` lists files
3
+ that are not canonical and exits non-zero without changing anything.
4
+
5
+ Mirrors the TS reference (``packages/metadata/src/fmt.ts`` +
6
+ ``packages/cli/src/lib/fmt-engine.ts``) and the C#/Java ports exactly:
7
+
8
+ - Each file is formatted STANDALONE — own-mode, declared-here layer only
9
+ (ADR-0039). ``parse_document`` already builds a fresh, unmerged tree per
10
+ document (this port's loader does parse -> merge -> super-resolve as three
11
+ separate steps, unlike TS/C#'s accumulating-root parser) — calling it
12
+ directly and never running ``merge_roots``/``resolve_supers`` is what makes
13
+ a cross-file ``extends`` round-trip untouched (the raw ``super_ref`` string
14
+ is read directly by ``canonical_serialize``, never its resolution) and an
15
+ ``overlay: true`` node never even attempt a merge.
16
+ - An ``overlay: true`` node is tagged (``is_overlay``) by the parser but never
17
+ resolved here — Python's overlay MERGE only happens in ``loader/merge.py``,
18
+ which this module never calls. A file containing one anywhere in its tree
19
+ (detected by :func:`_contains_overlay`) is reported as a skip rather than
20
+ guessed at — the concrete shape of "overlay files stay overlays".
21
+ - YAML is always skipped: no canonical YAML emitter exists (ADR-0006).
22
+ - Before writing, the whole project is reloaded with the candidate
23
+ substituted in via an in-memory source (never touching disk until proven
24
+ safe) and the write is refused unless that reload has no errors AND its
25
+ canonical form is byte-identical to the untouched baseline.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import json
31
+ from dataclasses import dataclass, field
32
+ from pathlib import Path
33
+ from typing import Callable
34
+
35
+ from metaobjects.errors import MetaError
36
+ from metaobjects.loader.meta_data_loader import MetaDataLoader
37
+ from metaobjects.loader.sources.file_source import FileSource
38
+ from metaobjects.loader.sources.meta_data_source import InMemoryStringSource, MetaDataSource
39
+ from metaobjects.meta.meta_data import MetaData
40
+ from metaobjects.parser import parse_document
41
+ from metaobjects.registry import TypeRegistry
42
+ from metaobjects.serializer_json import canonical_serialize
43
+
44
+ #: Statuses a single file's run can report.
45
+ STATUS_FORMATTED = "formatted"
46
+ STATUS_WOULD_FORMAT = "would-format"
47
+ STATUS_UNCHANGED = "unchanged"
48
+ STATUS_SKIPPED_YAML = "skipped-yaml"
49
+ STATUS_SKIPPED_OVERLAY = "skipped-overlay"
50
+ STATUS_ERROR = "error"
51
+
52
+
53
+ @dataclass
54
+ class FormatFileResult:
55
+ ok: bool
56
+ overlay: bool = False
57
+ text: str | None = None
58
+ message: str | None = None
59
+
60
+
61
+ def _contains_overlay(node: MetaData) -> bool:
62
+ """Whether *node* or any descendant (own children only — this tree was
63
+ never merged, so every child already is its own) carries ``overlay: true``.
64
+ """
65
+ if getattr(node, "is_overlay", False):
66
+ return True
67
+ return any(_contains_overlay(child) for child in node.own_children())
68
+
69
+
70
+ def format_file(content: str, registry: TypeRegistry, source_id: str) -> FormatFileResult:
71
+ """Format one file's own content. Parses *content* standalone via
72
+ :func:`parse_document` — never merged with any other file, super
73
+ resolution never run — and, on a clean parse with no overlay anywhere in
74
+ the tree, returns the canonical serialization of the resulting file root.
75
+ Never raises for a malformed file; that comes back as ``ok=False``.
76
+ """
77
+ # Strip a UTF-8 BOM before parsing — json.loads rejects one outright
78
+ # ("Unexpected UTF-8 BOM (decode using utf-8-sig)"), and Java-authored
79
+ # files often carry one.
80
+ normalized = content[1:] if content.startswith("") else content
81
+ try:
82
+ doc = json.loads(normalized)
83
+ except json.JSONDecodeError as exc:
84
+ return FormatFileResult(ok=False, message=f"invalid JSON: {exc}")
85
+
86
+ try:
87
+ result = parse_document(doc, registry, source_id)
88
+ except Exception as exc: # a few structural failures raise rather than record
89
+ return FormatFileResult(ok=False, message=str(exc))
90
+
91
+ if result.errors:
92
+ message = "; ".join(e.message for e in result.errors)
93
+ return FormatFileResult(ok=False, message=message)
94
+
95
+ if _contains_overlay(result.root):
96
+ return FormatFileResult(
97
+ ok=False,
98
+ overlay=True,
99
+ message="this file declares an overlay fmt cannot resolve standalone",
100
+ )
101
+
102
+ return FormatFileResult(ok=True, text=canonical_serialize(result.root))
103
+
104
+
105
+ @dataclass
106
+ class FileReport:
107
+ path: Path
108
+ status: str
109
+ detail: str | None = None
110
+
111
+
112
+ @dataclass
113
+ class RunResult:
114
+ files: list[FileReport] = field(default_factory=list)
115
+ fatal: str | None = None
116
+
117
+
118
+ def run(
119
+ all_files: list[Path],
120
+ target_files: list[Path],
121
+ file_ids: dict[Path, str],
122
+ registry: TypeRegistry,
123
+ lib_sources: list[MetaDataSource],
124
+ check: bool,
125
+ providers: list[object] | None = None,
126
+ ) -> RunResult:
127
+ """Run fmt over *target_files* (a subset of *all_files* — the project's
128
+ FULL resolved file set, needed for the whole-project safety-check reload
129
+ regardless of which files are in scope to format).
130
+
131
+ *providers* must be the SAME provider list *registry* (used for every
132
+ standalone per-file parse) was composed from — the whole-project baseline
133
+ and safety-check reloads build their own `MetaDataLoader`, which recomposes
134
+ a registry from *providers* itself rather than taking `registry` directly,
135
+ so passing a different set here would silently check two vocabularies
136
+ against each other.
137
+ """
138
+
139
+ def source_id(path: Path) -> str:
140
+ return file_ids.get(path) or path.name
141
+
142
+ def build_sources(
143
+ override_path: Path | None = None, override_text: str | None = None
144
+ ) -> list[MetaDataSource]:
145
+ sources: list[MetaDataSource] = list(lib_sources)
146
+ for p in all_files:
147
+ if override_path is not None and p == override_path:
148
+ sources.append(InMemoryStringSource(override_text or "", id=source_id(p)))
149
+ else:
150
+ sources.append(FileSource(p, id=source_id(p)))
151
+ return sources
152
+
153
+ baseline = MetaDataLoader(providers=providers, strict=False).load(build_sources())
154
+ if baseline.errors:
155
+ detail = "\n".join(f" {e.code}: {e.message}" for e in baseline.errors)
156
+ return RunResult(
157
+ fatal=(
158
+ "this project's metadata does not currently load cleanly — fix the "
159
+ f"error(s) below, then re-run fmt:\n{detail}"
160
+ )
161
+ )
162
+ baseline_canonical = canonical_serialize(baseline.root)
163
+
164
+ reports: list[FileReport] = []
165
+ for path in target_files:
166
+ ext = path.suffix.lower()
167
+ if ext in (".yaml", ".yml"):
168
+ reports.append(
169
+ FileReport(
170
+ path,
171
+ STATUS_SKIPPED_YAML,
172
+ "no canonical YAML emitter exists (ADR-0006: JSON is the canonical "
173
+ "interchange form) — left untouched",
174
+ )
175
+ )
176
+ continue
177
+
178
+ content = path.read_text(encoding="utf-8")
179
+ formatted = format_file(content, registry, source_id(path))
180
+ if not formatted.ok:
181
+ reports.append(
182
+ FileReport(
183
+ path,
184
+ STATUS_SKIPPED_OVERLAY if formatted.overlay else STATUS_ERROR,
185
+ formatted.message,
186
+ )
187
+ )
188
+ continue
189
+
190
+ if formatted.text == content:
191
+ reports.append(FileReport(path, STATUS_UNCHANGED))
192
+ continue
193
+
194
+ test_load = MetaDataLoader(providers=providers, strict=False).load(
195
+ build_sources(path, formatted.text)
196
+ )
197
+ safe = not test_load.errors and canonical_serialize(test_load.root) == baseline_canonical
198
+ if not safe:
199
+ reports.append(
200
+ FileReport(
201
+ path,
202
+ STATUS_ERROR,
203
+ "formatting this file would change the loaded model's meaning — left unchanged",
204
+ )
205
+ )
206
+ continue
207
+
208
+ if check:
209
+ reports.append(FileReport(path, STATUS_WOULD_FORMAT))
210
+ else:
211
+ path.write_text(formatted.text, encoding="utf-8")
212
+ reports.append(FileReport(path, STATUS_FORMATTED))
213
+
214
+ return RunResult(files=reports)
@@ -47,7 +47,17 @@ def _to_snake_case(s: str) -> str:
47
47
 
48
48
 
49
49
  def _pluralize(s: str) -> str:
50
- """Trivial cross-port pluralization (matches TS ``pluralize``)."""
50
+ """FROZEN — the DEFAULT PHYSICAL name derivation only (step 4 below, reached
51
+ only when metadata declares no explicit physical name). Matches the TS
52
+ reference ``pluralizeTableNameLegacy`` (metadata/src/naming.ts) — NOT the TS
53
+ ``pluralize``, which now differs for an already-plural word, deliberately
54
+ with NO already-plural detection. An adopter's live database was created
55
+ with this rule; adding the already-plural check here would make a schema
56
+ migration propose a rename for every already-plural entity name on the next
57
+ run. The API-surface analog (``metaobjects.apidocs.naming.pluralize``) has
58
+ that fix — this one must not, and the two are intentionally separate,
59
+ independently-maintained implementations (never merge them into one call
60
+ site)."""
51
61
  if not s:
52
62
  return s
53
63
  lower = s.lower()
@@ -128,7 +138,8 @@ class MetaSource(MetaData):
128
138
  2. Legacy ``@table`` for non-table kind (pre-1.0 fallback).
129
139
  3. Source's bare structural ``name`` via snake_case
130
140
  (no pluralize — the source's name IS the logical name).
131
- 4. Owning entity's name via ``pluralize(snake_case())``.
141
+ 4. Owning entity's name via the frozen legacy ``pluralize(snake_case())``
142
+ — see module-level ``_pluralize``'s docstring for why it is frozen.
132
143
 
133
144
  Callers needing the legacy raw ``@table`` slot only should use
134
145
  :meth:`table_name`; codegen / runtime should use ``physical_name``.
@@ -25,6 +25,7 @@ from metaobjects.render.extract.types import (
25
25
  Format,
26
26
  Normalizer,
27
27
  OnField,
28
+ OnLocate,
28
29
  ExtractOptions,
29
30
  ExtractionOutcome,
30
31
  ExtractSchema,
@@ -45,6 +46,7 @@ __all__ = [
45
46
  "JsonForgivingReader",
46
47
  "Normalizer",
47
48
  "OnField",
49
+ "OnLocate",
48
50
  "ExtractOptions",
49
51
  "ExtractionOutcome",
50
52
  "ExtractSchema",
@@ -38,23 +38,55 @@ def extract(
38
38
  stripped = _strip.strip(text)
39
39
  ci = o.tolerance != Tolerance.STRICT
40
40
 
41
+ # FR-364: the document-level on_locate hook runs BEFORE the default locator. A non-None
42
+ # return is the payload span, fed into the same format-specific forgiving reader a
43
+ # default-located span would be — tolerance/coercion/normalizers/on_field downstream are
44
+ # unaffected. A None return (or no hook) falls through to the default locate strategy
45
+ # unchanged. A raised exception propagates (not swallowed), matching on_field.
46
+ located: str | None = None if o.on_locate is None else o.on_locate(text if text is not None else "", schema.format)
47
+
41
48
  # XML rootless (opts.rootless): the payload's fields ARE the top-level elements — there
42
49
  # is no enclosing root to locate — so parse the whole stripped text's top-level elements
43
50
  # directly. Otherwise locate the <rootName> span as before. JSON is unaffected. Mirrors
44
51
  # Java Extract.extract.
45
52
  span: str | None
46
53
  raw: dict[str, object]
47
- if schema.format == Format.JSON:
54
+ # Whether the SELECTED region (not the original reply) was itself empty/blank — the signal
55
+ # mark_empty() keys on below. For the default path this is the pre-existing "nothing to
56
+ # parse" test (stripped == "" or span is None); for on_locate it must be judged against the
57
+ # hook's OWN return, not the original text — otherwise an empty located span (e.g. the hook
58
+ # deliberately returning "") reports "not empty" while every field is LOST, because the
59
+ # original reply was non-blank even though the thing on_locate chose to parse was.
60
+ region_blank: bool
61
+ if located is not None:
62
+ span = located
63
+ if schema.format == Format.JSON:
64
+ raw = JsonForgivingReader().read(located)
65
+ elif o.rootless:
66
+ raw = XmlForgivingReader().read_rootless(located, ci)
67
+ else:
68
+ raw = XmlForgivingReader().read(located, ci)
69
+ # `from_` is deliberately left empty rather than the original text: a document-level
70
+ # audit entry that copied the whole raw reply (which can be arbitrarily large) into the
71
+ # report on every call would make the report itself heavy for no benefit `to`'s length
72
+ # doesn't already give. `to` is the located span's LENGTH, not the span text, for the
73
+ # same reason.
74
+ report.add_coercion(Coercion("", "", str(len(located)), "onLocate"))
75
+ region_blank = located.strip() == ""
76
+ elif schema.format == Format.JSON:
48
77
  span = _select_json(text, stripped, schema.fields, ci)
49
78
  raw = {} if span is None else JsonForgivingReader().read(span)
79
+ region_blank = stripped == "" or span is None
50
80
  elif o.rootless:
51
81
  span = None if stripped == "" else stripped
52
82
  raw = {} if span is None else XmlForgivingReader().read_rootless(stripped, ci)
83
+ region_blank = stripped == "" or span is None
53
84
  else:
54
85
  span = _locate.xml(stripped, schema.root_name, ci)
55
86
  raw = {} if span is None else XmlForgivingReader().read(span, ci)
87
+ region_blank = stripped == "" or span is None
56
88
 
57
- if not raw and (stripped == "" or span is None):
89
+ if not raw and region_blank:
58
90
  report.mark_empty()
59
91
 
60
92
  _extract(schema.fields, raw, "", data, report, o, ci)