codeplain 0.2.3__py3-none-any.whl → 0.2.5__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 (43) hide show
  1. {codeplain-0.2.3.dist-info → codeplain-0.2.5.dist-info}/METADATA +3 -3
  2. {codeplain-0.2.3.dist-info → codeplain-0.2.5.dist-info}/RECORD +43 -43
  3. codeplain_REST_api.py +57 -43
  4. config/system_config.yaml +1 -16
  5. file_utils.py +5 -4
  6. git_utils.py +43 -13
  7. memory_management.py +1 -1
  8. module_renderer.py +114 -0
  9. plain2code.py +91 -30
  10. plain2code_console.py +3 -5
  11. plain2code_exceptions.py +26 -6
  12. plain2code_logger.py +11 -5
  13. plain2code_utils.py +7 -5
  14. plain_file.py +15 -37
  15. plain_modules.py +1 -4
  16. plain_spec.py +24 -6
  17. render_machine/actions/create_dist.py +1 -1
  18. render_machine/actions/exit_with_error.py +1 -1
  19. render_machine/actions/prepare_testing_environment.py +1 -1
  20. render_machine/actions/render_conformance_tests.py +2 -4
  21. render_machine/actions/render_functional_requirement.py +6 -6
  22. render_machine/actions/run_conformance_tests.py +3 -2
  23. render_machine/actions/run_unit_tests.py +1 -1
  24. render_machine/render_context.py +3 -3
  25. render_machine/render_utils.py +14 -6
  26. standard_template_library/golang-console-app-template.plain +2 -2
  27. standard_template_library/python-console-app-template.plain +2 -2
  28. standard_template_library/typescript-react-app-template.plain +2 -2
  29. system_config.py +3 -11
  30. tests/test_imports.py +2 -2
  31. tests/test_plainfile.py +2 -2
  32. tests/test_plainfileparser.py +10 -10
  33. tests/test_plainspec.py +2 -2
  34. tests/test_requires.py +2 -1
  35. tui/components.py +311 -103
  36. tui/plain2code_tui.py +101 -52
  37. tui/state_handlers.py +94 -47
  38. tui/styles.css +240 -52
  39. tui/widget_helpers.py +43 -47
  40. {codeplain-0.2.3.dist-info → codeplain-0.2.5.dist-info}/WHEEL +0 -0
  41. {codeplain-0.2.3.dist-info → codeplain-0.2.5.dist-info}/entry_points.txt +0 -0
  42. {codeplain-0.2.3.dist-info → codeplain-0.2.5.dist-info}/licenses/LICENSE +0 -0
  43. /spinner.py → /tui/spinner.py +0 -0
@@ -327,7 +327,7 @@ class RenderContext:
327
327
  def start_refactoring_code(self):
328
328
 
329
329
  if self.frid_context.refactoring_iteration == 0:
330
- console.info("[b]Refactoring the generated code...[/b]")
330
+ console.info("Refactoring the generated code...")
331
331
 
332
332
  self.frid_context.refactoring_iteration += 1
333
333
 
@@ -349,7 +349,7 @@ class RenderContext:
349
349
  self.machine.dispatch(triggers.MARK_TESTING_ENVIRONMENT_PREPARED)
350
350
 
351
351
  def start_conformance_tests_processing(self):
352
- console.info("[b]Implementing conformance tests...[/b]")
352
+ console.info("Implementing conformance tests...")
353
353
  self.conformance_tests_running_context = ConformanceTestsRunningContext(
354
354
  current_testing_module_name=self.module_name,
355
355
  current_testing_frid=None,
@@ -444,5 +444,5 @@ class RenderContext:
444
444
  def finish_fixing_conformance_tests(self):
445
445
  if self.verbose:
446
446
  console.info(
447
- f"[b]Running conformance tests attempt {self.conformance_tests_running_context.fix_attempts + 1}.[/b]"
447
+ f"Running conformance tests attempt {self.conformance_tests_running_context.fix_attempts + 1}."
448
448
  )
@@ -42,7 +42,7 @@ def print_inputs(render_context, existing_files_content, message):
42
42
 
43
43
 
44
44
  def execute_script(
45
- script: str, scripts_args: list[str], verbose: bool, script_type: str
45
+ script: str, scripts_args: list[str], verbose: bool, script_type: str, frid: Optional[str] = None
46
46
  ) -> tuple[int, str, Optional[str]]:
47
47
  temp_file_path = None
48
48
  try:
@@ -68,14 +68,22 @@ def execute_script(
68
68
  temp_file.write(f"{script_type} script {script} successfully passed.\n")
69
69
  temp_file.write(f"{script_type} script execution time: {elapsed_time:.2f} seconds.\n")
70
70
 
71
- console.info(f"[b]{script_type} script output stored in: {temp_file_path}[/b]")
71
+ console.info(f"[#888888]{script_type} script output stored in: {temp_file_path.strip()}[/#888888]")
72
72
 
73
73
  if result.returncode != 0:
74
- console.info(
75
- f"[b]The {script_type} script has failed. Initiating the patching mode to automatically correct the discrepancies.[/b]"
76
- )
74
+ if frid is not None:
75
+ console.info(
76
+ f"The {script_type} script for ID {frid} has failed. Initiating the patching mode to automatically correct the discrepancies."
77
+ )
78
+ else:
79
+ console.info(
80
+ f"The {script_type} script has failed. Initiating the patching mode to automatically correct the discrepancies."
81
+ )
77
82
  else:
78
- console.info(f"[b]All {script_type} script passed successfully.[/b]")
83
+ if frid is not None:
84
+ console.info(f"[#79FC96]The {script_type} script for ID {frid} has passed successfully.[/#79FC96]")
85
+ else:
86
+ console.info(f"[#79FC96]All {script_type} script passed successfully.[/#79FC96]")
79
87
 
80
88
  return result.returncode, result.stdout, temp_file_path
81
89
  except subprocess.TimeoutExpired as e:
@@ -7,14 +7,14 @@
7
7
  - :ConformanceTestsExecutableFile: is the main executable code file of :ConformanceTests:.
8
8
 
9
9
 
10
- ***technical specs***
10
+ ***implementation reqs***
11
11
 
12
12
  - :Implementation: should be in Go lang.
13
13
 
14
14
  - :Implementation: should include unit tests using Go's built-in testing package.
15
15
 
16
16
 
17
- ***test specs***
17
+ ***test reqs***
18
18
 
19
19
  - :ConformanceTests: should be implemented in Go lang.
20
20
 
@@ -7,13 +7,13 @@
7
7
  - :MainExecutableFile: is the main executable code file of :App:.
8
8
 
9
9
 
10
- ***technical specs***
10
+ ***implementation reqs***
11
11
 
12
12
  - :Implementation: should be in Python.
13
13
 
14
14
  - :Implementation: should include :Unittests: using Unittest framework! If :Unittests: are put in the subfolder, make sure to include __init__.py to make them discoverable.
15
15
 
16
- ***test specs***
16
+ ***test reqs***
17
17
 
18
18
  - :ConformanceTests: of :App: should be implemented in Python using Unittest framework. :ConformanceTests: will be run using "python -m unittest discover" command. Therefore, if :ConformanceTests: are put in the subfolder, make sure to include __init__.py to make them discoverable.
19
19
 
@@ -3,7 +3,7 @@
3
3
  - :App: is a web application.
4
4
 
5
5
 
6
- ***technical specs***
6
+ ***implementation reqs***
7
7
 
8
8
  - :App: should be implemented in TypeScript, using React as a web framework.
9
9
 
@@ -12,6 +12,6 @@
12
12
  - :App: should run on port 3000.
13
13
 
14
14
 
15
- ***test specs***
15
+ ***test reqs***
16
16
 
17
17
  - :ConformanceTests: of :App: should be written in TypeScript, using Cypress as the framework for :ConformanceTests:.
system_config.py CHANGED
@@ -1,5 +1,4 @@
1
1
  import importlib.resources
2
- import shutil
3
2
  import sys
4
3
 
5
4
  import yaml
@@ -12,12 +11,12 @@ class SystemConfig:
12
11
 
13
12
  def __init__(self):
14
13
  self.config = self._load_config()
15
- if "system_requirements" not in self.config:
16
- raise KeyError("Missing 'system_requirements' section in system_config.yaml")
14
+ if "client_version" not in self.config:
15
+ raise KeyError("Missing 'client_version' in system_config.yaml")
17
16
  if "error_messages" not in self.config:
18
17
  raise KeyError("Missing 'error_messages' section in system_config.yaml")
19
18
 
20
- self.requirements = self.config["system_requirements"]
19
+ self.client_version = self.config["client_version"]
21
20
  self.error_messages = self.config["error_messages"]
22
21
 
23
22
  def _load_config(self):
@@ -31,13 +30,6 @@ class SystemConfig:
31
30
  console.error(f"Failed to load system configuration: {e}")
32
31
  sys.exit(69)
33
32
 
34
- def verify_requirements(self):
35
- """Verify all system requirements are met."""
36
- for req_data in self.requirements.values():
37
- if not shutil.which(req_data["command"]):
38
- console.error(req_data["error_message"])
39
- sys.exit(69)
40
-
41
33
  def get_error_message(self, message_key, **kwargs):
42
34
  """Get a formatted error message by its key."""
43
35
  if message_key not in self.error_messages:
tests/test_imports.py CHANGED
@@ -27,13 +27,13 @@ def test_diamond_imports(load_test_data, get_test_data_path):
27
27
  {"markdown": "- :Import1Def: is a definition in diamond_import_1."},
28
28
  {"markdown": "- :Import2Def: is a definition in diamond_import_2."},
29
29
  ],
30
- "technical specs": [
30
+ "implementation reqs": [
31
31
  {"markdown": "- :CommonImportDef: is used in diamond_import_common."},
32
32
  {"markdown": "- :Import1Def: is used in diamond_import_1."},
33
33
  {"markdown": "- :Import2Def: is used in diamond_import_2."},
34
34
  {"markdown": '- :MainExecutableFile: of :App: should be called "hello_world.py".'},
35
35
  ],
36
- "test specs": [
36
+ "test reqs": [
37
37
  {"markdown": "- :CommonImportDef: is tested in diamond_import_common."},
38
38
  {"markdown": "- :Import1Def: is tested in diamond_import_1."},
39
39
  {"markdown": "- :Import2Def: is tested in diamond_import_2."},
tests/test_plainfile.py CHANGED
@@ -107,7 +107,7 @@ def test_process_acceptance_tests_no_sections_direct_frs(mock_process_single):
107
107
  plain_source_tree = {
108
108
  plain_spec.FUNCTIONAL_REQUIREMENTS: mock_frs_top_level,
109
109
  "definitions": MagicMock(name="TopLevelDefs"),
110
- "technical specs": MagicMock(name="TopLevelNFRs"),
110
+ "implementation reqs": MagicMock(name="TopLevelNFRs"),
111
111
  }
112
112
 
113
113
  process_acceptance_tests(plain_source_tree)
@@ -267,5 +267,5 @@ def test_psart_with_duplicate_acceptance_test_heading():
267
267
 
268
268
 
269
269
  def test_invalid_plain_file_extension():
270
- with pytest.raises(plain_file.InvalidPlainFileExtension):
270
+ with pytest.raises(PlainSyntaxError):
271
271
  plain_file.plain_file_parser("test.txt", [])
@@ -19,7 +19,7 @@ def test_regular_plain_source(get_test_data_path):
19
19
  )
20
20
  assert plain_sections == {
21
21
  "definitions": [],
22
- "technical specs": [
22
+ "implementation reqs": [
23
23
  {"markdown": "- First non-functional requirement."},
24
24
  {"markdown": "- Second non-functional requirement."},
25
25
  ],
@@ -36,7 +36,7 @@ def test_unknown_section():
36
36
  with pytest.raises(
37
37
  Exception,
38
38
  match=re.escape(
39
- "Syntax error at line 3: Invalid specification heading (`Unknown Section:`). Allowed headings: definitions, technical specs, test specs, functional specs, acceptance tests"
39
+ "Syntax error at line 3: Invalid specification heading (`Unknown Section:`). Allowed headings: definitions, implementation reqs, test reqs, functional specs, acceptance tests"
40
40
  ),
41
41
  ):
42
42
  plain_file.parse_plain_source(plain_source, {}, [], [], [])
@@ -76,7 +76,7 @@ def test_plain_file_parser_with_comments(get_test_data_path):
76
76
  )
77
77
  assert plain_sections == {
78
78
  "definitions": [],
79
- "technical specs": [{"markdown": "- Second non-functional requirement."}],
79
+ "implementation reqs": [{"markdown": "- Second non-functional requirement."}],
80
80
  "functional specs": [{"markdown": '- Display "hello, world"'}],
81
81
  }
82
82
 
@@ -88,7 +88,7 @@ def test_plain_file_parser_with_comments_indented(get_test_data_path):
88
88
  )
89
89
  assert plain_sections == {
90
90
  "definitions": [],
91
- "technical specs": [
91
+ "implementation reqs": [
92
92
  {"markdown": "- First non-functional requirement."},
93
93
  {"markdown": "- Second non-functional requirement."},
94
94
  ],
@@ -202,7 +202,7 @@ def test_indented_include_tags():
202
202
 
203
203
  - This is a definition.
204
204
 
205
- ***technical specs***
205
+ ***implementation reqs***
206
206
  - First non-functional requirement.
207
207
  - Second non-functional requirement.
208
208
 
@@ -230,7 +230,7 @@ def test_indented_include_tags():
230
230
 
231
231
  - This is a definition.
232
232
 
233
- ***technical specs***
233
+ ***implementation reqs***
234
234
  - First non-functional requirement.
235
235
  - Second non-functional requirement.
236
236
 
@@ -288,7 +288,7 @@ def test_code_variables(load_test_data, get_test_data_path):
288
288
 
289
289
  - :concept: is a concept.
290
290
 
291
- ***technical specs***
291
+ ***implementation reqs***
292
292
  - First non-functional requirement.
293
293
  - Second non-functional requirement.
294
294
 
@@ -303,7 +303,7 @@ def test_code_variables(load_test_data, get_test_data_path):
303
303
  _, plain_source, _ = plain_file.plain_file_parser("code_variables.plain", [get_test_data_path("data/templates")])
304
304
  expected_plain_source = {
305
305
  "definitions": [{"markdown": "- :concept: is a concept."}],
306
- "technical specs": [
306
+ "implementation reqs": [
307
307
  {"markdown": "- First non-functional requirement."},
308
308
  {"markdown": "- Second non-functional requirement."},
309
309
  ],
@@ -330,7 +330,7 @@ def test_code_variables(load_test_data, get_test_data_path):
330
330
 
331
331
  - :concept: is a concept.
332
332
 
333
- ***technical specs***
333
+ ***implementation reqs***
334
334
  - First non-functional requirement {keys[0]}.
335
335
  - Second non-functional requirement {keys[1]}.
336
336
 
@@ -345,7 +345,7 @@ def test_code_variables(load_test_data, get_test_data_path):
345
345
  _, plain_source, _ = plain_file.plain_file_parser("template_include.plain", [get_test_data_path("data/templates")])
346
346
  expected_plain_source = {
347
347
  "definitions": [{"markdown": "- :concept: is a concept."}],
348
- "technical specs": [
348
+ "implementation reqs": [
349
349
  {
350
350
  "markdown": "- First non-functional requirement {{ variable_name_1 }}.",
351
351
  "code_variables": [{"name": "variable_name_1", "value": "nice_1"}],
tests/test_plainspec.py CHANGED
@@ -61,7 +61,7 @@ def test_get_specifications_simple(get_test_data_path):
61
61
 
62
62
  assert specifications == {
63
63
  "definitions": [],
64
- "technical specs": ["- Simple non-functional requirement"],
65
- "test specs": [],
64
+ "implementation reqs": ["- Simple non-functional requirement"],
65
+ "test reqs": [],
66
66
  "functional specs": ["- Simple functional requirement"],
67
67
  }
tests/test_requires.py CHANGED
@@ -1,10 +1,11 @@
1
1
  import pytest
2
2
 
3
3
  import plain_file
4
+ from plain2code_exceptions import PlainSyntaxError
4
5
 
5
6
 
6
7
  def test_non_existent_require(get_test_data_path):
7
- with pytest.raises(Exception, match="Required module not found"):
8
+ with pytest.raises(PlainSyntaxError, match="Module does not exist"):
8
9
  plain_file.plain_file_parser("non_existent_require.plain", [get_test_data_path("data/requires")])
9
10
 
10
11