codeplain 0.3.1__tar.gz → 0.3.2__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 (232) hide show
  1. {codeplain-0.3.1 → codeplain-0.3.2}/.claude/settings.json +5 -0
  2. codeplain-0.3.2/.zed/settings.json +46 -0
  3. {codeplain-0.3.1 → codeplain-0.3.2}/PKG-INFO +20 -24
  4. {codeplain-0.3.1 → codeplain-0.3.2}/README.md +18 -22
  5. codeplain-0.3.2/_version.py +1 -0
  6. {codeplain-0.3.1 → codeplain-0.3.2}/cli_output/render_summary.py +6 -1
  7. {codeplain-0.3.1 → codeplain-0.3.2}/codeplain_REST_api.py +1 -1
  8. {codeplain-0.3.1 → codeplain-0.3.2}/concept_utils.py +0 -1
  9. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_python/hello_world_python.plain +3 -3
  10. codeplain-0.3.2/examples/example_hello_world_python/text.txt +1 -0
  11. {codeplain-0.3.1 → codeplain-0.3.2}/file_utils.py +18 -62
  12. {codeplain-0.3.1 → codeplain-0.3.2}/plain2code.py +7 -3
  13. {codeplain-0.3.1 → codeplain-0.3.2}/plain2code_exceptions.py +6 -0
  14. {codeplain-0.3.1 → codeplain-0.3.2}/plain2code_state.py +4 -7
  15. codeplain-0.3.2/plain2code_utils.py +22 -0
  16. {codeplain-0.3.1 → codeplain-0.3.2}/plain_file.py +6 -0
  17. {codeplain-0.3.1 → codeplain-0.3.2}/plain_modules.py +6 -2
  18. {codeplain-0.3.1 → codeplain-0.3.2}/pyproject.toml +1 -1
  19. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/run_conformance_tests.py +4 -2
  20. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/run_unit_tests.py +2 -2
  21. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/render_context.py +7 -2
  22. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/render_types.py +0 -10
  23. {codeplain-0.3.1 → codeplain-0.3.2}/system_config.py +0 -6
  24. codeplain-0.3.2/tests/data/plainfile/add_new_task_modal_specification.yaml +1 -0
  25. codeplain-0.3.2/tests/data/plainfile/task_list_ui_specification.yaml +1 -0
  26. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfile/task_manager_with_reference_links.plain +3 -3
  27. {codeplain-0.3.1 → codeplain-0.3.2}/tests/test_cli_output.py +9 -13
  28. {codeplain-0.3.1 → codeplain-0.3.2}/tests/test_plainfileparser.py +4 -4
  29. {codeplain-0.3.1 → codeplain-0.3.2}/tui/components.py +0 -6
  30. {codeplain-0.3.1 → codeplain-0.3.2}/tui/plain2code_tui.py +4 -0
  31. {codeplain-0.3.1 → codeplain-0.3.2}/tui/plain_module_render_choice_tui.py +9 -0
  32. {codeplain-0.3.1 → codeplain-0.3.2}/tui/styles.css +1 -1
  33. {codeplain-0.3.1 → codeplain-0.3.2}/tui/widget_helpers.py +0 -18
  34. codeplain-0.3.1/_version.py +0 -1
  35. codeplain-0.3.1/hash_key.py +0 -29
  36. codeplain-0.3.1/plain2code_utils.py +0 -56
  37. codeplain-0.3.1/render_machine/conformance_test_helpers.py +0 -68
  38. {codeplain-0.3.1 → codeplain-0.3.2}/.claude/settings.local.json +0 -0
  39. {codeplain-0.3.1 → codeplain-0.3.2}/.flake8 +0 -0
  40. {codeplain-0.3.1 → codeplain-0.3.2}/.github/dependabot.yml +0 -0
  41. {codeplain-0.3.1 → codeplain-0.3.2}/.github/workflows/e2e.yml +0 -0
  42. {codeplain-0.3.1 → codeplain-0.3.2}/.github/workflows/lint-and-test.yml +0 -0
  43. {codeplain-0.3.1 → codeplain-0.3.2}/.github/workflows/nofity-slack-on-main-merge.yml +0 -0
  44. {codeplain-0.3.1 → codeplain-0.3.2}/.github/workflows/publish-install-script.yml +0 -0
  45. {codeplain-0.3.1 → codeplain-0.3.2}/.github/workflows/publish-to-pypi.yml +0 -0
  46. {codeplain-0.3.1 → codeplain-0.3.2}/.gitignore +0 -0
  47. {codeplain-0.3.1 → codeplain-0.3.2}/.vscode/launch.json +0 -0
  48. {codeplain-0.3.1 → codeplain-0.3.2}/.vscode/settings.json +0 -0
  49. {codeplain-0.3.1 → codeplain-0.3.2}/CLAUDE.md +0 -0
  50. {codeplain-0.3.1 → codeplain-0.3.2}/LICENSE +0 -0
  51. {codeplain-0.3.1 → codeplain-0.3.2}/cli_output/__init__.py +0 -0
  52. {codeplain-0.3.1 → codeplain-0.3.2}/cli_output/dry_run.py +0 -0
  53. {codeplain-0.3.1 → codeplain-0.3.2}/cli_output/status.py +0 -0
  54. {codeplain-0.3.1 → codeplain-0.3.2}/config/__init__.py +0 -0
  55. {codeplain-0.3.1 → codeplain-0.3.2}/config/system_config.yaml +0 -0
  56. {codeplain-0.3.1 → codeplain-0.3.2}/diff_utils.py +0 -0
  57. {codeplain-0.3.1 → codeplain-0.3.2}/docs/generate_cli.py +0 -0
  58. {codeplain-0.3.1 → codeplain-0.3.2}/docs/plain2code_cli.md +0 -0
  59. {codeplain-0.3.1 → codeplain-0.3.2}/docs/starting_a_plain_project_from_scratch.md +0 -0
  60. {codeplain-0.3.1 → codeplain-0.3.2}/event_bus.py +0 -0
  61. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_golang/config.yaml +0 -0
  62. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
  63. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
  64. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_golang/run.sh +0 -0
  65. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_python/config.yaml +0 -0
  66. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
  67. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_python/run.sh +0 -0
  68. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_react/config.yaml +0 -0
  69. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
  70. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
  71. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
  72. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
  73. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
  74. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_react/hello_world_react.plain +0 -0
  75. {codeplain-0.3.1 → codeplain-0.3.2}/examples/example_hello_world_react/run.sh +0 -0
  76. {codeplain-0.3.1 → codeplain-0.3.2}/examples/run.sh +0 -0
  77. {codeplain-0.3.1 → codeplain-0.3.2}/git_utils.py +0 -0
  78. {codeplain-0.3.1 → codeplain-0.3.2}/install/bash/examples.sh +0 -0
  79. {codeplain-0.3.1 → codeplain-0.3.2}/install/bash/install.sh +0 -0
  80. {codeplain-0.3.1 → codeplain-0.3.2}/install/bash/walkthrough.sh +0 -0
  81. {codeplain-0.3.1 → codeplain-0.3.2}/install/powershell/examples.ps1 +0 -0
  82. {codeplain-0.3.1 → codeplain-0.3.2}/install/powershell/install.ps1 +0 -0
  83. {codeplain-0.3.1 → codeplain-0.3.2}/install/powershell/walkthrough.ps1 +0 -0
  84. {codeplain-0.3.1 → codeplain-0.3.2}/memory_management.py +0 -0
  85. {codeplain-0.3.1 → codeplain-0.3.2}/module_renderer.py +0 -0
  86. {codeplain-0.3.1 → codeplain-0.3.2}/partial_rendering.py +0 -0
  87. {codeplain-0.3.1 → codeplain-0.3.2}/plain2code_arguments.py +0 -0
  88. {codeplain-0.3.1 → codeplain-0.3.2}/plain2code_console.py +0 -0
  89. {codeplain-0.3.1 → codeplain-0.3.2}/plain2code_events.py +0 -0
  90. {codeplain-0.3.1 → codeplain-0.3.2}/plain2code_logger.py +0 -0
  91. {codeplain-0.3.1 → codeplain-0.3.2}/plain2code_nodes.py +0 -0
  92. {codeplain-0.3.1 → codeplain-0.3.2}/plain2code_read_config.py +0 -0
  93. {codeplain-0.3.1 → codeplain-0.3.2}/plain_spec.py +0 -0
  94. {codeplain-0.3.1 → codeplain-0.3.2}/pytest.ini +0 -0
  95. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/__init__.py +0 -0
  96. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/analyze_specification_ambiguity.py +0 -0
  97. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/base_action.py +0 -0
  98. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
  99. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/commit_implementation_code_changes.py +0 -0
  100. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/create_dist.py +0 -0
  101. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/exit_with_error.py +0 -0
  102. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/finish_functional_requirement.py +0 -0
  103. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/fix_conformance_test.py +0 -0
  104. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/fix_unit_tests.py +0 -0
  105. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/prepare_repositories.py +0 -0
  106. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/prepare_testing_environment.py +0 -0
  107. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/refactor_code.py +0 -0
  108. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/render_conformance_tests.py +0 -0
  109. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/render_functional_requirement.py +0 -0
  110. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/actions/summarize_conformance_tests.py +0 -0
  111. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/code_renderer.py +0 -0
  112. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/conformance_tests.py +0 -0
  113. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/implementation_code_helpers.py +0 -0
  114. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/render_utils.py +0 -0
  115. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/state_machine_config.py +0 -0
  116. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/states.py +0 -0
  117. {codeplain-0.3.1 → codeplain-0.3.2}/render_machine/triggers.py +0 -0
  118. {codeplain-0.3.1 → codeplain-0.3.2}/requirements.txt +0 -0
  119. {codeplain-0.3.1 → codeplain-0.3.2}/resources/codeplain_overview.png +0 -0
  120. {codeplain-0.3.1 → codeplain-0.3.2}/resources/plain_example.png +0 -0
  121. {codeplain-0.3.1 → codeplain-0.3.2}/standard_template_library/__init__.py +0 -0
  122. {codeplain-0.3.1 → codeplain-0.3.2}/standard_template_library/golang-console-app-template.plain +0 -0
  123. {codeplain-0.3.1 → codeplain-0.3.2}/standard_template_library/python-console-app-template.plain +0 -0
  124. {codeplain-0.3.1 → codeplain-0.3.2}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
  125. {codeplain-0.3.1 → codeplain-0.3.2}/standard_template_library/typescript-react-app-template.plain +0 -0
  126. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_conformance_tests_cypress.ps1 +0 -0
  127. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_conformance_tests_cypress.sh +0 -0
  128. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_conformance_tests_golang.ps1 +0 -0
  129. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_conformance_tests_golang.sh +0 -0
  130. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_conformance_tests_python.ps1 +0 -0
  131. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_conformance_tests_python.sh +0 -0
  132. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_unittests_flutter.ps1 +0 -0
  133. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_unittests_golang.ps1 +0 -0
  134. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_unittests_golang.sh +0 -0
  135. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_unittests_python.ps1 +0 -0
  136. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_unittests_python.sh +0 -0
  137. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_unittests_react.ps1 +0 -0
  138. {codeplain-0.3.1 → codeplain-0.3.2}/test_scripts/run_unittests_react.sh +0 -0
  139. {codeplain-0.3.1 → codeplain-0.3.2}/tests/__init__.py +0 -0
  140. {codeplain-0.3.1 → codeplain-0.3.2}/tests/conftest.py +0 -0
  141. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/imports/circular_imports_1.plain +0 -0
  142. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/imports/circular_imports_2.plain +0 -0
  143. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/imports/circular_imports_main.plain +0 -0
  144. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/imports/diamond_import_1.plain +0 -0
  145. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/imports/diamond_import_2.plain +0 -0
  146. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/imports/diamond_import_common.plain +0 -0
  147. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/imports/diamond_imports_main.plain +0 -0
  148. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/imports/non_existent_import.plain +0 -0
  149. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/partial_rendering/pr_leaf.plain +0 -0
  150. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/partial_rendering/pr_middle.plain +0 -0
  151. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/partial_rendering/pr_root.plain +0 -0
  152. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/partial_rendering/pr_solo.plain +0 -0
  153. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
  154. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfile/invalid_specification_order.plain +0 -0
  155. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
  156. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
  157. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
  158. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
  159. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
  160. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
  161. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
  162. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
  163. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
  164. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
  165. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
  166. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
  167. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
  168. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
  169. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
  170. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/exported_concepts.plain +0 -0
  171. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
  172. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
  173. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/exported_concepts_missing.plain +0 -0
  174. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/exported_concepts_missing_example.plain +0 -0
  175. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
  176. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
  177. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
  178. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
  179. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
  180. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
  181. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
  182. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
  183. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/required_concepts.plain +0 -0
  184. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
  185. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
  186. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
  187. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
  188. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
  189. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
  190. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
  191. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
  192. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/topological_sort.plain +0 -0
  193. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
  194. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/circular_requires_main.plain +0 -0
  195. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/circular_requires_sub.plain +0 -0
  196. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/diamond_requires_1.plain +0 -0
  197. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/diamond_requires_2.plain +0 -0
  198. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/diamond_requires_common.plain +0 -0
  199. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/diamond_requires_main.plain +0 -0
  200. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/independent_requires_1.plain +0 -0
  201. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/independent_requires_2.plain +0 -0
  202. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/independent_requires_main.plain +0 -0
  203. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/non_existent_require.plain +0 -0
  204. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/normal_requires_1.plain +0 -0
  205. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/normal_requires_2.plain +0 -0
  206. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/normal_requires_common.plain +0 -0
  207. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/requires/normal_requires_main.plain +0 -0
  208. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/simple.plain +0 -0
  209. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/templates/block_level_include.plain +0 -0
  210. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/templates/code_variables.plain +0 -0
  211. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/templates/header.plain +0 -0
  212. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/templates/implement.plain +0 -0
  213. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/templates/implement_2.plain +0 -0
  214. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/templates/template_include.plain +0 -0
  215. {codeplain-0.3.1 → codeplain-0.3.2}/tests/data/templates/test_hardest_problem.plain +0 -0
  216. {codeplain-0.3.1 → codeplain-0.3.2}/tests/e2e/Dockerfile +0 -0
  217. {codeplain-0.3.1 → codeplain-0.3.2}/tests/e2e/conftest.py +0 -0
  218. {codeplain-0.3.1 → codeplain-0.3.2}/tests/e2e/test_hello_world_python.py +0 -0
  219. {codeplain-0.3.1 → codeplain-0.3.2}/tests/e2e/test_hello_world_python_windows.py +0 -0
  220. {codeplain-0.3.1 → codeplain-0.3.2}/tests/test_file_utils.py +0 -0
  221. {codeplain-0.3.1 → codeplain-0.3.2}/tests/test_git_utils.py +0 -0
  222. {codeplain-0.3.1 → codeplain-0.3.2}/tests/test_imports.py +0 -0
  223. {codeplain-0.3.1 → codeplain-0.3.2}/tests/test_partial_rendering.py +0 -0
  224. {codeplain-0.3.1 → codeplain-0.3.2}/tests/test_plain_modules.py +0 -0
  225. {codeplain-0.3.1 → codeplain-0.3.2}/tests/test_plainfile.py +0 -0
  226. {codeplain-0.3.1 → codeplain-0.3.2}/tests/test_plainspec.py +0 -0
  227. {codeplain-0.3.1 → codeplain-0.3.2}/tests/test_requires.py +0 -0
  228. {codeplain-0.3.1 → codeplain-0.3.2}/tests/test_resolve_config_file.py +0 -0
  229. {codeplain-0.3.1 → codeplain-0.3.2}/tui/__init__.py +0 -0
  230. {codeplain-0.3.1 → codeplain-0.3.2}/tui/models.py +0 -0
  231. {codeplain-0.3.1 → codeplain-0.3.2}/tui/spinner.py +0 -0
  232. {codeplain-0.3.1 → codeplain-0.3.2}/tui/state_handlers.py +0 -0
@@ -13,6 +13,11 @@
13
13
  "Bash(git status*)",
14
14
  "Bash(git diff*)",
15
15
  "Bash(git log*)",
16
+ "Bash(gh issue *)",
17
+ "Bash(gh pr *)",
18
+ "Bash(gh api *)",
19
+ "Bash(gh repo *)",
20
+ "Bash(gh run *)",
16
21
  "Bash(ls *)",
17
22
  "Bash(cat *)",
18
23
  "Bash(grep *)",
@@ -0,0 +1,46 @@
1
+ // Zed project-local settings, converted from .vscode/settings.json.
2
+ // Docs: https://zed.dev/docs/configuring-zed
3
+ {
4
+ "format_on_save": "on",
5
+ "languages": {
6
+ "Python": {
7
+ "tab_size": 4,
8
+ "hard_tabs": false,
9
+ "preferred_line_length": 120,
10
+ "wrap_guides": [120],
11
+ "format_on_save": "on",
12
+ // Run isort first (organize imports), then black (format).
13
+ // Matches `source.organizeImports: explicit` + black-formatter from VS Code.
14
+ "formatter": [
15
+ {
16
+ "external": {
17
+ "command": "isort",
18
+ "arguments": ["--profile", "black", "--filename", "{buffer_path}", "-"]
19
+ }
20
+ },
21
+ {
22
+ "external": {
23
+ "command": "black",
24
+ "arguments": ["--quiet", "--stdin-filename", "{buffer_path}", "-"]
25
+ }
26
+ }
27
+ ]
28
+ }
29
+ },
30
+ // Treat fixture files under tests/data as plain text (matches files.associations).
31
+ "file_types": {
32
+ "Plain Text": ["tests/data/**"]
33
+ },
34
+ // python.analysis.extraPaths -> Pyright (Zed's default Python LSP).
35
+ "lsp": {
36
+ "pyright": {
37
+ "settings": {
38
+ "python": {
39
+ "analysis": {
40
+ "extraPaths": ["."]
41
+ }
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeplain
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Transform plain language specifications into working code
5
5
  License-File: LICENSE
6
6
  Classifier: Environment :: Console
7
7
  Classifier: Intended Audience :: Developers
8
8
  Classifier: Operating System :: OS Independent
9
9
  Classifier: Topic :: Software Development :: Code Generators
10
- Requires-Python: ==3.11
10
+ Requires-Python: >=3.11
11
11
  Requires-Dist: gitpython==3.1.50
12
12
  Requires-Dist: mistletoe==1.3.0
13
13
  Requires-Dist: networkx==3.6.1
@@ -29,31 +29,28 @@ Description-Content-Type: text/markdown
29
29
 
30
30
  # Codeplain plain2code renderer
31
31
 
32
- Render ***plain source to software code using the Codeplain API.
32
+ Render \*\*\*plain source to software code using the Codeplain API.
33
33
 
34
34
  ## Codeplain.ai - Code Generation as a Service
35
35
 
36
- Codeplain is a platform that generates software code using large language models based on requirements you specify in ***plain specification language.
36
+ Codeplain is a platform that generates software code using large language models based on requirements you specify in \*\*\*plain specification language.
37
37
 
38
38
  Schematic overview of the Codeplain's code generation service
39
39
 
40
40
  <img src="https://raw.githubusercontent.com/Codeplain-ai/plain2code_client/main/resources/codeplain_overview.png">
41
41
 
42
- ### Abstracting Away Code Generation Complexity with ***plain
42
+ ### Abstracting Away Code Generation Complexity with \*\*\*plain
43
43
 
44
+ \*\*\*plain is a novel specification language that helps abstracting away complexity of using large language models for code generation.
44
45
 
45
- ***plain is a novel specification language that helps abstracting away complexity of using large language models for code generation.
46
-
47
- An example application in ***plain
46
+ An example application in \*\*\*plain
48
47
 
49
48
  <img src="resources/plain_example.png" width="70%" height="70%">
50
49
 
51
-
52
50
  ## Getting started
53
51
 
54
52
  ### Prerequisites
55
53
 
56
-
57
54
  #### System requirements
58
55
 
59
56
  To run the plain2code client, you need Python 3.11 or a later version.
@@ -92,18 +89,19 @@ export CODEPLAIN_API_KEY="your_actual_api_key_here"
92
89
  After completing the installation steps above, you can immediately test the system with a simple "Hello World" example:
93
90
 
94
91
  - Change to the example folder and run the example:
95
- ```
96
- cd examples/example_hello_world_python
97
- python ../../plain2code.py hello_world_python.plain
98
- ```
99
92
 
100
- *Note: Rendering will take a few minutes to complete.*
93
+ ```
94
+ cd examples/example_hello_world_python
95
+ python ../../plain2code.py hello_world_python.plain
96
+ ```
97
+
98
+ _Note: Rendering will take a few minutes to complete._
101
99
 
102
100
  - The system will generate a Python application in the `build` directory. You can run it with:
103
- ```
104
- cd build
105
- python hello_world.py
106
- ```
101
+ ```
102
+ cd build
103
+ python hello_world.py
104
+ ```
107
105
 
108
106
  ## Releasing
109
107
 
@@ -112,7 +110,7 @@ Releases are built and published with [uv](https://docs.astral.sh/uv/). The vers
112
110
  1. Bump the version in `_version.py` and commit/tag (`git tag v<version>`).
113
111
  2. Build the distributions:
114
112
  ```bash
115
- uv build
113
+ uv build --python 3.11
116
114
  ```
117
115
  This produces `dist/codeplain-<version>-py3-none-any.whl` and `dist/codeplain-<version>.tar.gz`.
118
116
  3. (Optional) Smoke-test the wheel:
@@ -135,13 +133,11 @@ Releases are built and published with [uv](https://docs.astral.sh/uv/). The vers
135
133
  ### Examples and Sample Projects
136
134
 
137
135
  - See the [examples](examples) folder for sample projects in Golang, Python, and React.
138
- - For example application how to implement task manager in ***plain see [example-task-manager](https://github.com/Codeplain-ai/example-task-manager) repository.
139
- - For example application how to implement SaaS connectors in ***plain see [example-saas-connectors](https://github.com/Codeplain-ai/example-saas-connectors) repository.
136
+ - For example application how to implement task manager in \*\*\*plain see [example-task-manager](https://github.com/Codeplain-ai/example-task-manager) repository.
137
+ - For example application how to implement SaaS connectors in \*\*\*plain see [example-saas-connectors](https://github.com/Codeplain-ai/example-saas-connectors) repository.
140
138
 
141
139
  ### Documentation
142
140
 
143
141
  - For more details on the ***plain format, see the [***plain language specification](https://www.plainlang.org/docs/).
144
142
  - For step-by-step instructions for creating your first ***plain project see the [Kickstart your ***plain project](docs/starting_a_plain_project_from_scratch.md).
145
143
  - For complete CLI documentation and usage examples, see [plain2code CLI documentation](docs/plain2code_cli.md).
146
-
147
-
@@ -1,30 +1,27 @@
1
1
  # Codeplain plain2code renderer
2
2
 
3
- Render ***plain source to software code using the Codeplain API.
3
+ Render \*\*\*plain source to software code using the Codeplain API.
4
4
 
5
5
  ## Codeplain.ai - Code Generation as a Service
6
6
 
7
- Codeplain is a platform that generates software code using large language models based on requirements you specify in ***plain specification language.
7
+ Codeplain is a platform that generates software code using large language models based on requirements you specify in \*\*\*plain specification language.
8
8
 
9
9
  Schematic overview of the Codeplain's code generation service
10
10
 
11
11
  <img src="https://raw.githubusercontent.com/Codeplain-ai/plain2code_client/main/resources/codeplain_overview.png">
12
12
 
13
- ### Abstracting Away Code Generation Complexity with ***plain
13
+ ### Abstracting Away Code Generation Complexity with \*\*\*plain
14
14
 
15
+ \*\*\*plain is a novel specification language that helps abstracting away complexity of using large language models for code generation.
15
16
 
16
- ***plain is a novel specification language that helps abstracting away complexity of using large language models for code generation.
17
-
18
- An example application in ***plain
17
+ An example application in \*\*\*plain
19
18
 
20
19
  <img src="resources/plain_example.png" width="70%" height="70%">
21
20
 
22
-
23
21
  ## Getting started
24
22
 
25
23
  ### Prerequisites
26
24
 
27
-
28
25
  #### System requirements
29
26
 
30
27
  To run the plain2code client, you need Python 3.11 or a later version.
@@ -63,18 +60,19 @@ export CODEPLAIN_API_KEY="your_actual_api_key_here"
63
60
  After completing the installation steps above, you can immediately test the system with a simple "Hello World" example:
64
61
 
65
62
  - Change to the example folder and run the example:
66
- ```
67
- cd examples/example_hello_world_python
68
- python ../../plain2code.py hello_world_python.plain
69
- ```
70
63
 
71
- *Note: Rendering will take a few minutes to complete.*
64
+ ```
65
+ cd examples/example_hello_world_python
66
+ python ../../plain2code.py hello_world_python.plain
67
+ ```
68
+
69
+ _Note: Rendering will take a few minutes to complete._
72
70
 
73
71
  - The system will generate a Python application in the `build` directory. You can run it with:
74
- ```
75
- cd build
76
- python hello_world.py
77
- ```
72
+ ```
73
+ cd build
74
+ python hello_world.py
75
+ ```
78
76
 
79
77
  ## Releasing
80
78
 
@@ -83,7 +81,7 @@ Releases are built and published with [uv](https://docs.astral.sh/uv/). The vers
83
81
  1. Bump the version in `_version.py` and commit/tag (`git tag v<version>`).
84
82
  2. Build the distributions:
85
83
  ```bash
86
- uv build
84
+ uv build --python 3.11
87
85
  ```
88
86
  This produces `dist/codeplain-<version>-py3-none-any.whl` and `dist/codeplain-<version>.tar.gz`.
89
87
  3. (Optional) Smoke-test the wheel:
@@ -106,13 +104,11 @@ Releases are built and published with [uv](https://docs.astral.sh/uv/). The vers
106
104
  ### Examples and Sample Projects
107
105
 
108
106
  - See the [examples](examples) folder for sample projects in Golang, Python, and React.
109
- - For example application how to implement task manager in ***plain see [example-task-manager](https://github.com/Codeplain-ai/example-task-manager) repository.
110
- - For example application how to implement SaaS connectors in ***plain see [example-saas-connectors](https://github.com/Codeplain-ai/example-saas-connectors) repository.
107
+ - For example application how to implement task manager in \*\*\*plain see [example-task-manager](https://github.com/Codeplain-ai/example-task-manager) repository.
108
+ - For example application how to implement SaaS connectors in \*\*\*plain see [example-saas-connectors](https://github.com/Codeplain-ai/example-saas-connectors) repository.
111
109
 
112
110
  ### Documentation
113
111
 
114
112
  - For more details on the ***plain format, see the [***plain language specification](https://www.plainlang.org/docs/).
115
113
  - For step-by-step instructions for creating your first ***plain project see the [Kickstart your ***plain project](docs/starting_a_plain_project_from_scratch.md).
116
114
  - For complete CLI documentation and usage examples, see [plain2code CLI documentation](docs/plain2code_cli.md).
117
-
118
-
@@ -0,0 +1 @@
1
+ __version__ = "0.3.2"
@@ -15,7 +15,12 @@ def print_exit_summary(
15
15
  """Print render outcome after the TUI exits (terminal restored)."""
16
16
  console.quiet = False
17
17
 
18
- msg = "\n[#79FC96]✓ rendering completed\n\n" if run_state.render_succeeded else "[#FF6B6B]✗ rendering failed\n\n"
18
+ if run_state.render_succeeded:
19
+ msg = "\n[#79FC96]✓ rendering completed\n\n"
20
+ elif run_state.render_cancelled:
21
+ msg = "\n[#FFFFFF]— rendering canceled\n\n"
22
+ else:
23
+ msg = "\n[#FF6B6B]✗ rendering failed\n\n"
19
24
  msg += f" [#8E8F91]render id:\t\t\t[#FFFFFF]{run_state.render_id}\n"
20
25
  msg += f" [#8E8F91]input file:\t\t\t[#FFFFFF]{spec_filename}\n"
21
26
  msg += f" [#8E8F91]generated code folder:\t[#FFFFFF]{run_state.render_generated_code_path or '-'}\n\n"
@@ -108,7 +108,7 @@ class CodeplainAPI:
108
108
  if error_code == "InternalServerError":
109
109
  raise plain2code_exceptions.InternalServerError(
110
110
  "Internal server error.\n\n"
111
- f"Please report the error to support@codeplain.ai with the attached {self.log_file_name} file."
111
+ "Please report the error to support@codeplain.ai with the attached .log file."
112
112
  )
113
113
  exception_class = ERROR_CODE_EXCEPTIONS[error_code]
114
114
  raise exception_class(message)
@@ -2,7 +2,6 @@ import re
2
2
  from copy import deepcopy
3
3
  from typing import Optional
4
4
 
5
- import mistletoe
6
5
  import mistletoe.block_token
7
6
  import networkx as nx
8
7
 
@@ -13,7 +13,7 @@ import:
13
13
  - Display "hello, world"
14
14
 
15
15
  ***acceptance tests***
16
-
17
- - :App: should exit with status code 0 indicating successful execution.
18
16
 
19
- - :App: should complete execution in under 1 second.
17
+ - :App: should exit with status code 0 indicating successful execution [adsa](asdsa).
18
+
19
+ - :App: should complete execution in under 1 second.
@@ -54,15 +54,6 @@ def is_system_folder_path(file_path: str) -> bool:
54
54
  return bool(parts) and parts[0] in SYSTEM_FOLDERS
55
55
 
56
56
 
57
- def get_file_type(file_name):
58
-
59
- # Extract the file extension
60
- ext = Path(file_name).suffix.lower() # Convert to lowercase to handle case-insensitive matching
61
-
62
- # Use the dictionary to get the file type, defaulting to 'unknown' if the extension is not found
63
- return FILE_EXTENSION_MAPPING.get(ext, "unknown")
64
-
65
-
66
57
  def list_all_text_files(directory):
67
58
  all_files = []
68
59
  for root, dirs, files in os.walk(directory, topdown=True):
@@ -99,64 +90,29 @@ def list_folders_in_directory(directory):
99
90
  return folders
100
91
 
101
92
 
102
- # delete a folder and all its subfolders and files
103
- def delete_folder(folder_name):
104
- if os.path.exists(folder_name):
105
- # Use writable-aware deletion so read-only files (e.g. .git objects on Windows) don't cause PermissionError
106
- delete_files_and_subfolders(folder_name)
107
- _make_writable(folder_name)
108
- os.rmdir(folder_name)
93
+ def _on_rm_error(func, path, _exc_info):
94
+ """On Windows, clear read-only flag and retry the removal."""
95
+ os.chmod(path, stat.S_IWRITE)
96
+ func(path)
109
97
 
110
98
 
111
- def _make_writable(path: str) -> None:
112
- """On Windows, clear read-only so deletion can succeed."""
113
- # TODO - Check if this can be done in a cleaner way.
114
- is_windows = os.name == "nt"
115
- if is_windows:
116
- try:
117
- mode = os.stat(path).st_mode
118
- os.chmod(path, mode | stat.S_IWRITE)
119
- except OSError:
120
- pass
99
+ def delete_folder(folder_name):
100
+ """Delete a folder and all its subfolders and files."""
101
+ if os.path.exists(folder_name):
102
+ shutil.rmtree(folder_name, onerror=_on_rm_error)
121
103
 
122
104
 
123
105
  def delete_files_and_subfolders(directory):
124
- total_files_deleted = 0
125
- total_folders_deleted = 0
126
-
127
- # Walk the directory in reverse order (bottom-up)
128
- for root, dirs, files in os.walk(directory, topdown=False):
129
- # Delete files
130
- for file in files:
131
- file_path = os.path.join(root, file)
132
- _make_writable(file_path)
133
- os.remove(file_path)
134
- total_files_deleted += 1
135
-
136
- # Delete directories
137
- for dir_ in dirs:
138
- dir_path = os.path.join(root, dir_)
139
- _make_writable(dir_path)
140
- os.rmdir(dir_path)
141
- total_folders_deleted += 1
142
-
143
-
144
- def copy_file(source_path, destination_path):
145
- # Ensure the destination directory exists
146
- os.makedirs(os.path.dirname(destination_path), exist_ok=True)
147
-
148
- # Open the source file in read-binary ('rb') mode
149
- with open(source_path, "rb") as source_file:
150
- # Open the destination file in write-binary ('wb') mode
151
- with open(destination_path, "wb") as destination_file:
152
- # Copy the content from source to destination
153
- while True:
154
- # Read a chunk of the source file
155
- chunk = source_file.read(4096) # Reading in chunks of 4KB
156
- if not chunk:
157
- break # End of file reached
158
- # Write the chunk to the destination file
159
- destination_file.write(chunk)
106
+ """Delete all contents of a directory but keep the directory itself."""
107
+ for entry in os.scandir(directory):
108
+ if entry.is_dir(follow_symlinks=False):
109
+ shutil.rmtree(entry.path, onerror=_on_rm_error)
110
+ else:
111
+ try:
112
+ os.remove(entry.path)
113
+ except PermissionError:
114
+ os.chmod(entry.path, stat.S_IWRITE)
115
+ os.remove(entry.path)
160
116
 
161
117
 
162
118
  def add_current_path_if_no_path(filename):
@@ -25,6 +25,7 @@ from plain2code_console import console
25
25
  from plain2code_events import RenderFailed
26
26
  from plain2code_exceptions import (
27
27
  ConflictingRequirements,
28
+ GitNotInstalledError,
28
29
  InvalidAPIKey,
29
30
  InvalidFridArgument,
30
31
  MissingAPIKey,
@@ -181,6 +182,7 @@ def render(args, run_state: RunState, event_bus: EventBus, default_log_level: st
181
182
  render_choices,
182
183
  system_config.client_version,
183
184
  run_state.render_id,
185
+ on_cancel=run_state.set_render_cancelled,
184
186
  css_path="styles.css",
185
187
  )
186
188
  render_choice = app.run()
@@ -189,6 +191,7 @@ def render(args, run_state: RunState, event_bus: EventBus, default_log_level: st
189
191
  and render_choice.render_range is None
190
192
  and render_choice.choice_type == "quit"
191
193
  ):
194
+ run_state.set_render_cancelled()
192
195
  sys.exit(0)
193
196
  elif ask_user and args.headless:
194
197
  # ignore the default choice if it requires user input due to headless mode
@@ -217,7 +220,7 @@ def render(args, run_state: RunState, event_bus: EventBus, default_log_level: st
217
220
  try:
218
221
  module_renderer.render_module()
219
222
  except RenderCancelledError:
220
- pass # TUI already closed, nothing to report
223
+ run_state.set_render_cancelled() # TUI already closed, nothing to report
221
224
  except Exception as e:
222
225
  run_state.set_render_succeeded(False)
223
226
  render_error.append(e)
@@ -228,8 +231,7 @@ def render(args, run_state: RunState, event_bus: EventBus, default_log_level: st
228
231
  try:
229
232
  module_renderer.render_module()
230
233
  except RenderCancelledError:
231
- run_state.set_render_succeeded(False)
232
- pass
234
+ run_state.set_render_cancelled()
233
235
  return
234
236
  else:
235
237
  render_thread = threading.Thread(target=run_render, daemon=True)
@@ -242,6 +244,7 @@ def render(args, run_state: RunState, event_bus: EventBus, default_log_level: st
242
244
  prepare_environment_script=args.prepare_environment_script,
243
245
  state_machine_version=system_config.client_version,
244
246
  enter_pause_event=enter_pause_event,
247
+ on_cancel=run_state.set_render_cancelled,
245
248
  default_log_level=default_log_level,
246
249
  css_path="styles.css",
247
250
  )
@@ -354,6 +357,7 @@ def main(): # noqa: C901
354
357
  NetworkConnectionError,
355
358
  ModuleDoesNotExistError,
356
359
  UnsupportedResourceType,
360
+ GitNotInstalledError,
357
361
  ),
358
362
  ):
359
363
  exc_info = sys.exc_info()
@@ -89,3 +89,9 @@ class RenderCancelledError(Exception):
89
89
  """Raised when the render is cancelled by the user closing the TUI."""
90
90
 
91
91
  pass
92
+
93
+
94
+ class GitNotInstalledError(Exception):
95
+ """Raised when git is not installed or not found on PATH."""
96
+
97
+ pass
@@ -11,6 +11,7 @@ class RunState:
11
11
  def __init__(self, spec_filename: str, replay_with: Optional[str] = None):
12
12
  self.replay: bool = replay_with is not None
13
13
  self.render_succeeded: bool = False
14
+ self.render_cancelled: bool = False
14
15
  self.render_generated_code_path: Optional[str] = None
15
16
  self.rendered_functionalities: int = 0
16
17
  if replay_with:
@@ -20,7 +21,6 @@ class RunState:
20
21
  self.spec_filename: str = spec_filename
21
22
  self.call_count: int = 0
22
23
  self.unittest_batch_id: int = 0
23
- self.frid_render_anaysis: dict[str, str] = {}
24
24
  self.render_time_accumulated: int = 0
25
25
  self.last_render_start_timestamp: float = time.monotonic()
26
26
 
@@ -30,12 +30,12 @@ class RunState:
30
30
  def increment_unittest_batch_id(self):
31
31
  self.unittest_batch_id += 1
32
32
 
33
- def add_rendering_analysis_for_frid(self, frid, rendering_analysis) -> None:
34
- self.frid_render_anaysis[frid] = rendering_analysis
35
-
36
33
  def set_render_succeeded(self, succeeded: bool):
37
34
  self.render_succeeded = succeeded
38
35
 
36
+ def set_render_cancelled(self):
37
+ self.render_cancelled = True
38
+
39
39
  def set_render_generated_code_path(self, generated_code_path: str):
40
40
  self.render_generated_code_path = generated_code_path
41
41
 
@@ -55,6 +55,3 @@ class RunState:
55
55
  "replay": self.replay,
56
56
  "spec_filename": self.spec_filename,
57
57
  }
58
-
59
- def get_render_func_id(self, frid: str) -> str:
60
- return f"{self.render_id}-{frid}"
@@ -0,0 +1,22 @@
1
+ def format_duration_hms(total_seconds: int) -> str:
2
+ """Format a duration in seconds as hours, minutes, and seconds (e.g. ``1h 2m 3.45s``, ``45.67s``)."""
3
+ if total_seconds < 0:
4
+ total_seconds = 0
5
+ h = int(total_seconds // 3600)
6
+ m = int((total_seconds % 3600) // 60)
7
+ s = total_seconds % 60
8
+ if h:
9
+ return f"{h}h {m}m {s}s"
10
+ if m:
11
+ return f"{m}m {s}s"
12
+ text = f"{s}".rstrip("0").rstrip(".")
13
+ return f"{text}s" if text else "0s"
14
+
15
+
16
+ AMBIGUITY_CAUSES = {
17
+ "reference_resource_ambiguity": "Ambiguity is in the reference resources",
18
+ "definition_ambiguity": "Ambiguity is in the definitions",
19
+ "non_functional_requirement_ambiguity": "Ambiguity is in the implementation reqs",
20
+ "functional_requirement_ambiguity": "Ambiguity is in the functionality",
21
+ "other": "Ambiguity in the other parts of the specification",
22
+ }
@@ -91,6 +91,12 @@ def check_section_for_linked_resources(section):
91
91
  f"Plain syntax error: Only relative links are allowed (text: {link.node.children[0].content}, target: {link.node.target})."
92
92
  )
93
93
 
94
+ if not os.path.exists(link.node.target):
95
+ raise PlainSyntaxError(f"Plain syntax error: Link {link.node.target} does not exist.")
96
+
97
+ if not os.path.isfile(link.node.target):
98
+ raise PlainSyntaxError(f"Plain syntax error: Link {link.node.target} must be a file.")
99
+
94
100
  if len(link.node.children) != 1:
95
101
  raise PlainSyntaxError(f"Plain syntax error: Link must have text specified (link: {link.node.target}).")
96
102
 
@@ -5,13 +5,17 @@ import os
5
5
  import shutil
6
6
  from functools import cached_property
7
7
 
8
- from git.exc import NoSuchPathError
8
+ from plain2code_exceptions import GitNotInstalledError, MissingPreviousFunctionalitiesError, ModuleDoesNotExistError
9
+
10
+ try:
11
+ from git.exc import NoSuchPathError
12
+ except ImportError:
13
+ raise GitNotInstalledError("git is not installed. Please install git and try again.")
9
14
 
10
15
  import git_utils
11
16
  import plain_file
12
17
  import plain_spec
13
18
  from plain2code_console import console
14
- from plain2code_exceptions import MissingPreviousFunctionalitiesError, ModuleDoesNotExistError
15
19
  from render_machine.implementation_code_helpers import ImplementationCodeHelpers
16
20
 
17
21
  CODEPLAIN_MEMORY_SUBFOLDER = ".memory"
@@ -7,7 +7,7 @@ name = "codeplain"
7
7
  dynamic = ["version"]
8
8
  description = "Transform plain language specifications into working code"
9
9
  readme = "README.md"
10
- requires-python = "==3.11"
10
+ requires-python = ">=3.11"
11
11
  classifiers = [
12
12
  "Environment :: Console",
13
13
  "Intended Audience :: Developers",
@@ -40,7 +40,7 @@ class RunConformanceTests(BaseAction):
40
40
  + f"in module {render_context.conformance_tests_running_context.current_testing_module_name}"
41
41
  + ")."
42
42
  )
43
- exit_code, conformance_tests_issue, conformance_tests_temp_file_path = render_utils.execute_script(
43
+ exit_code, conformance_tests_issue, conformance_tests_temp_log_file_path = render_utils.execute_script(
44
44
  conformance_tests_script,
45
45
  [render_context.build_folder, conformance_tests_folder_name],
46
46
  "Conformance Tests",
@@ -49,7 +49,9 @@ class RunConformanceTests(BaseAction):
49
49
  timeout=render_context.test_script_timeout,
50
50
  stop_event=render_context.stop_event,
51
51
  )
52
- render_context.script_execution_history.latest_conformance_test_output_path = conformance_tests_temp_file_path
52
+ render_context.script_execution_history.latest_conformance_test_output_path = (
53
+ conformance_tests_temp_log_file_path
54
+ )
53
55
  render_context.script_execution_history.should_update_script_outputs = True
54
56
 
55
57
  render_context.memory_manager.create_conformance_tests_memory(
@@ -21,7 +21,7 @@ class RunUnitTests(BaseAction):
21
21
  console.info(
22
22
  f"Running unit tests script {unittests_script}. (attempt: {render_context.unit_tests_running_context.fix_attempts + 1})"
23
23
  )
24
- exit_code, unittests_issue, unittests_temp_file_path = render_utils.execute_script(
24
+ exit_code, unittests_issue, unittests_temp_log_file_path = render_utils.execute_script(
25
25
  unittests_script,
26
26
  [render_context.build_folder],
27
27
  "Unit Tests",
@@ -29,7 +29,7 @@ class RunUnitTests(BaseAction):
29
29
  stop_event=render_context.stop_event,
30
30
  )
31
31
 
32
- render_context.script_execution_history.latest_unit_test_output_path = unittests_temp_file_path
32
+ render_context.script_execution_history.latest_unit_test_output_path = unittests_temp_log_file_path
33
33
  render_context.script_execution_history.should_update_script_outputs = True
34
34
  if exit_code == 0:
35
35
  return self.SUCCESSFUL_OUTCOME, None
@@ -179,7 +179,11 @@ class RenderContext:
179
179
  )
180
180
 
181
181
  def has_next_frid(self) -> bool:
182
- return plain_spec.get_next_frid(self.plain_source_tree, self.frid_context.frid) is not None
182
+ next_frid = plain_spec.get_next_frid(self.plain_source_tree, self.frid_context.frid)
183
+ if self.render_range is None or len(self.render_range) == 0:
184
+ return next_frid is not None
185
+
186
+ return next_frid is not None and int(next_frid) <= int(self.render_range[-1])
183
187
 
184
188
  def finish_implementing_frid(self):
185
189
  self.functional_requirements_render_attempts_failed_unit_during_conformance_tests = 0
@@ -248,7 +252,8 @@ class RenderContext:
248
252
  conformance_tests_running_context = self.conformance_tests_running_context
249
253
  if conformance_tests_running_context.current_testing_module_name == self.module_name:
250
254
  conformance_tests_running_context.current_testing_frid = plain_spec.get_next_frid(
251
- self.plain_source_tree, self.conformance_tests_running_context.current_testing_frid
255
+ self.plain_source_tree,
256
+ self.conformance_tests_running_context.current_testing_frid,
252
257
  )
253
258
  else:
254
259
  all_frids = list(