codeplain 0.2.17__tar.gz → 0.2.19__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.
- codeplain-0.2.19/.claude/settings.local.json +39 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/PKG-INFO +1 -1
- codeplain-0.2.19/_version.py +1 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/codeplain_REST_api.py +10 -3
- {codeplain-0.2.17 → codeplain-0.2.19}/module_renderer.py +2 -1
- {codeplain-0.2.17 → codeplain-0.2.19}/plain2code.py +23 -6
- {codeplain-0.2.17 → codeplain-0.2.19}/plain2code_logger.py +6 -5
- {codeplain-0.2.17 → codeplain-0.2.19}/plain2code_state.py +21 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/plain2code_utils.py +16 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/plain_file.py +1 -1
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/exit_with_error.py +1 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/finish_functional_requirement.py +1 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/refactor_code.py +1 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/render_conformance_tests.py +1 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/render_functional_requirement.py +11 -14
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/code_renderer.py +3 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/render_context.py +12 -10
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/render_utils.py +24 -7
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/state_machine_config.py +9 -7
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/triggers.py +0 -1
- codeplain-0.2.17/.claude/settings.local.json +0 -7
- codeplain-0.2.17/_version.py +0 -1
- {codeplain-0.2.17 → codeplain-0.2.19}/.flake8 +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/.github/workflows/lint-and-test.yml +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/.github/workflows/nofity-slack-on-main-merge.yml +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/.github/workflows/publish-install-script.yml +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/.github/workflows/publish-to-pypi.yml +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/.gitignore +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/.vscode/launch.json +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/.vscode/settings.json +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/LICENSE +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/README.md +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/concept_utils.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/config/__init__.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/config/system_config.yaml +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/diff_utils.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/docs/generate_cli.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/docs/plain2code_cli.md +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/docs/starting_a_plain_project_from_scratch.md +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/event_bus.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_golang/config.yaml +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_golang/run.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_python/config.yaml +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_python/hello_world_python.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_python/run.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_react/config.yaml +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_react/hello_world_react.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_react/run.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/examples/run.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/file_utils.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/git_utils.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/hash_key.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/install/bash/examples.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/install/bash/install.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/install/bash/walkthrough.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/install/powershell/examples.ps1 +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/install/powershell/install.ps1 +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/install/powershell/walkthrough.ps1 +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/memory_management.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/plain2code_arguments.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/plain2code_console.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/plain2code_events.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/plain2code_exceptions.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/plain2code_nodes.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/plain2code_read_config.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/plain_modules.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/plain_spec.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/pyproject.toml +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/pytest.ini +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/__init__.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/analyze_specification_ambiguity.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/base_action.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/commit_implementation_code_changes.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/create_dist.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/fix_conformance_test.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/fix_unit_tests.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/prepare_repositories.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/prepare_testing_environment.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/run_conformance_tests.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/run_unit_tests.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/summarize_conformance_tests.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/conformance_test_helpers.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/conformance_tests.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/implementation_code_helpers.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/render_types.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/render_machine/states.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/requirements.txt +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/resources/codeplain_overview.png +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/resources/plain_example.png +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/standard_template_library/__init__.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/standard_template_library/golang-console-app-template.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/standard_template_library/python-console-app-template.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/standard_template_library/typescript-react-app-template.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/system_config.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/test_scripts/run_conformance_tests_cypress.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/test_scripts/run_conformance_tests_golang.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/test_scripts/run_conformance_tests_python.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/test_scripts/run_unittests_golang.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/test_scripts/run_unittests_python.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/test_scripts/run_unittests_react.sh +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/__init__.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/conftest.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/imports/circular_imports_1.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/imports/circular_imports_2.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/imports/circular_imports_main.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/imports/diamond_import_1.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/imports/diamond_import_2.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/imports/diamond_import_common.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/imports/diamond_imports_main.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/imports/non_existent_import.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfile/invalid_specification_order.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/exported_concepts.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/exported_concepts_missing.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/exported_concepts_missing_example.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/required_concepts.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/topological_sort.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/circular_requires_main.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/circular_requires_sub.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/diamond_requires_1.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/diamond_requires_2.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/diamond_requires_common.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/diamond_requires_main.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/independent_requires_1.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/independent_requires_2.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/independent_requires_main.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/non_existent_require.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/normal_requires_1.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/normal_requires_2.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/normal_requires_common.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/requires/normal_requires_main.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/simple.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/templates/block_level_include.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/templates/code_variables.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/templates/header.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/templates/implement.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/templates/implement_2.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/templates/template_include.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/data/templates/test_hardest_problem.plain +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/test_git_utils.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/test_imports.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/test_plainfile.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/test_plainfileparser.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/test_plainspec.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/test_requires.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tests/test_resolve_config_file.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tui/__init__.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tui/components.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tui/models.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tui/plain2code_tui.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tui/spinner.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tui/state_handlers.py +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tui/styles.css +0 -0
- {codeplain-0.2.17 → codeplain-0.2.19}/tui/widget_helpers.py +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
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
|
+
]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.19"
|
|
@@ -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(
|
|
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)
|
|
@@ -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
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
timestamp = f"{
|
|
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("
|
|
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,
|
|
@@ -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
|
][
|
{codeplain-0.2.17 → codeplain-0.2.19}/render_machine/actions/render_functional_requirement.py
RENAMED
|
@@ -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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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(
|
|
@@ -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
|
|
@@ -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()
|
|
@@ -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 =
|
|
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
|
-
|
|
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
|
-
#
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
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)
|
|
@@ -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"
|
codeplain-0.2.17/_version.py
DELETED
|
@@ -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
|
{codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_golang/hello_world_golang.plain
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codeplain-0.2.17 → codeplain-0.2.19}/examples/example_hello_world_python/hello_world_python.plain
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|