codeplain 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. codeplain-0.1.0.dist-info/METADATA +142 -0
  2. codeplain-0.1.0.dist-info/RECORD +51 -0
  3. codeplain-0.1.0.dist-info/WHEEL +5 -0
  4. codeplain-0.1.0.dist-info/entry_points.txt +2 -0
  5. codeplain-0.1.0.dist-info/licenses/LICENSE +21 -0
  6. codeplain-0.1.0.dist-info/top_level.txt +36 -0
  7. codeplain_REST_api.py +370 -0
  8. config/__init__.py +2 -0
  9. config/system_config.yaml +27 -0
  10. file_utils.py +316 -0
  11. git_utils.py +304 -0
  12. hash_key.py +29 -0
  13. plain2code.py +218 -0
  14. plain2code_arguments.py +286 -0
  15. plain2code_console.py +107 -0
  16. plain2code_exceptions.py +45 -0
  17. plain2code_nodes.py +108 -0
  18. plain2code_read_config.py +74 -0
  19. plain2code_state.py +75 -0
  20. plain2code_utils.py +56 -0
  21. plain_spec.py +360 -0
  22. render_machine/actions/analyze_specification_ambiguity.py +50 -0
  23. render_machine/actions/base_action.py +19 -0
  24. render_machine/actions/commit_conformance_tests_changes.py +46 -0
  25. render_machine/actions/commit_implementation_code_changes.py +22 -0
  26. render_machine/actions/create_dist.py +26 -0
  27. render_machine/actions/exit_with_error.py +22 -0
  28. render_machine/actions/fix_conformance_test.py +121 -0
  29. render_machine/actions/fix_unit_tests.py +57 -0
  30. render_machine/actions/prepare_repositories.py +50 -0
  31. render_machine/actions/prepare_testing_environment.py +30 -0
  32. render_machine/actions/refactor_code.py +48 -0
  33. render_machine/actions/render_conformance_tests.py +169 -0
  34. render_machine/actions/render_functional_requirement.py +69 -0
  35. render_machine/actions/run_conformance_tests.py +44 -0
  36. render_machine/actions/run_unit_tests.py +38 -0
  37. render_machine/actions/summarize_conformance_tests.py +34 -0
  38. render_machine/code_renderer.py +50 -0
  39. render_machine/conformance_test_helpers.py +68 -0
  40. render_machine/implementation_code_helpers.py +20 -0
  41. render_machine/render_context.py +280 -0
  42. render_machine/render_types.py +36 -0
  43. render_machine/render_utils.py +92 -0
  44. render_machine/state_machine_config.py +408 -0
  45. render_machine/states.py +52 -0
  46. render_machine/triggers.py +27 -0
  47. standard_template_library/__init__.py +1 -0
  48. standard_template_library/golang-console-app-template.plain +36 -0
  49. standard_template_library/python-console-app-template.plain +32 -0
  50. standard_template_library/typescript-react-app-template.plain +22 -0
  51. system_config.py +49 -0
@@ -0,0 +1,50 @@
1
+ from typing import Any
2
+
3
+ import file_utils
4
+ import git_utils
5
+ import plain_spec
6
+ from plain2code_console import console
7
+ from plain2code_utils import AMBIGUITY_CAUSES
8
+ from render_machine.actions.base_action import BaseAction
9
+ from render_machine.render_context import RenderContext
10
+
11
+
12
+ class AnalyzeSpecificationAmbiguity(BaseAction):
13
+ SUCCESSFUL_OUTCOME = "conformance_tests_postanalyzed"
14
+
15
+ def execute(self, render_context: RenderContext, _previous_action_payload: Any | None):
16
+ fixed_implementation_code_diff = git_utils.get_fixed_implementation_code_diff(
17
+ render_context.args.build_folder, render_context.frid_context.frid
18
+ )
19
+ if fixed_implementation_code_diff is None:
20
+ raise Exception(
21
+ "Fixes to the implementation code found during conformance testing are not committed to git."
22
+ )
23
+ previous_frid = plain_spec.get_previous_frid(render_context.plain_source_tree, render_context.frid_context.frid)
24
+ git_utils.checkout_commit_with_frid(render_context.args.build_folder, previous_frid)
25
+ existing_files = file_utils.list_all_text_files(render_context.args.build_folder)
26
+ existing_files_content = file_utils.get_existing_files_content(render_context.args.build_folder, existing_files)
27
+ git_utils.checkout_previous_branch(render_context.args.build_folder)
28
+ implementation_code_diff = git_utils.get_implementation_code_diff(
29
+ render_context.args.build_folder, render_context.frid_context.frid, previous_frid
30
+ )
31
+ rendering_analysis = render_context.codeplain_api.analyze_rendering(
32
+ render_context.frid_context.frid,
33
+ render_context.plain_source_tree,
34
+ render_context.frid_context.linked_resources,
35
+ existing_files_content,
36
+ implementation_code_diff,
37
+ fixed_implementation_code_diff,
38
+ render_context.run_state,
39
+ )
40
+ if rendering_analysis:
41
+ # TODO: Before this output is exposed to the user, we should check the 'guidance' field using LLM in the same way as we do conflicting requirements.
42
+ console.info(
43
+ f"Specification ambiguity detected! {AMBIGUITY_CAUSES[rendering_analysis['cause']]} of the functional requirement {render_context.frid_context.frid}."
44
+ )
45
+ console.info(rendering_analysis["guidance"])
46
+ else:
47
+ console.warning(
48
+ f"No specification ambiguity detected for functional requirement {render_context.frid_context.frid}."
49
+ )
50
+ return self.SUCCESSFUL_OUTCOME, None
@@ -0,0 +1,19 @@
1
+ from abc import abstractmethod
2
+ from typing import Any
3
+
4
+ from render_machine.render_context import RenderContext
5
+
6
+
7
+ class BaseAction:
8
+ def __init__(self):
9
+ pass
10
+
11
+ @abstractmethod
12
+ def execute(self, _render_context: RenderContext, _previous_action_payload: Any | None):
13
+ """
14
+ Execute the action with the given render context and optional previous action payload.
15
+
16
+ Returns:
17
+ tuple: (outcome, payload) where outcome is a string and payload can be any object or None
18
+ """
19
+ pass
@@ -0,0 +1,46 @@
1
+ from typing import Any
2
+
3
+ import git_utils
4
+ import plain_spec
5
+ from render_machine.actions.base_action import BaseAction
6
+ from render_machine.render_context import RenderContext
7
+
8
+
9
+ class CommitConformanceTestsChanges(BaseAction):
10
+ SUCCESSFUL_OUTCOME_IMPLEMENTATION_NOT_UPDATED = "conformance_tests_changes_committed_implementation_not_updated"
11
+ SUCCESSFUL_OUTCOME_IMPLEMENTATION_UPDATED = "conformance_tests_changes_committed_implementation_updated"
12
+
13
+ def __init__(self, implementation_code_commit_message: str, conformance_tests_commit_message: str):
14
+ self.implementation_code_commit_message = implementation_code_commit_message
15
+ self.conformance_tests_commit_message = conformance_tests_commit_message
16
+
17
+ def execute(self, render_context: RenderContext, _previous_action_payload: Any | None):
18
+ implementation_updated = False
19
+ if git_utils.is_dirty(render_context.args.build_folder):
20
+ git_utils.add_all_files_and_commit(
21
+ render_context.args.build_folder,
22
+ self.implementation_code_commit_message,
23
+ render_context.frid_context.frid,
24
+ render_context.run_state.render_id,
25
+ )
26
+ implementation_updated = True
27
+ functional_requirement_text = render_context.frid_context.specifications[plain_spec.FUNCTIONAL_REQUIREMENTS][-1]
28
+ templated_functional_requirement_finished_commit_msg = self.conformance_tests_commit_message.format(
29
+ render_context.frid_context.frid
30
+ )
31
+ formatted_conformance_commit_msg = (
32
+ f"{functional_requirement_text}\n\n{templated_functional_requirement_finished_commit_msg}"
33
+ )
34
+ render_context.conformance_tests_utils.dump_conformance_tests_json(
35
+ render_context.conformance_tests_running_context.conformance_tests_json
36
+ )
37
+ git_utils.add_all_files_and_commit(
38
+ render_context.args.conformance_tests_folder,
39
+ formatted_conformance_commit_msg,
40
+ None,
41
+ render_context.run_state.render_id,
42
+ )
43
+ if implementation_updated:
44
+ return self.SUCCESSFUL_OUTCOME_IMPLEMENTATION_UPDATED, None
45
+ else:
46
+ return self.SUCCESSFUL_OUTCOME_IMPLEMENTATION_NOT_UPDATED, None
@@ -0,0 +1,22 @@
1
+ from typing import Any
2
+
3
+ import git_utils
4
+ from render_machine.actions.base_action import BaseAction
5
+ from render_machine.render_context import RenderContext
6
+
7
+
8
+ class CommitImplementationCodeChanges(BaseAction):
9
+ SUCCESSFUL_OUTCOME = "implementation_code_changes_committed"
10
+
11
+ def __init__(self, base_commit_message: str):
12
+ self.base_commit_message = base_commit_message
13
+
14
+ def execute(self, render_context: RenderContext, _previous_action_payload: Any | None):
15
+ git_utils.add_all_files_and_commit(
16
+ render_context.args.build_folder,
17
+ self.base_commit_message.format(render_context.frid_context.frid),
18
+ render_context.frid_context.frid,
19
+ render_context.run_state.render_id,
20
+ )
21
+
22
+ return self.SUCCESSFUL_OUTCOME, None
@@ -0,0 +1,26 @@
1
+ from typing import Any
2
+
3
+ import file_utils
4
+ from plain2code_console import console
5
+ from render_machine.actions.base_action import BaseAction
6
+ from render_machine.render_context import RenderContext
7
+
8
+
9
+ class CreateDist(BaseAction):
10
+ SUCCESSFUL_OUTCOME = "dist_created"
11
+
12
+ def execute(self, render_context: RenderContext, _previous_action_payload: Any | None):
13
+ # Copy build and conformance tests folders to output folders if specified
14
+ if render_context.args.copy_build:
15
+ file_utils.copy_folder_to_output(
16
+ render_context.args.build_folder,
17
+ render_context.args.build_dest,
18
+ )
19
+ if render_context.args.copy_conformance_tests:
20
+ file_utils.copy_folder_to_output(
21
+ render_context.args.conformance_tests_folder,
22
+ render_context.args.conformance_tests_dest,
23
+ )
24
+ console.info(f"Render {render_context.run_state.render_id} completed successfully.")
25
+
26
+ return self.SUCCESSFUL_OUTCOME, None
@@ -0,0 +1,22 @@
1
+ from typing import Any
2
+
3
+ from plain2code_console import console
4
+ from render_machine.actions.base_action import BaseAction
5
+ from render_machine.render_context import RenderContext
6
+
7
+
8
+ class ExitWithError(BaseAction):
9
+ SUCCESSFUL_OUTCOME = "error_handled"
10
+
11
+ def execute(self, render_context: RenderContext, previous_action_payload: Any | None):
12
+ console.error(previous_action_payload)
13
+
14
+ if render_context.frid_context is not None:
15
+ console.info(
16
+ f"To continue rendering from the last successfully rendered functional requirement, provide the [red][b]--render-from {render_context.frid_context.frid}[/b][/red] flag."
17
+ )
18
+
19
+ if render_context.run_state.render_id is not None:
20
+ console.info(f"Render ID: {render_context.run_state.render_id}")
21
+
22
+ return self.SUCCESSFUL_OUTCOME, None
@@ -0,0 +1,121 @@
1
+ from typing import Any
2
+
3
+ import file_utils
4
+ import plain_spec
5
+ from plain2code_console import console
6
+ from plain2code_exceptions import UnexpectedState
7
+ from render_machine.actions.base_action import BaseAction
8
+ from render_machine.conformance_test_helpers import ConformanceTestHelpers
9
+ from render_machine.implementation_code_helpers import ImplementationCodeHelpers
10
+ from render_machine.render_context import RenderContext
11
+
12
+
13
+ class FixConformanceTest(BaseAction):
14
+ IMPLEMENTATION_CODE_NOT_UPDATED = "implementation_code_not_updated"
15
+ IMPLEMENTATION_CODE_UPDATED = "implementation_code_updated"
16
+
17
+ def execute(self, render_context: RenderContext, previous_action_payload: Any | None):
18
+ console.info(
19
+ f"Fixing conformance test for functional requirement {render_context.conformance_tests_running_context.current_testing_frid}."
20
+ )
21
+
22
+ if not previous_action_payload.get("previous_conformance_tests_issue"):
23
+ raise UnexpectedState("Previous action payload does not contain previous conformance tests issue.")
24
+ previous_conformance_tests_issue = previous_action_payload["previous_conformance_tests_issue"]
25
+
26
+ if render_context.conformance_tests_running_context.current_testing_frid == render_context.frid_context.frid:
27
+ console_message = f"Fixing conformance test for functional requirement {render_context.conformance_tests_running_context.current_testing_frid}."
28
+ else:
29
+ console_message = f"While implementing functional requirement {render_context.frid_context.frid}, conformance tests for functional requirement {render_context.conformance_tests_running_context.current_testing_frid} broke. Fixing them..."
30
+
31
+ existing_files, existing_files_content = ImplementationCodeHelpers.fetch_existing_files(render_context)
32
+ (
33
+ existing_conformance_test_files,
34
+ existing_conformance_test_files_content,
35
+ ) = ConformanceTestHelpers.fetch_existing_conformance_test_files(
36
+ render_context.conformance_tests_running_context # type: ignore
37
+ )
38
+ previous_frid_code_diff = ImplementationCodeHelpers.get_code_diff(render_context)
39
+
40
+ if render_context.args.verbose:
41
+ tmp_resources_list = []
42
+ plain_spec.collect_linked_resources(
43
+ render_context.plain_source_tree,
44
+ tmp_resources_list,
45
+ None,
46
+ False,
47
+ render_context.frid_context.frid,
48
+ )
49
+ console.print_resources(tmp_resources_list, render_context.frid_context.linked_resources)
50
+
51
+ console.print_files(
52
+ "Implementation files sent as input for fixing conformance tests issues:",
53
+ render_context.args.build_folder,
54
+ existing_files_content,
55
+ style=console.INPUT_STYLE,
56
+ )
57
+
58
+ console.print_files(
59
+ "Conformance tests files sent as input for fixing conformance tests issues:",
60
+ ConformanceTestHelpers.get_current_conformance_test_folder_name(
61
+ render_context.conformance_tests_running_context # type: ignore
62
+ ),
63
+ existing_conformance_test_files_content,
64
+ style=console.INPUT_STYLE,
65
+ )
66
+
67
+ acceptance_tests = ConformanceTestHelpers.get_current_acceptance_tests(
68
+ render_context.conformance_tests_running_context # type: ignore
69
+ )
70
+ conformance_tests_folder_name = ConformanceTestHelpers.get_current_conformance_test_folder_name(
71
+ render_context.conformance_tests_running_context # type: ignore
72
+ )
73
+ with console.status(console_message):
74
+ [conformance_tests_fixed, response_files] = render_context.codeplain_api.fix_conformance_tests_issue(
75
+ render_context.frid_context.frid,
76
+ render_context.conformance_tests_running_context.current_testing_frid,
77
+ render_context.plain_source_tree,
78
+ render_context.frid_context.linked_resources,
79
+ existing_files_content,
80
+ previous_frid_code_diff,
81
+ existing_conformance_test_files_content,
82
+ acceptance_tests,
83
+ previous_conformance_tests_issue,
84
+ render_context.conformance_tests_running_context.fix_attempts,
85
+ conformance_tests_folder_name,
86
+ render_context.conformance_tests_running_context.current_testing_frid_high_level_implementation_plan,
87
+ render_context.run_state,
88
+ )
89
+
90
+ if conformance_tests_fixed:
91
+ file_utils.store_response_files(
92
+ ConformanceTestHelpers.get_current_conformance_test_folder_name(
93
+ render_context.conformance_tests_running_context # type: ignore
94
+ ),
95
+ response_files,
96
+ existing_conformance_test_files,
97
+ )
98
+ if render_context.args.verbose:
99
+ console.print_files(
100
+ "Conformance test files fixed:",
101
+ ConformanceTestHelpers.get_current_conformance_test_folder_name(
102
+ render_context.conformance_tests_running_context # type: ignore
103
+ ),
104
+ response_files,
105
+ style=console.OUTPUT_STYLE,
106
+ )
107
+ return self.IMPLEMENTATION_CODE_NOT_UPDATED, None
108
+ else:
109
+ if len(response_files) > 0:
110
+ file_utils.store_response_files(render_context.args.build_folder, response_files, existing_files)
111
+ if render_context.args.verbose:
112
+ console.print_files(
113
+ "Files fixed:",
114
+ render_context.args.build_folder,
115
+ response_files,
116
+ style=console.OUTPUT_STYLE,
117
+ )
118
+ render_context.conformance_tests_running_context.should_prepare_testing_environment = True
119
+ return self.IMPLEMENTATION_CODE_UPDATED, None
120
+ else:
121
+ return self.IMPLEMENTATION_CODE_NOT_UPDATED, None
@@ -0,0 +1,57 @@
1
+ from typing import Any
2
+
3
+ import file_utils
4
+ import render_machine.render_utils as render_utils
5
+ from plain2code_console import console
6
+ from plain2code_exceptions import UnexpectedState
7
+ from render_machine.actions.base_action import BaseAction
8
+ from render_machine.implementation_code_helpers import ImplementationCodeHelpers
9
+ from render_machine.render_context import RenderContext
10
+
11
+ MAX_ISSUE_LENGTH = 10000
12
+
13
+
14
+ class FixUnitTests(BaseAction):
15
+ SUCCESSFUL_OUTCOME = "unit_tests_fix_generated"
16
+
17
+ def execute(self, render_context: RenderContext, previous_action_payload: Any | None):
18
+ if not previous_action_payload.get("previous_unittests_issue"):
19
+ raise UnexpectedState("Previous action payload does not contain previous unit tests issue.")
20
+ previous_unittests_issue = previous_action_payload["previous_unittests_issue"]
21
+
22
+ if previous_unittests_issue and len(previous_unittests_issue) > MAX_ISSUE_LENGTH:
23
+ console.warning(
24
+ f"Unit tests issue text is too long and will be smartly truncated to {MAX_ISSUE_LENGTH} characters."
25
+ )
26
+
27
+ existing_files, existing_files_content = ImplementationCodeHelpers.fetch_existing_files(render_context)
28
+
29
+ if render_context.args.verbose:
30
+ render_utils.print_inputs(
31
+ render_context, existing_files_content, "Files sent as input to unit tests fixing:"
32
+ )
33
+
34
+ with console.status(
35
+ f"[{console.INFO_STYLE}]Fixing unit tests issue for functional requirement {render_context.frid_context.frid}...\n"
36
+ ):
37
+ response_files = render_context.codeplain_api.fix_unittests_issue(
38
+ render_context.frid_context.frid,
39
+ render_context.plain_source_tree,
40
+ render_context.frid_context.linked_resources,
41
+ existing_files_content,
42
+ previous_unittests_issue,
43
+ render_context.run_state,
44
+ )
45
+
46
+ _, changed_files = file_utils.update_build_folder_with_rendered_files(
47
+ render_context.args.build_folder, existing_files, response_files
48
+ )
49
+
50
+ render_context.unit_tests_running_context.changed_files.update(changed_files)
51
+
52
+ if render_context.args.verbose:
53
+ console.print_files(
54
+ "Files fixed:", render_context.args.build_folder, response_files, style=console.OUTPUT_STYLE
55
+ )
56
+
57
+ return self.SUCCESSFUL_OUTCOME, None
@@ -0,0 +1,50 @@
1
+ from typing import Any
2
+
3
+ import file_utils
4
+ import git_utils
5
+ import plain_spec
6
+ from plain2code_console import console
7
+ from render_machine.actions.base_action import BaseAction
8
+ from render_machine.render_context import RenderContext
9
+
10
+
11
+ class PrepareRepositories(BaseAction):
12
+ SUCCESSFUL_OUTCOME = "repositories_prepared"
13
+
14
+ def execute(self, render_context: RenderContext, _previous_action_payload: Any | None):
15
+
16
+ if render_context.args.render_range is not None and render_context.args.render_range[
17
+ 0
18
+ ] != plain_spec.get_first_frid(render_context.plain_source_tree):
19
+ frid = render_context.args.render_range[0]
20
+
21
+ render_context.starting_frid = frid
22
+
23
+ previous_frid = plain_spec.get_previous_frid(render_context.plain_source_tree, frid)
24
+
25
+ if render_context.args.verbose:
26
+ console.info(f"Reverting code to version implemented for {previous_frid}.")
27
+
28
+ git_utils.revert_to_commit_with_frid(render_context.args.build_folder, previous_frid)
29
+ # conformance tests are still not fully implemented
30
+ if render_context.args.render_conformance_tests:
31
+ git_utils.revert_to_commit_with_frid(render_context.args.conformance_tests_folder, previous_frid)
32
+ else:
33
+ if render_context.args.verbose:
34
+ console.info("Initializing git repositories for the render folders.")
35
+
36
+ git_utils.init_git_repo(render_context.args.build_folder)
37
+
38
+ if render_context.args.base_folder:
39
+ file_utils.copy_folder_content(render_context.args.base_folder, render_context.args.build_folder)
40
+ git_utils.add_all_files_and_commit(
41
+ render_context.args.build_folder,
42
+ git_utils.BASE_FOLDER_COMMIT_MESSAGE,
43
+ None,
44
+ render_context.run_state.render_id,
45
+ )
46
+
47
+ if render_context.args.render_conformance_tests:
48
+ git_utils.init_git_repo(render_context.args.conformance_tests_folder)
49
+
50
+ return self.SUCCESSFUL_OUTCOME, None
@@ -0,0 +1,30 @@
1
+ from typing import Any
2
+
3
+ import render_machine.render_utils as render_utils
4
+ from plain2code_console import console
5
+ from render_machine.actions.base_action import BaseAction
6
+ from render_machine.render_context import RenderContext
7
+
8
+
9
+ class PrepareTestingEnvironment(BaseAction):
10
+ SUCCESSFUL_OUTCOME = "testing_environment_prepared"
11
+ FAILED_OUTCOME = "testing_environment_preparation_failed"
12
+
13
+ def execute(self, render_context: RenderContext, _previous_action_payload: Any | None):
14
+ if render_context.args.verbose:
15
+ console.info(
16
+ f"[b]Running testing environment preparation script {render_context.args.prepare_environment_script} for build folder {render_context.args.build_folder}.[/b]"
17
+ )
18
+ exit_code, _ = render_utils.execute_script(
19
+ render_context.args.prepare_environment_script,
20
+ [render_context.args.build_folder],
21
+ render_context.args.verbose,
22
+ "Testing Environment Preparation",
23
+ )
24
+
25
+ render_context.conformance_tests_running_context.should_prepare_testing_environment = False
26
+
27
+ if exit_code == 0:
28
+ return self.SUCCESSFUL_OUTCOME, None
29
+ else:
30
+ return self.FAILED_OUTCOME, None
@@ -0,0 +1,48 @@
1
+ from typing import Any
2
+
3
+ import file_utils
4
+ from plain2code_console import console
5
+ from render_machine.actions.base_action import BaseAction
6
+ from render_machine.implementation_code_helpers import ImplementationCodeHelpers
7
+ from render_machine.render_context import RenderContext
8
+
9
+
10
+ class RefactorCode(BaseAction):
11
+ SUCCESSFUL_OUTCOME = "refactoring_successful"
12
+ NO_FILES_REFACTORED_OUTCOME = "no_files_refactored"
13
+
14
+ def execute(self, render_context: RenderContext, _previous_action_payload: Any | None):
15
+ existing_files, existing_files_content = ImplementationCodeHelpers.fetch_existing_files(render_context)
16
+
17
+ if render_context.args.verbose:
18
+ console.info(f"\nRefactoring iteration {render_context.frid_context.refactoring_iteration}.")
19
+
20
+ if render_context.args.verbose:
21
+ console.print_files(
22
+ "Files sent as input for refactoring:",
23
+ render_context.args.build_folder,
24
+ existing_files_content,
25
+ style=console.INPUT_STYLE,
26
+ )
27
+ with console.status(
28
+ f"[{console.INFO_STYLE}]Refactoring the generated code for functional requirement {render_context.frid_context.frid}...\n"
29
+ ):
30
+ response_files = render_context.codeplain_api.refactor_source_files_if_needed(
31
+ frid=render_context.frid_context.frid,
32
+ files_to_check=render_context.frid_context.changed_files,
33
+ existing_files_content=existing_files_content,
34
+ run_state=render_context.run_state,
35
+ )
36
+
37
+ if len(response_files) == 0:
38
+ if render_context.args.verbose:
39
+ console.info("No files refactored.")
40
+ return self.NO_FILES_REFACTORED_OUTCOME, None
41
+
42
+ file_utils.store_response_files(render_context.args.build_folder, response_files, existing_files)
43
+
44
+ if render_context.args.verbose:
45
+ console.print_files(
46
+ "Files refactored:", render_context.args.build_folder, response_files, style=console.OUTPUT_STYLE
47
+ )
48
+ return self.SUCCESSFUL_OUTCOME, None
@@ -0,0 +1,169 @@
1
+ import os
2
+ from typing import Any
3
+
4
+ import file_utils
5
+ import plain_spec
6
+ from plain2code_console import console
7
+ from render_machine.actions.base_action import BaseAction
8
+ from render_machine.conformance_test_helpers import ConformanceTestHelpers
9
+ from render_machine.implementation_code_helpers import ImplementationCodeHelpers
10
+ from render_machine.render_context import RenderContext
11
+
12
+
13
+ class RenderConformanceTests(BaseAction):
14
+ SUCCESSFUL_OUTCOME = "conformance_test_rendered"
15
+
16
+ def execute(self, render_context: RenderContext, _previous_action_payload: Any | None):
17
+ if self._should_render_conformance_tests(render_context):
18
+ return self._render_conformance_tests(render_context)
19
+ else:
20
+ return self._render_acceptance_test(render_context)
21
+
22
+ def _should_render_conformance_tests(self, render_context: RenderContext) -> bool:
23
+ return render_context.conformance_tests_running_context.conformance_test_phase_index == 0
24
+
25
+ def _render_conformance_tests(self, render_context: RenderContext):
26
+ existing_conformance_test_folder_names = ConformanceTestHelpers.fetch_existing_conformance_test_folder_names(
27
+ render_context.args.conformance_tests_folder
28
+ )
29
+ if render_context.args.verbose:
30
+ console.info("\n[b]Implementing test requirements:[/b]")
31
+ console.print_list(
32
+ render_context.conformance_tests_running_context.current_testing_frid_specifications[
33
+ plain_spec.TEST_REQUIREMENTS
34
+ ],
35
+ style=console.INFO_STYLE,
36
+ )
37
+ console.info()
38
+ if not ConformanceTestHelpers.current_conformance_tests_exist(render_context.conformance_tests_running_context): # type: ignore
39
+ with console.status(
40
+ f"[{console.INFO_STYLE}]Generating folder name for conformance tests for functional requirement {render_context.conformance_tests_running_context.current_testing_frid}...\n"
41
+ ):
42
+ fr_subfolder_name = render_context.codeplain_api.generate_folder_name_from_functional_requirement(
43
+ frid=render_context.conformance_tests_running_context.current_testing_frid,
44
+ functional_requirement=render_context.conformance_tests_running_context.current_testing_frid_specifications[
45
+ plain_spec.FUNCTIONAL_REQUIREMENTS
46
+ ][
47
+ -1
48
+ ],
49
+ existing_folder_names=existing_conformance_test_folder_names,
50
+ run_state=render_context.run_state,
51
+ )
52
+
53
+ conformance_tests_folder_name = os.path.join(
54
+ render_context.args.conformance_tests_folder, fr_subfolder_name
55
+ )
56
+
57
+ if render_context.args.verbose:
58
+ console.info(f"Storing conformance test files in subfolder {conformance_tests_folder_name}/")
59
+
60
+ render_context.conformance_tests_running_context.conformance_tests_json[
61
+ render_context.conformance_tests_running_context.current_testing_frid
62
+ ] = {
63
+ "folder_name": conformance_tests_folder_name,
64
+ "functional_requirement": render_context.frid_context.specifications[
65
+ plain_spec.FUNCTIONAL_REQUIREMENTS
66
+ ][-1],
67
+ }
68
+ else:
69
+ conformance_tests_folder_name = ConformanceTestHelpers.get_current_conformance_test_folder_name(
70
+ render_context.conformance_tests_running_context # type: ignore
71
+ )
72
+
73
+ _, existing_files_content = ImplementationCodeHelpers.fetch_existing_files(render_context)
74
+ if render_context.args.verbose:
75
+ tmp_resources_list = []
76
+ plain_spec.collect_linked_resources(
77
+ render_context.plain_source_tree,
78
+ tmp_resources_list,
79
+ [
80
+ plain_spec.DEFINITIONS,
81
+ plain_spec.TEST_REQUIREMENTS,
82
+ plain_spec.FUNCTIONAL_REQUIREMENTS,
83
+ ],
84
+ False,
85
+ render_context.frid_context.frid,
86
+ )
87
+ console.print_resources(tmp_resources_list, render_context.frid_context.linked_resources)
88
+
89
+ console.print_files(
90
+ "Files sent as input for generating conformance tests:",
91
+ render_context.args.build_folder,
92
+ existing_files_content,
93
+ style=console.INPUT_STYLE,
94
+ )
95
+
96
+ all_acceptance_tests = render_context.frid_context.specifications.get(plain_spec.ACCEPTANCE_TESTS, [])
97
+ with console.status(
98
+ f"[{console.INFO_STYLE}]Rendering conformance test for functional requirement {render_context.conformance_tests_running_context.current_testing_frid}...\n"
99
+ ):
100
+ response_files, implementation_plan_summary = render_context.codeplain_api.render_conformance_tests(
101
+ render_context.frid_context.frid,
102
+ render_context.conformance_tests_running_context.current_testing_frid,
103
+ render_context.plain_source_tree,
104
+ render_context.frid_context.linked_resources,
105
+ existing_files_content,
106
+ conformance_tests_folder_name,
107
+ render_context.conformance_tests_running_context.conformance_tests_json,
108
+ all_acceptance_tests,
109
+ render_context.run_state,
110
+ )
111
+
112
+ render_context.conformance_tests_running_context.current_testing_frid_high_level_implementation_plan = (
113
+ implementation_plan_summary
114
+ )
115
+
116
+ file_utils.store_response_files(conformance_tests_folder_name, response_files, [])
117
+
118
+ if render_context.args.verbose:
119
+ console.print_files(
120
+ "Conformance test files generated:",
121
+ conformance_tests_folder_name,
122
+ response_files,
123
+ style=console.OUTPUT_STYLE,
124
+ )
125
+
126
+ return self.SUCCESSFUL_OUTCOME, None
127
+
128
+ def _render_acceptance_test(self, render_context: RenderContext):
129
+ _, existing_files_content = ImplementationCodeHelpers.fetch_existing_files(render_context)
130
+ (
131
+ conformance_tests_files,
132
+ conformance_tests_files_content,
133
+ ) = ConformanceTestHelpers.fetch_existing_conformance_test_files(
134
+ render_context.conformance_tests_running_context # type: ignore
135
+ )
136
+
137
+ acceptance_test = render_context.frid_context.specifications[plain_spec.ACCEPTANCE_TESTS][
138
+ render_context.conformance_tests_running_context.conformance_test_phase_index - 1
139
+ ]
140
+
141
+ if render_context.args.verbose:
142
+ console.info("\n[b]Generating acceptance test:[/b]")
143
+ console.info(f"[b]{acceptance_test}[/b]")
144
+ console.info()
145
+
146
+ with console.status(
147
+ f"[{console.INFO_STYLE}]Generating acceptance test for functional requirement {render_context.frid_context.frid}...\n"
148
+ ):
149
+ response_files = render_context.codeplain_api.render_acceptance_tests(
150
+ render_context.frid_context.frid,
151
+ render_context.plain_source_tree,
152
+ render_context.frid_context.linked_resources,
153
+ existing_files_content,
154
+ conformance_tests_files_content,
155
+ acceptance_test,
156
+ render_context.run_state,
157
+ )
158
+ conformance_tests_folder_name = ConformanceTestHelpers.get_current_conformance_test_folder_name(
159
+ render_context.conformance_tests_running_context # type: ignore
160
+ )
161
+
162
+ file_utils.store_response_files(conformance_tests_folder_name, response_files, conformance_tests_files)
163
+ console.print_files(
164
+ f"Conformance test files in folder {conformance_tests_folder_name} updated:",
165
+ conformance_tests_folder_name,
166
+ response_files,
167
+ style=console.OUTPUT_STYLE,
168
+ )
169
+ return self.SUCCESSFUL_OUTCOME, None