codeplain 0.2.6__tar.gz → 0.2.8__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 (193) hide show
  1. {codeplain-0.2.6 → codeplain-0.2.8}/PKG-INFO +2 -2
  2. {codeplain-0.2.6 → codeplain-0.2.8}/config/system_config.yaml +1 -1
  3. codeplain-0.2.8/docs/plain2code_cli.md +63 -0
  4. {codeplain-0.2.6 → codeplain-0.2.8}/git_utils.py +20 -0
  5. {codeplain-0.2.6 → codeplain-0.2.8}/install/walkthrough.sh +47 -50
  6. {codeplain-0.2.6 → codeplain-0.2.8}/module_renderer.py +8 -1
  7. {codeplain-0.2.6 → codeplain-0.2.8}/plain2code.py +43 -5
  8. {codeplain-0.2.6 → codeplain-0.2.8}/plain2code_arguments.py +26 -21
  9. {codeplain-0.2.6 → codeplain-0.2.8}/plain2code_events.py +2 -1
  10. {codeplain-0.2.6 → codeplain-0.2.8}/plain2code_utils.py +5 -5
  11. {codeplain-0.2.6 → codeplain-0.2.8}/pyproject.toml +2 -2
  12. {codeplain-0.2.6 → codeplain-0.2.8}/tui/plain2code_tui.py +7 -7
  13. {codeplain-0.2.6 → codeplain-0.2.8}/tui/state_handlers.py +8 -4
  14. {codeplain-0.2.6 → codeplain-0.2.8}/tui/widget_helpers.py +11 -3
  15. codeplain-0.2.6/docs/plain2code_cli.md +0 -66
  16. {codeplain-0.2.6 → codeplain-0.2.8}/.flake8 +0 -0
  17. {codeplain-0.2.6 → codeplain-0.2.8}/.github/workflows/lint-and-test.yml +0 -0
  18. {codeplain-0.2.6 → codeplain-0.2.8}/.github/workflows/nofity-slack-on-main-merge.yml +0 -0
  19. {codeplain-0.2.6 → codeplain-0.2.8}/.github/workflows/publish-install-script.yml +0 -0
  20. {codeplain-0.2.6 → codeplain-0.2.8}/.github/workflows/publish-to-pypi.yml +0 -0
  21. {codeplain-0.2.6 → codeplain-0.2.8}/.gitignore +0 -0
  22. {codeplain-0.2.6 → codeplain-0.2.8}/.vscode/launch.json +0 -0
  23. {codeplain-0.2.6 → codeplain-0.2.8}/.vscode/settings.json +0 -0
  24. {codeplain-0.2.6 → codeplain-0.2.8}/LICENSE +0 -0
  25. {codeplain-0.2.6 → codeplain-0.2.8}/README.md +0 -0
  26. {codeplain-0.2.6 → codeplain-0.2.8}/codeplain_REST_api.py +0 -0
  27. {codeplain-0.2.6 → codeplain-0.2.8}/concept_utils.py +0 -0
  28. {codeplain-0.2.6 → codeplain-0.2.8}/config/__init__.py +0 -0
  29. {codeplain-0.2.6 → codeplain-0.2.8}/diff_utils.py +0 -0
  30. {codeplain-0.2.6 → codeplain-0.2.8}/docs/generate_cli.py +0 -0
  31. {codeplain-0.2.6 → codeplain-0.2.8}/docs/plain_language_specification.md +0 -0
  32. {codeplain-0.2.6 → codeplain-0.2.8}/docs/starting_a_plain_project_from_scratch.md +0 -0
  33. {codeplain-0.2.6 → codeplain-0.2.8}/event_bus.py +0 -0
  34. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_golang/config.yaml +0 -0
  35. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
  36. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
  37. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_golang/run.sh +0 -0
  38. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_python/config.yaml +0 -0
  39. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
  40. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_python/hello_world_python.plain +0 -0
  41. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_python/run.sh +0 -0
  42. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_react/config.yaml +0 -0
  43. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
  44. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
  45. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
  46. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
  47. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
  48. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_react/hello_world_react.plain +0 -0
  49. {codeplain-0.2.6 → codeplain-0.2.8}/examples/example_hello_world_react/run.sh +0 -0
  50. {codeplain-0.2.6 → codeplain-0.2.8}/examples/run.sh +0 -0
  51. {codeplain-0.2.6 → codeplain-0.2.8}/file_utils.py +0 -0
  52. {codeplain-0.2.6 → codeplain-0.2.8}/hash_key.py +0 -0
  53. {codeplain-0.2.6 → codeplain-0.2.8}/install/examples.sh +0 -0
  54. {codeplain-0.2.6 → codeplain-0.2.8}/install/install.sh +0 -0
  55. {codeplain-0.2.6 → codeplain-0.2.8}/memory_management.py +0 -0
  56. {codeplain-0.2.6 → codeplain-0.2.8}/plain2code_console.py +0 -0
  57. {codeplain-0.2.6 → codeplain-0.2.8}/plain2code_exceptions.py +0 -0
  58. {codeplain-0.2.6 → codeplain-0.2.8}/plain2code_logger.py +0 -0
  59. {codeplain-0.2.6 → codeplain-0.2.8}/plain2code_nodes.py +0 -0
  60. {codeplain-0.2.6 → codeplain-0.2.8}/plain2code_read_config.py +0 -0
  61. {codeplain-0.2.6 → codeplain-0.2.8}/plain2code_state.py +0 -0
  62. {codeplain-0.2.6 → codeplain-0.2.8}/plain_file.py +0 -0
  63. {codeplain-0.2.6 → codeplain-0.2.8}/plain_modules.py +0 -0
  64. {codeplain-0.2.6 → codeplain-0.2.8}/plain_spec.py +0 -0
  65. {codeplain-0.2.6 → codeplain-0.2.8}/pytest.ini +0 -0
  66. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/__init__.py +0 -0
  67. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/analyze_specification_ambiguity.py +0 -0
  68. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/base_action.py +0 -0
  69. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
  70. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/commit_implementation_code_changes.py +0 -0
  71. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/create_dist.py +0 -0
  72. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/exit_with_error.py +0 -0
  73. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/finish_functional_requirement.py +0 -0
  74. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/fix_conformance_test.py +0 -0
  75. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/fix_unit_tests.py +0 -0
  76. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/prepare_repositories.py +0 -0
  77. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/prepare_testing_environment.py +0 -0
  78. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/refactor_code.py +0 -0
  79. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/render_conformance_tests.py +0 -0
  80. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/render_functional_requirement.py +0 -0
  81. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/run_conformance_tests.py +0 -0
  82. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/run_unit_tests.py +0 -0
  83. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/actions/summarize_conformance_tests.py +0 -0
  84. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/code_renderer.py +0 -0
  85. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/conformance_test_helpers.py +0 -0
  86. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/conformance_tests.py +0 -0
  87. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/implementation_code_helpers.py +0 -0
  88. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/render_context.py +0 -0
  89. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/render_types.py +0 -0
  90. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/render_utils.py +0 -0
  91. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/state_machine_config.py +0 -0
  92. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/states.py +0 -0
  93. {codeplain-0.2.6 → codeplain-0.2.8}/render_machine/triggers.py +0 -0
  94. {codeplain-0.2.6 → codeplain-0.2.8}/requirements.txt +0 -0
  95. {codeplain-0.2.6 → codeplain-0.2.8}/resources/codeplain_overview.png +0 -0
  96. {codeplain-0.2.6 → codeplain-0.2.8}/resources/plain_example.png +0 -0
  97. {codeplain-0.2.6 → codeplain-0.2.8}/standard_template_library/__init__.py +0 -0
  98. {codeplain-0.2.6 → codeplain-0.2.8}/standard_template_library/golang-console-app-template.plain +0 -0
  99. {codeplain-0.2.6 → codeplain-0.2.8}/standard_template_library/python-console-app-template.plain +0 -0
  100. {codeplain-0.2.6 → codeplain-0.2.8}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
  101. {codeplain-0.2.6 → codeplain-0.2.8}/standard_template_library/typescript-react-app-template.plain +0 -0
  102. {codeplain-0.2.6 → codeplain-0.2.8}/system_config.py +0 -0
  103. {codeplain-0.2.6 → codeplain-0.2.8}/test_scripts/run_conformance_tests_cypress.sh +0 -0
  104. {codeplain-0.2.6 → codeplain-0.2.8}/test_scripts/run_conformance_tests_golang.sh +0 -0
  105. {codeplain-0.2.6 → codeplain-0.2.8}/test_scripts/run_conformance_tests_python.sh +0 -0
  106. {codeplain-0.2.6 → codeplain-0.2.8}/test_scripts/run_unittests_golang.sh +0 -0
  107. {codeplain-0.2.6 → codeplain-0.2.8}/test_scripts/run_unittests_python.sh +0 -0
  108. {codeplain-0.2.6 → codeplain-0.2.8}/test_scripts/run_unittests_react.sh +0 -0
  109. {codeplain-0.2.6 → codeplain-0.2.8}/tests/__init__.py +0 -0
  110. {codeplain-0.2.6 → codeplain-0.2.8}/tests/conftest.py +0 -0
  111. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/imports/circular_imports_1.plain +0 -0
  112. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/imports/circular_imports_2.plain +0 -0
  113. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/imports/circular_imports_main.plain +0 -0
  114. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/imports/diamond_import_1.plain +0 -0
  115. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/imports/diamond_import_2.plain +0 -0
  116. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/imports/diamond_import_common.plain +0 -0
  117. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/imports/diamond_imports_main.plain +0 -0
  118. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/imports/non_existent_import.plain +0 -0
  119. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
  120. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfile/invalid_specification_order.plain +0 -0
  121. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
  122. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
  123. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
  124. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
  125. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
  126. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
  127. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
  128. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
  129. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
  130. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
  131. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
  132. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
  133. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
  134. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
  135. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
  136. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
  137. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/exported_concepts.plain +0 -0
  138. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
  139. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
  140. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/exported_concepts_missing.plain +0 -0
  141. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/exported_concepts_missing_example.plain +0 -0
  142. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
  143. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
  144. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
  145. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
  146. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
  147. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
  148. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
  149. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
  150. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/required_concepts.plain +0 -0
  151. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
  152. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
  153. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
  154. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
  155. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
  156. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
  157. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
  158. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
  159. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/topological_sort.plain +0 -0
  160. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
  161. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/circular_requires_main.plain +0 -0
  162. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/circular_requires_sub.plain +0 -0
  163. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/diamond_requires_1.plain +0 -0
  164. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/diamond_requires_2.plain +0 -0
  165. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/diamond_requires_common.plain +0 -0
  166. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/diamond_requires_main.plain +0 -0
  167. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/independent_requires_1.plain +0 -0
  168. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/independent_requires_2.plain +0 -0
  169. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/independent_requires_main.plain +0 -0
  170. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/non_existent_require.plain +0 -0
  171. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/normal_requires_1.plain +0 -0
  172. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/normal_requires_2.plain +0 -0
  173. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/normal_requires_common.plain +0 -0
  174. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/requires/normal_requires_main.plain +0 -0
  175. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/simple.plain +0 -0
  176. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/templates/block_level_include.plain +0 -0
  177. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/templates/code_variables.plain +0 -0
  178. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/templates/header.plain +0 -0
  179. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/templates/implement.plain +0 -0
  180. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/templates/implement_2.plain +0 -0
  181. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/templates/template_include.plain +0 -0
  182. {codeplain-0.2.6 → codeplain-0.2.8}/tests/data/templates/test_hardest_problem.plain +0 -0
  183. {codeplain-0.2.6 → codeplain-0.2.8}/tests/test_git_utils.py +0 -0
  184. {codeplain-0.2.6 → codeplain-0.2.8}/tests/test_imports.py +0 -0
  185. {codeplain-0.2.6 → codeplain-0.2.8}/tests/test_plainfile.py +0 -0
  186. {codeplain-0.2.6 → codeplain-0.2.8}/tests/test_plainfileparser.py +0 -0
  187. {codeplain-0.2.6 → codeplain-0.2.8}/tests/test_plainspec.py +0 -0
  188. {codeplain-0.2.6 → codeplain-0.2.8}/tests/test_requires.py +0 -0
  189. {codeplain-0.2.6 → codeplain-0.2.8}/tui/__init__.py +0 -0
  190. {codeplain-0.2.6 → codeplain-0.2.8}/tui/components.py +0 -0
  191. {codeplain-0.2.6 → codeplain-0.2.8}/tui/models.py +0 -0
  192. {codeplain-0.2.6 → codeplain-0.2.8}/tui/spinner.py +0 -0
  193. {codeplain-0.2.6 → codeplain-0.2.8}/tui/styles.css +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeplain
3
- Version: 0.2.6
3
+ Version: 0.2.8
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.0
11
11
  Requires-Dist: gitpython==3.1.42
12
12
  Requires-Dist: mistletoe==1.3.0
13
13
  Requires-Dist: networkx==3.6.1
@@ -1,4 +1,4 @@
1
- client_version: "0.2.6"
1
+ client_version: "0.2.8"
2
2
 
3
3
  error_messages:
4
4
  template_not_found:
@@ -0,0 +1,63 @@
1
+ # Plain2Code CLI Reference
2
+
3
+ ```text
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] [--config-name CONFIG_NAME] [--render-range RENDER_RANGE | --render-from RENDER_FROM] [--force-render]
5
+ [--unittests-script UNITTESTS_SCRIPT] [--conformance-tests-folder CONFORMANCE_TESTS_FOLDER] [--conformance-tests-script CONFORMANCE_TESTS_SCRIPT] [--prepare-environment-script PREPARE_ENVIRONMENT_SCRIPT] [--api [API]] [--api-key API_KEY]
6
+ [--full-plain] [--dry-run] [--replay-with REPLAY_WITH] [--template-dir TEMPLATE_DIR] [--copy-build] [--build-dest BUILD_DEST] [--copy-conformance-tests] [--conformance-tests-dest CONFORMANCE_TESTS_DEST] [--render-machine-graph]
7
+ [--logging-config-path]
8
+ filename
9
+
10
+ Render plain code to target code.
11
+
12
+ positional arguments:
13
+ 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 the defaults. See --template-dir for more details about template loading.
14
+
15
+ options:
16
+ -h, --help show this help message and exit
17
+ --verbose, -v Enable verbose output
18
+ --base-folder BASE_FOLDER
19
+ Base folder for the build files
20
+ --build-folder BUILD_FOLDER
21
+ Folder for build files
22
+ --log-to-file, --no-log-to-file
23
+ Enable logging to a file. Defaults to True. Use --no-log-to-file to disable.
24
+ --log-file-name LOG_FILE_NAME
25
+ Name of the log file. Defaults to 'codeplain.log'.Always resolved relative to the plain file directory.If file on this path already exists, it will be overwritten by the current logs.
26
+ --render-range RENDER_RANGE
27
+ Specify a range of functional requirements to render (e.g. '1.1,2.3'). Use comma to separate start and end IDs. If only one ID is provided, only that requirement is rendered. Range is inclusive of both start and end IDs.
28
+ --render-from RENDER_FROM
29
+ Continue generation starting from this specific functional requirement (e.g. '2.1'). The requirement with this ID will be included in the output. The ID must match one of the functional requirements in your plain file.
30
+ --force-render Force re-render of all the required modules.
31
+ --unittests-script UNITTESTS_SCRIPT
32
+ Shell script to run unit tests on generated code. Receives the build folder path as its first argument (default: 'plain_modules').
33
+ --conformance-tests-folder CONFORMANCE_TESTS_FOLDER
34
+ Folder for conformance test files
35
+ --conformance-tests-script CONFORMANCE_TESTS_SCRIPT
36
+ Path to conformance tests shell script. The script should accept two arguments: 1) First argument: path to a folder (e.g. 'plain_modules/module_name') containing generated source code, 2) Second argument: path to a subfolder of the conformance
37
+ tests folder (e.g. 'conformance_tests/subfoldername') containing test files.
38
+ --prepare-environment-script PREPARE_ENVIRONMENT_SCRIPT
39
+ Path to a shell script that prepares the testing environment. The script should accept the build folder path as its first argument (default: 'plain_modules').
40
+ --api [API] Alternative base URL for the API. Default: `https://api.codeplain.ai`
41
+ --api-key API_KEY API key used to access the API. If not provided, the CODEPLAIN_API_KEY environment variable is used.
42
+ --full-plain Display the complete plain specification before code generation. This shows your plain file with any included template content expanded. Useful for understanding what content is being processed.
43
+ --dry-run Preview of what Codeplain would do without actually making any changes.
44
+ --replay-with REPLAY_WITH
45
+ --template-dir TEMPLATE_DIR
46
+ Path to a custom template directory. Templates are searched in the following order: 1) directory containing the plain file, 2) this custom template directory (if provided), 3) built-in standard_template_library directory
47
+ --copy-build If set, copy the build folder to `--build-dest` after every successful rendering.
48
+ --build-dest BUILD_DEST
49
+ Target folder to copy build output to (used only if --copy-build is set).
50
+ --copy-conformance-tests
51
+ If set, copy the conformance tests folder to `--conformance-tests-dest` after every successful rendering. Requires --conformance-tests-script.
52
+ --conformance-tests-dest CONFORMANCE_TESTS_DEST
53
+ Target folder to copy conformance tests output to (used only if --copy-conformance-tests is set).
54
+ --render-machine-graph
55
+ If set, render the state machine graph.
56
+ --logging-config-path
57
+ Path to the logging configuration file.
58
+
59
+ configuration:
60
+ --config-name CONFIG_NAME
61
+ Path to the config file, defaults to config.yaml
62
+
63
+ ```
@@ -1,4 +1,5 @@
1
1
  import os
2
+ from configparser import NoOptionError, NoSectionError
2
3
  from typing import Optional, Union
3
4
 
4
5
  from git import Repo
@@ -42,6 +43,24 @@ def _get_full_commit_message(message, module_name, frid, render_id) -> str:
42
43
  return full_message
43
44
 
44
45
 
46
+ def _ensure_git_config(repo: Repo) -> None:
47
+ config = repo.config_reader()
48
+
49
+ try:
50
+ config.get_value("user", "name")
51
+ except (NoSectionError, NoOptionError):
52
+ # user.name not configured, set a default at repo level
53
+ with repo.config_writer(config_level="repository") as writer:
54
+ writer.set_value("user", "name", "Codeplain")
55
+
56
+ try:
57
+ config.get_value("user", "email")
58
+ except (NoSectionError, NoOptionError):
59
+ # user.email not configured, set a default at repo level
60
+ with repo.config_writer(config_level="repository") as writer:
61
+ writer.set_value("user", "email", "codeplain@localhost")
62
+
63
+
45
64
  def init_git_repo(
46
65
  path_to_repo: Union[str, os.PathLike], module_name: Optional[str] = None, render_id: Optional[str] = None
47
66
  ) -> Repo:
@@ -56,6 +75,7 @@ def init_git_repo(
56
75
  os.makedirs(path_to_repo)
57
76
 
58
77
  repo = Repo.init(path_to_repo)
78
+ _ensure_git_config(repo)
59
79
  repo.git.commit(
60
80
  "--allow-empty", "-m", _get_full_commit_message(INITIAL_COMMIT_MESSAGE, module_name, None, render_id)
61
81
  )
@@ -13,13 +13,13 @@ NC="${NC:-\033[0m}"
13
13
  # Onboarding Step 1: Introduction to Plain
14
14
  clear
15
15
  echo ""
16
- echo -e "${GRAY}────────────────────────────────────────────${NC}"
17
- echo -e " ${YELLOW}${BOLD}quick intro to ***plain specification language${NC} - Step 1 of 5"
18
- echo -e "${GRAY}────────────────────────────────────────────${NC}"
16
+ echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
17
+ echo -e " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 1 of 5"
18
+ echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
19
19
  echo ""
20
- echo -e " ***plain is a language of spec-driven development that allows developers to express intent on any level of detail."
20
+ echo -e " ***plain is a language of spec-driven development that allows developers to express intent at any level of detail."
21
21
  echo ""
22
- echo -e " write specs in ${YELLOW}plain English${NC}, in markdown with additional syntax"
22
+ echo -e " write specs in natural language extended with additional syntax based on markdown."
23
23
  echo ""
24
24
  echo -e " render production-ready code with *codeplain."
25
25
  echo ""
@@ -28,8 +28,8 @@ echo ""
28
28
  echo -e "${GRAY} ┌────────────────────────────────────────────────────────┐${NC}"
29
29
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
30
30
  echo -e "${GRAY} │${NC} ${YELLOW}***definitions***${NC} - key concepts in your app ${GRAY}│${NC}"
31
- echo -e "${GRAY} │${NC} ${YELLOW}***implementation reqs***${NC} - implementation details ${GRAY}│${NC}"
32
- echo -e "${GRAY} │${NC} ${YELLOW}***test reqs***${NC} - testing requirements ${GRAY}│${NC}"
31
+ echo -e "${GRAY} │${NC} ${YELLOW}***implementation reqs***${NC} - implementation details ${GRAY}│${NC}"
32
+ echo -e "${GRAY} │${NC} ${YELLOW}***test reqs***${NC} - testing requirements ${GRAY}│${NC}"
33
33
  echo -e "${GRAY} │${NC} ${YELLOW}***functional specs***${NC} - what the app should do ${GRAY}│${NC}"
34
34
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
35
35
  echo -e "${GRAY} └────────────────────────────────────────────────────────┘${NC}"
@@ -41,33 +41,32 @@ read -r -p " press [Enter] to continue..." < /dev/tty
41
41
  # Onboarding Step 2: Functional Specification
42
42
  clear
43
43
  echo ""
44
- echo -e "${GRAY}────────────────────────────────────────────${NC}"
45
- echo -e " ${YELLOW}${BOLD}Plain Language 101${NC} - Step 2 of 5"
46
- echo -e "${GRAY}────────────────────────────────────────────${NC}"
44
+ echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
45
+ echo -e " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 2 of 5"
46
+ echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
47
47
  echo ""
48
48
  echo -e " ${WHITE}${BOLD}FUNCTIONAL SPECS${NC} - what should the app do?"
49
49
  echo ""
50
50
  echo -e " This is where you describe ${GREEN}what your app should do${NC},"
51
- echo -e " written in plain English. No code, just requirements."
51
+ echo -e " written in natural language. No code, just requirements."
52
52
  echo ""
53
53
  echo -e "${GRAY} ┌────────────────────────────────────────────────────────┐${NC}"
54
54
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
55
- echo -e "${GRAY} │${NC} ${GRAY}***definitions***${NC} ${GRAY}│${NC}"
55
+ echo -e "${GRAY} │${NC} ${GRAY}***definitions***${NC} ${GRAY}│${NC}"
56
56
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
57
- echo -e "${GRAY} │${NC} ${GRAY}- :App: is a console application.${NC} ${GRAY}│${NC}"
57
+ echo -e "${GRAY} │${NC} ${GRAY}- :App: is a console application.${NC} ${GRAY}│${NC}"
58
58
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
59
- echo -e "${GRAY} │${NC} ${GRAY}***implementation reqs***${NC} ${GRAY}│${NC}"
59
+ echo -e "${GRAY} │${NC} ${GRAY}***implementation reqs***${NC} ${GRAY}│${NC}"
60
60
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
61
- echo -e "${GRAY} │${NC} ${GRAY}- :Implementation: should be in Python.${NC} ${GRAY}│${NC}"
62
- echo -e "${GRAY} │${NC} ${GRAY}- :UnitTests: should use Unittest framework.${NC} ${GRAY}│${NC}"
61
+ echo -e "${GRAY} │${NC} ${GRAY}- :Implementation: should be in Python.${NC} ${GRAY}│${NC}"
63
62
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
64
- echo -e "${GRAY} │${NC} ${GRAY}***test reqs***${NC} ${GRAY}│${NC}"
63
+ echo -e "${GRAY} │${NC} ${GRAY}***test reqs***${NC} ${GRAY}│${NC}"
65
64
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
66
- echo -e "${GRAY} │${NC} ${GRAY}- :ConformanceTests: should use Unittest.${NC} ${GRAY}│${NC}"
65
+ echo -e "${GRAY} │${NC} ${GRAY}- :ConformanceTests: should use pytest.${NC} ${GRAY}│${NC}"
67
66
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
68
- echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***functional specs***${NC} ${GRAY}│${NC}"
67
+ echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***functional specs***${NC} ${GRAY}│${NC}"
69
68
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
70
- echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :App: should display \"hello, world\".${NC} ${GRAY}│${NC}"
69
+ echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :App: should display \"hello, world\".${NC} ${GRAY}│${NC}"
71
70
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
72
71
  echo -e "${GRAY} └────────────────────────────────────────────────────────┘${NC}"
73
72
  echo ""
@@ -79,37 +78,36 @@ read -r -p " press [Enter] to continue..." < /dev/tty
79
78
  # Onboarding Step 3: Definitions
80
79
  clear
81
80
  echo ""
82
- echo -e "${GRAY}────────────────────────────────────────────${NC}"
83
- echo -e " ${YELLOW}${BOLD}Plain Language 101${NC} - Step 3 of 5"
84
- echo -e "${GRAY}────────────────────────────────────────────${NC}"
81
+ echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
82
+ echo -e " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 3 of 5"
83
+ echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
85
84
  echo ""
86
- echo -e " ${WHITE}${BOLD}DEFINITIONS${NC} - identify key concepts"
85
+ echo -e " ${WHITE}${BOLD}DEFINITIONS${NC} - definitions and descriptions of key concepts"
87
86
  echo ""
88
- echo -e " Define ${GREEN}reusable concepts${NC} with the ${YELLOW}:ConceptName:${NC} syntax."
87
+ echo -e " Define ${GREEN}reusable concepts${NC} using the ${YELLOW}:Concept:${NC} notation."
89
88
  echo -e " These become building blocks you can reference anywhere."
90
89
  echo ""
91
90
  echo -e "${GRAY} ┌────────────────────────────────────────────────────────┐${NC}"
92
91
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
93
- echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***definitions***${NC} ${GRAY}│${NC}"
92
+ echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***definitions***${NC} ${GRAY}│${NC}"
94
93
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
95
- echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :App: is a console application.${NC} ${GRAY}│${NC}"
94
+ echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :App: is a console application.${NC} ${GRAY}│${NC}"
96
95
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
97
- echo -e "${GRAY} │${NC} ${GRAY}***implementation reqs***${NC} ${GRAY}│${NC}"
96
+ echo -e "${GRAY} │${NC} ${GRAY}***implementation reqs***${NC} ${GRAY}│${NC}"
98
97
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
99
- echo -e "${GRAY} │${NC} ${GRAY}- :Implementation: should be in Python.${NC} ${GRAY}│${NC}"
100
- echo -e "${GRAY} │${NC} ${GRAY}- :UnitTests: should use Unittest framework.${NC} ${GRAY}│${NC}"
98
+ echo -e "${GRAY} │${NC} ${GRAY}- :Implementation: should be in Python.${NC} ${GRAY}│${NC}"
101
99
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
102
- echo -e "${GRAY} │${NC} ${GRAY}***test reqs***${NC} ${GRAY}│${NC}"
100
+ echo -e "${GRAY} │${NC} ${GRAY}***test reqs***${NC} ${GRAY}│${NC}"
103
101
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
104
- echo -e "${GRAY} │${NC} ${GRAY}- :ConformanceTests: should use Unittest.${NC} ${GRAY}│${NC}"
102
+ echo -e "${GRAY} │${NC} ${GRAY}- :ConformanceTests: should use pytest.${NC} ${GRAY}│${NC}"
105
103
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
106
- echo -e "${GRAY} │${NC} ${GRAY}***functional specs***${NC} ${GRAY}│${NC}"
104
+ echo -e "${GRAY} │${NC} ${GRAY}***functional specs***${NC} ${GRAY}│${NC}"
107
105
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
108
- echo -e "${GRAY} │${NC} ${GRAY}- :App: should display \"hello, world\".${NC} ${GRAY}│${NC}"
106
+ echo -e "${GRAY} │${NC} ${GRAY}- :App: should display \"hello, world\".${NC} ${GRAY}│${NC}"
109
107
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
110
108
  echo -e "${GRAY} └────────────────────────────────────────────────────────┘${NC}"
111
109
  echo ""
112
- echo -e " ${GREEN}▲${NC} The ${YELLOW}:App:${NC} concept is defined once and used throughout."
110
+ echo -e " ${GREEN}▲${NC} The ${YELLOW}:App:${NC} concept is defined once and used throughout the specs."
113
111
  echo -e " Concepts help keep your specs consistent and clear."
114
112
  echo ""
115
113
  read -r -p " press [Enter] to continue..." < /dev/tty
@@ -117,9 +115,9 @@ read -r -p " press [Enter] to continue..." < /dev/tty
117
115
  # Onboarding Step 4: Implementation & Test Reqs
118
116
  clear
119
117
  echo ""
120
- echo -e "${GRAY}────────────────────────────────────────────${NC}"
121
- echo -e " ${YELLOW}${BOLD}Plain Language 101${NC} - Step 4 of 5"
122
- echo -e "${GRAY}────────────────────────────────────────────${NC}"
118
+ echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
119
+ echo -e " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 4 of 5"
120
+ echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
123
121
  echo ""
124
122
  echo -e " ${WHITE}${BOLD}IMPLEMENTATION & TEST REQS${NC} - how to implement and test"
125
123
  echo ""
@@ -128,22 +126,21 @@ echo -e " This guides how the code should be generated and verified."
128
126
  echo ""
129
127
  echo -e "${GRAY} ┌────────────────────────────────────────────────────────┐${NC}"
130
128
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
131
- echo -e "${GRAY} │${NC} ${GRAY}***definitions***${NC} ${GRAY}│${NC}"
129
+ echo -e "${GRAY} │${NC} ${GRAY}***definitions***${NC} ${GRAY}│${NC}"
132
130
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
133
- echo -e "${GRAY} │${NC} ${GRAY}- :App: is a console application.${NC} ${GRAY}│${NC}"
131
+ echo -e "${GRAY} │${NC} ${GRAY}- :App: is a console application.${NC} ${GRAY}│${NC}"
134
132
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
135
- echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***implementation reqs***${NC} ${GRAY}│${NC}"
133
+ echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***implementation reqs***${NC} ${GRAY}│${NC}"
136
134
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
137
- echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :Implementation: should be in Python.${NC} ${GRAY}│${NC}"
138
- echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :UnitTests: should use Unittest framework.${NC} ${GRAY}│${NC}"
135
+ echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :Implementation: should be in Python.${NC} ${GRAY}│${NC}"
139
136
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
140
- echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***test reqs***${NC} ${GRAY}│${NC}"
137
+ echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***test reqs***${NC} ${GRAY}│${NC}"
141
138
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
142
- echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :ConformanceTests: should use Unittest.${NC} ${GRAY}│${NC}"
139
+ echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :ConformanceTests: should use pytest.${NC} ${GRAY}│${NC}"
143
140
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
144
- echo -e "${GRAY} │${NC} ${GRAY}***functional specs***${NC} ${GRAY}│${NC}"
141
+ echo -e "${GRAY} │${NC} ${GRAY}***functional specs***${NC} ${GRAY}│${NC}"
145
142
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
146
- echo -e "${GRAY} │${NC} ${GRAY}- :App: should display \"hello, world\".${NC} ${GRAY}│${NC}"
143
+ echo -e "${GRAY} │${NC} ${GRAY}- :App: should display \"hello, world\".${NC} ${GRAY}│${NC}"
147
144
  echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
148
145
  echo -e "${GRAY} └────────────────────────────────────────────────────────┘${NC}"
149
146
  echo ""
@@ -155,9 +152,9 @@ read -r -p " press [Enter] to continue..." < /dev/tty
155
152
  # Onboarding Step 5: Rendering Code
156
153
  clear
157
154
  echo ""
158
- echo -e "${GRAY}────────────────────────────────────────────${NC}"
159
- echo -e " ${YELLOW}${BOLD}Plain Language 101${NC} - Step 5 of 5"
160
- echo -e "${GRAY}────────────────────────────────────────────${NC}"
155
+ echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
156
+ echo -e " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 5 of 5"
157
+ echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
161
158
  echo ""
162
159
  echo -e " ${WHITE}${BOLD}RENDERING CODE${NC} - generate your app"
163
160
  echo ""
@@ -260,4 +260,11 @@ class ModuleRenderer:
260
260
  self.loaded_modules = list[PlainModule]()
261
261
  _, _, rendering_failed = self._render_module(self.filename, self.render_range, True)
262
262
  if not rendering_failed:
263
- self.event_bus.publish(RenderCompleted())
263
+ # Get the last module that completed rendering
264
+ if self.args.copy_build:
265
+ rendered_code_path = f"{self.args.build_dest}/"
266
+ else:
267
+ last_module_name = self.filename.replace(plain_file.PLAIN_SOURCE_FILE_EXTENSION, "")
268
+ rendered_code_path = f"{os.path.join(self.args.build_folder, last_module_name)}/"
269
+
270
+ self.event_bus.publish(RenderCompleted(rendered_code_path=rendered_code_path))
@@ -3,6 +3,7 @@ import logging
3
3
  import logging.config
4
4
  import os
5
5
  import sys
6
+ from pathlib import Path
6
7
  from typing import Optional
7
8
 
8
9
  import yaml
@@ -42,6 +43,7 @@ from plain2code_logger import (
42
43
  get_log_file_path,
43
44
  )
44
45
  from plain2code_state import RunState
46
+ from plain2code_utils import print_dry_run_output
45
47
  from system_config import system_config
46
48
  from tui.plain2code_tui import Plain2CodeTUI
47
49
 
@@ -72,6 +74,23 @@ def get_render_range_from(start, plain_source):
72
74
  return _get_frids_range(plain_source, start)
73
75
 
74
76
 
77
+ def compute_render_range(args, plain_source_tree):
78
+ """Compute render range from --render-range or --render-from arguments.
79
+
80
+ Args:
81
+ args: Parsed command line arguments
82
+ plain_source_tree: Parsed plain source tree
83
+
84
+ Returns:
85
+ List of FRIDs to render, or None to render all
86
+ """
87
+ if args.render_range:
88
+ return get_render_range(args.render_range, plain_source_tree)
89
+ elif args.render_from:
90
+ return get_render_range_from(args.render_from, plain_source_tree)
91
+ return None
92
+
93
+
75
94
  def _get_frids_range(plain_source, start, end=None):
76
95
  frids = list(plain_spec.get_frids(plain_source))
77
96
 
@@ -196,11 +215,7 @@ def render(args, run_state: RunState, event_bus: EventBus): # noqa: C901
196
215
  if args.render_range or args.render_from:
197
216
  # Parse the plain file to get the plain_source for FRID extraction
198
217
  _, plain_source, _ = plain_file.plain_file_parser(args.filename, template_dirs)
199
-
200
- if args.render_range:
201
- render_range = get_render_range(args.render_range, plain_source)
202
- elif args.render_from:
203
- render_range = get_render_range_from(args.render_from, plain_source)
218
+ render_range = compute_render_range(args, plain_source)
204
219
 
205
220
  codeplainAPI = codeplain_api.CodeplainAPI(args.api_key, console)
206
221
  codeplainAPI.verbose = args.verbose
@@ -242,6 +257,29 @@ def render(args, run_state: RunState, event_bus: EventBus): # noqa: C901
242
257
  def main(): # noqa: C901
243
258
  args = parse_arguments()
244
259
 
260
+ # Handle early-exit flags before heavy initialization
261
+ if args.dry_run or args.full_plain:
262
+ template_dirs = file_utils.get_template_directories(args.filename, args.template_dir, DEFAULT_TEMPLATE_DIRS)
263
+
264
+ try:
265
+ if args.full_plain:
266
+ module_name = Path(args.filename).stem
267
+ plain_source = plain_file.read_module_plain_source(module_name, template_dirs)
268
+ [full_plain_source, _] = file_utils.get_loaded_templates(template_dirs, plain_source)
269
+ console.info("Full plain text:\n")
270
+ console.info(full_plain_source)
271
+ return
272
+
273
+ if args.dry_run:
274
+ console.info("Printing dry run output...\n")
275
+ _, plain_source_tree, _ = plain_file.plain_file_parser(args.filename, template_dirs)
276
+ render_range = compute_render_range(args, plain_source_tree)
277
+ print_dry_run_output(plain_source_tree, render_range)
278
+ return
279
+ except Exception as e:
280
+ console.error(f"Error: {str(e)}")
281
+ return
282
+
245
283
  event_bus = EventBus()
246
284
 
247
285
  if not args.api:
@@ -15,6 +15,7 @@ DEFAULT_CONFORMANCE_TESTS_DEST = "dist_conformance_tests"
15
15
  UNIT_TESTS_SCRIPT_NAME = "unittests_script"
16
16
  CONFORMANCE_TESTS_SCRIPT_NAME = "conformance_tests_script"
17
17
  DEFAULT_LOG_FILE_NAME = "codeplain.log"
18
+ PREPARE_ENVIRONMENT_SCRIPT_NAME = "prepare_environment_script"
18
19
 
19
20
 
20
21
  def process_test_script_path(script_arg_name, config):
@@ -134,7 +135,7 @@ def create_parser():
134
135
  "--log-to-file",
135
136
  action=argparse.BooleanOptionalAction,
136
137
  default=True,
137
- help="Enable logging to a file. Defaults to True. Use --no-log-to-file to disable.",
138
+ help="Enable logging to a file. Defaults to True. Set to False to disable.",
138
139
  )
139
140
  parser.add_argument(
140
141
  "--log-file-name",
@@ -142,7 +143,7 @@ def create_parser():
142
143
  default=DEFAULT_LOG_FILE_NAME,
143
144
  help=f"Name of the log file. Defaults to '{DEFAULT_LOG_FILE_NAME}'."
144
145
  "Always resolved relative to the plain file directory."
145
- "If file on this path already exists, it will be overwritten by the current logs.",
146
+ "If file on this path already exists, the already existing log file will be overwritten by the current logs.",
146
147
  )
147
148
 
148
149
  # Add config file arguments
@@ -158,14 +159,14 @@ def create_parser():
158
159
  render_range_group.add_argument(
159
160
  "--render-range",
160
161
  type=frid_range_string,
161
- help="Specify a range of functional requirements to render (e.g. '1.1,2.3'). "
162
+ help="Specify a range of functional requirements to render (e.g. `1` , `2`, `3`). "
162
163
  "Use comma to separate start and end IDs. If only one ID is provided, only that requirement is rendered. "
163
164
  "Range is inclusive of both start and end IDs.",
164
165
  )
165
166
  render_range_group.add_argument(
166
167
  "--render-from",
167
168
  type=frid_string,
168
- help="Continue generation starting from this specific functional requirement (e.g. '2.1'). "
169
+ help="Continue generation starting from this specific functional requirement (e.g. `2`). "
169
170
  "The requirement with this ID will be included in the output. The ID must match one of the functional requirements in your plain file.",
170
171
  )
171
172
 
@@ -190,15 +191,15 @@ def create_parser():
190
191
  parser.add_argument(
191
192
  "--conformance-tests-script",
192
193
  type=str,
193
- help="Path to conformance tests shell script. The script should accept two arguments: "
194
- "1) First argument: path to a folder (e.g. 'plain_modules/module_name') containing generated source code, "
195
- "2) Second argument: path to a subfolder of the conformance tests folder (e.g. 'conformance_tests/subfoldername') containing test files.",
194
+ help="Path to conformance tests shell script. Every conformance test script should accept two arguments: "
195
+ "1) Path to a folder (e.g. `plain_modules/module_name`) containing generated source code, "
196
+ "2) Path to a subfolder of the conformance tests folder (e.g. `conformance_tests/subfoldername`) containing test files.",
196
197
  )
197
198
 
198
199
  parser.add_argument(
199
200
  "--prepare-environment-script",
200
201
  type=str,
201
- help="Path to a shell script that prepares the testing environment. The script should accept the build folder path as its first argument (default: 'plain_modules').",
202
+ help="Path to a shell script that prepares the testing environment. The script should accept the source code folder path as its first argument.",
202
203
  )
203
204
 
204
205
  parser.add_argument(
@@ -212,17 +213,18 @@ def create_parser():
212
213
  "--api-key",
213
214
  type=str,
214
215
  default=CODEPLAIN_API_KEY,
215
- help="API key used to access the API. If not provided, the CODEPLAIN_API_KEY environment variable is used.",
216
+ help="API key used to access the API. If not provided, the `CODEPLAIN_API_KEY` environment variable is used.",
216
217
  )
217
218
  parser.add_argument(
218
219
  "--full-plain",
219
220
  action="store_true",
220
- help="Display the complete plain specification before code generation. "
221
- "This shows your plain file with "
222
- "any included template content expanded. Useful for understanding what content is being processed.",
221
+ help="Full preview ***plain specification before code generation."
222
+ "Use when you want to preview context of all ***plain primitives that are going to be included in order to render the given module.",
223
223
  )
224
224
  parser.add_argument(
225
- "--dry-run", action="store_true", help="Preview of what Codeplain would do without actually making any changes."
225
+ "--dry-run",
226
+ action="store_true",
227
+ help="Dry run preview of the code generation (without actually making any changes).",
226
228
  )
227
229
  parser.add_argument(
228
230
  "--replay-with",
@@ -236,33 +238,33 @@ def create_parser():
236
238
  type=str,
237
239
  default=None,
238
240
  help="Path to a custom template directory. Templates are searched in the following order: "
239
- "1) directory containing the plain file, "
240
- "2) this custom template directory (if provided), "
241
- "3) built-in standard_template_library directory",
241
+ "1) Directory containing the plain file, "
242
+ "2) Custom template directory (if provided through this argument), "
243
+ "3) Built-in standard_template_library directory",
242
244
  )
243
245
  parser.add_argument(
244
246
  "--copy-build",
245
247
  action="store_true",
246
248
  default=False,
247
- help="If set, copy the build folder to `--build-dest` after every successful rendering.",
249
+ help="If set, copy the rendered contents of code in `--base-folder` folder to `--build-dest` folder after successful rendering.",
248
250
  )
249
251
  parser.add_argument(
250
252
  "--build-dest",
251
253
  type=non_empty_string,
252
254
  default=DEFAULT_BUILD_DEST,
253
- help="Target folder to copy build output to (used only if --copy-build is set).",
255
+ help="Target folder to copy rendered contents of code to (used only if --copy-build is set).",
254
256
  )
255
257
  parser.add_argument(
256
258
  "--copy-conformance-tests",
257
259
  action="store_true",
258
260
  default=False,
259
- help="If set, copy the conformance tests folder to `--conformance-tests-dest` after every successful rendering. Requires --conformance-tests-script.",
261
+ 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.",
260
262
  )
261
263
  parser.add_argument(
262
264
  "--conformance-tests-dest",
263
265
  type=non_empty_string,
264
266
  default=DEFAULT_CONFORMANCE_TESTS_DEST,
265
- help="Target folder to copy conformance tests output to (used only if --copy-conformance-tests is set).",
267
+ help="Target folder to copy conformance tests of code to (used only if --copy-conformance-tests is set).",
266
268
  )
267
269
 
268
270
  parser.add_argument(
@@ -301,7 +303,10 @@ def parse_arguments():
301
303
  if not args.log_to_file and args.log_file_name != DEFAULT_LOG_FILE_NAME:
302
304
  parser.error("--log-file-name cannot be used when --log-to-file is False.")
303
305
 
304
- script_arg_names = [UNIT_TESTS_SCRIPT_NAME, CONFORMANCE_TESTS_SCRIPT_NAME]
306
+ if args.full_plain and args.dry_run:
307
+ parser.error("--full-plain and --dry-run are mutually exclusive")
308
+
309
+ script_arg_names = [UNIT_TESTS_SCRIPT_NAME, CONFORMANCE_TESTS_SCRIPT_NAME, PREPARE_ENVIRONMENT_SCRIPT_NAME]
305
310
  for script_name in script_arg_names:
306
311
  args = process_test_script_path(script_name, args)
307
312
 
@@ -24,10 +24,11 @@ class RenderContextSnapshot:
24
24
  module_name: str
25
25
 
26
26
 
27
+ @dataclass
27
28
  class RenderCompleted(BaseEvent):
28
29
  """Event emitted when rendering completes successfully."""
29
30
 
30
- pass
31
+ rendered_code_path: str
31
32
 
32
33
 
33
34
  @dataclass
@@ -22,14 +22,14 @@ def print_dry_run_output(plain_source_tree: dict, render_range: Optional[list[st
22
22
  specifications, _ = plain_spec.get_specifications_for_frid(plain_source_tree, frid)
23
23
  functional_requirement_text = specifications[plain_spec.FUNCTIONAL_REQUIREMENTS][-1]
24
24
  console.info(
25
- "-------------------------------------"
26
- f"Rendering functional requirement {frid}"
27
- f"{functional_requirement_text}"
28
- "-------------------------------------"
25
+ "-------------------------------------\n"
26
+ f"Rendering functional requirement {frid}\n"
27
+ f"{functional_requirement_text}\n"
28
+ "-------------------------------------\n"
29
29
  )
30
30
  if plain_spec.ACCEPTANCE_TESTS in specifications:
31
31
  for i, acceptance_test in enumerate(specifications[plain_spec.ACCEPTANCE_TESTS], 1):
32
- console.info(f"Generating acceptance test #{i}:\n\n{acceptance_test}")
32
+ console.info(f"Generating acceptance test #{i}:\n\n{acceptance_test}\n")
33
33
  else:
34
34
  console.info(
35
35
  "-------------------------------------\n"
@@ -4,10 +4,10 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "codeplain"
7
- version = "0.2.6"
7
+ version = "0.2.8"
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.0"
11
11
  classifiers = [
12
12
  "Environment :: Console",
13
13
  "Intended Audience :: Developers",