codeplain 0.2.5__tar.gz → 0.2.7__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.5 → codeplain-0.2.7}/PKG-INFO +1 -1
- {codeplain-0.2.5 → codeplain-0.2.7}/codeplain_REST_api.py +47 -11
- {codeplain-0.2.5 → codeplain-0.2.7}/config/system_config.yaml +1 -1
- codeplain-0.2.7/docs/plain2code_cli.md +63 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_python/config.yaml +1 -1
- {codeplain-0.2.5 → codeplain-0.2.7}/git_utils.py +20 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/install/walkthrough.sh +47 -50
- {codeplain-0.2.5 → codeplain-0.2.7}/module_renderer.py +3 -1
- {codeplain-0.2.5 → codeplain-0.2.7}/plain2code.py +58 -10
- {codeplain-0.2.5 → codeplain-0.2.7}/plain2code_arguments.py +24 -20
- {codeplain-0.2.5 → codeplain-0.2.7}/plain2code_events.py +3 -1
- {codeplain-0.2.5 → codeplain-0.2.7}/plain2code_exceptions.py +7 -1
- {codeplain-0.2.5 → codeplain-0.2.7}/plain2code_utils.py +5 -5
- {codeplain-0.2.5 → codeplain-0.2.7}/plain_file.py +2 -2
- {codeplain-0.2.5 → codeplain-0.2.7}/pyproject.toml +1 -1
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/analyze_specification_ambiguity.py +2 -1
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/fix_conformance_test.py +2 -2
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/fix_unit_tests.py +2 -2
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/conformance_tests.py +2 -1
- {codeplain-0.2.5 → codeplain-0.2.7}/standard_template_library/typescript-react-app-template.plain +6 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/test_requires.py +2 -2
- {codeplain-0.2.5 → codeplain-0.2.7}/tui/plain2code_tui.py +8 -16
- {codeplain-0.2.5 → codeplain-0.2.7}/tui/state_handlers.py +9 -4
- {codeplain-0.2.5 → codeplain-0.2.7}/tui/widget_helpers.py +14 -3
- codeplain-0.2.5/docs/plain2code_cli.md +0 -66
- {codeplain-0.2.5 → codeplain-0.2.7}/.flake8 +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/.github/workflows/lint-and-test.yml +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/.github/workflows/nofity-slack-on-main-merge.yml +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/.github/workflows/publish-install-script.yml +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/.github/workflows/publish-to-pypi.yml +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/.gitignore +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/.vscode/launch.json +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/.vscode/settings.json +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/LICENSE +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/README.md +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/concept_utils.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/config/__init__.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/diff_utils.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/docs/generate_cli.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/docs/plain_language_specification.md +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/docs/starting_a_plain_project_from_scratch.md +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/event_bus.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_golang/config.yaml +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_golang/run.sh +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_python/hello_world_python.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_python/run.sh +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_react/config.yaml +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_react/hello_world_react.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/example_hello_world_react/run.sh +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/examples/run.sh +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/file_utils.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/hash_key.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/install/examples.sh +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/install/install.sh +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/memory_management.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/plain2code_console.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/plain2code_logger.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/plain2code_nodes.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/plain2code_read_config.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/plain2code_state.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/plain_modules.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/plain_spec.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/pytest.ini +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/__init__.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/base_action.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/commit_implementation_code_changes.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/create_dist.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/exit_with_error.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/finish_functional_requirement.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/prepare_repositories.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/prepare_testing_environment.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/refactor_code.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/render_conformance_tests.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/render_functional_requirement.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/run_conformance_tests.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/run_unit_tests.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/actions/summarize_conformance_tests.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/code_renderer.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/conformance_test_helpers.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/implementation_code_helpers.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/render_context.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/render_types.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/render_utils.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/state_machine_config.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/states.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/render_machine/triggers.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/requirements.txt +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/resources/codeplain_overview.png +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/resources/plain_example.png +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/standard_template_library/__init__.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/standard_template_library/golang-console-app-template.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/standard_template_library/python-console-app-template.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/system_config.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/test_scripts/run_conformance_tests_cypress.sh +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/test_scripts/run_conformance_tests_golang.sh +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/test_scripts/run_conformance_tests_python.sh +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/test_scripts/run_unittests_golang.sh +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/test_scripts/run_unittests_python.sh +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/test_scripts/run_unittests_react.sh +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/__init__.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/conftest.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/imports/circular_imports_1.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/imports/circular_imports_2.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/imports/circular_imports_main.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/imports/diamond_import_1.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/imports/diamond_import_2.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/imports/diamond_import_common.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/imports/diamond_imports_main.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/imports/non_existent_import.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfile/invalid_specification_order.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/exported_concepts.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/exported_concepts_missing.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/exported_concepts_missing_example.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/required_concepts.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/topological_sort.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/circular_requires_main.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/circular_requires_sub.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/diamond_requires_1.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/diamond_requires_2.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/diamond_requires_common.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/diamond_requires_main.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/independent_requires_1.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/independent_requires_2.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/independent_requires_main.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/non_existent_require.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/normal_requires_1.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/normal_requires_2.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/normal_requires_common.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/requires/normal_requires_main.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/simple.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/templates/block_level_include.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/templates/code_variables.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/templates/header.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/templates/implement.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/templates/implement_2.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/templates/template_include.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/data/templates/test_hardest_problem.plain +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/test_git_utils.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/test_imports.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/test_plainfile.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/test_plainfileparser.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tests/test_plainspec.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tui/__init__.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tui/components.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tui/models.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tui/spinner.py +0 -0
- {codeplain-0.2.5 → codeplain-0.2.7}/tui/styles.css +0 -0
|
@@ -2,6 +2,7 @@ import time
|
|
|
2
2
|
from typing import Optional
|
|
3
3
|
|
|
4
4
|
import requests
|
|
5
|
+
from requests.exceptions import ConnectionError, Timeout
|
|
5
6
|
|
|
6
7
|
import plain2code_exceptions
|
|
7
8
|
from plain2code_state import RunState
|
|
@@ -9,7 +10,6 @@ from plain2code_state import RunState
|
|
|
9
10
|
MAX_RETRIES = 4
|
|
10
11
|
RETRY_DELAY = 3
|
|
11
12
|
|
|
12
|
-
# TODO: Handle connection errors
|
|
13
13
|
RETRY_ERROR_CODES = [
|
|
14
14
|
"LLMInternalError",
|
|
15
15
|
]
|
|
@@ -44,6 +44,42 @@ class CodeplainAPI:
|
|
|
44
44
|
run_state.increment_call_count()
|
|
45
45
|
payload["render_state"] = run_state.to_dict()
|
|
46
46
|
|
|
47
|
+
def _handle_retry_logic(
|
|
48
|
+
self, attempt: int, retry_delay: int, num_retries: int, error: Exception, silent: bool
|
|
49
|
+
) -> int:
|
|
50
|
+
"""
|
|
51
|
+
Handles retry logic with exponential backoff.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
attempt: Current attempt number
|
|
55
|
+
retry_delay: Current retry delay in seconds
|
|
56
|
+
error: The exception that occurred
|
|
57
|
+
num_retries: Number of retries allowed
|
|
58
|
+
error_type: Type of error for logging (e.g., "Network error", "Error")
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Updated retry_delay for next attempt
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
The original exception if max retries exceeded
|
|
65
|
+
"""
|
|
66
|
+
is_connection_error = isinstance(error, ConnectionError) or isinstance(error, Timeout)
|
|
67
|
+
connection_error_type = "Network error" if is_connection_error else "Error"
|
|
68
|
+
if attempt < num_retries:
|
|
69
|
+
if not silent:
|
|
70
|
+
self.console.info(f"{connection_error_type} on attempt {attempt + 1}/{num_retries + 1}: {error}")
|
|
71
|
+
self.console.info(f"Retrying in {retry_delay} seconds...")
|
|
72
|
+
time.sleep(retry_delay)
|
|
73
|
+
# Exponential backoff
|
|
74
|
+
return retry_delay * 2
|
|
75
|
+
else:
|
|
76
|
+
if not silent:
|
|
77
|
+
self.console.error(f"Max retries ({num_retries}) exceeded. Last error: {error}")
|
|
78
|
+
if is_connection_error:
|
|
79
|
+
raise plain2code_exceptions.NetworkConnectionError("Failed to connect to API server.")
|
|
80
|
+
else:
|
|
81
|
+
raise error
|
|
82
|
+
|
|
47
83
|
def _raise_for_error_code(self, response_json):
|
|
48
84
|
"""Raise appropriate exception based on error code in response."""
|
|
49
85
|
error_code = response_json.get("error_code")
|
|
@@ -60,7 +96,13 @@ class CodeplainAPI:
|
|
|
60
96
|
raise exception_class(message)
|
|
61
97
|
|
|
62
98
|
def post_request(
|
|
63
|
-
self,
|
|
99
|
+
self,
|
|
100
|
+
endpoint_url,
|
|
101
|
+
headers,
|
|
102
|
+
payload,
|
|
103
|
+
run_state: Optional[RunState],
|
|
104
|
+
num_retries: int = MAX_RETRIES,
|
|
105
|
+
silent: bool = False,
|
|
64
106
|
):
|
|
65
107
|
if run_state is not None:
|
|
66
108
|
self._extend_payload_with_run_state(payload, run_state)
|
|
@@ -85,18 +127,12 @@ class CodeplainAPI:
|
|
|
85
127
|
return response_json
|
|
86
128
|
|
|
87
129
|
except Exception as e:
|
|
130
|
+
# For other errors, check if they should be retried
|
|
88
131
|
if response_json is not None and "error_code" in response_json:
|
|
89
132
|
if response_json["error_code"] not in RETRY_ERROR_CODES:
|
|
90
133
|
raise e
|
|
91
134
|
|
|
92
|
-
|
|
93
|
-
self.console.info(f"Error on attempt {attempt + 1}/{num_retries + 1}: {e}")
|
|
94
|
-
self.console.info(f"Retrying in {retry_delay} seconds...")
|
|
95
|
-
time.sleep(retry_delay)
|
|
96
|
-
retry_delay *= 2 # Exponential backoff
|
|
97
|
-
else:
|
|
98
|
-
self.console.error(f"Max retries ({num_retries}) exceeded. Last error: {e}")
|
|
99
|
-
raise e
|
|
135
|
+
retry_delay = self._handle_retry_logic(attempt, retry_delay, num_retries, e, silent)
|
|
100
136
|
|
|
101
137
|
def connection_check(self, client_version):
|
|
102
138
|
endpoint_url = f"{self.api_url}/connection_check"
|
|
@@ -105,7 +141,7 @@ class CodeplainAPI:
|
|
|
105
141
|
"api_key": self.api_key,
|
|
106
142
|
"client_version": client_version,
|
|
107
143
|
}
|
|
108
|
-
return self.post_request(endpoint_url, headers, payload, None, num_retries=0)
|
|
144
|
+
return self.post_request(endpoint_url, headers, payload, None, num_retries=0, silent=True)
|
|
109
145
|
|
|
110
146
|
def render_functional_requirement(
|
|
111
147
|
self,
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Plain2Code CLI Reference
|
|
2
|
+
|
|
3
|
+
```text
|
|
4
|
+
usage: generate_cli.py [-h] [--verbose] [--base-folder BASE_FOLDER] [--build-folder BUILD_FOLDER] [--log-to-file | --no-log-to-file] [--log-file-name LOG_FILE_NAME] [--config-name CONFIG_NAME] [--render-range RENDER_RANGE | --render-from RENDER_FROM] [--force-render]
|
|
5
|
+
[--unittests-script UNITTESTS_SCRIPT] [--conformance-tests-folder CONFORMANCE_TESTS_FOLDER] [--conformance-tests-script CONFORMANCE_TESTS_SCRIPT] [--prepare-environment-script PREPARE_ENVIRONMENT_SCRIPT] [--api [API]] [--api-key API_KEY]
|
|
6
|
+
[--full-plain] [--dry-run] [--replay-with REPLAY_WITH] [--template-dir TEMPLATE_DIR] [--copy-build] [--build-dest BUILD_DEST] [--copy-conformance-tests] [--conformance-tests-dest CONFORMANCE_TESTS_DEST] [--render-machine-graph]
|
|
7
|
+
[--logging-config-path]
|
|
8
|
+
filename
|
|
9
|
+
|
|
10
|
+
Render plain code to target code.
|
|
11
|
+
|
|
12
|
+
positional arguments:
|
|
13
|
+
filename Path to the plain file to render. The directory containing this file has highest precedence for template loading, so you can place custom templates here to override the defaults. See --template-dir for more details about template loading.
|
|
14
|
+
|
|
15
|
+
options:
|
|
16
|
+
-h, --help show this help message and exit
|
|
17
|
+
--verbose, -v Enable verbose output
|
|
18
|
+
--base-folder BASE_FOLDER
|
|
19
|
+
Base folder for the build files
|
|
20
|
+
--build-folder BUILD_FOLDER
|
|
21
|
+
Folder for build files
|
|
22
|
+
--log-to-file, --no-log-to-file
|
|
23
|
+
Enable logging to a file. Defaults to True. Use --no-log-to-file to disable.
|
|
24
|
+
--log-file-name LOG_FILE_NAME
|
|
25
|
+
Name of the log file. Defaults to 'codeplain.log'.Always resolved relative to the plain file directory.If file on this path already exists, it will be overwritten by the current logs.
|
|
26
|
+
--render-range RENDER_RANGE
|
|
27
|
+
Specify a range of functional requirements to render (e.g. '1.1,2.3'). Use comma to separate start and end IDs. If only one ID is provided, only that requirement is rendered. Range is inclusive of both start and end IDs.
|
|
28
|
+
--render-from RENDER_FROM
|
|
29
|
+
Continue generation starting from this specific functional requirement (e.g. '2.1'). The requirement with this ID will be included in the output. The ID must match one of the functional requirements in your plain file.
|
|
30
|
+
--force-render Force re-render of all the required modules.
|
|
31
|
+
--unittests-script UNITTESTS_SCRIPT
|
|
32
|
+
Shell script to run unit tests on generated code. Receives the build folder path as its first argument (default: 'plain_modules').
|
|
33
|
+
--conformance-tests-folder CONFORMANCE_TESTS_FOLDER
|
|
34
|
+
Folder for conformance test files
|
|
35
|
+
--conformance-tests-script CONFORMANCE_TESTS_SCRIPT
|
|
36
|
+
Path to conformance tests shell script. The script should accept two arguments: 1) First argument: path to a folder (e.g. 'plain_modules/module_name') containing generated source code, 2) Second argument: path to a subfolder of the conformance
|
|
37
|
+
tests folder (e.g. 'conformance_tests/subfoldername') containing test files.
|
|
38
|
+
--prepare-environment-script PREPARE_ENVIRONMENT_SCRIPT
|
|
39
|
+
Path to a shell script that prepares the testing environment. The script should accept the build folder path as its first argument (default: 'plain_modules').
|
|
40
|
+
--api [API] Alternative base URL for the API. Default: `https://api.codeplain.ai`
|
|
41
|
+
--api-key API_KEY API key used to access the API. If not provided, the CODEPLAIN_API_KEY environment variable is used.
|
|
42
|
+
--full-plain Display the complete plain specification before code generation. This shows your plain file with any included template content expanded. Useful for understanding what content is being processed.
|
|
43
|
+
--dry-run Preview of what Codeplain would do without actually making any changes.
|
|
44
|
+
--replay-with REPLAY_WITH
|
|
45
|
+
--template-dir TEMPLATE_DIR
|
|
46
|
+
Path to a custom template directory. Templates are searched in the following order: 1) directory containing the plain file, 2) this custom template directory (if provided), 3) built-in standard_template_library directory
|
|
47
|
+
--copy-build If set, copy the build folder to `--build-dest` after every successful rendering.
|
|
48
|
+
--build-dest BUILD_DEST
|
|
49
|
+
Target folder to copy build output to (used only if --copy-build is set).
|
|
50
|
+
--copy-conformance-tests
|
|
51
|
+
If set, copy the conformance tests folder to `--conformance-tests-dest` after every successful rendering. Requires --conformance-tests-script.
|
|
52
|
+
--conformance-tests-dest CONFORMANCE_TESTS_DEST
|
|
53
|
+
Target folder to copy conformance tests output to (used only if --copy-conformance-tests is set).
|
|
54
|
+
--render-machine-graph
|
|
55
|
+
If set, render the state machine graph.
|
|
56
|
+
--logging-config-path
|
|
57
|
+
Path to the logging configuration file.
|
|
58
|
+
|
|
59
|
+
configuration:
|
|
60
|
+
--config-name CONFIG_NAME
|
|
61
|
+
Path to the config file, defaults to config.yaml
|
|
62
|
+
|
|
63
|
+
```
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from configparser import NoOptionError, NoSectionError
|
|
2
3
|
from typing import Optional, Union
|
|
3
4
|
|
|
4
5
|
from git import Repo
|
|
@@ -42,6 +43,24 @@ def _get_full_commit_message(message, module_name, frid, render_id) -> str:
|
|
|
42
43
|
return full_message
|
|
43
44
|
|
|
44
45
|
|
|
46
|
+
def _ensure_git_config(repo: Repo) -> None:
|
|
47
|
+
config = repo.config_reader()
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
config.get_value("user", "name")
|
|
51
|
+
except (NoSectionError, NoOptionError):
|
|
52
|
+
# user.name not configured, set a default at repo level
|
|
53
|
+
with repo.config_writer(config_level="repository") as writer:
|
|
54
|
+
writer.set_value("user", "name", "Codeplain")
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
config.get_value("user", "email")
|
|
58
|
+
except (NoSectionError, NoOptionError):
|
|
59
|
+
# user.email not configured, set a default at repo level
|
|
60
|
+
with repo.config_writer(config_level="repository") as writer:
|
|
61
|
+
writer.set_value("user", "email", "codeplain@localhost")
|
|
62
|
+
|
|
63
|
+
|
|
45
64
|
def init_git_repo(
|
|
46
65
|
path_to_repo: Union[str, os.PathLike], module_name: Optional[str] = None, render_id: Optional[str] = None
|
|
47
66
|
) -> Repo:
|
|
@@ -56,6 +75,7 @@ def init_git_repo(
|
|
|
56
75
|
os.makedirs(path_to_repo)
|
|
57
76
|
|
|
58
77
|
repo = Repo.init(path_to_repo)
|
|
78
|
+
_ensure_git_config(repo)
|
|
59
79
|
repo.git.commit(
|
|
60
80
|
"--allow-empty", "-m", _get_full_commit_message(INITIAL_COMMIT_MESSAGE, module_name, None, render_id)
|
|
61
81
|
)
|
|
@@ -13,13 +13,13 @@ NC="${NC:-\033[0m}"
|
|
|
13
13
|
# Onboarding Step 1: Introduction to Plain
|
|
14
14
|
clear
|
|
15
15
|
echo ""
|
|
16
|
-
echo -e "${GRAY}
|
|
17
|
-
echo -e " ${YELLOW}${BOLD}
|
|
18
|
-
echo -e "${GRAY}
|
|
16
|
+
echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
|
|
17
|
+
echo -e " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 1 of 5"
|
|
18
|
+
echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
|
|
19
19
|
echo ""
|
|
20
|
-
echo -e " ***plain is a language of spec-driven development that allows developers to express intent
|
|
20
|
+
echo -e " ***plain is a language of spec-driven development that allows developers to express intent at any level of detail."
|
|
21
21
|
echo ""
|
|
22
|
-
echo -e " write specs in
|
|
22
|
+
echo -e " write specs in natural language extended with additional syntax based on markdown."
|
|
23
23
|
echo ""
|
|
24
24
|
echo -e " render production-ready code with *codeplain."
|
|
25
25
|
echo ""
|
|
@@ -28,8 +28,8 @@ echo ""
|
|
|
28
28
|
echo -e "${GRAY} ┌────────────────────────────────────────────────────────┐${NC}"
|
|
29
29
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
30
30
|
echo -e "${GRAY} │${NC} ${YELLOW}***definitions***${NC} - key concepts in your app ${GRAY}│${NC}"
|
|
31
|
-
echo -e "${GRAY} │${NC} ${YELLOW}***implementation reqs***${NC} - implementation details
|
|
32
|
-
echo -e "${GRAY} │${NC} ${YELLOW}***test reqs***${NC} - testing requirements
|
|
31
|
+
echo -e "${GRAY} │${NC} ${YELLOW}***implementation reqs***${NC} - implementation details ${GRAY}│${NC}"
|
|
32
|
+
echo -e "${GRAY} │${NC} ${YELLOW}***test reqs***${NC} - testing requirements ${GRAY}│${NC}"
|
|
33
33
|
echo -e "${GRAY} │${NC} ${YELLOW}***functional specs***${NC} - what the app should do ${GRAY}│${NC}"
|
|
34
34
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
35
35
|
echo -e "${GRAY} └────────────────────────────────────────────────────────┘${NC}"
|
|
@@ -41,33 +41,32 @@ read -r -p " press [Enter] to continue..." < /dev/tty
|
|
|
41
41
|
# Onboarding Step 2: Functional Specification
|
|
42
42
|
clear
|
|
43
43
|
echo ""
|
|
44
|
-
echo -e "${GRAY}
|
|
45
|
-
echo -e " ${YELLOW}${BOLD}
|
|
46
|
-
echo -e "${GRAY}
|
|
44
|
+
echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
|
|
45
|
+
echo -e " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 2 of 5"
|
|
46
|
+
echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
|
|
47
47
|
echo ""
|
|
48
48
|
echo -e " ${WHITE}${BOLD}FUNCTIONAL SPECS${NC} - what should the app do?"
|
|
49
49
|
echo ""
|
|
50
50
|
echo -e " This is where you describe ${GREEN}what your app should do${NC},"
|
|
51
|
-
echo -e " written in
|
|
51
|
+
echo -e " written in natural language. No code, just requirements."
|
|
52
52
|
echo ""
|
|
53
53
|
echo -e "${GRAY} ┌────────────────────────────────────────────────────────┐${NC}"
|
|
54
54
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
55
|
-
echo -e "${GRAY} │${NC} ${GRAY}***definitions***${NC}
|
|
55
|
+
echo -e "${GRAY} │${NC} ${GRAY}***definitions***${NC} ${GRAY}│${NC}"
|
|
56
56
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
57
|
-
echo -e "${GRAY} │${NC} ${GRAY}- :App: is a console application.${NC}
|
|
57
|
+
echo -e "${GRAY} │${NC} ${GRAY}- :App: is a console application.${NC} ${GRAY}│${NC}"
|
|
58
58
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
59
|
-
echo -e "${GRAY} │${NC} ${GRAY}***implementation reqs***${NC}
|
|
59
|
+
echo -e "${GRAY} │${NC} ${GRAY}***implementation reqs***${NC} ${GRAY}│${NC}"
|
|
60
60
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
61
|
-
echo -e "${GRAY} │${NC} ${GRAY}- :Implementation: should be in Python.${NC}
|
|
62
|
-
echo -e "${GRAY} │${NC} ${GRAY}- :UnitTests: should use Unittest framework.${NC} ${GRAY}│${NC}"
|
|
61
|
+
echo -e "${GRAY} │${NC} ${GRAY}- :Implementation: should be in Python.${NC} ${GRAY}│${NC}"
|
|
63
62
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
64
|
-
echo -e "${GRAY} │${NC} ${GRAY}***test reqs***${NC}
|
|
63
|
+
echo -e "${GRAY} │${NC} ${GRAY}***test reqs***${NC} ${GRAY}│${NC}"
|
|
65
64
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
66
|
-
echo -e "${GRAY} │${NC} ${GRAY}- :ConformanceTests: should use
|
|
65
|
+
echo -e "${GRAY} │${NC} ${GRAY}- :ConformanceTests: should use pytest.${NC} ${GRAY}│${NC}"
|
|
67
66
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
68
|
-
echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***functional specs***${NC}
|
|
67
|
+
echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***functional specs***${NC} ${GRAY}│${NC}"
|
|
69
68
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
70
|
-
echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :App: should display \"hello, world\".${NC}
|
|
69
|
+
echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :App: should display \"hello, world\".${NC} ${GRAY}│${NC}"
|
|
71
70
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
72
71
|
echo -e "${GRAY} └────────────────────────────────────────────────────────┘${NC}"
|
|
73
72
|
echo ""
|
|
@@ -79,37 +78,36 @@ read -r -p " press [Enter] to continue..." < /dev/tty
|
|
|
79
78
|
# Onboarding Step 3: Definitions
|
|
80
79
|
clear
|
|
81
80
|
echo ""
|
|
82
|
-
echo -e "${GRAY}
|
|
83
|
-
echo -e " ${YELLOW}${BOLD}
|
|
84
|
-
echo -e "${GRAY}
|
|
81
|
+
echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
|
|
82
|
+
echo -e " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 3 of 5"
|
|
83
|
+
echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
|
|
85
84
|
echo ""
|
|
86
|
-
echo -e " ${WHITE}${BOLD}DEFINITIONS${NC} -
|
|
85
|
+
echo -e " ${WHITE}${BOLD}DEFINITIONS${NC} - definitions and descriptions of key concepts"
|
|
87
86
|
echo ""
|
|
88
|
-
echo -e " Define ${GREEN}reusable concepts${NC}
|
|
87
|
+
echo -e " Define ${GREEN}reusable concepts${NC} using the ${YELLOW}:Concept:${NC} notation."
|
|
89
88
|
echo -e " These become building blocks you can reference anywhere."
|
|
90
89
|
echo ""
|
|
91
90
|
echo -e "${GRAY} ┌────────────────────────────────────────────────────────┐${NC}"
|
|
92
91
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
93
|
-
echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***definitions***${NC}
|
|
92
|
+
echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***definitions***${NC} ${GRAY}│${NC}"
|
|
94
93
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
95
|
-
echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :App: is a console application.${NC}
|
|
94
|
+
echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :App: is a console application.${NC} ${GRAY}│${NC}"
|
|
96
95
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
97
|
-
echo -e "${GRAY} │${NC} ${GRAY}***implementation reqs***${NC}
|
|
96
|
+
echo -e "${GRAY} │${NC} ${GRAY}***implementation reqs***${NC} ${GRAY}│${NC}"
|
|
98
97
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
99
|
-
echo -e "${GRAY} │${NC} ${GRAY}- :Implementation: should be in Python.${NC}
|
|
100
|
-
echo -e "${GRAY} │${NC} ${GRAY}- :UnitTests: should use Unittest framework.${NC} ${GRAY}│${NC}"
|
|
98
|
+
echo -e "${GRAY} │${NC} ${GRAY}- :Implementation: should be in Python.${NC} ${GRAY}│${NC}"
|
|
101
99
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
102
|
-
echo -e "${GRAY} │${NC} ${GRAY}***test reqs***${NC}
|
|
100
|
+
echo -e "${GRAY} │${NC} ${GRAY}***test reqs***${NC} ${GRAY}│${NC}"
|
|
103
101
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
104
|
-
echo -e "${GRAY} │${NC} ${GRAY}- :ConformanceTests: should use
|
|
102
|
+
echo -e "${GRAY} │${NC} ${GRAY}- :ConformanceTests: should use pytest.${NC} ${GRAY}│${NC}"
|
|
105
103
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
106
|
-
echo -e "${GRAY} │${NC} ${GRAY}***functional specs***${NC}
|
|
104
|
+
echo -e "${GRAY} │${NC} ${GRAY}***functional specs***${NC} ${GRAY}│${NC}"
|
|
107
105
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
108
|
-
echo -e "${GRAY} │${NC} ${GRAY}- :App: should display \"hello, world\".${NC}
|
|
106
|
+
echo -e "${GRAY} │${NC} ${GRAY}- :App: should display \"hello, world\".${NC} ${GRAY}│${NC}"
|
|
109
107
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
110
108
|
echo -e "${GRAY} └────────────────────────────────────────────────────────┘${NC}"
|
|
111
109
|
echo ""
|
|
112
|
-
echo -e " ${GREEN}▲${NC} The ${YELLOW}:App:${NC} concept is defined once and used throughout."
|
|
110
|
+
echo -e " ${GREEN}▲${NC} The ${YELLOW}:App:${NC} concept is defined once and used throughout the specs."
|
|
113
111
|
echo -e " Concepts help keep your specs consistent and clear."
|
|
114
112
|
echo ""
|
|
115
113
|
read -r -p " press [Enter] to continue..." < /dev/tty
|
|
@@ -117,9 +115,9 @@ read -r -p " press [Enter] to continue..." < /dev/tty
|
|
|
117
115
|
# Onboarding Step 4: Implementation & Test Reqs
|
|
118
116
|
clear
|
|
119
117
|
echo ""
|
|
120
|
-
echo -e "${GRAY}
|
|
121
|
-
echo -e " ${YELLOW}${BOLD}
|
|
122
|
-
echo -e "${GRAY}
|
|
118
|
+
echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
|
|
119
|
+
echo -e " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 4 of 5"
|
|
120
|
+
echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
|
|
123
121
|
echo ""
|
|
124
122
|
echo -e " ${WHITE}${BOLD}IMPLEMENTATION & TEST REQS${NC} - how to implement and test"
|
|
125
123
|
echo ""
|
|
@@ -128,22 +126,21 @@ echo -e " This guides how the code should be generated and verified."
|
|
|
128
126
|
echo ""
|
|
129
127
|
echo -e "${GRAY} ┌────────────────────────────────────────────────────────┐${NC}"
|
|
130
128
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
131
|
-
echo -e "${GRAY} │${NC} ${GRAY}***definitions***${NC}
|
|
129
|
+
echo -e "${GRAY} │${NC} ${GRAY}***definitions***${NC} ${GRAY}│${NC}"
|
|
132
130
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
133
|
-
echo -e "${GRAY} │${NC} ${GRAY}- :App: is a console application.${NC}
|
|
131
|
+
echo -e "${GRAY} │${NC} ${GRAY}- :App: is a console application.${NC} ${GRAY}│${NC}"
|
|
134
132
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
135
|
-
echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***implementation reqs***${NC}
|
|
133
|
+
echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***implementation reqs***${NC} ${GRAY}│${NC}"
|
|
136
134
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
137
|
-
echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :Implementation: should be in Python.${NC}
|
|
138
|
-
echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :UnitTests: should use Unittest framework.${NC} ${GRAY}│${NC}"
|
|
135
|
+
echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :Implementation: should be in Python.${NC} ${GRAY}│${NC}"
|
|
139
136
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
140
|
-
echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***test reqs***${NC}
|
|
137
|
+
echo -e "${GRAY} │${NC} ${YELLOW}${BOLD}***test reqs***${NC} ${GRAY}│${NC}"
|
|
141
138
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
142
|
-
echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :ConformanceTests: should use
|
|
139
|
+
echo -e "${GRAY} │${NC} ${GREEN}${BOLD}- :ConformanceTests: should use pytest.${NC} ${GRAY}│${NC}"
|
|
143
140
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
144
|
-
echo -e "${GRAY} │${NC} ${GRAY}***functional specs***${NC}
|
|
141
|
+
echo -e "${GRAY} │${NC} ${GRAY}***functional specs***${NC} ${GRAY}│${NC}"
|
|
145
142
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
146
|
-
echo -e "${GRAY} │${NC} ${GRAY}- :App: should display \"hello, world\".${NC}
|
|
143
|
+
echo -e "${GRAY} │${NC} ${GRAY}- :App: should display \"hello, world\".${NC} ${GRAY}│${NC}"
|
|
147
144
|
echo -e "${GRAY} │${NC} ${GRAY}│${NC}"
|
|
148
145
|
echo -e "${GRAY} └────────────────────────────────────────────────────────┘${NC}"
|
|
149
146
|
echo ""
|
|
@@ -155,9 +152,9 @@ read -r -p " press [Enter] to continue..." < /dev/tty
|
|
|
155
152
|
# Onboarding Step 5: Rendering Code
|
|
156
153
|
clear
|
|
157
154
|
echo ""
|
|
158
|
-
echo -e "${GRAY}
|
|
159
|
-
echo -e " ${YELLOW}${BOLD}
|
|
160
|
-
echo -e "${GRAY}
|
|
155
|
+
echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
|
|
156
|
+
echo -e " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 5 of 5"
|
|
157
|
+
echo -e "${GRAY}─────────────────────────────────────────────────────────${NC}"
|
|
161
158
|
echo ""
|
|
162
159
|
echo -e " ${WHITE}${BOLD}RENDERING CODE${NC} - generate your app"
|
|
163
160
|
echo ""
|
|
@@ -260,4 +260,6 @@ class ModuleRenderer:
|
|
|
260
260
|
self.loaded_modules = list[PlainModule]()
|
|
261
261
|
_, _, rendering_failed = self._render_module(self.filename, self.render_range, True)
|
|
262
262
|
if not rendering_failed:
|
|
263
|
-
|
|
263
|
+
# Get the last module that completed rendering
|
|
264
|
+
last_module_name = self.loaded_modules[-1].name if self.loaded_modules else ""
|
|
265
|
+
self.event_bus.publish(RenderCompleted(module_name=last_module_name, build_folder=self.args.build_folder))
|
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
import logging.config
|
|
4
4
|
import os
|
|
5
5
|
import sys
|
|
6
|
+
from pathlib import Path
|
|
6
7
|
from typing import Optional
|
|
7
8
|
|
|
8
9
|
import yaml
|
|
@@ -20,6 +21,7 @@ from plain2code_console import console
|
|
|
20
21
|
from plain2code_exceptions import (
|
|
21
22
|
ConflictingRequirements,
|
|
22
23
|
CreditBalanceTooLow,
|
|
24
|
+
InternalClientError,
|
|
23
25
|
InternalServerError,
|
|
24
26
|
InvalidAPIKey,
|
|
25
27
|
InvalidFridArgument,
|
|
@@ -27,9 +29,10 @@ from plain2code_exceptions import (
|
|
|
27
29
|
MissingAPIKey,
|
|
28
30
|
MissingPreviousFunctionalitiesError,
|
|
29
31
|
MissingResource,
|
|
32
|
+
ModuleDoesNotExistError,
|
|
33
|
+
NetworkConnectionError,
|
|
30
34
|
OutdatedClientVersion,
|
|
31
35
|
PlainSyntaxError,
|
|
32
|
-
UnexpectedState,
|
|
33
36
|
)
|
|
34
37
|
from plain2code_logger import (
|
|
35
38
|
CrashLogHandler,
|
|
@@ -40,6 +43,7 @@ from plain2code_logger import (
|
|
|
40
43
|
get_log_file_path,
|
|
41
44
|
)
|
|
42
45
|
from plain2code_state import RunState
|
|
46
|
+
from plain2code_utils import print_dry_run_output
|
|
43
47
|
from system_config import system_config
|
|
44
48
|
from tui.plain2code_tui import Plain2CodeTUI
|
|
45
49
|
|
|
@@ -70,6 +74,23 @@ def get_render_range_from(start, plain_source):
|
|
|
70
74
|
return _get_frids_range(plain_source, start)
|
|
71
75
|
|
|
72
76
|
|
|
77
|
+
def compute_render_range(args, plain_source_tree):
|
|
78
|
+
"""Compute render range from --render-range or --render-from arguments.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
args: Parsed command line arguments
|
|
82
|
+
plain_source_tree: Parsed plain source tree
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
List of FRIDs to render, or None to render all
|
|
86
|
+
"""
|
|
87
|
+
if args.render_range:
|
|
88
|
+
return get_render_range(args.render_range, plain_source_tree)
|
|
89
|
+
elif args.render_from:
|
|
90
|
+
return get_render_range_from(args.render_from, plain_source_tree)
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
|
|
73
94
|
def _get_frids_range(plain_source, start, end=None):
|
|
74
95
|
frids = list(plain_spec.get_frids(plain_source))
|
|
75
96
|
|
|
@@ -165,7 +186,7 @@ def setup_logging(
|
|
|
165
186
|
root_logger.info(f"Render ID: {render_id}") # Ensure render ID is logged in to codeplain.log file
|
|
166
187
|
|
|
167
188
|
|
|
168
|
-
def _check_connection(codeplainAPI):
|
|
189
|
+
def _check_connection(codeplainAPI: codeplain_api.CodeplainAPI):
|
|
169
190
|
"""Check API connectivity and validate API key and client version."""
|
|
170
191
|
response = codeplainAPI.connection_check(system_config.client_version)
|
|
171
192
|
|
|
@@ -184,7 +205,7 @@ def _check_connection(codeplainAPI):
|
|
|
184
205
|
)
|
|
185
206
|
|
|
186
207
|
|
|
187
|
-
def render(args, run_state: RunState,
|
|
208
|
+
def render(args, run_state: RunState, event_bus: EventBus): # noqa: C901
|
|
188
209
|
template_dirs = file_utils.get_template_directories(args.filename, args.template_dir, DEFAULT_TEMPLATE_DIRS)
|
|
189
210
|
|
|
190
211
|
console.info(f"Rendering {args.filename} to target code.")
|
|
@@ -194,11 +215,7 @@ def render(args, run_state: RunState, codeplain_api, event_bus: EventBus): # no
|
|
|
194
215
|
if args.render_range or args.render_from:
|
|
195
216
|
# Parse the plain file to get the plain_source for FRID extraction
|
|
196
217
|
_, plain_source, _ = plain_file.plain_file_parser(args.filename, template_dirs)
|
|
197
|
-
|
|
198
|
-
if args.render_range:
|
|
199
|
-
render_range = get_render_range(args.render_range, plain_source)
|
|
200
|
-
elif args.render_from:
|
|
201
|
-
render_range = get_render_range_from(args.render_from, plain_source)
|
|
218
|
+
render_range = compute_render_range(args, plain_source)
|
|
202
219
|
|
|
203
220
|
codeplainAPI = codeplain_api.CodeplainAPI(args.api_key, console)
|
|
204
221
|
codeplainAPI.verbose = args.verbose
|
|
@@ -240,6 +257,29 @@ def render(args, run_state: RunState, codeplain_api, event_bus: EventBus): # no
|
|
|
240
257
|
def main(): # noqa: C901
|
|
241
258
|
args = parse_arguments()
|
|
242
259
|
|
|
260
|
+
# Handle early-exit flags before heavy initialization
|
|
261
|
+
if args.dry_run or args.full_plain:
|
|
262
|
+
template_dirs = file_utils.get_template_directories(args.filename, args.template_dir, DEFAULT_TEMPLATE_DIRS)
|
|
263
|
+
|
|
264
|
+
try:
|
|
265
|
+
if args.full_plain:
|
|
266
|
+
module_name = Path(args.filename).stem
|
|
267
|
+
plain_source = plain_file.read_module_plain_source(module_name, template_dirs)
|
|
268
|
+
[full_plain_source, _] = file_utils.get_loaded_templates(template_dirs, plain_source)
|
|
269
|
+
console.info("Full plain text:\n")
|
|
270
|
+
console.info(full_plain_source)
|
|
271
|
+
return
|
|
272
|
+
|
|
273
|
+
if args.dry_run:
|
|
274
|
+
console.info("Printing dry run output...\n")
|
|
275
|
+
_, plain_source_tree, _ = plain_file.plain_file_parser(args.filename, template_dirs)
|
|
276
|
+
render_range = compute_render_range(args, plain_source_tree)
|
|
277
|
+
print_dry_run_output(plain_source_tree, render_range)
|
|
278
|
+
return
|
|
279
|
+
except Exception as e:
|
|
280
|
+
console.error(f"Error: {str(e)}")
|
|
281
|
+
return
|
|
282
|
+
|
|
243
283
|
event_bus = EventBus()
|
|
244
284
|
|
|
245
285
|
if not args.api:
|
|
@@ -258,7 +298,7 @@ def main(): # noqa: C901
|
|
|
258
298
|
)
|
|
259
299
|
|
|
260
300
|
console.debug(f"Render ID: {run_state.render_id}") # Ensure render ID is logged to the console
|
|
261
|
-
render(args, run_state,
|
|
301
|
+
render(args, run_state, event_bus)
|
|
262
302
|
except InvalidFridArgument as e:
|
|
263
303
|
exc_info = sys.exc_info()
|
|
264
304
|
console.error(f"Invalid FRID argument: {str(e)}.\n")
|
|
@@ -291,7 +331,7 @@ def main(): # noqa: C901
|
|
|
291
331
|
console.error(f"Invalid API key: {str(e)}\n")
|
|
292
332
|
except OutdatedClientVersion as e:
|
|
293
333
|
console.error(f"Outdated client version: {str(e)}\n")
|
|
294
|
-
except (InternalServerError,
|
|
334
|
+
except (InternalServerError, InternalClientError):
|
|
295
335
|
exc_info = sys.exc_info()
|
|
296
336
|
console.error(
|
|
297
337
|
f"Internal server error.\n\nPlease report the error to support@codeplain.ai with the attached {args.log_file_name} file."
|
|
@@ -313,6 +353,14 @@ def main(): # noqa: C901
|
|
|
313
353
|
exc_info = sys.exc_info()
|
|
314
354
|
console.error(f"Missing resource: {str(e)}\n")
|
|
315
355
|
console.debug(f"Render ID: {run_state.render_id}")
|
|
356
|
+
except NetworkConnectionError as e:
|
|
357
|
+
exc_info = sys.exc_info()
|
|
358
|
+
console.error(f"Connection error: {str(e)}\n")
|
|
359
|
+
console.error("Please check that your internet connection is working.")
|
|
360
|
+
except ModuleDoesNotExistError as e:
|
|
361
|
+
exc_info = sys.exc_info()
|
|
362
|
+
console.error(f"Module does not exist: {str(e)}\n")
|
|
363
|
+
console.debug(f"Render ID: {run_state.render_id}")
|
|
316
364
|
except Exception as e:
|
|
317
365
|
exc_info = sys.exc_info()
|
|
318
366
|
console.error(f"Error rendering plain code: {str(e)}\n")
|