codeplain 0.2.17__tar.gz → 0.2.18__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 (198) hide show
  1. {codeplain-0.2.17 → codeplain-0.2.18}/PKG-INFO +1 -1
  2. codeplain-0.2.18/_version.py +1 -0
  3. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/render_utils.py +24 -7
  4. codeplain-0.2.17/_version.py +0 -1
  5. {codeplain-0.2.17 → codeplain-0.2.18}/.claude/settings.local.json +0 -0
  6. {codeplain-0.2.17 → codeplain-0.2.18}/.flake8 +0 -0
  7. {codeplain-0.2.17 → codeplain-0.2.18}/.github/workflows/lint-and-test.yml +0 -0
  8. {codeplain-0.2.17 → codeplain-0.2.18}/.github/workflows/nofity-slack-on-main-merge.yml +0 -0
  9. {codeplain-0.2.17 → codeplain-0.2.18}/.github/workflows/publish-install-script.yml +0 -0
  10. {codeplain-0.2.17 → codeplain-0.2.18}/.github/workflows/publish-to-pypi.yml +0 -0
  11. {codeplain-0.2.17 → codeplain-0.2.18}/.gitignore +0 -0
  12. {codeplain-0.2.17 → codeplain-0.2.18}/.vscode/launch.json +0 -0
  13. {codeplain-0.2.17 → codeplain-0.2.18}/.vscode/settings.json +0 -0
  14. {codeplain-0.2.17 → codeplain-0.2.18}/LICENSE +0 -0
  15. {codeplain-0.2.17 → codeplain-0.2.18}/README.md +0 -0
  16. {codeplain-0.2.17 → codeplain-0.2.18}/codeplain_REST_api.py +0 -0
  17. {codeplain-0.2.17 → codeplain-0.2.18}/concept_utils.py +0 -0
  18. {codeplain-0.2.17 → codeplain-0.2.18}/config/__init__.py +0 -0
  19. {codeplain-0.2.17 → codeplain-0.2.18}/config/system_config.yaml +0 -0
  20. {codeplain-0.2.17 → codeplain-0.2.18}/diff_utils.py +0 -0
  21. {codeplain-0.2.17 → codeplain-0.2.18}/docs/generate_cli.py +0 -0
  22. {codeplain-0.2.17 → codeplain-0.2.18}/docs/plain2code_cli.md +0 -0
  23. {codeplain-0.2.17 → codeplain-0.2.18}/docs/starting_a_plain_project_from_scratch.md +0 -0
  24. {codeplain-0.2.17 → codeplain-0.2.18}/event_bus.py +0 -0
  25. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_golang/config.yaml +0 -0
  26. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
  27. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
  28. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_golang/run.sh +0 -0
  29. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_python/config.yaml +0 -0
  30. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
  31. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_python/hello_world_python.plain +0 -0
  32. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_python/run.sh +0 -0
  33. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_react/config.yaml +0 -0
  34. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
  35. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
  36. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
  37. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
  38. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
  39. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_react/hello_world_react.plain +0 -0
  40. {codeplain-0.2.17 → codeplain-0.2.18}/examples/example_hello_world_react/run.sh +0 -0
  41. {codeplain-0.2.17 → codeplain-0.2.18}/examples/run.sh +0 -0
  42. {codeplain-0.2.17 → codeplain-0.2.18}/file_utils.py +0 -0
  43. {codeplain-0.2.17 → codeplain-0.2.18}/git_utils.py +0 -0
  44. {codeplain-0.2.17 → codeplain-0.2.18}/hash_key.py +0 -0
  45. {codeplain-0.2.17 → codeplain-0.2.18}/install/bash/examples.sh +0 -0
  46. {codeplain-0.2.17 → codeplain-0.2.18}/install/bash/install.sh +0 -0
  47. {codeplain-0.2.17 → codeplain-0.2.18}/install/bash/walkthrough.sh +0 -0
  48. {codeplain-0.2.17 → codeplain-0.2.18}/install/powershell/examples.ps1 +0 -0
  49. {codeplain-0.2.17 → codeplain-0.2.18}/install/powershell/install.ps1 +0 -0
  50. {codeplain-0.2.17 → codeplain-0.2.18}/install/powershell/walkthrough.ps1 +0 -0
  51. {codeplain-0.2.17 → codeplain-0.2.18}/memory_management.py +0 -0
  52. {codeplain-0.2.17 → codeplain-0.2.18}/module_renderer.py +0 -0
  53. {codeplain-0.2.17 → codeplain-0.2.18}/plain2code.py +0 -0
  54. {codeplain-0.2.17 → codeplain-0.2.18}/plain2code_arguments.py +0 -0
  55. {codeplain-0.2.17 → codeplain-0.2.18}/plain2code_console.py +0 -0
  56. {codeplain-0.2.17 → codeplain-0.2.18}/plain2code_events.py +0 -0
  57. {codeplain-0.2.17 → codeplain-0.2.18}/plain2code_exceptions.py +0 -0
  58. {codeplain-0.2.17 → codeplain-0.2.18}/plain2code_logger.py +0 -0
  59. {codeplain-0.2.17 → codeplain-0.2.18}/plain2code_nodes.py +0 -0
  60. {codeplain-0.2.17 → codeplain-0.2.18}/plain2code_read_config.py +0 -0
  61. {codeplain-0.2.17 → codeplain-0.2.18}/plain2code_state.py +0 -0
  62. {codeplain-0.2.17 → codeplain-0.2.18}/plain2code_utils.py +0 -0
  63. {codeplain-0.2.17 → codeplain-0.2.18}/plain_file.py +0 -0
  64. {codeplain-0.2.17 → codeplain-0.2.18}/plain_modules.py +0 -0
  65. {codeplain-0.2.17 → codeplain-0.2.18}/plain_spec.py +0 -0
  66. {codeplain-0.2.17 → codeplain-0.2.18}/pyproject.toml +0 -0
  67. {codeplain-0.2.17 → codeplain-0.2.18}/pytest.ini +0 -0
  68. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/__init__.py +0 -0
  69. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/analyze_specification_ambiguity.py +0 -0
  70. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/base_action.py +0 -0
  71. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
  72. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/commit_implementation_code_changes.py +0 -0
  73. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/create_dist.py +0 -0
  74. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/exit_with_error.py +0 -0
  75. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/finish_functional_requirement.py +0 -0
  76. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/fix_conformance_test.py +0 -0
  77. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/fix_unit_tests.py +0 -0
  78. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/prepare_repositories.py +0 -0
  79. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/prepare_testing_environment.py +0 -0
  80. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/refactor_code.py +0 -0
  81. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/render_conformance_tests.py +0 -0
  82. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/render_functional_requirement.py +0 -0
  83. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/run_conformance_tests.py +0 -0
  84. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/run_unit_tests.py +0 -0
  85. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/actions/summarize_conformance_tests.py +0 -0
  86. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/code_renderer.py +0 -0
  87. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/conformance_test_helpers.py +0 -0
  88. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/conformance_tests.py +0 -0
  89. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/implementation_code_helpers.py +0 -0
  90. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/render_context.py +0 -0
  91. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/render_types.py +0 -0
  92. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/state_machine_config.py +0 -0
  93. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/states.py +0 -0
  94. {codeplain-0.2.17 → codeplain-0.2.18}/render_machine/triggers.py +0 -0
  95. {codeplain-0.2.17 → codeplain-0.2.18}/requirements.txt +0 -0
  96. {codeplain-0.2.17 → codeplain-0.2.18}/resources/codeplain_overview.png +0 -0
  97. {codeplain-0.2.17 → codeplain-0.2.18}/resources/plain_example.png +0 -0
  98. {codeplain-0.2.17 → codeplain-0.2.18}/standard_template_library/__init__.py +0 -0
  99. {codeplain-0.2.17 → codeplain-0.2.18}/standard_template_library/golang-console-app-template.plain +0 -0
  100. {codeplain-0.2.17 → codeplain-0.2.18}/standard_template_library/python-console-app-template.plain +0 -0
  101. {codeplain-0.2.17 → codeplain-0.2.18}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
  102. {codeplain-0.2.17 → codeplain-0.2.18}/standard_template_library/typescript-react-app-template.plain +0 -0
  103. {codeplain-0.2.17 → codeplain-0.2.18}/system_config.py +0 -0
  104. {codeplain-0.2.17 → codeplain-0.2.18}/test_scripts/run_conformance_tests_cypress.sh +0 -0
  105. {codeplain-0.2.17 → codeplain-0.2.18}/test_scripts/run_conformance_tests_golang.sh +0 -0
  106. {codeplain-0.2.17 → codeplain-0.2.18}/test_scripts/run_conformance_tests_python.sh +0 -0
  107. {codeplain-0.2.17 → codeplain-0.2.18}/test_scripts/run_unittests_golang.sh +0 -0
  108. {codeplain-0.2.17 → codeplain-0.2.18}/test_scripts/run_unittests_python.sh +0 -0
  109. {codeplain-0.2.17 → codeplain-0.2.18}/test_scripts/run_unittests_react.sh +0 -0
  110. {codeplain-0.2.17 → codeplain-0.2.18}/tests/__init__.py +0 -0
  111. {codeplain-0.2.17 → codeplain-0.2.18}/tests/conftest.py +0 -0
  112. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/imports/circular_imports_1.plain +0 -0
  113. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/imports/circular_imports_2.plain +0 -0
  114. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/imports/circular_imports_main.plain +0 -0
  115. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/imports/diamond_import_1.plain +0 -0
  116. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/imports/diamond_import_2.plain +0 -0
  117. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/imports/diamond_import_common.plain +0 -0
  118. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/imports/diamond_imports_main.plain +0 -0
  119. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/imports/non_existent_import.plain +0 -0
  120. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
  121. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfile/invalid_specification_order.plain +0 -0
  122. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
  123. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
  124. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
  125. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
  126. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
  127. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
  128. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
  129. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
  130. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
  131. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
  132. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
  133. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
  134. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
  135. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
  136. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
  137. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
  138. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/exported_concepts.plain +0 -0
  139. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
  140. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
  141. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/exported_concepts_missing.plain +0 -0
  142. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/exported_concepts_missing_example.plain +0 -0
  143. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
  144. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
  145. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
  146. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
  147. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
  148. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
  149. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
  150. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
  151. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/required_concepts.plain +0 -0
  152. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
  153. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
  154. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
  155. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
  156. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
  157. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
  158. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
  159. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
  160. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/topological_sort.plain +0 -0
  161. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
  162. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/circular_requires_main.plain +0 -0
  163. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/circular_requires_sub.plain +0 -0
  164. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/diamond_requires_1.plain +0 -0
  165. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/diamond_requires_2.plain +0 -0
  166. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/diamond_requires_common.plain +0 -0
  167. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/diamond_requires_main.plain +0 -0
  168. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/independent_requires_1.plain +0 -0
  169. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/independent_requires_2.plain +0 -0
  170. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/independent_requires_main.plain +0 -0
  171. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/non_existent_require.plain +0 -0
  172. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/normal_requires_1.plain +0 -0
  173. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/normal_requires_2.plain +0 -0
  174. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/normal_requires_common.plain +0 -0
  175. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/requires/normal_requires_main.plain +0 -0
  176. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/simple.plain +0 -0
  177. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/templates/block_level_include.plain +0 -0
  178. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/templates/code_variables.plain +0 -0
  179. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/templates/header.plain +0 -0
  180. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/templates/implement.plain +0 -0
  181. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/templates/implement_2.plain +0 -0
  182. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/templates/template_include.plain +0 -0
  183. {codeplain-0.2.17 → codeplain-0.2.18}/tests/data/templates/test_hardest_problem.plain +0 -0
  184. {codeplain-0.2.17 → codeplain-0.2.18}/tests/test_git_utils.py +0 -0
  185. {codeplain-0.2.17 → codeplain-0.2.18}/tests/test_imports.py +0 -0
  186. {codeplain-0.2.17 → codeplain-0.2.18}/tests/test_plainfile.py +0 -0
  187. {codeplain-0.2.17 → codeplain-0.2.18}/tests/test_plainfileparser.py +0 -0
  188. {codeplain-0.2.17 → codeplain-0.2.18}/tests/test_plainspec.py +0 -0
  189. {codeplain-0.2.17 → codeplain-0.2.18}/tests/test_requires.py +0 -0
  190. {codeplain-0.2.17 → codeplain-0.2.18}/tests/test_resolve_config_file.py +0 -0
  191. {codeplain-0.2.17 → codeplain-0.2.18}/tui/__init__.py +0 -0
  192. {codeplain-0.2.17 → codeplain-0.2.18}/tui/components.py +0 -0
  193. {codeplain-0.2.17 → codeplain-0.2.18}/tui/models.py +0 -0
  194. {codeplain-0.2.17 → codeplain-0.2.18}/tui/plain2code_tui.py +0 -0
  195. {codeplain-0.2.17 → codeplain-0.2.18}/tui/spinner.py +0 -0
  196. {codeplain-0.2.17 → codeplain-0.2.18}/tui/state_handlers.py +0 -0
  197. {codeplain-0.2.17 → codeplain-0.2.18}/tui/styles.css +0 -0
  198. {codeplain-0.2.17 → codeplain-0.2.18}/tui/widget_helpers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeplain
3
- Version: 0.2.17
3
+ Version: 0.2.18
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.18"
@@ -19,7 +19,7 @@ SCRIPT_EXECUTION_TIMEOUT = 120
19
19
  TIMEOUT_ERROR_EXIT_CODE = 124
20
20
  POLL_INTERVAL_SECONDS = 0.2
21
21
  SIGTERM_GRACE_PERIOD_SECONDS = 0.2
22
- STDOUT_READ_TIMEOUT_SECONDS = 5
22
+ STDOUT_READ_TIMEOUT_SECONDS = 2
23
23
  F_SETPIPE_SIZE = 1031 # Linux-only constant
24
24
  PIPE_SIZE_KB = 1024 # 1MB
25
25
 
@@ -120,11 +120,27 @@ def execute_script( # noqa: C901
120
120
  # Set the pipe size to 1MB to avoid buffer overflows
121
121
  fcntl.fcntl(proc.stdout.fileno(), F_SETPIPE_SIZE, PIPE_SIZE_KB * 1024) # 1MB
122
122
 
123
+ # Drain stdout in a background thread to prevent pipe buffer deadlock.
124
+ # macOS has a 64KB pipe buffer; without continuous draining, scripts that produce
125
+ # more output than that block on write and never exit, causing spurious timeouts.
126
+ output_chunks: list[str] = []
127
+
128
+ def _drain_stdout() -> None:
129
+ try:
130
+ for chunk in iter(lambda: proc.stdout.read(8192), ""):
131
+ output_chunks.append(chunk)
132
+ except (OSError, ValueError):
133
+ pass
134
+
135
+ reader = threading.Thread(target=_drain_stdout, daemon=True)
136
+ reader.start()
137
+
123
138
  try:
124
139
  while proc.poll() is None:
125
140
  if time.time() - start_time >= script_timeout:
126
141
  _kill_process(proc)
127
- partial_stdout = proc.stdout.read()
142
+ reader.join(timeout=2)
143
+ partial_stdout = "".join(output_chunks)
128
144
  exc = subprocess.TimeoutExpired(cmd, script_timeout)
129
145
  exc.stdout = partial_stdout
130
146
  raise exc
@@ -136,12 +152,13 @@ def execute_script( # noqa: C901
136
152
  else:
137
153
  time.sleep(POLL_INTERVAL_SECONDS)
138
154
 
139
- # Use communicate() with a timeout because child processes may hold the pipe open after the main process exits.
140
- try:
141
- stdout, _ = proc.communicate(timeout=STDOUT_READ_TIMEOUT_SECONDS)
142
- except subprocess.TimeoutExpired:
155
+ # Wait for the reader to finish draining remaining output.
156
+ # Close stdout if child processes keep the pipe open beyond the grace period.
157
+ reader.join(timeout=STDOUT_READ_TIMEOUT_SECONDS)
158
+ if reader.is_alive():
143
159
  proc.stdout.close()
144
- stdout = ""
160
+ reader.join(timeout=1)
161
+ stdout = "".join(output_chunks)
145
162
  elapsed_time = time.time() - start_time
146
163
 
147
164
  sanitized_script_output = _sanitize_script_output(stdout)
@@ -1 +0,0 @@
1
- __version__ = "0.2.17"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes