ofplang-validate 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. ofplang_validate-0.1.0/.github/workflows/ci.yml +45 -0
  2. ofplang_validate-0.1.0/.github/workflows/publish.yml +93 -0
  3. ofplang_validate-0.1.0/.gitignore +12 -0
  4. ofplang_validate-0.1.0/LICENSE +21 -0
  5. ofplang_validate-0.1.0/PKG-INFO +119 -0
  6. ofplang_validate-0.1.0/README.md +87 -0
  7. ofplang_validate-0.1.0/ofplang/validate/__init__.py +19 -0
  8. ofplang_validate-0.1.0/ofplang/validate/__main__.py +9 -0
  9. ofplang_validate-0.1.0/ofplang/validate/cli.py +178 -0
  10. ofplang_validate-0.1.0/ofplang/validate/contracts.py +531 -0
  11. ofplang_validate-0.1.0/ofplang/validate/diagnostics.py +65 -0
  12. ofplang_validate-0.1.0/ofplang/validate/duplicates.py +61 -0
  13. ofplang_validate-0.1.0/ofplang/validate/entry.py +129 -0
  14. ofplang_validate-0.1.0/ofplang/validate/errors.py +176 -0
  15. ofplang_validate-0.1.0/ofplang/validate/features.py +126 -0
  16. ofplang_validate-0.1.0/ofplang/validate/generics.py +394 -0
  17. ofplang_validate-0.1.0/ofplang/validate/identifiers.py +112 -0
  18. ofplang_validate-0.1.0/ofplang/validate/imports.py +185 -0
  19. ofplang_validate-0.1.0/ofplang/validate/nodes.py +493 -0
  20. ofplang_validate-0.1.0/ofplang/validate/objects.py +577 -0
  21. ofplang_validate-0.1.0/ofplang/validate/phases.py +87 -0
  22. ofplang_validate-0.1.0/ofplang/validate/py.typed +0 -0
  23. ofplang_validate-0.1.0/ofplang/validate/references.py +310 -0
  24. ofplang_validate-0.1.0/ofplang/validate/scheduling.py +187 -0
  25. ofplang_validate-0.1.0/ofplang/validate/script.py +81 -0
  26. ofplang_validate-0.1.0/ofplang/validate/shape.py +311 -0
  27. ofplang_validate-0.1.0/ofplang/validate/traits.py +59 -0
  28. ofplang_validate-0.1.0/ofplang/validate/typecheck.py +132 -0
  29. ofplang_validate-0.1.0/ofplang/validate/types.py +226 -0
  30. ofplang_validate-0.1.0/ofplang/validate/validator.py +166 -0
  31. ofplang_validate-0.1.0/ofplang/validate/views.py +139 -0
  32. ofplang_validate-0.1.0/ofplang/validate/yamlnode.py +241 -0
  33. ofplang_validate-0.1.0/ofplang_validate.egg-info/PKG-INFO +119 -0
  34. ofplang_validate-0.1.0/ofplang_validate.egg-info/SOURCES.txt +352 -0
  35. ofplang_validate-0.1.0/ofplang_validate.egg-info/dependency_links.txt +1 -0
  36. ofplang_validate-0.1.0/ofplang_validate.egg-info/entry_points.txt +2 -0
  37. ofplang_validate-0.1.0/ofplang_validate.egg-info/requires.txt +10 -0
  38. ofplang_validate-0.1.0/ofplang_validate.egg-info/scm_file_list.json +348 -0
  39. ofplang_validate-0.1.0/ofplang_validate.egg-info/scm_version.json +8 -0
  40. ofplang_validate-0.1.0/ofplang_validate.egg-info/top_level.txt +1 -0
  41. ofplang_validate-0.1.0/pyproject.toml +83 -0
  42. ofplang_validate-0.1.0/setup.cfg +4 -0
  43. ofplang_validate-0.1.0/tests/__init__.py +0 -0
  44. ofplang_validate-0.1.0/tests/conformance/README.md +122 -0
  45. ofplang_validate-0.1.0/tests/conformance/__init__.py +0 -0
  46. ofplang_validate-0.1.0/tests/conformance/cases/_baseline.yaml +9 -0
  47. ofplang_validate-0.1.0/tests/conformance/cases/aggregation/multiple_independent_errors.expected.yaml +15 -0
  48. ofplang_validate-0.1.0/tests/conformance/cases/aggregation/multiple_independent_errors.yaml +17 -0
  49. ofplang_validate-0.1.0/tests/conformance/cases/contracts/comparison_chain.expected.yaml +5 -0
  50. ofplang_validate-0.1.0/tests/conformance/cases/contracts/comparison_chain.yaml +13 -0
  51. ofplang_validate-0.1.0/tests/conformance/cases/contracts/missing_view.expected.yaml +4 -0
  52. ofplang_validate-0.1.0/tests/conformance/cases/contracts/missing_view.yaml +13 -0
  53. ofplang_validate-0.1.0/tests/conformance/cases/contracts/parse_error.expected.yaml +4 -0
  54. ofplang_validate-0.1.0/tests/conformance/cases/contracts/parse_error.yaml +13 -0
  55. ofplang_validate-0.1.0/tests/conformance/cases/contracts/requires_references_output.expected.yaml +5 -0
  56. ofplang_validate-0.1.0/tests/conformance/cases/contracts/requires_references_output.yaml +16 -0
  57. ofplang_validate-0.1.0/tests/conformance/cases/contracts/static_false.expected.yaml +4 -0
  58. ofplang_validate-0.1.0/tests/conformance/cases/contracts/static_false.yaml +13 -0
  59. ofplang_validate-0.1.0/tests/conformance/cases/contracts/type_error.expected.yaml +4 -0
  60. ofplang_validate-0.1.0/tests/conformance/cases/contracts/type_error.yaml +13 -0
  61. ofplang_validate-0.1.0/tests/conformance/cases/contracts/unknown_view_field.expected.yaml +5 -0
  62. ofplang_validate-0.1.0/tests/conformance/cases/contracts/unknown_view_field.yaml +26 -0
  63. ofplang_validate-0.1.0/tests/conformance/cases/contracts/valid_ensures.expected.yaml +2 -0
  64. ofplang_validate-0.1.0/tests/conformance/cases/contracts/valid_ensures.yaml +16 -0
  65. ofplang_validate-0.1.0/tests/conformance/cases/contracts/valid_numeric_promotion.expected.yaml +2 -0
  66. ofplang_validate-0.1.0/tests/conformance/cases/contracts/valid_numeric_promotion.yaml +13 -0
  67. ofplang_validate-0.1.0/tests/conformance/cases/contracts/valid_requires.expected.yaml +2 -0
  68. ofplang_validate-0.1.0/tests/conformance/cases/contracts/valid_requires.yaml +13 -0
  69. ofplang_validate-0.1.0/tests/conformance/cases/entry/implicit_main.expected.yaml +2 -0
  70. ofplang_validate-0.1.0/tests/conformance/cases/entry/implicit_main.yaml +6 -0
  71. ofplang_validate-0.1.0/tests/conformance/cases/entry/no_entry.expected.yaml +4 -0
  72. ofplang_validate-0.1.0/tests/conformance/cases/entry/no_entry.yaml +6 -0
  73. ofplang_validate-0.1.0/tests/conformance/cases/entry/recursive_dependency.expected.yaml +4 -0
  74. ofplang_validate-0.1.0/tests/conformance/cases/entry/recursive_dependency.yaml +24 -0
  75. ofplang_validate-0.1.0/tests/conformance/cases/entry/unknown_entry.expected.yaml +5 -0
  76. ofplang_validate-0.1.0/tests/conformance/cases/entry/unknown_entry.yaml +7 -0
  77. ofplang_validate-0.1.0/tests/conformance/cases/extensions/x_feature_tolerant.expected.yaml +3 -0
  78. ofplang_validate-0.1.0/tests/conformance/cases/extensions/x_feature_tolerant.yaml +9 -0
  79. ofplang_validate-0.1.0/tests/conformance/cases/extensions/x_key_strict.expected.yaml +6 -0
  80. ofplang_validate-0.1.0/tests/conformance/cases/extensions/x_key_strict.yaml +8 -0
  81. ofplang_validate-0.1.0/tests/conformance/cases/extensions/x_key_tolerant.expected.yaml +3 -0
  82. ofplang_validate-0.1.0/tests/conformance/cases/extensions/x_key_tolerant.yaml +8 -0
  83. ofplang_validate-0.1.0/tests/conformance/cases/extensions/x_prefer_kind_tolerant.expected.yaml +3 -0
  84. ofplang_validate-0.1.0/tests/conformance/cases/extensions/x_prefer_kind_tolerant.yaml +17 -0
  85. ofplang_validate-0.1.0/tests/conformance/cases/features/derived_ok.expected.yaml +2 -0
  86. ofplang_validate-0.1.0/tests/conformance/cases/features/derived_ok.yaml +19 -0
  87. ofplang_validate-0.1.0/tests/conformance/cases/features/derived_omitted.expected.yaml +2 -0
  88. ofplang_validate-0.1.0/tests/conformance/cases/features/derived_omitted.yaml +28 -0
  89. ofplang_validate-0.1.0/tests/conformance/cases/features/generic_derived_ok.expected.yaml +2 -0
  90. ofplang_validate-0.1.0/tests/conformance/cases/features/generic_derived_ok.yaml +25 -0
  91. ofplang_validate-0.1.0/tests/conformance/cases/features/generic_missing_feature.expected.yaml +5 -0
  92. ofplang_validate-0.1.0/tests/conformance/cases/features/generic_missing_feature.yaml +24 -0
  93. ofplang_validate-0.1.0/tests/conformance/cases/features/missing_required_feature.expected.yaml +5 -0
  94. ofplang_validate-0.1.0/tests/conformance/cases/features/missing_required_feature.yaml +35 -0
  95. ofplang_validate-0.1.0/tests/conformance/cases/features/unknown_feature.expected.yaml +5 -0
  96. ofplang_validate-0.1.0/tests/conformance/cases/features/unknown_feature.yaml +9 -0
  97. ofplang_validate-0.1.0/tests/conformance/cases/generics/conflicting_inference.expected.yaml +6 -0
  98. ofplang_validate-0.1.0/tests/conformance/cases/generics/conflicting_inference.yaml +47 -0
  99. ofplang_validate-0.1.0/tests/conformance/cases/generics/constraint_not_satisfied.expected.yaml +4 -0
  100. ofplang_validate-0.1.0/tests/conformance/cases/generics/constraint_not_satisfied.yaml +54 -0
  101. ofplang_validate-0.1.0/tests/conformance/cases/generics/constraint_on_concrete.expected.yaml +4 -0
  102. ofplang_validate-0.1.0/tests/conformance/cases/generics/constraint_on_concrete.yaml +32 -0
  103. ofplang_validate-0.1.0/tests/conformance/cases/generics/malformed_constraint.expected.yaml +5 -0
  104. ofplang_validate-0.1.0/tests/conformance/cases/generics/malformed_constraint.yaml +27 -0
  105. ofplang_validate-0.1.0/tests/conformance/cases/generics/type_param_not_in_input.expected.yaml +5 -0
  106. ofplang_validate-0.1.0/tests/conformance/cases/generics/type_param_not_in_input.yaml +17 -0
  107. ofplang_validate-0.1.0/tests/conformance/cases/generics/type_param_shadow.expected.yaml +4 -0
  108. ofplang_validate-0.1.0/tests/conformance/cases/generics/type_param_shadow.yaml +26 -0
  109. ofplang_validate-0.1.0/tests/conformance/cases/generics/uninferable_type_param.expected.yaml +8 -0
  110. ofplang_validate-0.1.0/tests/conformance/cases/generics/uninferable_type_param.yaml +33 -0
  111. ofplang_validate-0.1.0/tests/conformance/cases/generics/valid_inference.expected.yaml +5 -0
  112. ofplang_validate-0.1.0/tests/conformance/cases/generics/valid_inference.yaml +38 -0
  113. ofplang_validate-0.1.0/tests/conformance/cases/generics/valid_where.expected.yaml +2 -0
  114. ofplang_validate-0.1.0/tests/conformance/cases/generics/valid_where.yaml +32 -0
  115. ofplang_validate-0.1.0/tests/conformance/cases/identifiers/bad_identifier.expected.yaml +5 -0
  116. ofplang_validate-0.1.0/tests/conformance/cases/identifiers/bad_identifier.yaml +7 -0
  117. ofplang_validate-0.1.0/tests/conformance/cases/identifiers/dot_in_process_name.expected.yaml +5 -0
  118. ofplang_validate-0.1.0/tests/conformance/cases/identifiers/dot_in_process_name.yaml +7 -0
  119. ofplang_validate-0.1.0/tests/conformance/cases/identifiers/duplicate_port_name.expected.yaml +5 -0
  120. ofplang_validate-0.1.0/tests/conformance/cases/identifiers/duplicate_port_name.yaml +13 -0
  121. ofplang_validate-0.1.0/tests/conformance/cases/identifiers/reserved_type_name.expected.yaml +5 -0
  122. ofplang_validate-0.1.0/tests/conformance/cases/identifiers/reserved_type_name.yaml +10 -0
  123. ofplang_validate-0.1.0/tests/conformance/cases/imports/basic/expected.yaml +2 -0
  124. ofplang_validate-0.1.0/tests/conformance/cases/imports/basic/main.yaml +12 -0
  125. ofplang_validate-0.1.0/tests/conformance/cases/imports/basic/types_fragment.yaml +2 -0
  126. ofplang_validate-0.1.0/tests/conformance/cases/imports/cycle/a.yaml +1 -0
  127. ofplang_validate-0.1.0/tests/conformance/cases/imports/cycle/b.yaml +1 -0
  128. ofplang_validate-0.1.0/tests/conformance/cases/imports/cycle/expected.yaml +4 -0
  129. ofplang_validate-0.1.0/tests/conformance/cases/imports/cycle/main.yaml +4 -0
  130. ofplang_validate-0.1.0/tests/conformance/cases/imports/duplicate_key/expected.yaml +5 -0
  131. ofplang_validate-0.1.0/tests/conformance/cases/imports/duplicate_key/frag.yaml +2 -0
  132. ofplang_validate-0.1.0/tests/conformance/cases/imports/duplicate_key/main.yaml +11 -0
  133. ofplang_validate-0.1.0/tests/conformance/cases/imports/empty_import.expected.yaml +5 -0
  134. ofplang_validate-0.1.0/tests/conformance/cases/imports/empty_import.yaml +4 -0
  135. ofplang_validate-0.1.0/tests/conformance/cases/imports/invalid_shape/expected.yaml +4 -0
  136. ofplang_validate-0.1.0/tests/conformance/cases/imports/invalid_shape/main.yaml +9 -0
  137. ofplang_validate-0.1.0/tests/conformance/cases/imports/invalid_shape/seq.yaml +2 -0
  138. ofplang_validate-0.1.0/tests/conformance/cases/imports/multidoc/expected.yaml +4 -0
  139. ofplang_validate-0.1.0/tests/conformance/cases/imports/multidoc/main.yaml +9 -0
  140. ofplang_validate-0.1.0/tests/conformance/cases/imports/multidoc/multi.yaml +5 -0
  141. ofplang_validate-0.1.0/tests/conformance/cases/imports/non_string_path/expected.yaml +4 -0
  142. ofplang_validate-0.1.0/tests/conformance/cases/imports/non_string_path/main.yaml +9 -0
  143. ofplang_validate-0.1.0/tests/conformance/cases/imports/unreadable/expected.yaml +4 -0
  144. ofplang_validate-0.1.0/tests/conformance/cases/imports/unreadable/main.yaml +9 -0
  145. ofplang_validate-0.1.0/tests/conformance/cases/imports/uri_fragment/expected.yaml +4 -0
  146. ofplang_validate-0.1.0/tests/conformance/cases/imports/uri_fragment/main.yaml +9 -0
  147. ofplang_validate-0.1.0/tests/conformance/cases/linearity/data_indegree_zero.expected.yaml +4 -0
  148. ofplang_validate-0.1.0/tests/conformance/cases/linearity/data_indegree_zero.yaml +17 -0
  149. ofplang_validate-0.1.0/tests/conformance/cases/linearity/object_fanout.expected.yaml +5 -0
  150. ofplang_validate-0.1.0/tests/conformance/cases/linearity/object_fanout.yaml +43 -0
  151. ofplang_validate-0.1.0/tests/conformance/cases/linearity/object_input_no_source.expected.yaml +4 -0
  152. ofplang_validate-0.1.0/tests/conformance/cases/linearity/object_input_no_source.yaml +23 -0
  153. ofplang_validate-0.1.0/tests/conformance/cases/linearity/object_output_unused.expected.yaml +5 -0
  154. ofplang_validate-0.1.0/tests/conformance/cases/linearity/object_output_unused.yaml +23 -0
  155. ofplang_validate-0.1.0/tests/conformance/cases/linearity/valid_object_flow.expected.yaml +2 -0
  156. ofplang_validate-0.1.0/tests/conformance/cases/linearity/valid_object_flow.yaml +38 -0
  157. ofplang_validate-0.1.0/tests/conformance/cases/linearity/valid_return_object.expected.yaml +2 -0
  158. ofplang_validate-0.1.0/tests/conformance/cases/linearity/valid_return_object.yaml +21 -0
  159. ofplang_validate-0.1.0/tests/conformance/cases/metadata/float_spec_version.expected.yaml +5 -0
  160. ofplang_validate-0.1.0/tests/conformance/cases/metadata/float_spec_version.yaml +7 -0
  161. ofplang_validate-0.1.0/tests/conformance/cases/metadata/malformed_spec_version.expected.yaml +5 -0
  162. ofplang_validate-0.1.0/tests/conformance/cases/metadata/malformed_spec_version.yaml +7 -0
  163. ofplang_validate-0.1.0/tests/conformance/cases/metadata/omitted_spec_version.expected.yaml +2 -0
  164. ofplang_validate-0.1.0/tests/conformance/cases/metadata/omitted_spec_version.yaml +6 -0
  165. ofplang_validate-0.1.0/tests/conformance/cases/nodes/bad_condition_output.expected.yaml +4 -0
  166. ofplang_validate-0.1.0/tests/conformance/cases/nodes/bad_condition_output.yaml +42 -0
  167. ofplang_validate-0.1.0/tests/conformance/cases/nodes/branch_common_type_mismatch.expected.yaml +5 -0
  168. ofplang_validate-0.1.0/tests/conformance/cases/nodes/branch_common_type_mismatch.yaml +44 -0
  169. ofplang_validate-0.1.0/tests/conformance/cases/nodes/branch_drop_object.expected.yaml +5 -0
  170. ofplang_validate-0.1.0/tests/conformance/cases/nodes/branch_drop_object.yaml +46 -0
  171. ofplang_validate-0.1.0/tests/conformance/cases/nodes/branch_implicit_else_not_identity.expected.yaml +5 -0
  172. ofplang_validate-0.1.0/tests/conformance/cases/nodes/branch_implicit_else_not_identity.yaml +33 -0
  173. ofplang_validate-0.1.0/tests/conformance/cases/nodes/branch_not_identity_equivalent.expected.yaml +4 -0
  174. ofplang_validate-0.1.0/tests/conformance/cases/nodes/branch_not_identity_equivalent.yaml +67 -0
  175. ofplang_validate-0.1.0/tests/conformance/cases/nodes/branch_object_omitted.expected.yaml +5 -0
  176. ofplang_validate-0.1.0/tests/conformance/cases/nodes/branch_object_omitted.yaml +47 -0
  177. ofplang_validate-0.1.0/tests/conformance/cases/nodes/branch_one_sided_object.expected.yaml +5 -0
  178. ofplang_validate-0.1.0/tests/conformance/cases/nodes/branch_one_sided_object.yaml +54 -0
  179. ofplang_validate-0.1.0/tests/conformance/cases/nodes/dowhile_missing_max_iterations.expected.yaml +5 -0
  180. ofplang_validate-0.1.0/tests/conformance/cases/nodes/dowhile_missing_max_iterations.yaml +40 -0
  181. ofplang_validate-0.1.0/tests/conformance/cases/nodes/dowhile_noncarry_object.expected.yaml +4 -0
  182. ofplang_validate-0.1.0/tests/conformance/cases/nodes/dowhile_noncarry_object.yaml +49 -0
  183. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_carry_not_carry_mode.expected.yaml +5 -0
  184. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_carry_not_carry_mode.yaml +31 -0
  185. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_carry_output_missing.expected.yaml +5 -0
  186. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_carry_output_missing.yaml +44 -0
  187. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_carry_phase_mismatch.expected.yaml +7 -0
  188. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_carry_phase_mismatch.yaml +47 -0
  189. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_carry_type_mismatch.expected.yaml +6 -0
  190. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_carry_type_mismatch.yaml +47 -0
  191. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_invalid_output_mode.expected.yaml +5 -0
  192. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_invalid_output_mode.yaml +31 -0
  193. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_noncarry_object_unlisted.expected.yaml +4 -0
  194. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_noncarry_object_unlisted.yaml +36 -0
  195. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_output_not_listed.expected.yaml +5 -0
  196. ofplang_validate-0.1.0/tests/conformance/cases/nodes/fold_output_not_listed.yaml +30 -0
  197. ofplang_validate-0.1.0/tests/conformance/cases/nodes/last_on_empty_fold.expected.yaml +4 -0
  198. ofplang_validate-0.1.0/tests/conformance/cases/nodes/last_on_empty_fold.yaml +29 -0
  199. ofplang_validate-0.1.0/tests/conformance/cases/nodes/object_output_last_mode.expected.yaml +4 -0
  200. ofplang_validate-0.1.0/tests/conformance/cases/nodes/object_output_last_mode.yaml +39 -0
  201. ofplang_validate-0.1.0/tests/conformance/cases/nodes/ordinary_output_section.expected.yaml +5 -0
  202. ofplang_validate-0.1.0/tests/conformance/cases/nodes/ordinary_output_section.yaml +17 -0
  203. ofplang_validate-0.1.0/tests/conformance/cases/nodes/unknown_node_key.expected.yaml +5 -0
  204. ofplang_validate-0.1.0/tests/conformance/cases/nodes/unknown_node_key.yaml +17 -0
  205. ofplang_validate-0.1.0/tests/conformance/cases/nodes/valid_branch_common.expected.yaml +2 -0
  206. ofplang_validate-0.1.0/tests/conformance/cases/nodes/valid_branch_common.yaml +66 -0
  207. ofplang_validate-0.1.0/tests/conformance/cases/nodes/valid_do_while.expected.yaml +2 -0
  208. ofplang_validate-0.1.0/tests/conformance/cases/nodes/valid_do_while.yaml +42 -0
  209. ofplang_validate-0.1.0/tests/conformance/cases/nodes/valid_fold_collect.expected.yaml +2 -0
  210. ofplang_validate-0.1.0/tests/conformance/cases/nodes/valid_fold_collect.yaml +47 -0
  211. ofplang_validate-0.1.0/tests/conformance/cases/nodes/valid_map.expected.yaml +2 -0
  212. ofplang_validate-0.1.0/tests/conformance/cases/nodes/valid_map.yaml +52 -0
  213. ofplang_validate-0.1.0/tests/conformance/cases/nodes/zip_mismatch.expected.yaml +4 -0
  214. ofplang_validate-0.1.0/tests/conformance/cases/nodes/zip_mismatch.yaml +31 -0
  215. ofplang_validate-0.1.0/tests/conformance/cases/objects/consume_path_not_found.expected.yaml +5 -0
  216. ofplang_validate-0.1.0/tests/conformance/cases/objects/consume_path_not_found.yaml +21 -0
  217. ofplang_validate-0.1.0/tests/conformance/cases/objects/implicit_create_output.expected.yaml +5 -0
  218. ofplang_validate-0.1.0/tests/conformance/cases/objects/implicit_create_output.yaml +18 -0
  219. ofplang_validate-0.1.0/tests/conformance/cases/objects/incomplete_input_fate.expected.yaml +5 -0
  220. ofplang_validate-0.1.0/tests/conformance/cases/objects/incomplete_input_fate.yaml +18 -0
  221. ofplang_validate-0.1.0/tests/conformance/cases/objects/multiple_fates.expected.yaml +5 -0
  222. ofplang_validate-0.1.0/tests/conformance/cases/objects/multiple_fates.yaml +25 -0
  223. ofplang_validate-0.1.0/tests/conformance/cases/objects/multiple_provenances.expected.yaml +4 -0
  224. ofplang_validate-0.1.0/tests/conformance/cases/objects/multiple_provenances.yaml +25 -0
  225. ofplang_validate-0.1.0/tests/conformance/cases/objects/valid_cross_wired_map.expected.yaml +2 -0
  226. ofplang_validate-0.1.0/tests/conformance/cases/objects/valid_cross_wired_map.yaml +30 -0
  227. ofplang_validate-0.1.0/tests/conformance/cases/objects/valid_elidable_iso.expected.yaml +2 -0
  228. ofplang_validate-0.1.0/tests/conformance/cases/objects/valid_elidable_iso.yaml +22 -0
  229. ofplang_validate-0.1.0/tests/conformance/cases/objects/valid_map.expected.yaml +2 -0
  230. ofplang_validate-0.1.0/tests/conformance/cases/objects/valid_map.yaml +23 -0
  231. ofplang_validate-0.1.0/tests/conformance/cases/objects/valid_object_replacement.expected.yaml +2 -0
  232. ofplang_validate-0.1.0/tests/conformance/cases/objects/valid_object_replacement.yaml +25 -0
  233. ofplang_validate-0.1.0/tests/conformance/cases/phases/bad_phase_value.expected.yaml +5 -0
  234. ofplang_validate-0.1.0/tests/conformance/cases/phases/bad_phase_value.yaml +10 -0
  235. ofplang_validate-0.1.0/tests/conformance/cases/phases/invalid_phase_flow.expected.yaml +4 -0
  236. ofplang_validate-0.1.0/tests/conformance/cases/phases/invalid_phase_flow.yaml +29 -0
  237. ofplang_validate-0.1.0/tests/conformance/cases/phases/object_graph_phase.expected.yaml +5 -0
  238. ofplang_validate-0.1.0/tests/conformance/cases/phases/object_graph_phase.yaml +19 -0
  239. ofplang_validate-0.1.0/tests/conformance/cases/phases/valid_object_data_phase.expected.yaml +2 -0
  240. ofplang_validate-0.1.0/tests/conformance/cases/phases/valid_object_data_phase.yaml +19 -0
  241. ofplang_validate-0.1.0/tests/conformance/cases/references/binding_source_both.expected.yaml +4 -0
  242. ofplang_validate-0.1.0/tests/conformance/cases/references/binding_source_both.yaml +25 -0
  243. ofplang_validate-0.1.0/tests/conformance/cases/references/binding_source_neither.expected.yaml +4 -0
  244. ofplang_validate-0.1.0/tests/conformance/cases/references/binding_source_neither.yaml +19 -0
  245. ofplang_validate-0.1.0/tests/conformance/cases/references/object_via_bind.expected.yaml +4 -0
  246. ofplang_validate-0.1.0/tests/conformance/cases/references/object_via_bind.yaml +38 -0
  247. ofplang_validate-0.1.0/tests/conformance/cases/references/return_unknown_ref.expected.yaml +4 -0
  248. ofplang_validate-0.1.0/tests/conformance/cases/references/return_unknown_ref.yaml +23 -0
  249. ofplang_validate-0.1.0/tests/conformance/cases/references/unknown_reference.expected.yaml +4 -0
  250. ofplang_validate-0.1.0/tests/conformance/cases/references/unknown_reference.yaml +29 -0
  251. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/bad_temporal_ref.expected.yaml +4 -0
  252. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/bad_temporal_ref.yaml +25 -0
  253. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/gap_with_object.expected.yaml +5 -0
  254. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/gap_with_object.yaml +34 -0
  255. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/malformed_prefer_payload.expected.yaml +4 -0
  256. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/malformed_prefer_payload.yaml +17 -0
  257. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/non_object_bearing_target.expected.yaml +4 -0
  258. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/non_object_bearing_target.yaml +25 -0
  259. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/on_atomic.expected.yaml +5 -0
  260. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/on_atomic.yaml +18 -0
  261. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/temperature_without_object.expected.yaml +5 -0
  262. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/temperature_without_object.yaml +25 -0
  263. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/unknown_prefer_kind.expected.yaml +4 -0
  264. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/unknown_prefer_kind.yaml +19 -0
  265. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/valid_max_gap.expected.yaml +2 -0
  266. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/valid_max_gap.yaml +31 -0
  267. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/valid_min_gap.expected.yaml +2 -0
  268. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/valid_min_gap.yaml +31 -0
  269. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/valid_temperature.expected.yaml +2 -0
  270. ofplang_validate-0.1.0/tests/conformance/cases/scheduling/valid_temperature.yaml +34 -0
  271. ofplang_validate-0.1.0/tests/conformance/cases/script/has_objects.expected.yaml +4 -0
  272. ofplang_validate-0.1.0/tests/conformance/cases/script/has_objects.yaml +26 -0
  273. ofplang_validate-0.1.0/tests/conformance/cases/script/object_port.expected.yaml +5 -0
  274. ofplang_validate-0.1.0/tests/conformance/cases/script/object_port.yaml +26 -0
  275. ofplang_validate-0.1.0/tests/conformance/cases/script/unsupported_language.expected.yaml +5 -0
  276. ofplang_validate-0.1.0/tests/conformance/cases/script/unsupported_language.yaml +22 -0
  277. ofplang_validate-0.1.0/tests/conformance/cases/script/valid_python.expected.yaml +2 -0
  278. ofplang_validate-0.1.0/tests/conformance/cases/script/valid_python.yaml +26 -0
  279. ofplang_validate-0.1.0/tests/conformance/cases/shape/duplicate_process_name.expected.yaml +5 -0
  280. ofplang_validate-0.1.0/tests/conformance/cases/shape/duplicate_process_name.yaml +11 -0
  281. ofplang_validate-0.1.0/tests/conformance/cases/shape/node_missing_process.expected.yaml +5 -0
  282. ofplang_validate-0.1.0/tests/conformance/cases/shape/node_missing_process.yaml +9 -0
  283. ofplang_validate-0.1.0/tests/conformance/cases/shape/null_phase.expected.yaml +5 -0
  284. ofplang_validate-0.1.0/tests/conformance/cases/shape/null_phase.yaml +10 -0
  285. ofplang_validate-0.1.0/tests/conformance/cases/shape/objects_on_composite.expected.yaml +5 -0
  286. ofplang_validate-0.1.0/tests/conformance/cases/shape/objects_on_composite.yaml +10 -0
  287. ofplang_validate-0.1.0/tests/conformance/cases/shape/port_missing_phase.expected.yaml +5 -0
  288. ofplang_validate-0.1.0/tests/conformance/cases/shape/port_missing_phase.yaml +9 -0
  289. ofplang_validate-0.1.0/tests/conformance/cases/shape/port_missing_type.expected.yaml +5 -0
  290. ofplang_validate-0.1.0/tests/conformance/cases/shape/port_missing_type.yaml +9 -0
  291. ofplang_validate-0.1.0/tests/conformance/cases/shape/reserved_dollar_key.expected.yaml +5 -0
  292. ofplang_validate-0.1.0/tests/conformance/cases/shape/reserved_dollar_key.yaml +8 -0
  293. ofplang_validate-0.1.0/tests/conformance/cases/shape/unknown_top_level_key.expected.yaml +5 -0
  294. ofplang_validate-0.1.0/tests/conformance/cases/shape/unknown_top_level_key.yaml +8 -0
  295. ofplang_validate-0.1.0/tests/conformance/cases/shape/valid_minimal.expected.yaml +2 -0
  296. ofplang_validate-0.1.0/tests/conformance/cases/shape/valid_minimal.yaml +7 -0
  297. ofplang_validate-0.1.0/tests/conformance/cases/traits/implements_numeric.expected.yaml +5 -0
  298. ofplang_validate-0.1.0/tests/conformance/cases/traits/implements_numeric.yaml +12 -0
  299. ofplang_validate-0.1.0/tests/conformance/cases/traits/redeclare_numeric.expected.yaml +5 -0
  300. ofplang_validate-0.1.0/tests/conformance/cases/traits/redeclare_numeric.yaml +9 -0
  301. ofplang_validate-0.1.0/tests/conformance/cases/traits/unknown_trait.expected.yaml +5 -0
  302. ofplang_validate-0.1.0/tests/conformance/cases/traits/unknown_trait.yaml +12 -0
  303. ofplang_validate-0.1.0/tests/conformance/cases/traits/valid_implements.expected.yaml +2 -0
  304. ofplang_validate-0.1.0/tests/conformance/cases/traits/valid_implements.yaml +18 -0
  305. ofplang_validate-0.1.0/tests/conformance/cases/transforms/array_role_not_array.expected.yaml +5 -0
  306. ofplang_validate-0.1.0/tests/conformance/cases/transforms/array_role_not_array.yaml +27 -0
  307. ofplang_validate-0.1.0/tests/conformance/cases/transforms/missing_role.expected.yaml +5 -0
  308. ofplang_validate-0.1.0/tests/conformance/cases/transforms/missing_role.yaml +27 -0
  309. ofplang_validate-0.1.0/tests/conformance/cases/transforms/pure_data_in_transform.expected.yaml +5 -0
  310. ofplang_validate-0.1.0/tests/conformance/cases/transforms/pure_data_in_transform.yaml +24 -0
  311. ofplang_validate-0.1.0/tests/conformance/cases/transforms/role_type_mismatch.expected.yaml +4 -0
  312. ofplang_validate-0.1.0/tests/conformance/cases/transforms/role_type_mismatch.yaml +33 -0
  313. ofplang_validate-0.1.0/tests/conformance/cases/transforms/transform_path_not_found.expected.yaml +7 -0
  314. ofplang_validate-0.1.0/tests/conformance/cases/transforms/transform_path_not_found.yaml +27 -0
  315. ofplang_validate-0.1.0/tests/conformance/cases/transforms/unknown_transform_kind.expected.yaml +5 -0
  316. ofplang_validate-0.1.0/tests/conformance/cases/transforms/unknown_transform_kind.yaml +27 -0
  317. ofplang_validate-0.1.0/tests/conformance/cases/transforms/valid_array_cons.expected.yaml +2 -0
  318. ofplang_validate-0.1.0/tests/conformance/cases/transforms/valid_array_cons.yaml +31 -0
  319. ofplang_validate-0.1.0/tests/conformance/cases/transforms/valid_array_reverse.expected.yaml +2 -0
  320. ofplang_validate-0.1.0/tests/conformance/cases/transforms/valid_array_reverse.yaml +27 -0
  321. ofplang_validate-0.1.0/tests/conformance/cases/transforms/valid_array_uncons.expected.yaml +2 -0
  322. ofplang_validate-0.1.0/tests/conformance/cases/transforms/valid_array_uncons.yaml +31 -0
  323. ofplang_validate-0.1.0/tests/conformance/cases/transforms/valid_nested_uncons.expected.yaml +2 -0
  324. ofplang_validate-0.1.0/tests/conformance/cases/transforms/valid_nested_uncons.yaml +31 -0
  325. ofplang_validate-0.1.0/tests/conformance/cases/types/array_arity.expected.yaml +5 -0
  326. ofplang_validate-0.1.0/tests/conformance/cases/types/array_arity.yaml +13 -0
  327. ofplang_validate-0.1.0/tests/conformance/cases/types/array_arity_zero.expected.yaml +5 -0
  328. ofplang_validate-0.1.0/tests/conformance/cases/types/array_arity_zero.yaml +10 -0
  329. ofplang_validate-0.1.0/tests/conformance/cases/types/array_internal_whitespace.expected.yaml +2 -0
  330. ofplang_validate-0.1.0/tests/conformance/cases/types/array_internal_whitespace.yaml +10 -0
  331. ofplang_validate-0.1.0/tests/conformance/cases/types/malformed_array_space.expected.yaml +5 -0
  332. ofplang_validate-0.1.0/tests/conformance/cases/types/malformed_array_space.yaml +13 -0
  333. ofplang_validate-0.1.0/tests/conformance/cases/types/redeclare_builtin.expected.yaml +5 -0
  334. ofplang_validate-0.1.0/tests/conformance/cases/types/redeclare_builtin.yaml +10 -0
  335. ofplang_validate-0.1.0/tests/conformance/cases/types/type_field_not_string.expected.yaml +4 -0
  336. ofplang_validate-0.1.0/tests/conformance/cases/types/type_field_not_string.yaml +10 -0
  337. ofplang_validate-0.1.0/tests/conformance/cases/types/unknown_type.expected.yaml +5 -0
  338. ofplang_validate-0.1.0/tests/conformance/cases/types/unknown_type.yaml +10 -0
  339. ofplang_validate-0.1.0/tests/conformance/cases/types/valid_user_and_array.expected.yaml +2 -0
  340. ofplang_validate-0.1.0/tests/conformance/cases/types/valid_user_and_array.yaml +16 -0
  341. ofplang_validate-0.1.0/tests/conformance/cases/views/invalid_view_field_type.expected.yaml +4 -0
  342. ofplang_validate-0.1.0/tests/conformance/cases/views/invalid_view_field_type.yaml +15 -0
  343. ofplang_validate-0.1.0/tests/conformance/cases/views/null_static_value.expected.yaml +4 -0
  344. ofplang_validate-0.1.0/tests/conformance/cases/views/null_static_value.yaml +14 -0
  345. ofplang_validate-0.1.0/tests/conformance/cases/views/object_bearing_view_field.expected.yaml +5 -0
  346. ofplang_validate-0.1.0/tests/conformance/cases/views/object_bearing_view_field.yaml +15 -0
  347. ofplang_validate-0.1.0/tests/conformance/cases/views/static_value_type_mismatch.expected.yaml +5 -0
  348. ofplang_validate-0.1.0/tests/conformance/cases/views/static_value_type_mismatch.yaml +14 -0
  349. ofplang_validate-0.1.0/tests/conformance/cases/views/valid_static_value.expected.yaml +2 -0
  350. ofplang_validate-0.1.0/tests/conformance/cases/views/valid_static_value.yaml +14 -0
  351. ofplang_validate-0.1.0/tests/conformance/cases.py +153 -0
  352. ofplang_validate-0.1.0/tests/conformance/test_conformance.py +125 -0
  353. ofplang_validate-0.1.0/tests/test_cli.py +65 -0
  354. ofplang_validate-0.1.0/tests/test_positions.py +106 -0
@@ -0,0 +1,45 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+ cache: pip
22
+ - run: pip install -e ".[test]"
23
+ - run: pytest
24
+
25
+ lint:
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - uses: actions/setup-python@v5
30
+ with:
31
+ python-version: "3.12"
32
+ cache: pip
33
+ - run: pip install -e ".[dev]"
34
+ - run: ruff check ofplang tests
35
+
36
+ typecheck:
37
+ runs-on: ubuntu-latest
38
+ steps:
39
+ - uses: actions/checkout@v4
40
+ - uses: actions/setup-python@v5
41
+ with:
42
+ python-version: "3.12"
43
+ cache: pip
44
+ - run: pip install -e ".[dev]"
45
+ - run: mypy
@@ -0,0 +1,93 @@
1
+ name: Publish
2
+
3
+ # Tag-driven release via PyPI Trusted Publishing (OIDC) — no API tokens.
4
+ #
5
+ # Version comes from the pushed git tag via setuptools-scm (`v0.1.0` -> 0.1.0).
6
+ # Routing:
7
+ # - a pre-release tag containing `rc` (e.g. v0.1.0rc1) -> TestPyPI (rehearsal)
8
+ # - any other `v*` tag (e.g. v0.1.0) -> PyPI (production)
9
+ # - manual workflow_dispatch -> choose the target explicitly (run it from a
10
+ # tagged commit, else setuptools-scm yields a dev+local version PyPI rejects)
11
+ #
12
+ # PyPI-side setup (done once, by the project owner): register a Trusted Publisher
13
+ # for owner=ofplang, repo=validate, workflow=publish.yml, environment=pypi
14
+ # (and environment=testpypi on TestPyPI). First release: register as "pending".
15
+
16
+ on:
17
+ push:
18
+ tags: ["v*"]
19
+ workflow_dispatch:
20
+ inputs:
21
+ target:
22
+ description: "Publish target"
23
+ type: choice
24
+ options: [testpypi, pypi]
25
+ default: testpypi
26
+
27
+ jobs:
28
+ build:
29
+ runs-on: ubuntu-latest
30
+ steps:
31
+ - uses: actions/checkout@v4
32
+ with:
33
+ # setuptools-scm derives the version from tags + history.
34
+ fetch-depth: 0
35
+ - uses: actions/setup-python@v5
36
+ with:
37
+ python-version: "3.12"
38
+ - run: python -m pip install --upgrade build twine
39
+ - run: python -m build
40
+ - run: twine check dist/*
41
+ # Guard against ambiguous tags: the built version (from setuptools-scm) must
42
+ # equal the pushed tag — e.g. tag v0.1.0 must build 0.1.0. Catches a commit
43
+ # carrying two tags (an rc and a release) where git describe can resolve to
44
+ # the wrong one and publish the wrong artifact.
45
+ - name: Verify built version matches tag
46
+ if: startsWith(github.ref, 'refs/tags/')
47
+ shell: bash
48
+ run: |
49
+ tag="${GITHUB_REF_NAME#v}"
50
+ built="$(ls dist/*.tar.gz | sed -E 's#.*/[^/]*-([0-9][^-]*)\.tar\.gz#\1#')"
51
+ echo "tag=$tag built=$built"
52
+ if [ "$tag" != "$built" ]; then
53
+ echo "::error::built version $built != tag $tag (ambiguous or misplaced tag?)"
54
+ exit 1
55
+ fi
56
+ - uses: actions/upload-artifact@v4
57
+ with:
58
+ name: dist
59
+ path: dist/
60
+
61
+ publish-testpypi:
62
+ needs: build
63
+ if: >-
64
+ github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
65
+ || (github.event_name == 'push' && contains(github.ref_name, 'rc'))
66
+ runs-on: ubuntu-latest
67
+ environment: testpypi
68
+ permissions:
69
+ id-token: write
70
+ steps:
71
+ - uses: actions/download-artifact@v4
72
+ with:
73
+ name: dist
74
+ path: dist/
75
+ - uses: pypa/gh-action-pypi-publish@release/v1
76
+ with:
77
+ repository-url: https://test.pypi.org/legacy/
78
+
79
+ publish-pypi:
80
+ needs: build
81
+ if: >-
82
+ github.event_name == 'workflow_dispatch' && inputs.target == 'pypi'
83
+ || (github.event_name == 'push' && !contains(github.ref_name, 'rc'))
84
+ runs-on: ubuntu-latest
85
+ environment: pypi
86
+ permissions:
87
+ id-token: write
88
+ steps:
89
+ - uses: actions/download-artifact@v4
90
+ with:
91
+ name: dist
92
+ path: dist/
93
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .pytest_cache/
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ venv/
9
+
10
+ # Local working notes, not part of the published project (until explicitly committed).
11
+ CLAUDE.md
12
+ dev-notes/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kazunari Kaizu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: ofplang-validate
3
+ Version: 0.1.0
4
+ Summary: Object-flow programming language v0 validator
5
+ Author-email: Kazunari Kaizu <kwaizu@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/ofplang/validate
8
+ Project-URL: Repository, https://github.com/ofplang/validate
9
+ Keywords: ofplang,dataflow,workflow,validator,yaml
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Compilers
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: PyYAML>=6.0
24
+ Provides-Extra: test
25
+ Requires-Dist: pytest>=7.0; extra == "test"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == "dev"
28
+ Requires-Dist: ruff>=0.16; extra == "dev"
29
+ Requires-Dist: mypy>=1.11; extra == "dev"
30
+ Requires-Dist: types-PyYAML; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # ofplang validate
34
+
35
+ [![CI](https://github.com/ofplang/validate/actions/workflows/ci.yml/badge.svg)](https://github.com/ofplang/validate/actions/workflows/ci.yml)
36
+ [![PyPI](https://img.shields.io/pypi/v/ofplang-validate.svg)](https://pypi.org/project/ofplang-validate/)
37
+
38
+ A validator for **Object-flow Programming Language v0** — a YAML-based dataflow
39
+ workflow IR with linear Object tracking. The language is defined in the
40
+ [ofplang/spec](https://github.com/ofplang/spec) repository.
41
+
42
+ The validator checks that a document is well-formed portable v0: structure and
43
+ types, the feature model, linear Object tracking, structured nodes, contracts,
44
+ and scheduling policies. It reports findings as stable **error codes** rather
45
+ than free text, so results are easy to consume in tests and tooling.
46
+
47
+ ## Install
48
+
49
+ ```sh
50
+ pip install ofplang-validate
51
+ ```
52
+
53
+ Requires Python 3.10+. The only runtime dependency is PyYAML. For development,
54
+ install editable with the test extra from a clone:
55
+
56
+ ```sh
57
+ pip install -e ".[test]"
58
+ ```
59
+
60
+ ## Command line
61
+
62
+ ```sh
63
+ ofp-validate <file>... # or: python -m ofplang.validate <file>...
64
+ ofp-validate --mode extension-tolerant doc.yaml
65
+ ofp-validate --format json doc.yaml
66
+ ```
67
+
68
+ Options: `--mode {strict,extension-tolerant}`, `--format {text,json}`,
69
+ `-q/--quiet`, `--no-color`.
70
+
71
+ Exit codes: `0` all valid, `1` validation errors found, `2` usage/input error.
72
+
73
+ ```
74
+ $ ofp-validate workflow.yaml
75
+ workflow.yaml:7:15: error unknown_type processes.main.inputs.x.type unknown type in 'Foo'
76
+ 1 error in 1 of 1 file
77
+ ```
78
+
79
+ Diagnostics carry a `file:line:col` source position (an imported fragment's own
80
+ file when the problem is inside an `$import`); `--format json` includes
81
+ `file`/`line`/`col` fields.
82
+
83
+ This tool is also intended to be exposed as the `validate` subcommand of the
84
+ umbrella `ofp` CLI (a separate repository in the `ofplang` organization).
85
+
86
+ ## Library
87
+
88
+ ```python
89
+ from ofplang.validate import validate
90
+
91
+ result = validate("workflow.yaml", mode="strict")
92
+ if not result.ok:
93
+ for d in result.diagnostics:
94
+ print(d.code, d.path, d.message)
95
+ ```
96
+
97
+ `validate(source, *, mode="strict")` returns a `ValidationResult` with `.ok` and
98
+ `.diagnostics` (each a `Diagnostic(code, message, path, file, line, col)`). The
99
+ validator collects all independent findings rather than stopping at the first;
100
+ only a YAML parse or `$import` resolution failure is terminal.
101
+
102
+ The package lives under the `ofplang` PEP 420 namespace (`ofplang.validate`),
103
+ shared across the organization's tools.
104
+
105
+ ## Scope
106
+
107
+ Covers graph-time validation of portable v0. Runtime failures, and run/data-phase
108
+ preflight checks, are out of scope (spec §6.2, §25). Two modes are supported:
109
+ `strict` (portable v0) and `extension-tolerant` (accepts `x-` extension keys).
110
+
111
+ ## Tests
112
+
113
+ The behavior is pinned by a spec-derived conformance suite that matches on error
114
+ codes (see [tests/conformance/README.md](tests/conformance/README.md)).
115
+
116
+ ```sh
117
+ pytest # run everything
118
+ OFPLANG_STRICT_TESTS=1 pytest # full contract, no pending escapes
119
+ ```
@@ -0,0 +1,87 @@
1
+ # ofplang validate
2
+
3
+ [![CI](https://github.com/ofplang/validate/actions/workflows/ci.yml/badge.svg)](https://github.com/ofplang/validate/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/ofplang-validate.svg)](https://pypi.org/project/ofplang-validate/)
5
+
6
+ A validator for **Object-flow Programming Language v0** — a YAML-based dataflow
7
+ workflow IR with linear Object tracking. The language is defined in the
8
+ [ofplang/spec](https://github.com/ofplang/spec) repository.
9
+
10
+ The validator checks that a document is well-formed portable v0: structure and
11
+ types, the feature model, linear Object tracking, structured nodes, contracts,
12
+ and scheduling policies. It reports findings as stable **error codes** rather
13
+ than free text, so results are easy to consume in tests and tooling.
14
+
15
+ ## Install
16
+
17
+ ```sh
18
+ pip install ofplang-validate
19
+ ```
20
+
21
+ Requires Python 3.10+. The only runtime dependency is PyYAML. For development,
22
+ install editable with the test extra from a clone:
23
+
24
+ ```sh
25
+ pip install -e ".[test]"
26
+ ```
27
+
28
+ ## Command line
29
+
30
+ ```sh
31
+ ofp-validate <file>... # or: python -m ofplang.validate <file>...
32
+ ofp-validate --mode extension-tolerant doc.yaml
33
+ ofp-validate --format json doc.yaml
34
+ ```
35
+
36
+ Options: `--mode {strict,extension-tolerant}`, `--format {text,json}`,
37
+ `-q/--quiet`, `--no-color`.
38
+
39
+ Exit codes: `0` all valid, `1` validation errors found, `2` usage/input error.
40
+
41
+ ```
42
+ $ ofp-validate workflow.yaml
43
+ workflow.yaml:7:15: error unknown_type processes.main.inputs.x.type unknown type in 'Foo'
44
+ 1 error in 1 of 1 file
45
+ ```
46
+
47
+ Diagnostics carry a `file:line:col` source position (an imported fragment's own
48
+ file when the problem is inside an `$import`); `--format json` includes
49
+ `file`/`line`/`col` fields.
50
+
51
+ This tool is also intended to be exposed as the `validate` subcommand of the
52
+ umbrella `ofp` CLI (a separate repository in the `ofplang` organization).
53
+
54
+ ## Library
55
+
56
+ ```python
57
+ from ofplang.validate import validate
58
+
59
+ result = validate("workflow.yaml", mode="strict")
60
+ if not result.ok:
61
+ for d in result.diagnostics:
62
+ print(d.code, d.path, d.message)
63
+ ```
64
+
65
+ `validate(source, *, mode="strict")` returns a `ValidationResult` with `.ok` and
66
+ `.diagnostics` (each a `Diagnostic(code, message, path, file, line, col)`). The
67
+ validator collects all independent findings rather than stopping at the first;
68
+ only a YAML parse or `$import` resolution failure is terminal.
69
+
70
+ The package lives under the `ofplang` PEP 420 namespace (`ofplang.validate`),
71
+ shared across the organization's tools.
72
+
73
+ ## Scope
74
+
75
+ Covers graph-time validation of portable v0. Runtime failures, and run/data-phase
76
+ preflight checks, are out of scope (spec §6.2, §25). Two modes are supported:
77
+ `strict` (portable v0) and `extension-tolerant` (accepts `x-` extension keys).
78
+
79
+ ## Tests
80
+
81
+ The behavior is pinned by a spec-derived conformance suite that matches on error
82
+ codes (see [tests/conformance/README.md](tests/conformance/README.md)).
83
+
84
+ ```sh
85
+ pytest # run everything
86
+ OFPLANG_STRICT_TESTS=1 pytest # full contract, no pending escapes
87
+ ```
@@ -0,0 +1,19 @@
1
+ """ofplang.validate -- validator for Object-flow Programming Language v0."""
2
+
3
+ from ofplang.validate.validator import (
4
+ EXTENSION_TOLERANT,
5
+ MODES,
6
+ STRICT,
7
+ Diagnostic,
8
+ ValidationResult,
9
+ validate,
10
+ )
11
+
12
+ __all__ = [
13
+ "Diagnostic",
14
+ "ValidationResult",
15
+ "validate",
16
+ "STRICT",
17
+ "EXTENSION_TOLERANT",
18
+ "MODES",
19
+ ]
@@ -0,0 +1,9 @@
1
+ """Enable `python -m ofplang <file>...`.
2
+
3
+ Intent: mirror the console-script entry point so the CLI is reachable without an
4
+ installed script, which is convenient in dev checkouts and CI.
5
+ """
6
+
7
+ from ofplang.validate.cli import main
8
+
9
+ raise SystemExit(main())
@@ -0,0 +1,178 @@
1
+ """Command-line interface for the ofplang v0 validator.
2
+
3
+ Intent: this is a thin presentation layer over :func:`ofplang.validate.validate` — it
4
+ does no validation itself, it only parses arguments, drives the library over one
5
+ or more files, and renders results. Keeping all logic in the library means the
6
+ CLI cannot drift from the conformance-tested behavior.
7
+
8
+ Usage:
9
+ ofp-validate [--mode {strict,extension-tolerant}] [--format {text,json}]
10
+ [-q/--quiet] [--no-color] <file>...
11
+
12
+ Also invocable as `python -m ofplang.validate`, and (once installed) as the
13
+ `validate` subcommand of the umbrella `ofp` CLI.
14
+
15
+ Exit codes (linter convention):
16
+ 0 every file is valid
17
+ 1 at least one file has validation errors
18
+ 2 usage / input error (bad arguments, missing input file)
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import argparse
24
+ import json
25
+ import sys
26
+ from pathlib import Path
27
+
28
+ from ofplang.validate import validate
29
+ from ofplang.validate.validator import EXTENSION_TOLERANT, STRICT, ValidationResult
30
+
31
+ # Exit codes are part of the CLI contract (scripts/CI depend on them).
32
+ EXIT_OK = 0
33
+ EXIT_INVALID = 1
34
+ EXIT_USAGE = 2
35
+
36
+ # ANSI colors, applied only when writing to a TTY and not disabled.
37
+ _RED = "\033[31m"
38
+ _GREEN = "\033[32m"
39
+ _DIM = "\033[2m"
40
+ _RESET = "\033[0m"
41
+
42
+
43
+ def _build_parser() -> argparse.ArgumentParser:
44
+ parser = argparse.ArgumentParser(
45
+ prog="ofp-validate",
46
+ description="Validate ofplang v0 documents.",
47
+ )
48
+ parser.add_argument("paths", nargs="+", metavar="FILE", help="document(s) to validate")
49
+ parser.add_argument(
50
+ "--mode",
51
+ choices=[STRICT, EXTENSION_TOLERANT],
52
+ default=STRICT,
53
+ help="validation mode (default: strict)",
54
+ )
55
+ parser.add_argument(
56
+ "--format",
57
+ choices=["text", "json"],
58
+ default="text",
59
+ help="output format (default: text)",
60
+ )
61
+ parser.add_argument(
62
+ "-q",
63
+ "--quiet",
64
+ action="store_true",
65
+ help="suppress per-diagnostic lines; show only the summary",
66
+ )
67
+ parser.add_argument("--no-color", action="store_true", help="disable ANSI color output")
68
+ return parser
69
+
70
+
71
+ def _color_enabled(no_color: bool) -> bool:
72
+ # Color only when explicitly allowed AND attached to a terminal, so piped or
73
+ # redirected output stays clean and parseable.
74
+ return not no_color and sys.stdout.isatty()
75
+
76
+
77
+ def _render_text(results: list[tuple[str, ValidationResult]], quiet: bool, color: bool) -> str:
78
+ """Human-oriented report. One block per file, then a one-line summary."""
79
+ def c(text: str, code: str) -> str:
80
+ return f"{code}{text}{_RESET}" if color else text
81
+
82
+ lines: list[str] = []
83
+ total_errors = 0
84
+ invalid_files = 0
85
+ multi = len(results) > 1
86
+
87
+ for path, result in results:
88
+ if result.ok:
89
+ # Only announce OK files explicitly when validating several, so
90
+ # single-file runs stay terse.
91
+ if not quiet and multi:
92
+ lines.append(f"{path}: {c('OK', _GREEN)}")
93
+ continue
94
+ invalid_files += 1
95
+ total_errors += len(result.diagnostics)
96
+ if multi:
97
+ lines.append(f"{path}:")
98
+ if not quiet:
99
+ for d in result.diagnostics:
100
+ # Prefer a concrete source position as the locator; fall back to
101
+ # the logical path. When both exist, show the path as a dim
102
+ # trailing detail (position primary, path for context).
103
+ if d.location:
104
+ locator = d.location
105
+ detail = f" {c(d.path, _DIM)}" if d.path else ""
106
+ else:
107
+ locator = d.path or "<root>"
108
+ detail = ""
109
+ msg = f" {d.message}" if d.message else ""
110
+ indent = " " if multi else ""
111
+ lines.append(f"{indent}{locator}: {c('error', _RED)} {d.code}{detail}{msg}")
112
+
113
+ if total_errors == 0:
114
+ lines.append(
115
+ c(f"all valid ({len(results)} file{'s' if len(results) != 1 else ''})", _GREEN)
116
+ )
117
+ else:
118
+ lines.append(
119
+ c(f"{total_errors} error{'s' if total_errors != 1 else ''} in "
120
+ f"{invalid_files} of {len(results)} file{'s' if len(results) != 1 else ''}", _RED)
121
+ )
122
+ return "\n".join(lines)
123
+
124
+
125
+ def _render_json(results: list[tuple[str, ValidationResult]]) -> str:
126
+ """Machine-readable report for CI/editor integration."""
127
+ payload = {
128
+ "ok": all(r.ok for _, r in results),
129
+ "results": [
130
+ {
131
+ "file": path,
132
+ "ok": result.ok,
133
+ "diagnostics": [
134
+ {
135
+ "code": d.code,
136
+ "path": d.path,
137
+ "message": d.message,
138
+ "file": d.file,
139
+ "line": d.line,
140
+ "col": d.col,
141
+ }
142
+ for d in result.diagnostics
143
+ ],
144
+ }
145
+ for path, result in results
146
+ ],
147
+ }
148
+ return json.dumps(payload, indent=2, ensure_ascii=False)
149
+
150
+
151
+ def main(argv: list[str] | None = None) -> int:
152
+ parser = _build_parser()
153
+ args = parser.parse_args(argv)
154
+
155
+ # Pre-check inputs so a mistyped/missing path is a usage error (exit 2)
156
+ # rather than being reported as an in-document diagnostic.
157
+ missing = [p for p in args.paths if not Path(p).is_file()]
158
+ if missing:
159
+ for p in missing:
160
+ print(f"ofp-validate: cannot open {p!r}: no such file", file=sys.stderr)
161
+ return EXIT_USAGE
162
+
163
+ # Validate each file via the library (the sole source of truth).
164
+ results: list[tuple[str, ValidationResult]] = [
165
+ (p, validate(p, mode=args.mode)) for p in args.paths
166
+ ]
167
+
168
+ if args.format == "json":
169
+ print(_render_json(results))
170
+ else:
171
+ print(_render_text(results, args.quiet, _color_enabled(args.no_color)))
172
+
173
+ # Exit code reflects the worst outcome across all inputs.
174
+ return EXIT_OK if all(r.ok for _, r in results) else EXIT_INVALID
175
+
176
+
177
+ if __name__ == "__main__": # pragma: no cover - module entry
178
+ raise SystemExit(main())