codeplain 0.2.18__tar.gz → 0.2.20__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 (199) hide show
  1. codeplain-0.2.20/.claude/settings.local.json +64 -0
  2. {codeplain-0.2.18 → codeplain-0.2.20}/PKG-INFO +1 -1
  3. codeplain-0.2.20/_version.py +1 -0
  4. {codeplain-0.2.18 → codeplain-0.2.20}/codeplain_REST_api.py +10 -3
  5. {codeplain-0.2.18 → codeplain-0.2.20}/memory_management.py +13 -2
  6. {codeplain-0.2.18 → codeplain-0.2.20}/module_renderer.py +2 -1
  7. {codeplain-0.2.18 → codeplain-0.2.20}/plain2code.py +23 -6
  8. {codeplain-0.2.18 → codeplain-0.2.20}/plain2code_logger.py +6 -5
  9. {codeplain-0.2.18 → codeplain-0.2.20}/plain2code_state.py +21 -0
  10. {codeplain-0.2.18 → codeplain-0.2.20}/plain2code_utils.py +16 -0
  11. {codeplain-0.2.18 → codeplain-0.2.20}/plain_file.py +1 -1
  12. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/exit_with_error.py +8 -1
  13. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/finish_functional_requirement.py +1 -0
  14. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/fix_conformance_test.py +3 -0
  15. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/refactor_code.py +1 -0
  16. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/render_conformance_tests.py +1 -0
  17. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/render_functional_requirement.py +11 -14
  18. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/code_renderer.py +3 -2
  19. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/render_context.py +13 -11
  20. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/render_types.py +1 -0
  21. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/state_machine_config.py +9 -7
  22. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/triggers.py +0 -1
  23. codeplain-0.2.18/.claude/settings.local.json +0 -7
  24. codeplain-0.2.18/_version.py +0 -1
  25. {codeplain-0.2.18 → codeplain-0.2.20}/.flake8 +0 -0
  26. {codeplain-0.2.18 → codeplain-0.2.20}/.github/workflows/lint-and-test.yml +0 -0
  27. {codeplain-0.2.18 → codeplain-0.2.20}/.github/workflows/nofity-slack-on-main-merge.yml +0 -0
  28. {codeplain-0.2.18 → codeplain-0.2.20}/.github/workflows/publish-install-script.yml +0 -0
  29. {codeplain-0.2.18 → codeplain-0.2.20}/.github/workflows/publish-to-pypi.yml +0 -0
  30. {codeplain-0.2.18 → codeplain-0.2.20}/.gitignore +0 -0
  31. {codeplain-0.2.18 → codeplain-0.2.20}/.vscode/launch.json +0 -0
  32. {codeplain-0.2.18 → codeplain-0.2.20}/.vscode/settings.json +0 -0
  33. {codeplain-0.2.18 → codeplain-0.2.20}/LICENSE +0 -0
  34. {codeplain-0.2.18 → codeplain-0.2.20}/README.md +0 -0
  35. {codeplain-0.2.18 → codeplain-0.2.20}/concept_utils.py +0 -0
  36. {codeplain-0.2.18 → codeplain-0.2.20}/config/__init__.py +0 -0
  37. {codeplain-0.2.18 → codeplain-0.2.20}/config/system_config.yaml +0 -0
  38. {codeplain-0.2.18 → codeplain-0.2.20}/diff_utils.py +0 -0
  39. {codeplain-0.2.18 → codeplain-0.2.20}/docs/generate_cli.py +0 -0
  40. {codeplain-0.2.18 → codeplain-0.2.20}/docs/plain2code_cli.md +0 -0
  41. {codeplain-0.2.18 → codeplain-0.2.20}/docs/starting_a_plain_project_from_scratch.md +0 -0
  42. {codeplain-0.2.18 → codeplain-0.2.20}/event_bus.py +0 -0
  43. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_golang/config.yaml +0 -0
  44. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
  45. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
  46. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_golang/run.sh +0 -0
  47. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_python/config.yaml +0 -0
  48. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
  49. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_python/hello_world_python.plain +0 -0
  50. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_python/run.sh +0 -0
  51. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_react/config.yaml +0 -0
  52. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
  53. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
  54. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
  55. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
  56. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
  57. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_react/hello_world_react.plain +0 -0
  58. {codeplain-0.2.18 → codeplain-0.2.20}/examples/example_hello_world_react/run.sh +0 -0
  59. {codeplain-0.2.18 → codeplain-0.2.20}/examples/run.sh +0 -0
  60. {codeplain-0.2.18 → codeplain-0.2.20}/file_utils.py +0 -0
  61. {codeplain-0.2.18 → codeplain-0.2.20}/git_utils.py +0 -0
  62. {codeplain-0.2.18 → codeplain-0.2.20}/hash_key.py +0 -0
  63. {codeplain-0.2.18 → codeplain-0.2.20}/install/bash/examples.sh +0 -0
  64. {codeplain-0.2.18 → codeplain-0.2.20}/install/bash/install.sh +0 -0
  65. {codeplain-0.2.18 → codeplain-0.2.20}/install/bash/walkthrough.sh +0 -0
  66. {codeplain-0.2.18 → codeplain-0.2.20}/install/powershell/examples.ps1 +0 -0
  67. {codeplain-0.2.18 → codeplain-0.2.20}/install/powershell/install.ps1 +0 -0
  68. {codeplain-0.2.18 → codeplain-0.2.20}/install/powershell/walkthrough.ps1 +0 -0
  69. {codeplain-0.2.18 → codeplain-0.2.20}/plain2code_arguments.py +0 -0
  70. {codeplain-0.2.18 → codeplain-0.2.20}/plain2code_console.py +0 -0
  71. {codeplain-0.2.18 → codeplain-0.2.20}/plain2code_events.py +0 -0
  72. {codeplain-0.2.18 → codeplain-0.2.20}/plain2code_exceptions.py +0 -0
  73. {codeplain-0.2.18 → codeplain-0.2.20}/plain2code_nodes.py +0 -0
  74. {codeplain-0.2.18 → codeplain-0.2.20}/plain2code_read_config.py +0 -0
  75. {codeplain-0.2.18 → codeplain-0.2.20}/plain_modules.py +0 -0
  76. {codeplain-0.2.18 → codeplain-0.2.20}/plain_spec.py +0 -0
  77. {codeplain-0.2.18 → codeplain-0.2.20}/pyproject.toml +0 -0
  78. {codeplain-0.2.18 → codeplain-0.2.20}/pytest.ini +0 -0
  79. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/__init__.py +0 -0
  80. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/analyze_specification_ambiguity.py +0 -0
  81. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/base_action.py +0 -0
  82. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
  83. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/commit_implementation_code_changes.py +0 -0
  84. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/create_dist.py +0 -0
  85. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/fix_unit_tests.py +0 -0
  86. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/prepare_repositories.py +0 -0
  87. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/prepare_testing_environment.py +0 -0
  88. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/run_conformance_tests.py +0 -0
  89. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/run_unit_tests.py +0 -0
  90. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/actions/summarize_conformance_tests.py +0 -0
  91. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/conformance_test_helpers.py +0 -0
  92. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/conformance_tests.py +0 -0
  93. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/implementation_code_helpers.py +0 -0
  94. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/render_utils.py +0 -0
  95. {codeplain-0.2.18 → codeplain-0.2.20}/render_machine/states.py +0 -0
  96. {codeplain-0.2.18 → codeplain-0.2.20}/requirements.txt +0 -0
  97. {codeplain-0.2.18 → codeplain-0.2.20}/resources/codeplain_overview.png +0 -0
  98. {codeplain-0.2.18 → codeplain-0.2.20}/resources/plain_example.png +0 -0
  99. {codeplain-0.2.18 → codeplain-0.2.20}/standard_template_library/__init__.py +0 -0
  100. {codeplain-0.2.18 → codeplain-0.2.20}/standard_template_library/golang-console-app-template.plain +0 -0
  101. {codeplain-0.2.18 → codeplain-0.2.20}/standard_template_library/python-console-app-template.plain +0 -0
  102. {codeplain-0.2.18 → codeplain-0.2.20}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
  103. {codeplain-0.2.18 → codeplain-0.2.20}/standard_template_library/typescript-react-app-template.plain +0 -0
  104. {codeplain-0.2.18 → codeplain-0.2.20}/system_config.py +0 -0
  105. {codeplain-0.2.18 → codeplain-0.2.20}/test_scripts/run_conformance_tests_cypress.sh +0 -0
  106. {codeplain-0.2.18 → codeplain-0.2.20}/test_scripts/run_conformance_tests_golang.sh +0 -0
  107. {codeplain-0.2.18 → codeplain-0.2.20}/test_scripts/run_conformance_tests_python.sh +0 -0
  108. {codeplain-0.2.18 → codeplain-0.2.20}/test_scripts/run_unittests_golang.sh +0 -0
  109. {codeplain-0.2.18 → codeplain-0.2.20}/test_scripts/run_unittests_python.sh +0 -0
  110. {codeplain-0.2.18 → codeplain-0.2.20}/test_scripts/run_unittests_react.sh +0 -0
  111. {codeplain-0.2.18 → codeplain-0.2.20}/tests/__init__.py +0 -0
  112. {codeplain-0.2.18 → codeplain-0.2.20}/tests/conftest.py +0 -0
  113. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/imports/circular_imports_1.plain +0 -0
  114. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/imports/circular_imports_2.plain +0 -0
  115. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/imports/circular_imports_main.plain +0 -0
  116. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/imports/diamond_import_1.plain +0 -0
  117. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/imports/diamond_import_2.plain +0 -0
  118. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/imports/diamond_import_common.plain +0 -0
  119. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/imports/diamond_imports_main.plain +0 -0
  120. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/imports/non_existent_import.plain +0 -0
  121. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
  122. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfile/invalid_specification_order.plain +0 -0
  123. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
  124. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
  125. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
  126. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
  127. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
  128. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
  129. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
  130. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
  131. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
  132. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
  133. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
  134. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
  135. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
  136. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
  137. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
  138. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
  139. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/exported_concepts.plain +0 -0
  140. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
  141. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
  142. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/exported_concepts_missing.plain +0 -0
  143. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/exported_concepts_missing_example.plain +0 -0
  144. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
  145. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
  146. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
  147. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
  148. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
  149. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
  150. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
  151. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
  152. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/required_concepts.plain +0 -0
  153. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
  154. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
  155. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
  156. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
  157. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
  158. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
  159. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
  160. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
  161. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/topological_sort.plain +0 -0
  162. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
  163. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/circular_requires_main.plain +0 -0
  164. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/circular_requires_sub.plain +0 -0
  165. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/diamond_requires_1.plain +0 -0
  166. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/diamond_requires_2.plain +0 -0
  167. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/diamond_requires_common.plain +0 -0
  168. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/diamond_requires_main.plain +0 -0
  169. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/independent_requires_1.plain +0 -0
  170. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/independent_requires_2.plain +0 -0
  171. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/independent_requires_main.plain +0 -0
  172. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/non_existent_require.plain +0 -0
  173. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/normal_requires_1.plain +0 -0
  174. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/normal_requires_2.plain +0 -0
  175. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/normal_requires_common.plain +0 -0
  176. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/requires/normal_requires_main.plain +0 -0
  177. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/simple.plain +0 -0
  178. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/templates/block_level_include.plain +0 -0
  179. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/templates/code_variables.plain +0 -0
  180. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/templates/header.plain +0 -0
  181. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/templates/implement.plain +0 -0
  182. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/templates/implement_2.plain +0 -0
  183. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/templates/template_include.plain +0 -0
  184. {codeplain-0.2.18 → codeplain-0.2.20}/tests/data/templates/test_hardest_problem.plain +0 -0
  185. {codeplain-0.2.18 → codeplain-0.2.20}/tests/test_git_utils.py +0 -0
  186. {codeplain-0.2.18 → codeplain-0.2.20}/tests/test_imports.py +0 -0
  187. {codeplain-0.2.18 → codeplain-0.2.20}/tests/test_plainfile.py +0 -0
  188. {codeplain-0.2.18 → codeplain-0.2.20}/tests/test_plainfileparser.py +0 -0
  189. {codeplain-0.2.18 → codeplain-0.2.20}/tests/test_plainspec.py +0 -0
  190. {codeplain-0.2.18 → codeplain-0.2.20}/tests/test_requires.py +0 -0
  191. {codeplain-0.2.18 → codeplain-0.2.20}/tests/test_resolve_config_file.py +0 -0
  192. {codeplain-0.2.18 → codeplain-0.2.20}/tui/__init__.py +0 -0
  193. {codeplain-0.2.18 → codeplain-0.2.20}/tui/components.py +0 -0
  194. {codeplain-0.2.18 → codeplain-0.2.20}/tui/models.py +0 -0
  195. {codeplain-0.2.18 → codeplain-0.2.20}/tui/plain2code_tui.py +0 -0
  196. {codeplain-0.2.18 → codeplain-0.2.20}/tui/spinner.py +0 -0
  197. {codeplain-0.2.18 → codeplain-0.2.20}/tui/state_handlers.py +0 -0
  198. {codeplain-0.2.18 → codeplain-0.2.20}/tui/styles.css +0 -0
  199. {codeplain-0.2.18 → codeplain-0.2.20}/tui/widget_helpers.py +0 -0
@@ -0,0 +1,64 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(gh pr:*)",
5
+ "Bash(git diff *)",
6
+ "Bash(mypy . --check-untyped-defs)",
7
+ "Bash(flake8 .)",
8
+ "Bash(MASTER_KEY=test-master-key GOOGLE_API_KEY=test-google-api-key pytest tests/test_git_utils.py -v --no-header)",
9
+ "Bash(MASTER_KEY=test-master-key GOOGLE_API_KEY=test-google-api-key python *)",
10
+ "Bash(MASTER_KEY=test-master-key GOOGLE_API_KEY=test-google-api-key pytest tests/_sandbox_check.py -v -s)",
11
+ "Bash(MASTER_KEY=test-master-key GOOGLE_API_KEY=test-google-api-key pytest tests/test_partial_rendering.py -v)",
12
+ "Bash(MASTER_KEY=test-master-key GOOGLE_API_KEY=test-google-api-key pytest tests/test_plain_modules.py -v)",
13
+ "Bash(MASTER_KEY=test-master-key GOOGLE_API_KEY=test-google-api-key pytest tests/ -v)",
14
+ "Bash(flake8 tests/)",
15
+ "Bash(git stash *)",
16
+ "Bash(flake8 tests/test_git_utils.py)",
17
+ "Bash(MASTER_KEY=test-master-key GOOGLE_API_KEY=test-google-api-key coverage run -m pytest tests/ -v)",
18
+ "Bash(.venv/bin/coverage run *)",
19
+ "Bash(.venv/bin/coverage report *)",
20
+ "Bash(.venv/bin/python -m coverage run -m pytest tests/)",
21
+ "Bash(.venv/bin/python -m coverage report)",
22
+ "Bash(MASTER_KEY=test-master-key GOOGLE_API_KEY=test-google-api-key pytest tests/)",
23
+ "Bash(flake8 tests/test_partial_rendering.py tests/test_plain_modules.py)",
24
+ "Bash(MASTER_KEY=test-master-key GOOGLE_API_KEY=test-google-api-key pytest tests/test_partial_rendering.py tests/test_plain_modules.py tests/test_git_utils.py)",
25
+ "Bash(pytest tests *)",
26
+ "Bash(pytest tests/test_git_utils.py::test_diff_without_previous_frid_and_no_base_folder -x -v)",
27
+ "Bash(git checkout *)",
28
+ "Bash(python -c ' *)",
29
+ "Bash(python3 -c ' *)",
30
+ "Bash(/opt/homebrew/opt/python@3.11/bin/python3.11 -c ' *)",
31
+ "Bash(pytest tests/test_git_utils.py -x -v)",
32
+ "Bash(pytest tests/test_git_utils.py -v)",
33
+ "Bash(pytest -x -v)",
34
+ "Bash(pytest tests/test_partial_rendering.py -v)",
35
+ "Bash(pytest -v)",
36
+ "Bash(pytest)",
37
+ "Bash(python -m pytest tests/test_partial_rendering.py -x -v)",
38
+ "Bash(python -m pytest -x -v)",
39
+ "Bash(python -m pytest tests/test_partial_rendering.py -v)",
40
+ "Bash(python -m pytest)",
41
+ "Bash(python -m pytest tests/test_plain_modules.py -q)",
42
+ "Bash(python3 -m pytest tests/test_plain_modules.py -q)",
43
+ "Bash(.venv/bin/pytest tests/test_plain_modules.py -q)",
44
+ "Bash(git -C /Users/zanjonke/Work/codeplain/codeplain log --oneline -5)",
45
+ "Bash(git -C /Users/zanjonke/Work/codeplain/codeplain branch --show-current)",
46
+ "Bash(python -m pytest tests/test_git_utils.py::test_get_last_finished_frid_empty_repo -x)",
47
+ "Bash(python3 -m pytest tests/test_git_utils.py::test_get_last_finished_frid_empty_repo -x)",
48
+ "Bash(.venv/bin/python -m pytest tests/test_git_utils.py::test_get_last_finished_frid_empty_repo -x)",
49
+ "Bash(.venv/bin/python -m pytest tests/test_git_utils.py::test_get_last_finished_frid_without_module_name tests/test_git_utils.py::test_get_last_finished_frid_empty_repo -x)",
50
+ "Bash(.venv/bin/python -m pytest tests/test_git_utils.py)",
51
+ "Bash(python -m pytest tests/test_partial_rendering.py -x)",
52
+ "Bash(python3 -m pytest tests/test_partial_rendering.py)",
53
+ "Bash(/Users/zanjonke/Work/codeplain/codeplain/.venv/bin/python -m pytest tests/test_partial_rendering.py)",
54
+ "Bash(/Users/zanjonke/Work/codeplain/codeplain/.venv/bin/python -m pytest tests/test_plain_modules.py tests/test_partial_rendering.py)",
55
+ "Bash(git *)",
56
+ "Bash(python -m pytest tests/test_plain_modules.py -x --tb=short)",
57
+ "Bash(python3 -m pytest tests/test_plain_modules.py -x --tb=short)",
58
+ "Bash(/Users/zanjonke/Work/codeplain/codeplain/venv/bin/python -m pytest tests/test_plain_modules.py --tb=short)",
59
+ "Bash(/Users/zanjonke/Work/codeplain/codeplain/.venv/bin/python -m pytest tests/test_plain_modules.py --tb=short)",
60
+ "Bash(/Users/zanjonke/Work/codeplain/codeplain/.venv/bin/python -m pytest tests/test_partial_rendering.py tests/test_git_utils.py --tb=short)",
61
+ "Bash(.venv/bin/python *)"
62
+ ]
63
+ }
64
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeplain
3
- Version: 0.2.18
3
+ Version: 0.2.20
4
4
  Summary: Transform plain language specifications into working code
5
5
  License-File: LICENSE
6
6
  Classifier: Environment :: Console
@@ -0,0 +1 @@
1
+ __version__ = "0.2.20"
@@ -262,12 +262,15 @@ class CodeplainAPI:
262
262
 
263
263
  return self.post_request(endpoint_url, headers, payload, run_state)
264
264
 
265
- def refactor_source_files_if_needed(self, frid, files_to_check, existing_files_content, run_state: RunState):
265
+ def refactor_source_files_if_needed(
266
+ self, frid, module_name: str, files_to_check, existing_files_content, run_state: RunState
267
+ ):
266
268
  endpoint_url = f"{self.api_url}/refactor_source_files_if_needed"
267
269
  headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
268
270
 
269
271
  payload = {
270
272
  "frid": frid,
273
+ "module_name": module_name,
271
274
  "files_to_check": list(files_to_check),
272
275
  "existing_files_content": existing_files_content,
273
276
  }
@@ -312,6 +315,7 @@ class CodeplainAPI:
312
315
  def generate_folder_name_from_functional_requirement(
313
316
  self,
314
317
  frid,
318
+ module_name: str,
315
319
  functional_requirement,
316
320
  existing_folder_names,
317
321
  run_state: RunState,
@@ -321,6 +325,7 @@ class CodeplainAPI:
321
325
 
322
326
  payload = {
323
327
  "frid": frid,
328
+ "module_name": module_name,
324
329
  "functional_requirement": functional_requirement,
325
330
  "existing_folder_names": existing_folder_names,
326
331
  }
@@ -454,22 +459,24 @@ class CodeplainAPI:
454
459
 
455
460
  return self.post_request(endpoint_url, headers, payload, run_state)
456
461
 
457
- def finish_functional_requirement(self, frid, run_state: RunState):
462
+ def finish_functional_requirement(self, frid, module_name: str, run_state: RunState):
458
463
  endpoint_url = f"{self.api_url}/finish_functional_requirement"
459
464
  headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
460
465
 
461
466
  payload = {
462
467
  "frid": frid,
468
+ "module_name": module_name,
463
469
  }
464
470
 
465
471
  return self.post_request(endpoint_url, headers, payload, run_state)
466
472
 
467
- def fail_functional_requirement(self, frid, run_state: RunState):
473
+ def fail_functional_requirement(self, frid, module_name: str, run_state: RunState):
468
474
  endpoint_url = f"{self.api_url}/fail_functional_requirement"
469
475
  headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
470
476
 
471
477
  payload = {
472
478
  "frid": frid,
479
+ "module_name": module_name,
473
480
  }
474
481
 
475
482
  return self.post_request(endpoint_url, headers, payload, run_state)
@@ -33,18 +33,29 @@ class MemoryManager:
33
33
  ):
34
34
 
35
35
  current_conformance_tests_issue_frid = render_context.conformance_tests_running_context.current_testing_frid
36
+ current_conformance_tests_issue_module = (
37
+ render_context.conformance_tests_running_context.current_testing_module_name
38
+ )
36
39
  old_conformance_tests_issue_frid = (
37
40
  render_context.conformance_tests_running_context.previous_conformance_tests_issue_frid
38
41
  )
42
+ old_conformance_tests_issue_module = (
43
+ render_context.conformance_tests_running_context.previous_conformance_tests_issue_module
44
+ )
39
45
 
40
46
  old_conformance_tests_issue = (
41
47
  render_context.conformance_tests_running_context.previous_conformance_tests_issue_old
42
48
  )
43
49
 
44
50
  is_first_time_running_conformance_tests = (
45
- old_conformance_tests_issue_frid is None or old_conformance_tests_issue_frid == ""
51
+ old_conformance_tests_issue_frid is None
52
+ or old_conformance_tests_issue_frid == ""
53
+ or old_conformance_tests_issue_module != current_conformance_tests_issue_module
54
+ )
55
+ is_same_frid_as_previous_failing_test = (
56
+ current_conformance_tests_issue_frid == old_conformance_tests_issue_frid
57
+ and current_conformance_tests_issue_module == old_conformance_tests_issue_module
46
58
  )
47
- is_same_frid_as_previous_failing_test = current_conformance_tests_issue_frid == old_conformance_tests_issue_frid
48
59
  is_conformance_test_failed = exit_code != CONFORMANCE_TESTS_SUCCESS_EXIT_CODE
49
60
 
50
61
  should_create_memory = not is_first_time_running_conformance_tests and (
@@ -66,7 +66,7 @@ class ModuleRenderer:
66
66
  f" codeplain {module_name}{plain_file.PLAIN_SOURCE_FILE_EXTENSION}"
67
67
  )
68
68
 
69
- if not os.path.exists(conformance_tests_path):
69
+ if not os.path.exists(conformance_tests_path) and self.args.render_conformance_tests:
70
70
  raise MissingPreviousFunctionalitiesError(
71
71
  f"Cannot start rendering from functionality {first_render_frid} for module '{module_name}' because the conformance tests folder does not exist.\n\n"
72
72
  f"To fix this, please render the module from the beginning by running:\n"
@@ -275,4 +275,5 @@ class ModuleRenderer:
275
275
  last_module_name = self.filename.replace(plain_file.PLAIN_SOURCE_FILE_EXTENSION, "")
276
276
  rendered_code_path = f"{os.path.join(self.args.build_folder, last_module_name)}/"
277
277
 
278
+ self.run_state.set_render_generated_code_path(rendered_code_path)
278
279
  self.event_bus.publish(RenderCompleted(rendered_code_path=rendered_code_path))
@@ -47,7 +47,7 @@ from plain2code_logger import (
47
47
  get_log_file_path,
48
48
  )
49
49
  from plain2code_state import RunState
50
- from plain2code_utils import print_dry_run_output
50
+ from plain2code_utils import format_duration_hms, print_dry_run_output
51
51
  from system_config import system_config
52
52
  from tui.plain2code_tui import Plain2CodeTUI
53
53
 
@@ -55,6 +55,21 @@ DEFAULT_TEMPLATE_DIRS = importlib.resources.files("standard_template_library")
55
55
  RENDER_THREAD_SHUTDOWN_TIMEOUT = 0.7
56
56
 
57
57
 
58
+ def print_exit_summary(
59
+ run_state: RunState,
60
+ spec_filename: str,
61
+ ) -> None:
62
+ console.quiet = False
63
+ """Print render outcome after the TUI exits (terminal restored)."""
64
+ msg = "\n[#79FC96]✓ rendering completed\n\n" if run_state.render_succeeded else "[#FF6B6B]✗ rendering failed\n\n"
65
+ msg += f" [#8E8F91]render id:\t\t\t[#FFFFFF]{run_state.render_id}\n"
66
+ msg += f" [#8E8F91]input file:\t\t\t[#FFFFFF]{spec_filename}\n"
67
+ msg += f" [#8E8F91]generated code folder:\t[#FFFFFF]{run_state.render_generated_code_path or '-'}\n\n"
68
+ msg += f"[#8E8F91]functionalities [#FFFFFF]{run_state.rendered_functionalities} [#8E8F91]used credits [#FFFFFF]{run_state.rendered_functionalities} [#8E8F91]render time [#FFFFFF]{format_duration_hms(run_state.render_time_accumulated)}\n"
69
+ console.info(msg)
70
+ console.quiet = True
71
+
72
+
58
73
  def get_render_range(render_range, plain_source):
59
74
  render_range = render_range.split(",")
60
75
  range_end = render_range[1] if len(render_range) == 2 else render_range[0]
@@ -186,8 +201,6 @@ def _check_connection(codeplainAPI: codeplain_api.CodeplainAPI):
186
201
  def render(args, run_state: RunState, event_bus: EventBus): # noqa: C901
187
202
  template_dirs = file_utils.get_template_directories(args.filename, args.template_dir, DEFAULT_TEMPLATE_DIRS)
188
203
 
189
- console.info(f"Rendering {args.filename} to target code.")
190
-
191
204
  # Compute render range from either --render-range or --render-from
192
205
  render_range = None
193
206
  if args.render_range or args.render_from:
@@ -219,14 +232,16 @@ def render(args, run_state: RunState, event_bus: EventBus): # noqa: C901
219
232
  )
220
233
 
221
234
  render_error: list[Exception] = []
235
+ run_state.render_succeeded = False
222
236
 
223
237
  def run_render():
224
238
  try:
225
239
  module_renderer.render_module()
226
- console.info(f"[#79FC96]Render {run_state.render_id} completed successfully.[/#79FC96]")
240
+ run_state.set_render_succeeded(True)
227
241
  except RenderCancelledError:
228
242
  pass # TUI already closed, nothing to report
229
243
  except Exception as e:
244
+ run_state.set_render_succeeded(False)
230
245
  render_error.append(e)
231
246
  event_bus.publish(RenderFailed(error_message=str(e)))
232
247
 
@@ -234,7 +249,9 @@ def render(args, run_state: RunState, event_bus: EventBus): # noqa: C901
234
249
  console.info(f"Render started. Render ID: {run_state.render_id}")
235
250
  try:
236
251
  module_renderer.render_module()
252
+ run_state.set_render_succeeded(True)
237
253
  except RenderCancelledError:
254
+ run_state.set_render_succeeded(False)
238
255
  pass
239
256
  return
240
257
  else:
@@ -251,6 +268,7 @@ def render(args, run_state: RunState, event_bus: EventBus): # noqa: C901
251
268
  css_path="styles.css",
252
269
  )
253
270
  app.run()
271
+
254
272
  stop_event.set()
255
273
  render_thread.join(timeout=RENDER_THREAD_SHUTDOWN_TIMEOUT)
256
274
 
@@ -304,8 +322,6 @@ def main(): # noqa: C901
304
322
  raise MissingAPIKey(
305
323
  "API key is required. Please set the CODEPLAIN_API_KEY environment variable or provide it with the --api-key argument."
306
324
  )
307
-
308
- console.info(f"Render ID: {run_state.render_id}")
309
325
  render(args, run_state, event_bus)
310
326
  except InvalidFridArgument as e:
311
327
  exc_info = sys.exc_info()
@@ -374,6 +390,7 @@ def main(): # noqa: C901
374
390
  console.error(f"Error rendering plain code: {str(e)}\n")
375
391
  console.debug(f"Render ID: {run_state.render_id}")
376
392
  finally:
393
+ print_exit_summary(run_state, args.filename)
377
394
  if exc_info:
378
395
  # Log traceback using the logging system
379
396
  logging.error("Render crashed with exception:", exc_info=exc_info)
@@ -27,11 +27,12 @@ class TuiLoggingHandler(logging.Handler):
27
27
 
28
28
  def emit(self, record):
29
29
  try:
30
- offset_seconds = record.created - self.start_time
31
- minutes = int(offset_seconds // 60)
32
- seconds = int(offset_seconds % 60)
33
- milliseconds = int((offset_seconds % 1) * 100)
34
- timestamp = f"{minutes:02d}:{seconds:02d}:{milliseconds:02d}"
30
+ offset_seconds = int(record.created - self.start_time)
31
+ hours = offset_seconds // 3600
32
+ minutes = (offset_seconds % 3600) // 60
33
+ seconds = offset_seconds % 60
34
+ timestamp = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
35
+
35
36
  event = LogMessageEmitted(
36
37
  logger_name=record.name,
37
38
  level=record.levelname,
@@ -1,5 +1,6 @@
1
1
  """Contains all state and context information we need for the rendering process."""
2
2
 
3
+ import time
3
4
  import uuid
4
5
  from typing import Optional
5
6
 
@@ -9,6 +10,9 @@ class RunState:
9
10
 
10
11
  def __init__(self, spec_filename: str, replay_with: Optional[str] = None):
11
12
  self.replay: bool = replay_with is not None
13
+ self.render_succeeded: bool = False
14
+ self.render_generated_code_path: Optional[str] = None
15
+ self.rendered_functionalities: int = 0
12
16
  if replay_with:
13
17
  self.render_id: str = replay_with
14
18
  else:
@@ -17,6 +21,8 @@ class RunState:
17
21
  self.call_count: int = 0
18
22
  self.unittest_batch_id: int = 0
19
23
  self.frid_render_anaysis: dict[str, str] = {}
24
+ self.render_time_accumulated: int = 0
25
+ self.last_render_start_timestamp: float = time.monotonic()
20
26
 
21
27
  def increment_call_count(self):
22
28
  self.call_count += 1
@@ -27,6 +33,21 @@ class RunState:
27
33
  def add_rendering_analysis_for_frid(self, frid, rendering_analysis) -> None:
28
34
  self.frid_render_anaysis[frid] = rendering_analysis
29
35
 
36
+ def set_render_succeeded(self, succeeded: bool):
37
+ self.render_succeeded = succeeded
38
+
39
+ def set_render_generated_code_path(self, generated_code_path: str):
40
+ self.render_generated_code_path = generated_code_path
41
+
42
+ def increment_rendered_functionalities(self):
43
+ self.rendered_functionalities += 1
44
+
45
+ def add_to_render_time(self):
46
+ self.render_time_accumulated += int(time.monotonic() - self.last_render_start_timestamp)
47
+
48
+ def set_last_render_start_timestamp(self):
49
+ self.last_render_start_timestamp = time.monotonic()
50
+
30
51
  def to_dict(self):
31
52
  return {
32
53
  "render_id": self.render_id,
@@ -3,6 +3,22 @@ from typing import Optional
3
3
  import plain_spec
4
4
  from plain2code_console import console
5
5
 
6
+
7
+ def format_duration_hms(total_seconds: int) -> str:
8
+ """Format a duration in seconds as hours, minutes, and seconds (e.g. ``1h 2m 3.45s``, ``45.67s``)."""
9
+ if total_seconds < 0:
10
+ total_seconds = 0
11
+ h = int(total_seconds // 3600)
12
+ m = int((total_seconds % 3600) // 60)
13
+ s = total_seconds % 60
14
+ if h:
15
+ return f"{h}h {m}m {s}s"
16
+ if m:
17
+ return f"{m}m {s}s"
18
+ text = f"{s}".rstrip("0").rstrip(".")
19
+ return f"{text}s" if text else "0s"
20
+
21
+
6
22
  AMBIGUITY_CAUSES = {
7
23
  "reference_resource_ambiguity": "Ambiguity is in the reference resources",
8
24
  "definition_ambiguity": "Ambiguity is in the definitions",
@@ -649,7 +649,7 @@ def plain_file_parser( # noqa: C901
649
649
  )
650
650
 
651
651
  if not check_if_functional_requirements_are_specified(plain_file_parse_result.plain_source, []):
652
- raise PlainSyntaxError("Syntax error: No functionality specified.")
652
+ raise PlainSyntaxError(f"Module '{module_name}' was required but does not contain functional requirements.")
653
653
 
654
654
  exported_definitions = process_required_modules(
655
655
  plain_file_parse_result.required_modules,
@@ -3,6 +3,7 @@ from typing import Any
3
3
  from plain2code_console import console
4
4
  from render_machine.actions.base_action import BaseAction
5
5
  from render_machine.render_context import RenderContext
6
+ from render_machine.render_types import RenderError
6
7
 
7
8
 
8
9
  class ExitWithError(BaseAction):
@@ -13,6 +14,7 @@ class ExitWithError(BaseAction):
13
14
 
14
15
  render_context.codeplain_api.fail_functional_requirement(
15
16
  render_context.frid_context.frid,
17
+ module_name=render_context.module_name,
16
18
  run_state=render_context.run_state,
17
19
  )
18
20
 
@@ -24,4 +26,9 @@ class ExitWithError(BaseAction):
24
26
  if render_context.run_state.render_id is not None:
25
27
  console.info(f"Render ID: {render_context.run_state.render_id}")
26
28
 
27
- return self.SUCCESSFUL_OUTCOME, previous_action_payload
29
+ return (
30
+ self.SUCCESSFUL_OUTCOME,
31
+ RenderError.encode(
32
+ message=render_context.last_error_message or "Unknown error",
33
+ ).to_payload(),
34
+ )
@@ -12,6 +12,7 @@ class FinishFunctionalRequirement(CommitImplementationCodeChanges):
12
12
 
13
13
  render_context.codeplain_api.finish_functional_requirement(
14
14
  render_context.frid_context.frid,
15
+ module_name=render_context.module_name,
15
16
  run_state=render_context.run_state,
16
17
  )
17
18
 
@@ -30,6 +30,9 @@ class FixConformanceTest(BaseAction):
30
30
  render_context.conformance_tests_running_context.previous_conformance_tests_issue_frid = (
31
31
  render_context.conformance_tests_running_context.current_testing_frid
32
32
  )
33
+ render_context.conformance_tests_running_context.previous_conformance_tests_issue_module = (
34
+ render_context.conformance_tests_running_context.current_testing_module_name
35
+ )
33
36
 
34
37
  if render_context.conformance_tests_running_context.current_testing_frid == render_context.frid_context.frid:
35
38
  console_message = f"Fixing conformance test for functionality {render_context.conformance_tests_running_context.current_testing_frid} in module {render_context.conformance_tests_running_context.current_testing_module_name}."
@@ -31,6 +31,7 @@ class RefactorCode(BaseAction):
31
31
  ):
32
32
  response_files = render_context.codeplain_api.refactor_source_files_if_needed(
33
33
  frid=render_context.frid_context.frid,
34
+ module_name=render_context.module_name,
34
35
  files_to_check=render_context.frid_context.changed_files,
35
36
  existing_files_content=existing_files_content,
36
37
  run_state=render_context.run_state,
@@ -38,6 +38,7 @@ class RenderConformanceTests(BaseAction):
38
38
  ):
39
39
  fr_subfolder_name = render_context.codeplain_api.generate_folder_name_from_functional_requirement(
40
40
  frid=render_context.conformance_tests_running_context.current_testing_frid,
41
+ module_name=render_context.conformance_tests_running_context.current_testing_module_name,
41
42
  functional_requirement=render_context.conformance_tests_running_context.current_testing_frid_specifications[
42
43
  plain_spec.FUNCTIONAL_REQUIREMENTS
43
44
  ][
@@ -40,20 +40,17 @@ class RenderFunctionalRequirement(BaseAction):
40
40
  render_context, existing_files_content, "Files sent as input to code generation:"
41
41
  )
42
42
 
43
- with console.status(
44
- f"[{console.INFO_STYLE}]Generating functionality {render_context.frid_context.frid}...\n"
45
- ):
46
- response_files = render_context.codeplain_api.render_functional_requirement(
47
- render_context.frid_context.frid,
48
- render_context.plain_source_tree,
49
- render_context.frid_context.linked_resources,
50
- existing_files_content,
51
- memory_files_content,
52
- render_context.module_name,
53
- render_context.get_required_modules_functionalities(),
54
- render_context.should_run_unit_tests(),
55
- render_context.run_state,
56
- )
43
+ response_files = render_context.codeplain_api.render_functional_requirement(
44
+ render_context.frid_context.frid,
45
+ render_context.plain_source_tree,
46
+ render_context.frid_context.linked_resources,
47
+ existing_files_content,
48
+ memory_files_content,
49
+ render_context.module_name,
50
+ render_context.get_required_modules_functionalities(),
51
+ render_context.should_run_unit_tests(),
52
+ render_context.run_state,
53
+ )
57
54
  except FunctionalRequirementTooComplex as e:
58
55
  error_message = f"The functionality:\n{render_context.frid_context.functional_requirement_text}\n is too complex to be implemented. Please break down the functionality into smaller parts ({str(e)})."
59
56
  if e.proposed_breakdown:
@@ -43,8 +43,11 @@ class CodeRenderer:
43
43
  if self.render_context.enter_pause_event.is_set():
44
44
  self.render_context.event_bus.publish(RenderPaused())
45
45
 
46
+ # don't take sleep time into account for render time
47
+ self.render_context.run_state.add_to_render_time()
46
48
  while self.render_context.enter_pause_event.is_set():
47
49
  time.sleep(PAUSE_POLL_INTERVAL_SECONDS)
50
+ self.render_context.run_state.set_last_render_start_timestamp()
48
51
 
49
52
  self.render_context.event_bus.publish(
50
53
  RenderStateUpdated(
@@ -55,8 +58,6 @@ class CodeRenderer:
55
58
  )
56
59
  previous_state = deepcopy(self.render_context.state)
57
60
  self.render_context.script_execution_history.should_update_script_outputs = False
58
- # Reset error message at start of each iteration to prevent stale data
59
- self.render_context.last_error_message = None
60
61
 
61
62
  outcome, previous_action_payload = self.action_map[self.render_context.state].execute(
62
63
  self.render_context, previous_action_payload
@@ -146,12 +146,6 @@ class RenderContext:
146
146
  else:
147
147
  frid = plain_spec.get_next_frid(self.plain_source_tree, self.frid_context.frid)
148
148
 
149
- if frid is None:
150
- # If frid context is empty, it means that all frids have been implemented
151
- self.frid_context = None
152
- self.machine.dispatch(triggers.PREPARE_FINAL_OUTPUT)
153
- return
154
-
155
149
  specifications, _ = plain_spec.get_specifications_for_frid(self.plain_source_tree, frid)
156
150
  functional_requirement_text = specifications[plain_spec.FUNCTIONAL_REQUIREMENTS][-1]
157
151
 
@@ -172,10 +166,6 @@ class RenderContext:
172
166
  return
173
167
 
174
168
  def check_frid_iteration_limit(self):
175
- # If frid context is not set, it means that all frids have been implemented
176
- if self.frid_context is None:
177
- return
178
-
179
169
  if self.frid_context.functional_requirement_render_attempts >= MAX_CODE_GENERATION_RETRIES:
180
170
  error_msg = f"Unittests could not be fixed after rendering the functionality {self.frid_context.frid} for the {MAX_CODE_GENERATION_RETRIES} times."
181
171
  self.dispatch_error(error_msg)
@@ -189,8 +179,12 @@ class RenderContext:
189
179
  f"Restarting rendering the functionality {self.frid_context.frid} from scratch."
190
180
  )
191
181
 
182
+ def has_next_frid(self) -> bool:
183
+ return plain_spec.get_next_frid(self.plain_source_tree, self.frid_context.frid) is not None
184
+
192
185
  def finish_implementing_frid(self):
193
186
  self.functional_requirements_render_attempts_failed_unit_during_conformance_tests = 0
187
+ self.run_state.increment_rendered_functionalities()
194
188
 
195
189
  def should_run_unit_tests(self) -> bool:
196
190
  return self.unittests_script is not None
@@ -442,7 +436,7 @@ class RenderContext:
442
436
  self.conformance_tests_running_context.conformance_tests_render_attempts
443
437
  >= MAX_CONFORMANCE_TEST_RERENDER_ATTEMPTS
444
438
  ):
445
- error_msg = f"We've already tried to fix the issue by recreating the conformance tests but tests still fail. Please fix the issues manually. FRID: {self.frid_context.frid}, Render ID: {self.run_state.render_id}"
439
+ error_msg = f"The renderer was unable to produce an implementation that passes conformance tests for functionality '{self.frid_context.frid}' after many attempts. Please review and rewrite the specification. (Render ID: {self.run_state.render_id})"
446
440
  self.dispatch_error(error_msg)
447
441
  else:
448
442
  self.conformance_tests_running_context.regenerating_conformance_tests = True
@@ -453,3 +447,11 @@ class RenderContext:
453
447
  console.info(
454
448
  f"Running conformance tests attempt {self.conformance_tests_running_context.fix_attempts + 1}."
455
449
  )
450
+
451
+ def start_render_completed(self):
452
+ self.run_state.set_render_succeeded(True)
453
+ self.run_state.add_to_render_time()
454
+
455
+ def start_render_failed(self):
456
+ self.run_state.set_render_succeeded(False)
457
+ self.run_state.add_to_render_time()
@@ -49,6 +49,7 @@ class ConformanceTestsRunningContext:
49
49
  self.current_testing_frid_high_level_implementation_plan: Optional[str] = None
50
50
  self.previous_conformance_tests_issue_old: Optional[str] = None
51
51
  self.previous_conformance_tests_issue_frid: Optional[str] = None
52
+ self.previous_conformance_tests_issue_module: Optional[str] = None
52
53
  self.code_diff_files: Optional[dict[str, str]] = None
53
54
 
54
55
  def get_conformance_tests_json(self, module_name: str) -> dict:
@@ -233,8 +233,8 @@ class StateMachineConfig:
233
233
  States.FRID_FULLY_IMPLEMENTED.value,
234
234
  ],
235
235
  },
236
- States.RENDER_COMPLETED.value,
237
- States.RENDER_FAILED.value,
236
+ {"name": States.RENDER_COMPLETED.value, "on_enter": "start_render_completed"},
237
+ {"name": States.RENDER_FAILED.value, "on_enter": "start_render_failed"},
238
238
  ]
239
239
 
240
240
  def get_transitions(self) -> List[Dict[str, Any]]:
@@ -261,11 +261,6 @@ class StateMachineConfig:
261
261
  "dest": f"{States.IMPLEMENTING_FRID.value}_{States.STEP_COMPLETED.value}",
262
262
  "unless": "should_run_unit_tests",
263
263
  },
264
- {
265
- "source": f"{States.IMPLEMENTING_FRID.value}",
266
- "trigger": triggers.PREPARE_FINAL_OUTPUT,
267
- "dest": States.RENDER_COMPLETED.value,
268
- },
269
264
  {
270
265
  "source": "*",
271
266
  "trigger": triggers.HANDLE_ERROR,
@@ -349,6 +344,13 @@ class StateMachineConfig:
349
344
  "source": f"{States.IMPLEMENTING_FRID.value}_{States.FRID_FULLY_IMPLEMENTED.value}",
350
345
  "trigger": triggers.PROCEED_FRID_PROCESSING,
351
346
  "dest": f"{States.IMPLEMENTING_FRID.value}",
347
+ "conditions": "has_next_frid",
348
+ },
349
+ {
350
+ "source": f"{States.IMPLEMENTING_FRID.value}_{States.FRID_FULLY_IMPLEMENTED.value}",
351
+ "trigger": triggers.PROCEED_FRID_PROCESSING,
352
+ "dest": States.RENDER_COMPLETED.value,
353
+ "unless": "has_next_frid",
352
354
  },
353
355
  {
354
356
  "source": f"{States.IMPLEMENTING_FRID.value}_{States.REFACTORING_CODE.value}_{States.PROCESSING_UNIT_TESTS.value}_{States.UNIT_TESTS_READY.value}",
@@ -12,7 +12,6 @@ PROCEED_FRID_PROCESSING = "proceed_frid_processing"
12
12
  MARK_UNIT_TESTS_FAILED = "mark_unit_tests_failed"
13
13
  MARK_UNIT_TESTS_PASSED = "mark_unit_tests_passed"
14
14
  MARK_UNIT_TESTS_READY = "mark_unit_tests_ready"
15
- PREPARE_FINAL_OUTPUT = "prepare_final_output"
16
15
  FINISH_RENDER = "finish_render"
17
16
  HANDLE_ERROR = "handle_error"
18
17
  REFACTOR_CODE = "refactor_code"
@@ -1,7 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(gh pr:*)"
5
- ]
6
- }
7
- }
@@ -1 +0,0 @@
1
- __version__ = "0.2.18"
File without changes
File without changes