codeplain 0.3.8__tar.gz → 0.3.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. {codeplain-0.3.8 → codeplain-0.3.9}/.github/workflows/publish-install-script.yml +17 -0
  2. {codeplain-0.3.8 → codeplain-0.3.9}/.github/workflows/publish-to-pypi.yml +34 -0
  3. {codeplain-0.3.8 → codeplain-0.3.9}/CLAUDE.md +6 -2
  4. {codeplain-0.3.8 → codeplain-0.3.9}/PKG-INFO +1 -1
  5. {codeplain-0.3.8 → codeplain-0.3.9}/docs/plain2code_cli.md +22 -20
  6. {codeplain-0.3.8 → codeplain-0.3.9}/docs/starting_a_plain_project_from_scratch.md +8 -2
  7. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_golang/run.sh +2 -2
  8. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_python/run.sh +2 -2
  9. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_react/run.sh +1 -1
  10. {codeplain-0.3.8 → codeplain-0.3.9}/git_utils.py +0 -10
  11. {codeplain-0.3.8 → codeplain-0.3.9}/memory_management.py +2 -3
  12. codeplain-0.3.9/metadata_utils.py +46 -0
  13. {codeplain-0.3.8 → codeplain-0.3.9}/module_renderer.py +3 -6
  14. {codeplain-0.3.8 → codeplain-0.3.9}/plain2code.py +6 -1
  15. {codeplain-0.3.8 → codeplain-0.3.9}/plain2code_arguments.py +6 -15
  16. {codeplain-0.3.8 → codeplain-0.3.9}/plain2code_cli.md +17 -19
  17. {codeplain-0.3.8 → codeplain-0.3.9}/plain2code_telemetry.py +17 -11
  18. {codeplain-0.3.8 → codeplain-0.3.9}/plain_modules.py +73 -41
  19. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/prepare_repositories.py +3 -10
  20. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/conformance_tests.py +8 -6
  21. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/render_context.py +1 -3
  22. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/render_utils.py +1 -2
  23. {codeplain-0.3.8 → codeplain-0.3.9}/system_config.py +45 -0
  24. {codeplain-0.3.8 → codeplain-0.3.9}/tests/e2e/test_hello_world_python.py +1 -1
  25. {codeplain-0.3.8 → codeplain-0.3.9}/tests/e2e/test_hello_world_python_windows.py +1 -1
  26. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_arg_provenance.py +3 -3
  27. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_folder_path_resolution.py +12 -13
  28. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_plain2code.py +1 -2
  29. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_plain_modules.py +200 -15
  30. codeplain-0.3.9/tests/test_prepare_repositories_layout.py +119 -0
  31. codeplain-0.3.9/tests/test_system_config.py +58 -0
  32. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_telemetry.py +31 -10
  33. {codeplain-0.3.8 → codeplain-0.3.9}/.claude/settings.json +0 -0
  34. {codeplain-0.3.8 → codeplain-0.3.9}/.flake8 +0 -0
  35. {codeplain-0.3.8 → codeplain-0.3.9}/.github/dependabot.yml +0 -0
  36. {codeplain-0.3.8 → codeplain-0.3.9}/.github/workflows/e2e.yml +0 -0
  37. {codeplain-0.3.8 → codeplain-0.3.9}/.github/workflows/lint-and-test.yml +0 -0
  38. {codeplain-0.3.8 → codeplain-0.3.9}/.github/workflows/nofity-slack-on-main-merge.yml +0 -0
  39. {codeplain-0.3.8 → codeplain-0.3.9}/.gitignore +0 -0
  40. {codeplain-0.3.8 → codeplain-0.3.9}/.vscode/launch.json +0 -0
  41. {codeplain-0.3.8 → codeplain-0.3.9}/.vscode/settings.json +0 -0
  42. {codeplain-0.3.8 → codeplain-0.3.9}/LICENSE +0 -0
  43. {codeplain-0.3.8 → codeplain-0.3.9}/README.md +0 -0
  44. {codeplain-0.3.8 → codeplain-0.3.9}/change_detection.py +0 -0
  45. {codeplain-0.3.8 → codeplain-0.3.9}/cli_output/__init__.py +0 -0
  46. {codeplain-0.3.8 → codeplain-0.3.9}/cli_output/dry_run.py +0 -0
  47. {codeplain-0.3.8 → codeplain-0.3.9}/cli_output/render_summary.py +0 -0
  48. {codeplain-0.3.8 → codeplain-0.3.9}/cli_output/status.py +0 -0
  49. {codeplain-0.3.8 → codeplain-0.3.9}/codeplain_REST_api.py +0 -0
  50. {codeplain-0.3.8 → codeplain-0.3.9}/concept_utils.py +0 -0
  51. {codeplain-0.3.8 → codeplain-0.3.9}/config/__init__.py +0 -0
  52. {codeplain-0.3.8 → codeplain-0.3.9}/config/system_config.yaml +0 -0
  53. {codeplain-0.3.8 → codeplain-0.3.9}/diff_utils.py +0 -0
  54. {codeplain-0.3.8 → codeplain-0.3.9}/docs/generate_cli.py +0 -0
  55. {codeplain-0.3.8 → codeplain-0.3.9}/event_bus.py +0 -0
  56. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_golang/config.yaml +0 -0
  57. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
  58. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
  59. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_python/config.yaml +0 -0
  60. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
  61. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_python/hello_world_python.plain +0 -0
  62. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_react/config.yaml +0 -0
  63. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
  64. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
  65. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
  66. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
  67. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
  68. {codeplain-0.3.8 → codeplain-0.3.9}/examples/example_hello_world_react/hello_world_react.plain +0 -0
  69. {codeplain-0.3.8 → codeplain-0.3.9}/examples/run.sh +0 -0
  70. {codeplain-0.3.8 → codeplain-0.3.9}/file_utils.py +0 -0
  71. {codeplain-0.3.8 → codeplain-0.3.9}/install/bash/examples.sh +0 -0
  72. {codeplain-0.3.8 → codeplain-0.3.9}/install/bash/install.sh +0 -0
  73. {codeplain-0.3.8 → codeplain-0.3.9}/install/bash/walkthrough.sh +0 -0
  74. {codeplain-0.3.8 → codeplain-0.3.9}/install/powershell/examples.ps1 +0 -0
  75. {codeplain-0.3.8 → codeplain-0.3.9}/install/powershell/install.ps1 +0 -0
  76. {codeplain-0.3.8 → codeplain-0.3.9}/install/powershell/walkthrough.ps1 +0 -0
  77. {codeplain-0.3.8 → codeplain-0.3.9}/partial_rendering.py +0 -0
  78. {codeplain-0.3.8 → codeplain-0.3.9}/path_resolution.py +0 -0
  79. {codeplain-0.3.8 → codeplain-0.3.9}/plain2code_console.py +0 -0
  80. {codeplain-0.3.8 → codeplain-0.3.9}/plain2code_events.py +0 -0
  81. {codeplain-0.3.8 → codeplain-0.3.9}/plain2code_exceptions.py +0 -0
  82. {codeplain-0.3.8 → codeplain-0.3.9}/plain2code_logger.py +0 -0
  83. {codeplain-0.3.8 → codeplain-0.3.9}/plain2code_nodes.py +0 -0
  84. {codeplain-0.3.8 → codeplain-0.3.9}/plain2code_read_config.py +0 -0
  85. {codeplain-0.3.8 → codeplain-0.3.9}/plain2code_state.py +0 -0
  86. {codeplain-0.3.8 → codeplain-0.3.9}/plain2code_utils.py +0 -0
  87. {codeplain-0.3.8 → codeplain-0.3.9}/plain_file.py +0 -0
  88. {codeplain-0.3.8 → codeplain-0.3.9}/plain_spec.py +0 -0
  89. {codeplain-0.3.8 → codeplain-0.3.9}/pyproject.toml +0 -0
  90. {codeplain-0.3.8 → codeplain-0.3.9}/pytest.ini +0 -0
  91. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/__init__.py +0 -0
  92. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/analyze_specification_ambiguity.py +0 -0
  93. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/base_action.py +0 -0
  94. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
  95. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/commit_implementation_code_changes.py +0 -0
  96. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/create_dist.py +0 -0
  97. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/exit_with_error.py +0 -0
  98. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/finish_functional_requirement.py +0 -0
  99. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/fix_conformance_test.py +0 -0
  100. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/fix_unit_tests.py +0 -0
  101. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/prepare_testing_environment.py +0 -0
  102. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/refactor_code.py +0 -0
  103. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/render_conformance_tests.py +0 -0
  104. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/render_functional_requirement.py +0 -0
  105. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/run_conformance_tests.py +0 -0
  106. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/run_unit_tests.py +0 -0
  107. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/actions/summarize_conformance_tests.py +0 -0
  108. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/code_renderer.py +0 -0
  109. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/implementation_code_helpers.py +0 -0
  110. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/render_types.py +0 -0
  111. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/state_machine_config.py +0 -0
  112. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/states.py +0 -0
  113. {codeplain-0.3.8 → codeplain-0.3.9}/render_machine/triggers.py +0 -0
  114. {codeplain-0.3.8 → codeplain-0.3.9}/requirements.txt +0 -0
  115. {codeplain-0.3.8 → codeplain-0.3.9}/resources/codeplain_overview.png +0 -0
  116. {codeplain-0.3.8 → codeplain-0.3.9}/resources/plain_example.png +0 -0
  117. {codeplain-0.3.8 → codeplain-0.3.9}/standard_template_library/golang-console-app-template.plain +0 -0
  118. {codeplain-0.3.8 → codeplain-0.3.9}/standard_template_library/python-console-app-template.plain +0 -0
  119. {codeplain-0.3.8 → codeplain-0.3.9}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
  120. {codeplain-0.3.8 → codeplain-0.3.9}/standard_template_library/typescript-react-app-template.plain +0 -0
  121. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_conformance_tests_cypress.ps1 +0 -0
  122. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_conformance_tests_cypress.sh +0 -0
  123. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_conformance_tests_golang.ps1 +0 -0
  124. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_conformance_tests_golang.sh +0 -0
  125. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_conformance_tests_python.ps1 +0 -0
  126. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_conformance_tests_python.sh +0 -0
  127. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_unittests_flutter.ps1 +0 -0
  128. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_unittests_flutter.sh +0 -0
  129. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_unittests_golang.ps1 +0 -0
  130. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_unittests_golang.sh +0 -0
  131. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_unittests_python.ps1 +0 -0
  132. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_unittests_python.sh +0 -0
  133. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_unittests_react.ps1 +0 -0
  134. {codeplain-0.3.8 → codeplain-0.3.9}/test_scripts/run_unittests_react.sh +0 -0
  135. {codeplain-0.3.8 → codeplain-0.3.9}/tests/__init__.py +0 -0
  136. {codeplain-0.3.8 → codeplain-0.3.9}/tests/conftest.py +0 -0
  137. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/acceptance_tests_warning/main_requiring_acceptance_tests.plain +0 -0
  138. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/acceptance_tests_warning/required_with_acceptance_tests.plain +0 -0
  139. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/imports/circular_imports_1.plain +0 -0
  140. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/imports/circular_imports_2.plain +0 -0
  141. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/imports/circular_imports_main.plain +0 -0
  142. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/imports/diamond_import_1.plain +0 -0
  143. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/imports/diamond_import_2.plain +0 -0
  144. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/imports/diamond_import_common.plain +0 -0
  145. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/imports/diamond_imports_main.plain +0 -0
  146. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/imports/import_with_functionalities.plain +0 -0
  147. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/imports/imports_module_with_functionalities.plain +0 -0
  148. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/imports/non_existent_import.plain +0 -0
  149. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/partial_rendering/pr_code_var.plain +0 -0
  150. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/partial_rendering/pr_implement.plain +0 -0
  151. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/partial_rendering/pr_leaf.plain +0 -0
  152. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/partial_rendering/pr_middle.plain +0 -0
  153. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/partial_rendering/pr_root.plain +0 -0
  154. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/partial_rendering/pr_solo.plain +0 -0
  155. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfile/add_new_task_modal_specification.yaml +0 -0
  156. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
  157. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfile/empty_functional_specs_section.plain +0 -0
  158. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfile/invalid_specification_order.plain +0 -0
  159. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
  160. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfile/no_functional_specs_section.plain +0 -0
  161. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
  162. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
  163. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfile/task_list_ui_specification.yaml +0 -0
  164. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
  165. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
  166. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
  167. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
  168. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
  169. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
  170. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
  171. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
  172. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
  173. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
  174. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
  175. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
  176. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
  177. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/exported_concepts.plain +0 -0
  178. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
  179. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
  180. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/exported_concepts_missing.plain +0 -0
  181. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/exported_concepts_missing_example.plain +0 -0
  182. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
  183. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
  184. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
  185. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
  186. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
  187. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
  188. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
  189. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
  190. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/required_concepts.plain +0 -0
  191. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
  192. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
  193. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
  194. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
  195. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
  196. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
  197. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
  198. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
  199. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/topological_sort.plain +0 -0
  200. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
  201. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/circular_requires_main.plain +0 -0
  202. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/circular_requires_sub.plain +0 -0
  203. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/diamond_requires_1.plain +0 -0
  204. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/diamond_requires_2.plain +0 -0
  205. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/diamond_requires_common.plain +0 -0
  206. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/diamond_requires_main.plain +0 -0
  207. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/independent_requires_1.plain +0 -0
  208. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/independent_requires_2.plain +0 -0
  209. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/independent_requires_main.plain +0 -0
  210. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/non_existent_require.plain +0 -0
  211. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/normal_requires_1.plain +0 -0
  212. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/normal_requires_2.plain +0 -0
  213. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/normal_requires_common.plain +0 -0
  214. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/requires/normal_requires_main.plain +0 -0
  215. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/sample_base64_image.txt +0 -0
  216. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/simple.plain +0 -0
  217. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/templates/block_level_include.plain +0 -0
  218. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/templates/code_variables.plain +0 -0
  219. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/templates/header.plain +0 -0
  220. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/templates/implement.plain +0 -0
  221. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/templates/implement_2.plain +0 -0
  222. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/templates/template_include.plain +0 -0
  223. {codeplain-0.3.8 → codeplain-0.3.9}/tests/data/templates/test_hardest_problem.plain +0 -0
  224. {codeplain-0.3.8 → codeplain-0.3.9}/tests/e2e/Dockerfile +0 -0
  225. {codeplain-0.3.8 → codeplain-0.3.9}/tests/e2e/conftest.py +0 -0
  226. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_change_detection.py +0 -0
  227. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_cli_output.py +0 -0
  228. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_console_log_styles.py +0 -0
  229. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_file_utils.py +0 -0
  230. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_git_utils.py +0 -0
  231. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_imports.py +0 -0
  232. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_log_file_name_resolution.py +0 -0
  233. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_logging_config_path_resolution.py +0 -0
  234. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_partial_rendering.py +0 -0
  235. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_path_resolution.py +0 -0
  236. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_plain2code_state.py +0 -0
  237. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_plain2code_utils.py +0 -0
  238. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_plainfile.py +0 -0
  239. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_plainfileparser.py +0 -0
  240. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_plainspec.py +0 -0
  241. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_requires.py +0 -0
  242. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_resolve_config_file.py +0 -0
  243. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_script_path_resolution.py +0 -0
  244. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_tui_usage.py +0 -0
  245. {codeplain-0.3.8 → codeplain-0.3.9}/tests/test_usage_summary.py +0 -0
  246. {codeplain-0.3.8 → codeplain-0.3.9}/tui/__init__.py +0 -0
  247. {codeplain-0.3.8 → codeplain-0.3.9}/tui/components.py +0 -0
  248. {codeplain-0.3.8 → codeplain-0.3.9}/tui/models.py +0 -0
  249. {codeplain-0.3.8 → codeplain-0.3.9}/tui/plain2code_tui.py +0 -0
  250. {codeplain-0.3.8 → codeplain-0.3.9}/tui/plain_module_render_choice_tui.py +0 -0
  251. {codeplain-0.3.8 → codeplain-0.3.9}/tui/spinner.py +0 -0
  252. {codeplain-0.3.8 → codeplain-0.3.9}/tui/state_handlers.py +0 -0
  253. {codeplain-0.3.8 → codeplain-0.3.9}/tui/styles.css +0 -0
  254. {codeplain-0.3.8 → codeplain-0.3.9}/tui/widget_helpers.py +0 -0
  255. {codeplain-0.3.8 → codeplain-0.3.9}/usage_summary.py +0 -0
@@ -14,6 +14,9 @@ jobs:
14
14
  name: Upload to Cloudflare R2
15
15
  runs-on: ubuntu-latest
16
16
 
17
+ env:
18
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
19
+
17
20
  steps:
18
21
  - uses: actions/checkout@v4
19
22
 
@@ -54,3 +57,17 @@ jobs:
54
57
  --content-type "text/plain"
55
58
  echo "✓ examples.ps1 uploaded to R2"
56
59
 
60
+ - name: Notify Slack (success)
61
+ if: ${{ success() && env.SLACK_WEBHOOK_URL != '' }}
62
+ run: |
63
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
64
+ -H 'Content-type: application/json' \
65
+ --data "{\"text\":\"*Codeplain Client*: Install scripts deployed to R2 :white_check_mark: (\`${GITHUB_SHA:0:7}\`, by *${{ github.actor }}*).\"}"
66
+
67
+ - name: Notify Slack (failure)
68
+ if: ${{ failure() && env.SLACK_WEBHOOK_URL != '' }}
69
+ run: |
70
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
71
+ -H 'Content-type: application/json' \
72
+ --data "{\"text\":\"*Codeplain Client*: Install script deploy to R2 FAILED :x: (\`${GITHUB_SHA:0:7}\`). Users may be getting a stale installer. See <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|the run log>.\"}"
73
+
@@ -15,12 +15,22 @@ jobs:
15
15
  permissions:
16
16
  contents: write
17
17
 
18
+ env:
19
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
20
+
18
21
  steps:
19
22
  - uses: actions/checkout@v4
20
23
  with:
21
24
  # hatch-vcs derives the version from git tags, so we need full history.
22
25
  fetch-depth: 0
23
26
 
27
+ - name: Notify Slack (start)
28
+ if: ${{ env.SLACK_WEBHOOK_URL != '' }}
29
+ run: |
30
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
31
+ -H 'Content-type: application/json' \
32
+ --data "{\"text\":\"*Codeplain Client*: Release \`${{ github.ref_name }}\` published by *${{ github.actor }}* — building and publishing to PyPI...\"}"
33
+
24
34
  - name: Install uv
25
35
  # uv provisions its own Python (honoring requires-python), so no
26
36
  # separate actions/setup-python step is needed.
@@ -47,6 +57,13 @@ jobs:
47
57
  run: |
48
58
  gh release upload ${{ github.ref_name }} dist/* --clobber
49
59
 
60
+ - name: Notify Slack (build failure)
61
+ if: ${{ failure() && env.SLACK_WEBHOOK_URL != '' }}
62
+ run: |
63
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
64
+ -H 'Content-type: application/json' \
65
+ --data "{\"text\":\"*Codeplain Client*: Build of \`${{ github.ref_name }}\` FAILED :x:. Nothing was published to PyPI. See <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|the run log>.\"}"
66
+
50
67
  publish-to-pypi:
51
68
  name: Publish to PyPI
52
69
  needs: build
@@ -59,6 +76,9 @@ jobs:
59
76
  # authenticate this run — no long-lived API token needed.
60
77
  id-token: write
61
78
 
79
+ env:
80
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
81
+
62
82
  steps:
63
83
  - name: Download distribution packages
64
84
  uses: actions/download-artifact@v4
@@ -68,3 +88,17 @@ jobs:
68
88
 
69
89
  - name: Publish to PyPI
70
90
  uses: pypa/gh-action-pypi-publish@release/v1
91
+
92
+ - name: Notify Slack (success)
93
+ if: ${{ success() && env.SLACK_WEBHOOK_URL != '' }}
94
+ run: |
95
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
96
+ -H 'Content-type: application/json' \
97
+ --data "{\"text\":\"*Codeplain Client*: \`${{ github.ref_name }}\` published to PyPI :white_check_mark:. Install with \`pip install --upgrade codeplain\`.\"}"
98
+
99
+ - name: Notify Slack (failure)
100
+ if: ${{ failure() && env.SLACK_WEBHOOK_URL != '' }}
101
+ run: |
102
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
103
+ -H 'Content-type: application/json' \
104
+ --data "{\"text\":\"*Codeplain Client*: Publishing \`${{ github.ref_name }}\` to PyPI FAILED :x:. See <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|the run log>.\"}"
@@ -212,8 +212,12 @@ Two logging modes:
212
212
  ### Code Generation Process
213
213
  - Templates in `standard_template_library/` use Liquid2 syntax
214
214
  - Template search order: (1) `.plain` file dir, (2) `--template-dir`, (3) built-in standard lib
215
- - Generated code written to `build/` (configurable via `--build-folder`)
216
- - Each FRID render produces a git commit in build folder for rollback capability
215
+ - Each module renders into its own tree under the build folder (configurable via `--build-folder`, default `plain_modules/`):
216
+ - `<build-folder>/<module>/code/` implementation code (its own git repo)
217
+ - `<build-folder>/<module>/tests/` — conformance tests (its own git repo; only created when a conformance tests script is configured)
218
+ - `<build-folder>/<module>/.codeplain/` — module metadata (`module_metadata.json`), not tracked in git
219
+ - `<build-folder>/<module>/.memory/` — conformance test memory, not tracked in git
220
+ - Each FRID render produces a git commit in the `code/` and `tests/` repos for rollback capability
217
221
 
218
222
  ### Configuration
219
223
  - `config.yaml` can be placed in `.plain` file dir or CWD
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeplain
3
- Version: 0.3.8
3
+ Version: 0.3.9
4
4
  Summary: Transform plain language specifications into working code
5
5
  License-File: LICENSE
6
6
  Classifier: Environment :: Console
@@ -9,7 +9,6 @@ usage: generate_cli.py [-h] [--verbose] [--base-folder BASE_FOLDER]
9
9
  [--render-range RENDER_RANGE |
10
10
  --render-from RENDER_FROM] [--force-render]
11
11
  [--unittests-script UNITTESTS_SCRIPT]
12
- [--conformance-tests-folder CONFORMANCE_TESTS_FOLDER]
13
12
  [--conformance-tests-script CONFORMANCE_TESTS_SCRIPT]
14
13
  [--prepare-environment-script PREPARE_ENVIRONMENT_SCRIPT]
15
14
  [--test-script-timeout TEST_SCRIPT_TIMEOUT]
@@ -20,8 +19,8 @@ usage: generate_cli.py [-h] [--verbose] [--base-folder BASE_FOLDER]
20
19
  [--conformance-tests-dest CONFORMANCE_TESTS_DEST]
21
20
  [--render-machine-graph]
22
21
  [--logging-config-path LOGGING_CONFIG_PATH]
23
- [--headless]
24
- filename
22
+ [--headless] [--status] [--version]
23
+ [filename]
25
24
 
26
25
  Render plain code to target code. Path arguments resolve based on where they
27
26
  were written: values given on the command line are resolved against the
@@ -39,7 +38,7 @@ positional arguments:
39
38
 
40
39
  options:
41
40
  -h, --help show this help message and exit
42
- --verbose, -v Enable verbose output
41
+ --verbose, -v Set default log level to DEBUG for TUI and file logs
43
42
  --base-folder BASE_FOLDER
44
43
  Base folder for the build files
45
44
  --build-folder BUILD_FOLDER
@@ -66,18 +65,17 @@ options:
66
65
  --force-render Force re-render of all the required modules.
67
66
  --unittests-script UNITTESTS_SCRIPT
68
67
  Shell script to run unit tests on generated code.
69
- Receives the build folder path as its first argument
70
- (default: 'plain_modules').
71
- --conformance-tests-folder CONFORMANCE_TESTS_FOLDER
72
- Folder for conformance test files
68
+ Receives the module's code folder path as its first
69
+ argument (e.g. `plain_modules/module_name/code`).
73
70
  --conformance-tests-script CONFORMANCE_TESTS_SCRIPT
74
71
  Path to conformance tests shell script. Every
75
72
  conformance test script should accept two arguments:
76
- 1) Path to a folder (e.g. `plain_modules/module_name`)
77
- containing generated source code, 2) Path to a
78
- subfolder of the conformance tests folder (e.g.
79
- `conformance_tests/subfoldername`) containing test
80
- files.
73
+ 1) Path to a folder (e.g.
74
+ `plain_modules/module_name/code`) containing generated
75
+ source code, 2) Path to a subfolder of the module's
76
+ tests folder (e.g.
77
+ `plain_modules/module_name/tests/subfoldername`)
78
+ containing test files.
81
79
  --prepare-environment-script PREPARE_ENVIRONMENT_SCRIPT
82
80
  Path to a shell script that prepares the testing
83
81
  environment. The script should accept the source code
@@ -90,9 +88,9 @@ options:
90
88
  --api-key API_KEY API key used to access the API. If not provided, the
91
89
  `CODEPLAIN_API_KEY` environment variable is used.
92
90
  --full-plain Full preview ***plain specification before code
93
- generation.Use when you want to preview context of all
94
- ***plain primitives that are going to be included in
95
- order to render the given module.
91
+ generation. Use when you want to preview context of
92
+ all ***plain primitives that are going to be included
93
+ in order to render the given module.
96
94
  --dry-run Dry run preview of the code generation (without
97
95
  actually making any changes).
98
96
  --replay-with REPLAY_WITH
@@ -109,10 +107,10 @@ options:
109
107
  Target folder to copy rendered contents of code to
110
108
  (used only if --copy-build is set).
111
109
  --copy-conformance-tests
112
- If set, copy the conformance tests of code in
113
- `--conformance-tests-folder` folder to `--conformance-
114
- tests-dest` folder successful rendering. Requires
115
- --conformance-tests-script.
110
+ If set, copy the module's conformance tests (from
111
+ `<build-folder>/<module>/tests`) to `--conformance-
112
+ tests-dest` folder after successful rendering.
113
+ Requires --conformance-tests-script.
116
114
  --conformance-tests-dest CONFORMANCE_TESTS_DEST
117
115
  Target folder to copy conformance tests of code to
118
116
  (used only if --copy-conformance-tests is set).
@@ -123,6 +121,10 @@ options:
123
121
  --headless Run in headless mode: no TUI, no terminal output
124
122
  except a single render-started message. All logs are
125
123
  written to the log file.
124
+ --status Display account status including user information, API
125
+ key label, and rendering credits. Does not render any
126
+ code.
127
+ --version Display the client version and exit.
126
128
 
127
129
  configuration:
128
130
  --config-name CONFIG_NAME
@@ -22,10 +22,16 @@ my-new-project/
22
22
  ├── run_unittests_[language].sh # Unit test script
23
23
  ├── run_conformance_tests_[language].sh # Conformance test script
24
24
  ├── build/ # Generated final code
25
- ├── plain_modules/ # Generated modules code
26
- └── conformance_tests/ # Generated conformanece tests code
25
+ └── plain_modules/ # Generated modules
26
+ └── my_app/ # One folder per module
27
+ ├── .codeplain/ # Module metadata
28
+ ├── .memory/ # Conformance test memory
29
+ ├── code/ # Generated code
30
+ └── tests/ # Generated conformance tests
27
31
  ```
28
32
 
33
+ The `tests/` folder is only created when a conformance test script is configured.
34
+
29
35
  In this guide we will cover how to create each of these step by step.
30
36
 
31
37
  ## 1. Define Your .plain File
@@ -20,11 +20,11 @@ if [ $? -ne 0 ]; then
20
20
  exit 1
21
21
  fi
22
22
 
23
- cd plain_modules/hello_world_golang
23
+ cd plain_modules/hello_world_golang/code
24
24
 
25
25
  # We need to compile the tests so that we can execute them in the current folder
26
26
  # (https://stackoverflow.com/questions/23847003/golang-tests-and-working-directory/29541248#29541248)
27
- go test -c ../../harness_tests/hello_world_test.go
27
+ go test -c ../../../harness_tests/hello_world_test.go
28
28
 
29
29
  # Check if test compilation has failed for the hello world example
30
30
  if [ $? -ne 0 ]; then
@@ -7,9 +7,9 @@ if [ $? -ne 0 ]; then
7
7
  exit 1
8
8
  fi
9
9
 
10
- cd plain_modules/hello_world_python
10
+ cd plain_modules/hello_world_python/code
11
11
 
12
- python ../../harness_tests/hello_world_display/test_hello_world.py
12
+ python ../../../harness_tests/hello_world_display/test_hello_world.py
13
13
 
14
14
  # Check if the test harness has failed for the hello world example
15
15
  if [ $? -ne 0 ]; then
@@ -20,7 +20,7 @@ if [ $? -ne 0 ]; then
20
20
  exit 1
21
21
  fi
22
22
 
23
- ../../test_scripts/run_conformance_tests_cypress.sh plain_modules/hello_world_react harness_tests/hello_world_display ${VERBOSE:+-v}
23
+ ../../test_scripts/run_conformance_tests_cypress.sh plain_modules/hello_world_react/code harness_tests/hello_world_display ${VERBOSE:+-v}
24
24
 
25
25
  # Check if the test harness has failed for the hello world example
26
26
  if [ $? -ne 0 ]; then
@@ -64,7 +64,6 @@ def init_git_repo(
64
64
  path_to_repo: Union[str, os.PathLike],
65
65
  module_name: Optional[str] = None,
66
66
  render_id: Optional[str] = None,
67
- initial_files: Optional[dict[str, str]] = None,
68
67
  ) -> Repo:
69
68
  """
70
69
  Initializes a new git repository in the given path.
@@ -79,10 +78,6 @@ def init_git_repo(
79
78
  repo = Repo.init(path_to_repo)
80
79
  _ensure_git_config(repo)
81
80
 
82
- if initial_files:
83
- file_utils.store_response_files(path_to_repo, initial_files, [])
84
- repo.git.add(".")
85
-
86
81
  repo.git.commit(
87
82
  "--allow-empty", "-m", _get_full_commit_message(INITIAL_COMMIT_MESSAGE, module_name, None, render_id)
88
83
  )
@@ -95,14 +90,9 @@ def clone_repo(
95
90
  new_repo_path: str,
96
91
  module_name: Optional[str] = None,
97
92
  render_id: Optional[str] = None,
98
- initial_files: Optional[dict[str, str]] = None,
99
93
  ) -> Repo:
100
94
  repo = Repo.clone_from(source_repo_path, new_repo_path)
101
95
 
102
- if initial_files:
103
- file_utils.store_response_files(new_repo_path, initial_files, [])
104
- repo.git.add(".")
105
-
106
96
  repo.git.commit(
107
97
  "--allow-empty", "-m", _get_full_commit_message(INITIAL_COMMIT_MESSAGE, module_name, None, render_id)
108
98
  )
@@ -3,7 +3,6 @@ import os
3
3
 
4
4
  import file_utils
5
5
  from plain2code_console import console
6
- from plain_modules import CODEPLAIN_MEMORY_SUBFOLDER
7
6
  from render_machine.implementation_code_helpers import ImplementationCodeHelpers
8
7
  from render_machine.render_context import RenderContext
9
8
 
@@ -24,9 +23,9 @@ class MemoryManager:
24
23
  console.debug(f"Loaded {len(memory_files_content)} memory files.")
25
24
  return memory_files, memory_files_content
26
25
 
27
- def __init__(self, codeplain_api, module_name: str, conformance_tests_folder: str):
26
+ def __init__(self, codeplain_api, memory_folder: str):
28
27
  self.codeplain_api = codeplain_api
29
- self.memory_folder = os.path.join(conformance_tests_folder, module_name, CODEPLAIN_MEMORY_SUBFOLDER)
28
+ self.memory_folder = memory_folder
30
29
 
31
30
  def create_conformance_tests_memory(
32
31
  self, render_context: RenderContext, exit_code: int, conformance_tests_issue: str
@@ -0,0 +1,46 @@
1
+ """Read/write helpers for the per-module metadata file (``module_metadata.json``).
2
+
3
+ These helpers operate purely on a metadata path or a plain dict. Module-specific
4
+ logic — computing the hashes, assembling the payload from the spec and required
5
+ modules — stays on :class:`plain_modules.PlainModule`.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import os
12
+
13
+ MODULE_METADATA_FILENAME = "module_metadata.json"
14
+ MODULE_FUNCTIONALITIES = "functionalities"
15
+ REQUIRED_MODULES_FUNCTIONALITIES = "required_modules_functionalities"
16
+
17
+
18
+ def load_metadata(metadata_path: str) -> dict | None:
19
+ """Return the parsed metadata dict, or None if the file does not exist."""
20
+ if not os.path.exists(metadata_path):
21
+ return None
22
+
23
+ with open(metadata_path, "r", encoding="utf-8") as f:
24
+ return json.load(f)
25
+
26
+
27
+ def write_metadata(metadata_path: str, metadata: dict) -> None:
28
+ """Write metadata as indented JSON, creating the parent folder if needed."""
29
+ os.makedirs(os.path.dirname(metadata_path), exist_ok=True)
30
+
31
+ with open(metadata_path, "w", encoding="utf-8") as f:
32
+ json.dump(metadata, f, indent=4)
33
+
34
+
35
+ def truncate_functionalities(metadata: dict, keep_count: int) -> bool:
36
+ """Trim the functionalities list in ``metadata`` in place to ``keep_count`` entries.
37
+
38
+ Returns True if the list was shortened, False if it was already short enough
39
+ (in which case ``metadata`` is left untouched).
40
+ """
41
+ functionalities = metadata.get(MODULE_FUNCTIONALITIES, [])
42
+ if len(functionalities) <= keep_count:
43
+ return False
44
+
45
+ metadata[MODULE_FUNCTIONALITIES] = functionalities[:keep_count]
46
+ return True
@@ -1,5 +1,4 @@
1
1
  import argparse
2
- import os
3
2
  import threading
4
3
 
5
4
  from event_bus import EventBus
@@ -48,9 +47,8 @@ class ModuleRenderer:
48
47
  self.codeplainAPI,
49
48
  memory_manager,
50
49
  plain_module,
51
- build_folder=os.path.join(self.args.build_folder, plain_module.module_name),
50
+ build_folder=plain_module.module_build_folder,
52
51
  build_dest=self.args.build_dest,
53
- conformance_tests_folder=self.args.conformance_tests_folder,
54
52
  conformance_tests_dest=self.args.conformance_tests_dest,
55
53
  unittests_script=self.args.unittests_script,
56
54
  conformance_tests_script=self.args.conformance_tests_script,
@@ -115,8 +113,7 @@ class ModuleRenderer:
115
113
 
116
114
  memory_manager = MemoryManager(
117
115
  self.codeplainAPI,
118
- plain_module.module_name,
119
- self.args.conformance_tests_folder,
116
+ plain_module.module_memory_folder,
120
117
  )
121
118
  render_context = self._build_render_context_for_module(
122
119
  plain_module,
@@ -165,7 +162,7 @@ class ModuleRenderer:
165
162
  if self.args.copy_build:
166
163
  rendered_code_path = f"{self.args.build_dest}/"
167
164
  else:
168
- rendered_code_path = self.args.build_folder
165
+ rendered_code_path = self.plain_module.module_build_folder
169
166
 
170
167
  self.run_state.set_render_generated_code_path(rendered_code_path)
171
168
  self.event_bus.publish(RenderCompleted(rendered_code_path=rendered_code_path))
@@ -212,6 +212,12 @@ def render( # noqa: C901
212
212
 
213
213
  warn_if_acceptance_tests_without_conformance_script(plain_module, args)
214
214
 
215
+ # The module_metadata file lives outside the code git repo. That means that a crash mid-render can leave it
216
+ # claiming a functionality was implemented even thought it wasn't yet committed (because of the crash).
217
+ # Out of precaution, this reconciles every module_metadata against the code repo.
218
+ for module in plain_module.all_required_modules + [plain_module]:
219
+ module.reconcile_metadata_with_git()
220
+
215
221
  render_choice = None
216
222
  if render_range is None:
217
223
  plain_module_render_state = get_plain_module_render_state(plain_module)
@@ -356,7 +362,6 @@ def main(): # noqa: C901
356
362
  plain_module = plain_modules.PlainModule(
357
363
  os.path.basename(args.filename),
358
364
  args.build_folder,
359
- args.conformance_tests_folder,
360
365
  template_dirs,
361
366
  )
362
367
  except Exception as e:
@@ -16,7 +16,6 @@ CODEPLAIN_API_KEY = os.getenv("CODEPLAIN_API_KEY")
16
16
 
17
17
 
18
18
  DEFAULT_BUILD_FOLDER = "plain_modules"
19
- DEFAULT_CONFORMANCE_TESTS_FOLDER = "conformance_tests"
20
19
  DEFAULT_BUILD_DEST = "dist"
21
20
  DEFAULT_CONFORMANCE_TESTS_DEST = "dist_conformance_tests"
22
21
 
@@ -299,23 +298,15 @@ def create_parser():
299
298
  parser,
300
299
  "--unittests-script",
301
300
  type=str,
302
- help="Shell script to run unit tests on generated code. Receives the build folder path as its first argument (default: 'plain_modules').",
303
- )
304
- _add_arg(
305
- parser,
306
- "--conformance-tests-folder",
307
- type=non_empty_string,
308
- default=DEFAULT_CONFORMANCE_TESTS_FOLDER,
309
- help="Folder for conformance test files",
310
- path=True,
301
+ help="Shell script to run unit tests on generated code. Receives the module's code folder path as its first argument (e.g. `plain_modules/module_name/code`).",
311
302
  )
312
303
  _add_arg(
313
304
  parser,
314
305
  "--conformance-tests-script",
315
306
  type=str,
316
307
  help="Path to conformance tests shell script. Every conformance test script should accept two arguments: "
317
- "1) Path to a folder (e.g. `plain_modules/module_name`) containing generated source code, "
318
- "2) Path to a subfolder of the conformance tests folder (e.g. `conformance_tests/subfoldername`) containing test files.",
308
+ "1) Path to a folder (e.g. `plain_modules/module_name/code`) containing generated source code, "
309
+ "2) Path to a subfolder of the module's tests folder (e.g. `plain_modules/module_name/tests/subfoldername`) containing test files.",
319
310
  )
320
311
 
321
312
  _add_arg(
@@ -400,7 +391,7 @@ def create_parser():
400
391
  "--copy-conformance-tests",
401
392
  action="store_true",
402
393
  default=False,
403
- help="If set, copy the conformance tests of code in `--conformance-tests-folder` folder to `--conformance-tests-dest` folder successful rendering. Requires --conformance-tests-script.",
394
+ help="If set, copy the module's conformance tests (from `<build-folder>/<module>/tests`) to `--conformance-tests-dest` folder after successful rendering. Requires --conformance-tests-script.",
404
395
  )
405
396
  _add_arg(
406
397
  parser,
@@ -490,8 +481,8 @@ def parse_arguments(command_line: Optional[Sequence[str]] = None):
490
481
 
491
482
  if args.build_folder == args.build_dest:
492
483
  parser.error("--build-folder and --build-dest cannot be the same")
493
- if args.conformance_tests_folder == args.conformance_tests_dest:
494
- parser.error("--conformance-tests-folder and --conformance-tests-dest cannot be the same")
484
+ if args.conformance_tests_dest == args.build_folder:
485
+ parser.error("--conformance-tests-dest and --build-folder cannot be the same")
495
486
 
496
487
  args.render_conformance_tests = args.conformance_tests_script is not None
497
488
 
@@ -3,19 +3,19 @@
3
3
  ```text
4
4
  usage: generate_cli.py [-h] [--verbose] [--base-folder BASE_FOLDER] [--build-folder BUILD_FOLDER] [--log-to-file | --no-log-to-file] [--log-file-name LOG_FILE_NAME]
5
5
  [--config-name CONFIG_NAME] [--render-range RENDER_RANGE | --render-from RENDER_FROM] [--force-render] [--unittests-script UNITTESTS_SCRIPT]
6
- [--conformance-tests-folder CONFORMANCE_TESTS_FOLDER] [--conformance-tests-script CONFORMANCE_TESTS_SCRIPT]
7
- [--prepare-environment-script PREPARE_ENVIRONMENT_SCRIPT] [--test-script-timeout TEST_SCRIPT_TIMEOUT] [--api [API]] [--api-key API_KEY] [--full-plain] [--dry-run]
8
- [--replay-with REPLAY_WITH] [--template-dir TEMPLATE_DIR] [--copy-build] [--build-dest BUILD_DEST] [--copy-conformance-tests]
9
- [--conformance-tests-dest CONFORMANCE_TESTS_DEST] [--render-machine-graph] [--logging-config-path LOGGING_CONFIG_PATH] [--headless] [--status] [--version]
6
+ [--conformance-tests-script CONFORMANCE_TESTS_SCRIPT] [--prepare-environment-script PREPARE_ENVIRONMENT_SCRIPT] [--test-script-timeout TEST_SCRIPT_TIMEOUT]
7
+ [--api [API]] [--api-key API_KEY] [--full-plain] [--dry-run] [--replay-with REPLAY_WITH] [--template-dir TEMPLATE_DIR] [--copy-build] [--build-dest BUILD_DEST]
8
+ [--copy-conformance-tests] [--conformance-tests-dest CONFORMANCE_TESTS_DEST] [--render-machine-graph] [--logging-config-path LOGGING_CONFIG_PATH] [--headless]
9
+ [--status] [--version]
10
10
  [filename]
11
11
 
12
- Render plain code to target code. Path arguments resolve based on where they were written: values given on the command line are resolved against the current working directory, values
13
- read from config.yaml are resolved against the config file's directory, and defaults are resolved against the directory containing the plain file. Absolute paths (and paths starting
14
- with '~') are used as-is.
12
+ Render plain code to target code. Path arguments resolve based on where they were written: values given on the command line are resolved against the current working directory, values read
13
+ from config.yaml are resolved against the config file's directory, and defaults are resolved against the directory containing the plain file. Absolute paths (and paths starting with '~')
14
+ are used as-is.
15
15
 
16
16
  positional arguments:
17
- filename Path to the plain file to render. The directory containing this file has highest precedence for template loading, so you can place custom templates here to
18
- override the defaults. See --template-dir for more details about template loading.
17
+ filename Path to the plain file to render. The directory containing this file has highest precedence for template loading, so you can place custom templates here to override
18
+ the defaults. See --template-dir for more details about template loading.
19
19
 
20
20
  options:
21
21
  -h, --help show this help message and exit
@@ -32,24 +32,22 @@ with '~') are used as-is.
32
32
  Specify a range of functionalities to render (e.g. `1` , `2`, `3`). Use comma to separate start and end IDs. If only one functionality ID is provided, only that
33
33
  functionality is rendered. Range is inclusive of both start and end IDs.
34
34
  --render-from RENDER_FROM
35
- Continue generation starting from this specific functionality (e.g. `2`). The functionality with this ID will be included in the output. The functionality ID
36
- must match one of the functionalities in your plain file.
35
+ Continue generation starting from this specific functionality (e.g. `2`). The functionality with this ID will be included in the output. The functionality ID must
36
+ match one of the functionalities in your plain file.
37
37
  --force-render Force re-render of all the required modules.
38
38
  --unittests-script UNITTESTS_SCRIPT
39
- Shell script to run unit tests on generated code. Receives the build folder path as its first argument (default: 'plain_modules').
40
- --conformance-tests-folder CONFORMANCE_TESTS_FOLDER
41
- Folder for conformance test files
39
+ Shell script to run unit tests on generated code. Receives the module's code folder path as its first argument (e.g. `plain_modules/module_name/code`).
42
40
  --conformance-tests-script CONFORMANCE_TESTS_SCRIPT
43
- Path to conformance tests shell script. Every conformance test script should accept two arguments: 1) Path to a folder (e.g. `plain_modules/module_name`)
44
- containing generated source code, 2) Path to a subfolder of the conformance tests folder (e.g. `conformance_tests/subfoldername`) containing test files.
41
+ Path to conformance tests shell script. Every conformance test script should accept two arguments: 1) Path to a folder (e.g. `plain_modules/module_name/code`)
42
+ containing generated source code, 2) Path to a subfolder of the module's tests folder (e.g. `plain_modules/module_name/tests/subfoldername`) containing test files.
45
43
  --prepare-environment-script PREPARE_ENVIRONMENT_SCRIPT
46
44
  Path to a shell script that prepares the testing environment. The script should accept the source code folder path as its first argument.
47
45
  --test-script-timeout TEST_SCRIPT_TIMEOUT
48
46
  Timeout for test scripts in seconds. If not provided, the default timeout of 120 seconds is used.
49
47
  --api [API] Alternative base URL for the API. Default: `https://api.codeplain.ai`
50
48
  --api-key API_KEY API key used to access the API. If not provided, the `CODEPLAIN_API_KEY` environment variable is used.
51
- --full-plain Full preview ***plain specification before code generation. Use when you want to preview context of all ***plain primitives that are going to be included in
52
- order to render the given module.
49
+ --full-plain Full preview ***plain specification before code generation. Use when you want to preview context of all ***plain primitives that are going to be included in order
50
+ to render the given module.
53
51
  --dry-run Dry run preview of the code generation (without actually making any changes).
54
52
  --replay-with REPLAY_WITH
55
53
  --template-dir TEMPLATE_DIR
@@ -59,7 +57,7 @@ with '~') are used as-is.
59
57
  --build-dest BUILD_DEST
60
58
  Target folder to copy rendered contents of code to (used only if --copy-build is set).
61
59
  --copy-conformance-tests
62
- If set, copy the conformance tests of code in `--conformance-tests-folder` folder to `--conformance-tests-dest` folder successful rendering. Requires
60
+ If set, copy the module's conformance tests (from `<build-folder>/<module>/tests`) to `--conformance-tests-dest` folder after successful rendering. Requires
63
61
  --conformance-tests-script.
64
62
  --conformance-tests-dest CONFORMANCE_TESTS_DEST
65
63
  Target folder to copy conformance tests of code to (used only if --copy-conformance-tests is set).
@@ -1,9 +1,10 @@
1
1
  """Crash reporting via Sentry.
2
2
 
3
3
  Only unexpected exceptions are reported (the caller decides which exceptions are
4
- expected; see EXPECTED_EXCEPTIONS in plain2code.py). Reporting is on by default
5
- and can be disabled by setting the CODEPLAIN_NO_TELEMETRY environment variable
6
- to any non-empty value.
4
+ expected; see EXPECTED_EXCEPTIONS in plain2code.py). In production, reporting is
5
+ on by default and can be disabled by setting CODEPLAIN_TELEMETRY to 0, false or
6
+ off. In any other environment it is off unless CODEPLAIN_TELEMETRY is explicitly
7
+ set to 1, true or on.
7
8
  """
8
9
 
9
10
  import os
@@ -20,9 +21,7 @@ from system_config import system_config
20
21
 
21
22
  SENTRY_DSN = "https://64d0d86b50b34e2dede3e4eaf5142282@o4510793955934208.ingest.us.sentry.io/4511540621213696"
22
23
 
23
- NO_TELEMETRY_ENV_VAR = "CODEPLAIN_NO_TELEMETRY"
24
- ENVIRONMENT_ENV_VAR = "CODEPLAIN_ENV"
25
- DEFAULT_ENVIRONMENT = "production"
24
+ TELEMETRY_ENV_VAR = "CODEPLAIN_TELEMETRY"
26
25
 
27
26
  FLUSH_TIMEOUT_SECONDS = 2
28
27
 
@@ -50,10 +49,17 @@ SCRUB_DENYLIST = DEFAULT_DENYLIST + [
50
49
 
51
50
 
52
51
  def telemetry_enabled() -> bool:
53
- """Return True if crash reporting should be active."""
54
- if os.environ.get(NO_TELEMETRY_ENV_VAR):
55
- return False
56
- return True
52
+ """Return True if crash reporting should be active.
53
+
54
+ In production it is on unless CODEPLAIN_TELEMETRY disables it.
55
+ Anywhere else it is off unless CODEPLAIN_TELEMETRY enables it.
56
+ """
57
+ setting = os.environ.get(TELEMETRY_ENV_VAR, "").strip().lower()
58
+
59
+ if system_config.environment == "production":
60
+ return setting not in {"0", "false", "off"}
61
+
62
+ return setting in {"1", "true", "on"}
57
63
 
58
64
 
59
65
  def initialize_telemetry(**init_overrides: Any) -> bool:
@@ -65,7 +71,7 @@ def initialize_telemetry(**init_overrides: Any) -> bool:
65
71
  init_kwargs: dict[str, Any] = dict(
66
72
  dsn=SENTRY_DSN,
67
73
  release=system_config.client_version,
68
- environment=os.environ.get(ENVIRONMENT_ENV_VAR, DEFAULT_ENVIRONMENT),
74
+ environment=system_config.environment,
69
75
  send_default_pii=False,
70
76
  server_name="", # hostname is identifying; don't send it
71
77
  default_integrations=False,