codeplain 0.3.11.dev10__tar.gz → 0.3.11.dev12__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.3.11.dev10 → codeplain-0.3.11.dev12}/PKG-INFO +1 -1
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/codeplain_REST_api.py +5 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/fix_conformance_test.py +11 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/fix_unit_tests.py +25 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/render_types.py +5 -0
- codeplain-0.3.11.dev12/tests/test_fix_unit_tests_conformance_context.py +230 -0
- codeplain-0.3.11.dev12/tests/test_tui_components.py +88 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tui/components.py +13 -9
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tui/widget_helpers.py +11 -4
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.claude/settings.json +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.flake8 +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.github/dependabot.yml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.github/workflows/e2e.yml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.github/workflows/lint-and-test.yml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.github/workflows/lint-powershell.yml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.github/workflows/nofity-slack-on-main-merge.yml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.github/workflows/publish-dev-to-pypi.yml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.github/workflows/publish-install-script.yml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.github/workflows/publish-to-pypi.yml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.gitignore +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.vscode/launch.json +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.vscode/settings.json +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/CLAUDE.md +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/CONTRIBUTING.md +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/LICENSE +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/README.md +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/change_detection.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/cli_output/__init__.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/cli_output/dry_run.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/cli_output/render_summary.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/cli_output/status.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/concept_utils.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/config/__init__.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/config/system_config.yaml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/conformance_fix_journal.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/diff_utils.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/docs/generate_cli.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/docs/plain2code_cli.md +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/docs/starting_a_plain_project_from_scratch.md +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/event_bus.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_golang/config.yaml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_golang/run.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_python/config.yaml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_python/hello_world_python.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_python/run.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_react/config.yaml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_react/hello_world_react.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_react/run.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/run.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/file_utils.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/git_utils.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/install/bash/examples.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/install/bash/install.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/install/bash/walkthrough.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/install/powershell/examples.ps1 +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/install/powershell/install.ps1 +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/install/powershell/walkthrough.ps1 +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/memory_management.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/metadata_utils.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/module_renderer.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/partial_rendering.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/path_resolution.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain2code.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain2code_arguments.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain2code_cli.md +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain2code_console.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain2code_events.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain2code_exceptions.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain2code_logger.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain2code_nodes.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain2code_read_config.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain2code_state.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain2code_telemetry.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain2code_utils.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain_file.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain_modules.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/plain_spec.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/pyproject.toml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/pytest.ini +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/__init__.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/analyze_specification_ambiguity.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/base_action.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/commit_implementation_code_changes.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/create_dist.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/distill_conformance_test_memory.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/exit_with_error.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/finish_functional_requirement.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/prepare_repositories.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/prepare_testing_environment.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/refactor_code.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/render_conformance_tests.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/render_functional_requirement.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/run_conformance_tests.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/run_unit_tests.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/summarize_conformance_tests.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/code_renderer.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/conformance_tests.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/implementation_code_helpers.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/render_context.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/render_utils.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/state_machine_config.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/states.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/triggers.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/requirements.txt +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/resources/codeplain_overview.png +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/resources/plain_example.png +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/standard_template_library/golang-console-app-template.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/standard_template_library/python-console-app-template.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/standard_template_library/typescript-react-app-template.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/system_config.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_conformance_tests_cypress.ps1 +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_conformance_tests_cypress.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_conformance_tests_golang.ps1 +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_conformance_tests_golang.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_conformance_tests_python.ps1 +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_conformance_tests_python.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_unittests_flutter.ps1 +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_unittests_flutter.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_unittests_golang.ps1 +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_unittests_golang.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_unittests_python.ps1 +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_unittests_python.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_unittests_react.ps1 +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/test_scripts/run_unittests_react.sh +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/__init__.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/conftest.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/acceptance_tests_warning/main_requiring_acceptance_tests.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/acceptance_tests_warning/required_with_acceptance_tests.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/imports/circular_imports_1.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/imports/circular_imports_2.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/imports/circular_imports_main.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/imports/diamond_import_1.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/imports/diamond_import_2.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/imports/diamond_import_common.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/imports/diamond_imports_main.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/imports/import_with_functionalities.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/imports/imports_module_with_functionalities.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/imports/non_existent_import.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/partial_rendering/pr_code_var.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/partial_rendering/pr_implement.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/partial_rendering/pr_leaf.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/partial_rendering/pr_middle.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/partial_rendering/pr_root.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/partial_rendering/pr_solo.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfile/add_new_task_modal_specification.yaml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfile/empty_functional_specs_section.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfile/invalid_specification_order.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfile/no_functional_specs_section.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfile/task_list_ui_specification.yaml +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/exported_concepts.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/exported_concepts_missing.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/exported_concepts_missing_example.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/required_concepts.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/topological_sort.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/circular_requires_main.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/circular_requires_sub.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/diamond_requires_1.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/diamond_requires_2.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/diamond_requires_common.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/diamond_requires_main.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/independent_requires_1.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/independent_requires_2.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/independent_requires_main.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/non_existent_require.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/normal_requires_1.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/normal_requires_2.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/normal_requires_common.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/requires/normal_requires_main.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/sample_base64_image.txt +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/simple.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/templates/block_level_include.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/templates/code_variables.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/templates/header.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/templates/implement.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/templates/implement_2.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/templates/template_include.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/data/templates/test_hardest_problem.plain +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/e2e/Dockerfile +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/e2e/conftest.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/e2e/test_hello_world_python.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/e2e/test_hello_world_python_windows.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_arg_provenance.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_change_detection.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_cli_output.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_conformance_fix_journal.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_console_log_styles.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_distill_conformance_test_memory.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_dry_run_link_validation.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_file_utils.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_folder_path_resolution.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_git_utils.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_headless_logging.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_imports.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_log_file_name_resolution.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_logging_config_path_resolution.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_partial_rendering.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_path_resolution.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_plain2code.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_plain2code_state.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_plain2code_utils.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_plain_modules.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_plainfile.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_plainfileparser.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_plainspec.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_prepare_repositories_layout.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_requires.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_resolve_config_file.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_script_path_resolution.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_system_config.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_telemetry.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_tui_usage.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tests/test_usage_summary.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tui/__init__.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tui/models.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tui/plain2code_tui.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tui/plain_module_render_choice_tui.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tui/spinner.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tui/state_handlers.py +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/tui/styles.css +0 -0
- {codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/usage_summary.py +0 -0
|
@@ -237,6 +237,7 @@ class CodeplainAPI:
|
|
|
237
237
|
required_modules,
|
|
238
238
|
unittests_issue,
|
|
239
239
|
run_state: RunState,
|
|
240
|
+
conformance_tests_fixes: list[dict] | None = None,
|
|
240
241
|
):
|
|
241
242
|
endpoint_url = f"{self.api_url}/fix_unittests_issue"
|
|
242
243
|
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
@@ -251,6 +252,10 @@ class CodeplainAPI:
|
|
|
251
252
|
"unittests_issue": unittests_issue,
|
|
252
253
|
"unittest_batch_id": run_state.unittest_batch_id,
|
|
253
254
|
}
|
|
255
|
+
# Implementation code changes made by the conformance tests fixer right before this unit tests run;
|
|
256
|
+
# only sent when unit tests are processed inside the conformance tests phase.
|
|
257
|
+
if conformance_tests_fixes is not None:
|
|
258
|
+
payload["conformance_tests_fixes"] = conformance_tests_fixes
|
|
254
259
|
|
|
255
260
|
return self.post_request(endpoint_url, headers, payload, run_state)
|
|
256
261
|
|
{codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/render_machine/actions/fix_conformance_test.py
RENAMED
|
@@ -189,6 +189,17 @@ class FixConformanceTest(BaseAction):
|
|
|
189
189
|
ctx.test_that_triggered_code_change = (ctx.current_testing_module_name, ctx.current_testing_frid)
|
|
190
190
|
ctx.execution_phase = TestExecutionPhase.RETRYING_AFTER_CODE_CHANGE
|
|
191
191
|
|
|
192
|
+
# Remember the change so that the unit tests fixer (which runs next) preserves it instead of
|
|
193
|
+
# reverting it - see FixUnitTests.
|
|
194
|
+
summary = fix_attempt_summary if isinstance(fix_attempt_summary, dict) else {}
|
|
195
|
+
ctx.implementation_code_fixes.append(
|
|
196
|
+
{
|
|
197
|
+
"hypothesis": summary.get("hypothesis"),
|
|
198
|
+
"approach": summary.get("approach"),
|
|
199
|
+
"code_diff": code_diff_files_content,
|
|
200
|
+
}
|
|
201
|
+
)
|
|
202
|
+
|
|
192
203
|
journal.record_fix(
|
|
193
204
|
ctx.current_testing_module_name,
|
|
194
205
|
ctx.current_testing_frid,
|
|
@@ -32,6 +32,13 @@ class FixUnitTests(BaseAction):
|
|
|
32
32
|
|
|
33
33
|
render_utils.print_inputs(render_context, existing_files_content, "Files sent as input to unit tests fixing:")
|
|
34
34
|
|
|
35
|
+
conformance_tests_fixes = self._get_conformance_tests_fixes(render_context)
|
|
36
|
+
if conformance_tests_fixes:
|
|
37
|
+
console.info(
|
|
38
|
+
f"Unit tests are fixed while preserving {len(conformance_tests_fixes)} implementation code change(s) "
|
|
39
|
+
"made to fix the conformance tests."
|
|
40
|
+
)
|
|
41
|
+
|
|
35
42
|
response_files = render_context.codeplain_api.fix_unittests_issue(
|
|
36
43
|
render_context.frid_context.frid,
|
|
37
44
|
render_context.plain_source_tree,
|
|
@@ -41,6 +48,7 @@ class FixUnitTests(BaseAction):
|
|
|
41
48
|
render_context.get_required_modules_functionalities(),
|
|
42
49
|
previous_unittests_issue,
|
|
43
50
|
run_state=render_context.run_state,
|
|
51
|
+
conformance_tests_fixes=conformance_tests_fixes,
|
|
44
52
|
)
|
|
45
53
|
|
|
46
54
|
_, changed_files = file_utils.update_build_folder_with_rendered_files(
|
|
@@ -52,3 +60,20 @@ class FixUnitTests(BaseAction):
|
|
|
52
60
|
console.print_files("Files fixed:", render_context.build_folder, response_files, style=console.OUTPUT_STYLE)
|
|
53
61
|
|
|
54
62
|
return self.SUCCESSFUL_OUTCOME, None
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
def _get_conformance_tests_fixes(render_context: RenderContext) -> list[dict] | None:
|
|
66
|
+
"""Implementation code changes the conformance tests fixer made before these unit tests were run.
|
|
67
|
+
|
|
68
|
+
Only present when unit tests are processed inside the conformance tests phase - the implementation
|
|
69
|
+
and refactoring unit test passes have no conformance tests running context.
|
|
70
|
+
"""
|
|
71
|
+
conformance_tests_running_context = getattr(render_context, "conformance_tests_running_context", None)
|
|
72
|
+
if conformance_tests_running_context is None:
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
implementation_code_fixes = getattr(conformance_tests_running_context, "implementation_code_fixes", None)
|
|
76
|
+
if not implementation_code_fixes:
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
return list(implementation_code_fixes)
|
|
@@ -91,6 +91,11 @@ class ConformanceTestsRunningContext:
|
|
|
91
91
|
|
|
92
92
|
self.current_testing_frid_high_level_implementation_plan: Optional[str] = None
|
|
93
93
|
|
|
94
|
+
# Implementation code changes made by the conformance tests fixer during this conformance phase, in
|
|
95
|
+
# order. Each entry is {"hypothesis": str | None, "approach": str | None, "code_diff": {file: diff}}.
|
|
96
|
+
# Handed to the unit tests fixer so it adjusts the unit tests instead of reverting these changes.
|
|
97
|
+
self.implementation_code_fixes: list[dict] = []
|
|
98
|
+
|
|
94
99
|
def get_conformance_tests_json(self, module_name: str) -> dict:
|
|
95
100
|
return self._conformance_tests_json[module_name]
|
|
96
101
|
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"""Tests for handing the conformance tests fixer's implementation changes to the unit tests fixer.
|
|
2
|
+
|
|
3
|
+
When the conformance tests fixer changes implementation code, the unit tests are re-run and fixed next.
|
|
4
|
+
The unit tests fixer must know about that change so it adjusts the unit tests instead of reverting it.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import tempfile
|
|
9
|
+
from types import SimpleNamespace
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
import plain_spec
|
|
14
|
+
from memory_management import MemoryManager
|
|
15
|
+
from render_machine.actions import fix_unit_tests as fix_unit_tests_module
|
|
16
|
+
from render_machine.actions.fix_conformance_test import FixConformanceTest
|
|
17
|
+
from render_machine.actions.fix_unit_tests import FixUnitTests
|
|
18
|
+
from render_machine.implementation_code_helpers import ImplementationCodeHelpers
|
|
19
|
+
from render_machine.render_types import ConformanceTestsRunningContext, UnitTestsRunningContext
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class FakeCodeplainAPI:
|
|
23
|
+
def __init__(self, conformance_fix_response=None, unittests_fix_response=None):
|
|
24
|
+
self.conformance_fix_response = conformance_fix_response
|
|
25
|
+
self.unittests_fix_response = unittests_fix_response or {}
|
|
26
|
+
self.unittests_fix_calls = []
|
|
27
|
+
|
|
28
|
+
def fix_conformance_tests_issue(self, *args, **kwargs):
|
|
29
|
+
return self.conformance_fix_response
|
|
30
|
+
|
|
31
|
+
def fix_unittests_issue(self, *args, **kwargs):
|
|
32
|
+
self.unittests_fix_calls.append(kwargs)
|
|
33
|
+
return self.unittests_fix_response
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class FakeConformanceTests:
|
|
37
|
+
def fetch_existing_conformance_test_files(self, *args):
|
|
38
|
+
return {}, {}
|
|
39
|
+
|
|
40
|
+
def store_conformance_tests_files(self, *args):
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@pytest.fixture
|
|
45
|
+
def build_folder():
|
|
46
|
+
with tempfile.TemporaryDirectory() as folder:
|
|
47
|
+
with open(os.path.join(folder, "app.py"), "w", encoding="utf-8") as source_file:
|
|
48
|
+
source_file.write("def add(a, b):\n return a + b\n")
|
|
49
|
+
yield folder
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@pytest.fixture
|
|
53
|
+
def memory_folder():
|
|
54
|
+
with tempfile.TemporaryDirectory() as folder:
|
|
55
|
+
yield folder
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@pytest.fixture(autouse=True)
|
|
59
|
+
def isolate_from_git_and_console(monkeypatch):
|
|
60
|
+
monkeypatch.setattr(ImplementationCodeHelpers, "get_code_diff", staticmethod(lambda *args: {}))
|
|
61
|
+
monkeypatch.setattr(plain_spec, "collect_linked_resources", lambda *args: None)
|
|
62
|
+
monkeypatch.setattr(fix_unit_tests_module.render_utils, "print_inputs", lambda *args: None)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def make_conformance_context():
|
|
66
|
+
return ConformanceTestsRunningContext(
|
|
67
|
+
current_testing_module_name="mod",
|
|
68
|
+
current_testing_frid="1",
|
|
69
|
+
fix_attempts=0,
|
|
70
|
+
conformance_tests_json={"1": {"folder_name": "conformance_1"}},
|
|
71
|
+
conformance_tests_render_attempts=0,
|
|
72
|
+
current_testing_frid_specifications={},
|
|
73
|
+
should_prepare_testing_environment=False,
|
|
74
|
+
frid_being_implemented="1",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def make_render_context(api, build_folder, memory_folder, conformance_tests_running_context):
|
|
79
|
+
return SimpleNamespace(
|
|
80
|
+
codeplain_api=api,
|
|
81
|
+
build_folder=build_folder,
|
|
82
|
+
memory_manager=MemoryManager(api, memory_folder),
|
|
83
|
+
conformance_tests=FakeConformanceTests(),
|
|
84
|
+
conformance_tests_running_context=conformance_tests_running_context,
|
|
85
|
+
unit_tests_running_context=UnitTestsRunningContext(fix_attempts=1),
|
|
86
|
+
plain_source_tree={},
|
|
87
|
+
module_name="mod",
|
|
88
|
+
required_modules=None,
|
|
89
|
+
frid_context=SimpleNamespace(frid="1", linked_resources={}),
|
|
90
|
+
get_required_modules_functionalities=lambda: {},
|
|
91
|
+
run_state=SimpleNamespace(render_id="test-render-id", unittest_batch_id=1),
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def run_conformance_fix(render_context):
|
|
96
|
+
return FixConformanceTest().execute(render_context, {"previous_conformance_tests_issue": "tests failed"})
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_conformance_fix_of_implementation_code_is_remembered(build_folder, memory_folder):
|
|
100
|
+
api = FakeCodeplainAPI(
|
|
101
|
+
conformance_fix_response=[
|
|
102
|
+
FixConformanceTest.ISSUE_REASON_CODE_IMPLEMENTATION_CODE,
|
|
103
|
+
{"app.py": "def add(a, b):\n return a + b + 1\n"},
|
|
104
|
+
{"hypothesis": "off by one", "approach": "add one"},
|
|
105
|
+
"prepared issue",
|
|
106
|
+
]
|
|
107
|
+
)
|
|
108
|
+
ctx = make_conformance_context()
|
|
109
|
+
render_context = make_render_context(api, build_folder, memory_folder, ctx)
|
|
110
|
+
|
|
111
|
+
outcome, _ = run_conformance_fix(render_context)
|
|
112
|
+
|
|
113
|
+
assert outcome == FixConformanceTest.IMPLEMENTATION_CODE_UPDATED
|
|
114
|
+
assert len(ctx.implementation_code_fixes) == 1
|
|
115
|
+
recorded_fix = ctx.implementation_code_fixes[0]
|
|
116
|
+
assert recorded_fix["hypothesis"] == "off by one"
|
|
117
|
+
assert recorded_fix["approach"] == "add one"
|
|
118
|
+
assert list(recorded_fix["code_diff"]) == ["app.py"]
|
|
119
|
+
assert "+ return a + b + 1" in recorded_fix["code_diff"]["app.py"]
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_consecutive_implementation_fixes_accumulate(build_folder, memory_folder):
|
|
123
|
+
ctx = make_conformance_context()
|
|
124
|
+
for attempt in range(2):
|
|
125
|
+
api = FakeCodeplainAPI(
|
|
126
|
+
conformance_fix_response=[
|
|
127
|
+
FixConformanceTest.ISSUE_REASON_CODE_IMPLEMENTATION_CODE,
|
|
128
|
+
{"app.py": f"def add(a, b):\n return a + b + {attempt + 1}\n"},
|
|
129
|
+
{"hypothesis": f"hypothesis {attempt}", "approach": f"approach {attempt}"},
|
|
130
|
+
"prepared issue",
|
|
131
|
+
]
|
|
132
|
+
)
|
|
133
|
+
render_context = make_render_context(api, build_folder, memory_folder, ctx)
|
|
134
|
+
run_conformance_fix(render_context)
|
|
135
|
+
|
|
136
|
+
assert [fix["hypothesis"] for fix in ctx.implementation_code_fixes] == ["hypothesis 0", "hypothesis 1"]
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def test_conformance_fix_without_summary_is_still_remembered(build_folder, memory_folder):
|
|
140
|
+
api = FakeCodeplainAPI(
|
|
141
|
+
conformance_fix_response=[
|
|
142
|
+
FixConformanceTest.ISSUE_REASON_CODE_IMPLEMENTATION_CODE,
|
|
143
|
+
{"app.py": "def add(a, b):\n return a + b + 1\n"},
|
|
144
|
+
None,
|
|
145
|
+
"prepared issue",
|
|
146
|
+
]
|
|
147
|
+
)
|
|
148
|
+
ctx = make_conformance_context()
|
|
149
|
+
render_context = make_render_context(api, build_folder, memory_folder, ctx)
|
|
150
|
+
|
|
151
|
+
run_conformance_fix(render_context)
|
|
152
|
+
|
|
153
|
+
assert ctx.implementation_code_fixes[0]["hypothesis"] is None
|
|
154
|
+
assert ctx.implementation_code_fixes[0]["approach"] is None
|
|
155
|
+
assert "app.py" in ctx.implementation_code_fixes[0]["code_diff"]
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def test_conformance_fix_of_conformance_tests_is_not_remembered(build_folder, memory_folder):
|
|
159
|
+
api = FakeCodeplainAPI(
|
|
160
|
+
conformance_fix_response=[
|
|
161
|
+
FixConformanceTest.ISSUE_REASON_CODE_CONFORMANCE_TESTS,
|
|
162
|
+
{"test_app.py": "def test_add(): pass\n"},
|
|
163
|
+
{"hypothesis": "wrong assertion", "approach": "fix test"},
|
|
164
|
+
"prepared issue",
|
|
165
|
+
]
|
|
166
|
+
)
|
|
167
|
+
ctx = make_conformance_context()
|
|
168
|
+
render_context = make_render_context(api, build_folder, memory_folder, ctx)
|
|
169
|
+
|
|
170
|
+
outcome, _ = run_conformance_fix(render_context)
|
|
171
|
+
|
|
172
|
+
assert outcome == FixConformanceTest.IMPLEMENTATION_CODE_NOT_UPDATED
|
|
173
|
+
assert ctx.implementation_code_fixes == []
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def test_implementation_fix_with_no_files_is_not_remembered(build_folder, memory_folder):
|
|
177
|
+
api = FakeCodeplainAPI(
|
|
178
|
+
conformance_fix_response=[
|
|
179
|
+
FixConformanceTest.ISSUE_REASON_CODE_IMPLEMENTATION_CODE,
|
|
180
|
+
{},
|
|
181
|
+
{"hypothesis": "nothing", "approach": "nothing"},
|
|
182
|
+
"prepared issue",
|
|
183
|
+
]
|
|
184
|
+
)
|
|
185
|
+
ctx = make_conformance_context()
|
|
186
|
+
render_context = make_render_context(api, build_folder, memory_folder, ctx)
|
|
187
|
+
|
|
188
|
+
outcome, _ = run_conformance_fix(render_context)
|
|
189
|
+
|
|
190
|
+
assert outcome == FixConformanceTest.IMPLEMENTATION_CODE_NOT_UPDATED
|
|
191
|
+
assert ctx.implementation_code_fixes == []
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def run_unit_tests_fix(render_context):
|
|
195
|
+
return FixUnitTests().execute(render_context, {"previous_unittests_issue": "1 failed"})
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def test_unit_tests_fix_forwards_conformance_fixes(build_folder, memory_folder):
|
|
199
|
+
api = FakeCodeplainAPI(unittests_fix_response={"test_app.py": "def test_add(): pass\n"})
|
|
200
|
+
ctx = make_conformance_context()
|
|
201
|
+
ctx.implementation_code_fixes.append(
|
|
202
|
+
{"hypothesis": "off by one", "approach": "add one", "code_diff": {"app.py": "+ return a + b + 1"}}
|
|
203
|
+
)
|
|
204
|
+
render_context = make_render_context(api, build_folder, memory_folder, ctx)
|
|
205
|
+
|
|
206
|
+
outcome, _ = run_unit_tests_fix(render_context)
|
|
207
|
+
|
|
208
|
+
assert outcome == FixUnitTests.SUCCESSFUL_OUTCOME
|
|
209
|
+
assert len(api.unittests_fix_calls) == 1
|
|
210
|
+
assert api.unittests_fix_calls[0]["conformance_tests_fixes"] == ctx.implementation_code_fixes
|
|
211
|
+
# The forwarded list is a copy, so later conformance fixes do not mutate what was sent.
|
|
212
|
+
assert api.unittests_fix_calls[0]["conformance_tests_fixes"] is not ctx.implementation_code_fixes
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def test_unit_tests_fix_outside_conformance_phase_sends_no_fixes(build_folder, memory_folder):
|
|
216
|
+
api = FakeCodeplainAPI()
|
|
217
|
+
render_context = make_render_context(api, build_folder, memory_folder, None)
|
|
218
|
+
|
|
219
|
+
run_unit_tests_fix(render_context)
|
|
220
|
+
|
|
221
|
+
assert api.unittests_fix_calls[0]["conformance_tests_fixes"] is None
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def test_unit_tests_fix_in_conformance_phase_without_implementation_changes_sends_no_fixes(build_folder, memory_folder):
|
|
225
|
+
api = FakeCodeplainAPI()
|
|
226
|
+
render_context = make_render_context(api, build_folder, memory_folder, make_conformance_context())
|
|
227
|
+
|
|
228
|
+
run_unit_tests_fix(render_context)
|
|
229
|
+
|
|
230
|
+
assert api.unittests_fix_calls[0]["conformance_tests_fixes"] is None
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Regression tests: spec-derived text with square brackets must never be parsed as Textual markup."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
|
|
5
|
+
from textual.widgets import Static
|
|
6
|
+
|
|
7
|
+
from event_bus import EventBus
|
|
8
|
+
from plain2code_state import RunState
|
|
9
|
+
from tui.components import ProgressItem, SubstateLine, TUIComponents
|
|
10
|
+
from tui.models import Substate
|
|
11
|
+
from tui.plain2code_tui import Plain2CodeTUI
|
|
12
|
+
from tui.widget_helpers import display_error_message, display_success_message, update_progress_item_substates
|
|
13
|
+
|
|
14
|
+
# Exact acceptance-test text that crashed the TUI with
|
|
15
|
+
# "MarkupError: closing tag '[/#888888]' does not match any open tag":
|
|
16
|
+
# the unterminated "[b" swallowed the timer's opening tag.
|
|
17
|
+
UNTERMINATED_BRACKET_TEXT = (
|
|
18
|
+
"Rendering acceptance test: With a=1, b=2, c=3, d=4: ZRANK z c should reply 2, "
|
|
19
|
+
'ZREVRANK z c WITHSCORE should reply [1, "3"], ZRANK z zz should reply null, '
|
|
20
|
+
"ZCOUNT z (1 3 should reply 2, and ZLEXCOUNT z [b + should reply 3."
|
|
21
|
+
)
|
|
22
|
+
# Terminated brackets used to be silently eaten as a markup tag ("LPOP key ").
|
|
23
|
+
TERMINATED_BRACKET_TEXT = "LPOP key [count] and RPOP key [count] reply one element"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _make_app(run_state: RunState, event_bus: EventBus) -> Plain2CodeTUI:
|
|
27
|
+
return Plain2CodeTUI(
|
|
28
|
+
event_bus=event_bus,
|
|
29
|
+
run_state=run_state,
|
|
30
|
+
on_ready=lambda: None,
|
|
31
|
+
render_id="test-render-id",
|
|
32
|
+
unittests_script=None,
|
|
33
|
+
conformance_tests_script="run_conformance_tests.sh",
|
|
34
|
+
prepare_environment_script=None,
|
|
35
|
+
state_machine_version="0.0.0",
|
|
36
|
+
css_path="styles.css",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_substate_line_keeps_bracket_text_verbatim():
|
|
41
|
+
for text in (UNTERMINATED_BRACKET_TEXT, TERMINATED_BRACKET_TEXT):
|
|
42
|
+
line = SubstateLine(text, " ", ProgressItem.PROCESSING)._format_line()
|
|
43
|
+
assert text in line.plain
|
|
44
|
+
assert line.plain.endswith("(0s)")
|
|
45
|
+
# Only the timer carries the muted style; the text itself is unstyled.
|
|
46
|
+
assert len(line.spans) == 1
|
|
47
|
+
assert line.plain[line.spans[0].start : line.spans[0].end] == "(0s)"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_substate_with_brackets_renders_without_markup_error():
|
|
51
|
+
async def scenario():
|
|
52
|
+
event_bus = EventBus()
|
|
53
|
+
run_state = RunState(spec_filename="x.plain")
|
|
54
|
+
app = _make_app(run_state, event_bus)
|
|
55
|
+
async with app.run_test() as pilot:
|
|
56
|
+
widget_id = TUIComponents.FRID_PROGRESS_CONFORMANCE_TEST.value
|
|
57
|
+
update_progress_item_substates(
|
|
58
|
+
app, widget_id, [Substate(UNTERMINATED_BRACKET_TEXT), Substate(TERMINATED_BRACKET_TEXT)]
|
|
59
|
+
)
|
|
60
|
+
await pilot.pause()
|
|
61
|
+
await pilot.pause()
|
|
62
|
+
|
|
63
|
+
lines = app.query(".substate-line-text").results(Static)
|
|
64
|
+
rendered = [str(line.content) for line in lines]
|
|
65
|
+
assert any(UNTERMINATED_BRACKET_TEXT in text for text in rendered)
|
|
66
|
+
assert any(TERMINATED_BRACKET_TEXT in text for text in rendered)
|
|
67
|
+
|
|
68
|
+
asyncio.run(scenario())
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_status_messages_keep_brackets():
|
|
72
|
+
async def scenario():
|
|
73
|
+
event_bus = EventBus()
|
|
74
|
+
run_state = RunState(spec_filename="x.plain")
|
|
75
|
+
app = _make_app(run_state, event_bus)
|
|
76
|
+
async with app.run_test() as pilot:
|
|
77
|
+
status = app.query_one(f"#{TUIComponents.RENDER_STATUS_WIDGET.value}", Static)
|
|
78
|
+
|
|
79
|
+
display_success_message(app, "out/[weird] path")
|
|
80
|
+
await pilot.pause()
|
|
81
|
+
assert "rendering completed!" in str(status.content)
|
|
82
|
+
assert "generated code folder: out/[weird] path" in str(status.content)
|
|
83
|
+
|
|
84
|
+
display_error_message(app, "Error: [Errno 2] No such file: run_tests.sh [b")
|
|
85
|
+
await pilot.pause()
|
|
86
|
+
assert "[Errno 2] No such file: run_tests.sh [b" in str(status.content)
|
|
87
|
+
|
|
88
|
+
asyncio.run(scenario())
|
|
@@ -3,6 +3,7 @@ from typing import Literal, Optional
|
|
|
3
3
|
|
|
4
4
|
from rich.markup import escape
|
|
5
5
|
from textual.containers import Horizontal, Vertical, VerticalScroll
|
|
6
|
+
from textual.content import Content
|
|
6
7
|
from textual.message import Message
|
|
7
8
|
from textual.timer import Timer
|
|
8
9
|
from textual.widgets import Button, Static
|
|
@@ -71,7 +72,7 @@ class CustomFooter(Horizontal):
|
|
|
71
72
|
self._footer_text_widget = Static(footer_rendering_text, classes="custom-footer-text")
|
|
72
73
|
yield self._footer_text_widget
|
|
73
74
|
if self.render_id:
|
|
74
|
-
yield Static(f"render id: {self.render_id} ", classes="custom-footer-render-id")
|
|
75
|
+
yield Static(f"render id: {self.render_id} ", classes="custom-footer-render-id", markup=False)
|
|
75
76
|
|
|
76
77
|
def update_footer_state(self, state: Literal["rendering", "pausing", "paused", "finished"]) -> None:
|
|
77
78
|
self.remove_class("footer-state-default")
|
|
@@ -201,9 +202,12 @@ class SubstateLine(Horizontal):
|
|
|
201
202
|
def _format_timer(self) -> str:
|
|
202
203
|
return format_duration_hms(self._seconds_elapsed)
|
|
203
204
|
|
|
204
|
-
def _format_line(self) ->
|
|
205
|
+
def _format_line(self) -> Content:
|
|
206
|
+
# The substate text is arbitrary (acceptance-test text from the spec, module names, ...)
|
|
207
|
+
# and may contain square brackets, so it must never go through the markup parser.
|
|
208
|
+
# Build the line as Content and style only the timer part.
|
|
205
209
|
timer = self._format_timer()
|
|
206
|
-
return f"{self.indent} └ {self.text}
|
|
210
|
+
return Content.assemble(f"{self.indent} └ {self.text} ", (f"({timer})", "#888888"))
|
|
207
211
|
|
|
208
212
|
def _refresh_timer(self) -> None:
|
|
209
213
|
try:
|
|
@@ -232,7 +236,7 @@ class ProgressItem(Vertical):
|
|
|
232
236
|
# Main row with status and description
|
|
233
237
|
with Horizontal(id=f"{self.id}-main-row", classes="progress-main-row"):
|
|
234
238
|
yield Static(self._get_status_text(self.PENDING), classes=f"status {self.PENDING}")
|
|
235
|
-
yield Static(self.initial_text, classes="description")
|
|
239
|
+
yield Static(self.initial_text, classes="description", markup=False)
|
|
236
240
|
# Substates container (full width, aligned to left)
|
|
237
241
|
yield Vertical(id=f"{self.id}-substates", classes="substates-container")
|
|
238
242
|
|
|
@@ -367,8 +371,8 @@ class RenderingInfoBox(Vertical):
|
|
|
367
371
|
self._refresh_content()
|
|
368
372
|
|
|
369
373
|
def compose(self):
|
|
370
|
-
self.module_widget = Static(self.module_text, classes="rendering-info-row")
|
|
371
|
-
self.functionality_widget = Static(self.functionality_text, classes="rendering-info-row")
|
|
374
|
+
self.module_widget = Static(self.module_text, classes="rendering-info-row", markup=False)
|
|
375
|
+
self.functionality_widget = Static(self.functionality_text, classes="rendering-info-row", markup=False)
|
|
372
376
|
yield Static("module status", classes="rendering-info-title")
|
|
373
377
|
with Vertical(classes="rendering-info-box"):
|
|
374
378
|
yield self.module_widget
|
|
@@ -430,9 +434,9 @@ class TestScriptsContainer(Vertical):
|
|
|
430
434
|
def compose(self):
|
|
431
435
|
yield Static("testing status", classes="test-scripts-title")
|
|
432
436
|
with Vertical(classes="test-scripts-box"):
|
|
433
|
-
self.unit_widget = Static(self.unit_test_text, classes="test-script-row")
|
|
434
|
-
self.conformance_widget = Static(self.conformance_test_text, classes="test-script-row")
|
|
435
|
-
self.testing_widget = Static(self.testing_env_text, classes="test-script-row")
|
|
437
|
+
self.unit_widget = Static(self.unit_test_text, classes="test-script-row", markup=False)
|
|
438
|
+
self.conformance_widget = Static(self.conformance_test_text, classes="test-script-row", markup=False)
|
|
439
|
+
self.testing_widget = Static(self.testing_env_text, classes="test-script-row", markup=False)
|
|
436
440
|
yield self.unit_widget
|
|
437
441
|
yield self.conformance_widget
|
|
438
442
|
yield self.testing_widget
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
|
|
5
|
+
from textual.content import Content
|
|
5
6
|
from textual.css.query import NoMatches
|
|
6
7
|
from textual.widgets import Static
|
|
7
8
|
|
|
@@ -89,9 +90,14 @@ def display_success_message(tui, rendered_code_path: str):
|
|
|
89
90
|
rendered_code_path: The path to the rendered code
|
|
90
91
|
"""
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
# rendered_code_path is user-controlled and may contain square brackets, so build the
|
|
94
|
+
# message as Content instead of interpolating it into a markup string.
|
|
95
|
+
message = Content.assemble(
|
|
96
|
+
("✓ rendering completed!", "#79FC96"),
|
|
97
|
+
" ",
|
|
98
|
+
("(press enter to exit)", "#888888"),
|
|
99
|
+
"\n",
|
|
100
|
+
(f"generated code folder: {rendered_code_path} ", "#888888"),
|
|
95
101
|
)
|
|
96
102
|
|
|
97
103
|
widget: Static = tui.query_one(f"#{TUIComponents.RENDER_STATUS_WIDGET.value}", Static)
|
|
@@ -120,7 +126,8 @@ def transition_frid_progress(tui, from_status: str | None, to_status: str):
|
|
|
120
126
|
def display_error_message(tui, error_message: str):
|
|
121
127
|
widget: Static = tui.query_one(f"#{TUIComponents.RENDER_STATUS_WIDGET.value}", Static)
|
|
122
128
|
widget.add_class("error")
|
|
123
|
-
|
|
129
|
+
# Error text may contain square brackets (paths, tracebacks); keep it out of the markup parser.
|
|
130
|
+
widget.update(Content(error_message))
|
|
124
131
|
|
|
125
132
|
|
|
126
133
|
def display_usage_summary(tui, functionalities: int, render_time_seconds: float) -> None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.github/workflows/nofity-slack-on-main-merge.yml
RENAMED
|
File without changes
|
|
File without changes
|
{codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/.github/workflows/publish-install-script.yml
RENAMED
|
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
|
{codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/docs/starting_a_plain_project_from_scratch.md
RENAMED
|
File without changes
|
|
File without changes
|
{codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_golang/config.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_golang/run.sh
RENAMED
|
File without changes
|
{codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_python/config.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_python/run.sh
RENAMED
|
File without changes
|
{codeplain-0.3.11.dev10 → codeplain-0.3.11.dev12}/examples/example_hello_world_react/config.yaml
RENAMED
|
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
|