codeplain 0.2.2__py3-none-any.whl → 0.2.3__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.
- {codeplain-0.2.2.dist-info → codeplain-0.2.3.dist-info}/METADATA +15 -16
- {codeplain-0.2.2.dist-info → codeplain-0.2.3.dist-info}/RECORD +17 -6
- {codeplain-0.2.2.dist-info → codeplain-0.2.3.dist-info}/WHEEL +1 -2
- diff_utils.py +32 -0
- docs/generate_cli.py +20 -0
- examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +17 -0
- memory_management.py +97 -0
- tests/__init__.py +1 -0
- tests/conftest.py +34 -0
- tests/test_git_utils.py +458 -0
- tests/test_imports.py +42 -0
- tests/test_plainfile.py +271 -0
- tests/test_plainfileparser.py +532 -0
- tests/test_plainspec.py +67 -0
- tests/test_requires.py +27 -0
- codeplain-0.2.2.dist-info/top_level.txt +0 -41
- {codeplain-0.2.2.dist-info → codeplain-0.2.3.dist-info}/entry_points.txt +0 -0
- {codeplain-0.2.2.dist-info → codeplain-0.2.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,32 +1,31 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codeplain
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Transform plain language specifications into working code
|
|
5
|
+
License-File: LICENSE
|
|
5
6
|
Classifier: Environment :: Console
|
|
6
7
|
Classifier: Intended Audience :: Developers
|
|
7
8
|
Classifier: Operating System :: OS Independent
|
|
8
9
|
Classifier: Topic :: Software Development :: Code Generators
|
|
9
10
|
Requires-Python: >=3.11
|
|
10
|
-
|
|
11
|
-
License-File: LICENSE
|
|
12
|
-
Requires-Dist: python-liquid2==0.3.0
|
|
11
|
+
Requires-Dist: gitpython==3.1.42
|
|
13
12
|
Requires-Dist: mistletoe==1.3.0
|
|
13
|
+
Requires-Dist: networkx==3.6.1
|
|
14
|
+
Requires-Dist: python-frontmatter==1.1.0
|
|
15
|
+
Requires-Dist: python-liquid2==0.3.0
|
|
16
|
+
Requires-Dist: pyyaml==6.0.2
|
|
14
17
|
Requires-Dist: requests==2.32.3
|
|
18
|
+
Requires-Dist: rich==14.2.0
|
|
19
|
+
Requires-Dist: textual==1.0.0
|
|
15
20
|
Requires-Dist: tiktoken==0.12.0
|
|
16
|
-
Requires-Dist: PyYAML==6.0.2
|
|
17
|
-
Requires-Dist: gitpython==3.1.42
|
|
18
21
|
Requires-Dist: transitions==0.9.3
|
|
19
|
-
Requires-Dist: textual==1.0.0
|
|
20
|
-
Requires-Dist: rich==14.2.0
|
|
21
|
-
Requires-Dist: python-frontmatter==1.1.0
|
|
22
|
-
Requires-Dist: networkx==3.6.1
|
|
23
22
|
Provides-Extra: dev
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist: flake8==7.0.0; extra ==
|
|
26
|
-
Requires-Dist:
|
|
27
|
-
Requires-Dist:
|
|
28
|
-
Requires-Dist:
|
|
29
|
-
|
|
23
|
+
Requires-Dist: black==24.2.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: flake8==7.0.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: isort==5.13.2; extra == 'dev'
|
|
26
|
+
Requires-Dist: mypy==1.11.2; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest==8.3.5; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
30
29
|
|
|
31
30
|
# Codeplain plain2code renderer
|
|
32
31
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
codeplain_REST_api.py,sha256=qfzUw9v0-NKII4ibw3vqSBrCeU2WP4RcrrEti43F3zs,18400
|
|
2
2
|
concept_utils.py,sha256=vwSY4-FmxyqaDBxhntYzqG8t9pXvAWwiULP0DYQI32o,7905
|
|
3
|
+
diff_utils.py,sha256=AjiQlqo5pRos_8hVXZo5yBurl5BzSrTMGrQv4dCtRCg,1198
|
|
3
4
|
event_bus.py,sha256=sduIR3bgIbxAbLhwKd8Gx9YN9gzaeqy9-mNupS04aKw,1759
|
|
4
5
|
file_utils.py,sha256=4BIxzsteZQOaK-efkvQcoaIfYydsQNFR6elpsxJgXLQ,11591
|
|
5
6
|
git_utils.py,sha256=gTRps6RIzJJkyy9amaDxP38FPoxYulZViBWr9V0IPQg,12414
|
|
6
7
|
hash_key.py,sha256=lMKgKpOhPeC4UpFf9e7eCNK20FEaDsXTCJ8j3eCWidE,837
|
|
8
|
+
memory_management.py,sha256=ABrM6PhOsalP_PBq2hCazQvQX9C5rpPHhgT35l68RM4,4357
|
|
7
9
|
module_renderer.py,sha256=LLjLb34phSJlF2YblwGDy5HKWVdi9mo57rr7s-Hj3RA,6261
|
|
8
10
|
plain2code.py,sha256=cIxPkxfxZkPlen5RG5H_rvo22sSGYQ9PnqSlw3ECVkY,9841
|
|
9
11
|
plain2code_arguments.py,sha256=PdQjd3orklrtlEyz7-Qdz_m2SvjZtZp6dmbkqXgglSU,11826
|
|
@@ -20,9 +22,10 @@ plain_modules.py,sha256=iDqqamtix5KahMC_v-vfQ7yndugmqtBW1z6XxTB4x6w,4876
|
|
|
20
22
|
plain_spec.py,sha256=zC-VOb_UJOs8OxtEiwQJuonw7Lkmbi7YHyFvvCvUZNo,13529
|
|
21
23
|
spinner.py,sha256=Ro6Gd9Przf-whuHqPRY6HwI0T57yJjyNPbhDbigZKZE,2471
|
|
22
24
|
system_config.py,sha256=mgHLn-CRHLO9Y9vKyI_eFBreY_YhFad-ctZgBYp-rIg,1777
|
|
23
|
-
codeplain-0.2.2.dist-info/licenses/LICENSE,sha256=wsFi5dpbJurnRNfBj8q2RCcF3ryrmdRIfxc3lPcmc4c,1069
|
|
24
25
|
config/__init__.py,sha256=beYSsJWmBNHDP5rYmVDouqgEeP3t1lkkepbXJ-oq0F8,37
|
|
25
26
|
config/system_config.yaml,sha256=bB5Th5jxgXFyaIvceUPID1ReebMMXsyMibV4gtu9sWQ,1148
|
|
27
|
+
docs/generate_cli.py,sha256=xJmiihtdgqEDBYt_wBsRbniZvIfq7Q6tjAsi3SjoMJg,531
|
|
28
|
+
examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py,sha256=dwTowrHiVKKbrDv21v8xJC30Q57AXZkQasdGOO5JsBE,470
|
|
26
29
|
render_machine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
30
|
render_machine/code_renderer.py,sha256=jOoYivkZzCuGG947YlNPlvD1Dpd2xTWVK8pwfF_OqDU,2957
|
|
28
31
|
render_machine/conformance_test_helpers.py,sha256=6Ru7Dh24SLNIKWfz_sP5hE_EmWpvk6nfgN1T1yaCZus,2887
|
|
@@ -56,6 +59,14 @@ standard_template_library/golang-console-app-template.plain,sha256=M3gE1wZ6o_F-H
|
|
|
56
59
|
standard_template_library/python-console-app-template.plain,sha256=ofIJIkNXScGFTx2w8mY3lP4KmRml2GQv2EiEoXlbqqs,1005
|
|
57
60
|
standard_template_library/typescript-react-app-boilerplate.plain,sha256=6LFxhEOzWnDHdVpFj-XBTq6s4_2dy7LKV3lVkCzv8i4,114
|
|
58
61
|
standard_template_library/typescript-react-app-template.plain,sha256=SG1cBMVt1ncMRK4cOGOyVVj0MmsQTmF4MI67IBn1lFg,380
|
|
62
|
+
tests/__init__.py,sha256=Wk73Io62J15BtlLVIzxmASDWaaJkQLevS4BLK5LDAQg,16
|
|
63
|
+
tests/conftest.py,sha256=QZcp08htUlJGgmHDlRWFgsWXZ8o8IBWTD5QqJaUMlU8,790
|
|
64
|
+
tests/test_git_utils.py,sha256=Knc4R2ZkHYVj9iPFKhb0_ewaad_mxPrakOn6gpziHMc,13138
|
|
65
|
+
tests/test_imports.py,sha256=cdw7u93xNFD064sjwwEWy4oLHhJNlt1-DRDYhHjymFw,2078
|
|
66
|
+
tests/test_plainfile.py,sha256=N3f59hpxOO5zULdBtmXZM6KO2PKADoOL5d3WxNTUYXg,11106
|
|
67
|
+
tests/test_plainfileparser.py,sha256=9B9r2jEeUKDMhqb4TJEPK7aatYl1op1z92GDAD4fJ20,18685
|
|
68
|
+
tests/test_plainspec.py,sha256=ouS899oejStu8u1D3399y5NAxcKlNbLcinNoxZUp59M,2437
|
|
69
|
+
tests/test_requires.py,sha256=u8wY-UI7Ryat84htaI0yFXpl-PjX7G90EnMKM35S6No,1182
|
|
59
70
|
tui/__init__.py,sha256=_fy7FowY0RkWdn4kC7XV2jgvQPCj-2gE8fNUb-Mny0A,60
|
|
60
71
|
tui/components.py,sha256=l7f-jLk0sj9WM8z2IpaHksmSyytXe_bl2GBdHASoIg4,13901
|
|
61
72
|
tui/models.py,sha256=KMjlWubmPD41GA-BjgiqkaV9v7tLJ0fuWKBDPmZj4JA,1493
|
|
@@ -63,8 +74,8 @@ tui/plain2code_tui.py,sha256=7agVU0NnaCuF1LuOSEmjx-XfEOQ6HHr1HlWe_b1Tses,11695
|
|
|
63
74
|
tui/state_handlers.py,sha256=HbjgaV-9xGhp3E-3X114zOqPkeNcCjT-R1PbVRxVdso,12674
|
|
64
75
|
tui/styles.css,sha256=Umm2TLePmywizZGV4Nd8UezZRiK5pFyibYRbpRvGqbs,3056
|
|
65
76
|
tui/widget_helpers.py,sha256=VJorEM2PjRBzN-jIDmKJPolFgo2d8-2NmTumgC5xeNo,5229
|
|
66
|
-
codeplain-0.2.
|
|
67
|
-
codeplain-0.2.
|
|
68
|
-
codeplain-0.2.
|
|
69
|
-
codeplain-0.2.
|
|
70
|
-
codeplain-0.2.
|
|
77
|
+
codeplain-0.2.3.dist-info/METADATA,sha256=8GLBTQ7B-NEivsGSRPlOqsTvnFnvkAsF6qyjAAQ0yRc,4278
|
|
78
|
+
codeplain-0.2.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
79
|
+
codeplain-0.2.3.dist-info/entry_points.txt,sha256=oDZkBqu9WhtZApb_K6ia8-fn9aojwmAsgnKELceX5T4,46
|
|
80
|
+
codeplain-0.2.3.dist-info/licenses/LICENSE,sha256=wsFi5dpbJurnRNfBj8q2RCcF3ryrmdRIfxc3lPcmc4c,1069
|
|
81
|
+
codeplain-0.2.3.dist-info/RECORD,,
|
diff_utils.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from difflib import unified_diff
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_unified_diff(filename: str, existing_file_content: str, response_file_content: str) -> str:
|
|
5
|
+
diff = unified_diff(
|
|
6
|
+
existing_file_content.splitlines(keepends=True),
|
|
7
|
+
response_file_content.splitlines(keepends=True),
|
|
8
|
+
fromfile=filename,
|
|
9
|
+
tofile=filename,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
return "".join(diff)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_code_diff(response_files: dict[str, str], existing_files_content: dict[str, str]) -> dict[str, str]:
|
|
16
|
+
code_diff: dict[str, str] = {}
|
|
17
|
+
for file_name in response_files:
|
|
18
|
+
if file_name in existing_files_content and existing_files_content[file_name]:
|
|
19
|
+
if response_files[file_name]:
|
|
20
|
+
unified_diff_result = get_unified_diff(
|
|
21
|
+
file_name,
|
|
22
|
+
existing_files_content[file_name],
|
|
23
|
+
response_files[file_name],
|
|
24
|
+
)
|
|
25
|
+
if unified_diff_result and unified_diff_result.strip():
|
|
26
|
+
code_diff[file_name] = unified_diff_result
|
|
27
|
+
else:
|
|
28
|
+
code_diff[file_name] = f"File {file_name} was deleted."
|
|
29
|
+
else:
|
|
30
|
+
code_diff[file_name] = response_files[file_name]
|
|
31
|
+
|
|
32
|
+
return code_diff
|
docs/generate_cli.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from plain2code_arguments import create_parser
|
|
5
|
+
|
|
6
|
+
# Add the parent directory to the path so we can import plain2code_arguments
|
|
7
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Get the parser and generate help text
|
|
11
|
+
parser = create_parser()
|
|
12
|
+
help_text = parser.format_help()
|
|
13
|
+
|
|
14
|
+
# Create markdown
|
|
15
|
+
md = "# Plain2Code CLI Reference\n\n```text\n" + help_text + "\n```"
|
|
16
|
+
|
|
17
|
+
# Run generate_cli.py in the docs folder
|
|
18
|
+
|
|
19
|
+
with open("plain2code_cli.md", "w", encoding="utf-8") as f:
|
|
20
|
+
f.write(md)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestHelloWorld(unittest.TestCase):
|
|
8
|
+
def test_hello_world_output(self):
|
|
9
|
+
# Run the hello_world.py script and capture its output
|
|
10
|
+
result = subprocess.run(["python3", "hello_world.py"], capture_output=True, text=True)
|
|
11
|
+
|
|
12
|
+
# Check if the output matches the expected string
|
|
13
|
+
self.assertEqual(result.stdout.strip(), "hello, world")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
if __name__ == "__main__":
|
|
17
|
+
unittest.main()
|
memory_management.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import file_utils
|
|
4
|
+
from plain2code_console import console
|
|
5
|
+
from plain_modules import CODEPLAIN_MEMORY_SUBFOLDER
|
|
6
|
+
from render_machine.implementation_code_helpers import ImplementationCodeHelpers
|
|
7
|
+
from render_machine.render_context import RenderContext
|
|
8
|
+
|
|
9
|
+
CONFORMANCE_TESTS_SUCCESS_EXIT_CODE = 0
|
|
10
|
+
CONFORMANCE_TEST_MEMORY_SUBFOLDER = "conformance_test_memory"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MemoryManager:
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
def fetch_memory_files(memory_folder: str):
|
|
17
|
+
"""Fetch memory files from memory_folder/conformance_test_memory."""
|
|
18
|
+
memory_path = os.path.join(memory_folder, CONFORMANCE_TEST_MEMORY_SUBFOLDER)
|
|
19
|
+
if not os.path.exists(memory_path):
|
|
20
|
+
return {}, {}
|
|
21
|
+
memory_files = file_utils.list_all_text_files(memory_path)
|
|
22
|
+
memory_files_content = file_utils.get_existing_files_content(memory_path, memory_files)
|
|
23
|
+
return memory_files, memory_files_content
|
|
24
|
+
|
|
25
|
+
def __init__(self, codeplain_api, module_build_folder: str):
|
|
26
|
+
self.codeplain_api = codeplain_api
|
|
27
|
+
self.memory_folder = os.path.join(module_build_folder, CODEPLAIN_MEMORY_SUBFOLDER)
|
|
28
|
+
|
|
29
|
+
def create_conformance_tests_memory(
|
|
30
|
+
self, render_context: RenderContext, exit_code: int, conformance_tests_issue: str
|
|
31
|
+
):
|
|
32
|
+
|
|
33
|
+
current_conformance_tests_issue_frid = render_context.conformance_tests_running_context.current_testing_frid
|
|
34
|
+
old_conformance_tests_issue_frid = (
|
|
35
|
+
render_context.conformance_tests_running_context.previous_conformance_tests_issue_frid
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
old_conformance_tests_issue = (
|
|
39
|
+
render_context.conformance_tests_running_context.previous_conformance_tests_issue_old
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
is_first_time_running_conformance_tests = (
|
|
43
|
+
old_conformance_tests_issue_frid is None or old_conformance_tests_issue_frid == ""
|
|
44
|
+
)
|
|
45
|
+
is_same_frid_as_previous_failing_test = current_conformance_tests_issue_frid == old_conformance_tests_issue_frid
|
|
46
|
+
is_conformance_test_failed = exit_code != CONFORMANCE_TESTS_SUCCESS_EXIT_CODE
|
|
47
|
+
|
|
48
|
+
should_create_memory = not is_first_time_running_conformance_tests and (
|
|
49
|
+
is_same_frid_as_previous_failing_test or is_conformance_test_failed
|
|
50
|
+
)
|
|
51
|
+
code_diff_files = render_context.conformance_tests_running_context.code_diff_files
|
|
52
|
+
|
|
53
|
+
if not should_create_memory or code_diff_files is None:
|
|
54
|
+
console.info(
|
|
55
|
+
"Skipping creation of conformance test memory because the conditions for creating memories are not met."
|
|
56
|
+
)
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
existing_files, existing_files_content = ImplementationCodeHelpers.fetch_existing_files(
|
|
60
|
+
render_context.build_folder
|
|
61
|
+
)
|
|
62
|
+
_, memory_files_content = MemoryManager.fetch_memory_files(self.memory_folder)
|
|
63
|
+
|
|
64
|
+
conformance_tests_folder_name = (
|
|
65
|
+
render_context.conformance_tests_running_context.get_current_conformance_test_folder_name()
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
(
|
|
69
|
+
_,
|
|
70
|
+
existing_conformance_test_files_content,
|
|
71
|
+
) = render_context.conformance_tests.fetch_existing_conformance_test_files(
|
|
72
|
+
render_context.module_name,
|
|
73
|
+
render_context.required_modules,
|
|
74
|
+
render_context.conformance_tests_running_context.current_testing_module_name,
|
|
75
|
+
conformance_tests_folder_name,
|
|
76
|
+
)
|
|
77
|
+
acceptance_tests = render_context.conformance_tests_running_context.get_current_acceptance_tests()
|
|
78
|
+
|
|
79
|
+
response_files = render_context.codeplain_api.create_conformance_test_memory(
|
|
80
|
+
render_context.frid_context.frid,
|
|
81
|
+
render_context.plain_source_tree,
|
|
82
|
+
render_context.frid_context.linked_resources,
|
|
83
|
+
existing_files_content,
|
|
84
|
+
memory_files_content,
|
|
85
|
+
render_context.module_name,
|
|
86
|
+
render_context.get_required_modules_functionalities(),
|
|
87
|
+
code_diff_files,
|
|
88
|
+
existing_conformance_test_files_content,
|
|
89
|
+
acceptance_tests,
|
|
90
|
+
conformance_tests_issue,
|
|
91
|
+
conformance_tests_folder_name,
|
|
92
|
+
old_conformance_tests_issue,
|
|
93
|
+
run_state=render_context.run_state,
|
|
94
|
+
)
|
|
95
|
+
if len(response_files) > 0:
|
|
96
|
+
memory_folder_path = os.path.join(self.memory_folder, CONFORMANCE_TEST_MEMORY_SUBFOLDER)
|
|
97
|
+
file_utils.store_response_files(memory_folder_path, response_files, existing_files)
|
tests/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Tests package
|
tests/conftest.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
os.environ["MASTER_KEY"] = "test-master-key"
|
|
6
|
+
os.environ["GOOGLE_API_KEY"] = "test-google-api-key"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.fixture
|
|
10
|
+
def test_data_path():
|
|
11
|
+
"""Returns the path to the test data directory."""
|
|
12
|
+
return os.path.dirname(__file__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture
|
|
16
|
+
def load_test_data(test_data_path):
|
|
17
|
+
"""Returns a function to load test data files."""
|
|
18
|
+
|
|
19
|
+
def _load(file_name):
|
|
20
|
+
file_path = os.path.join(test_data_path, file_name)
|
|
21
|
+
with open(file_path, "r") as file:
|
|
22
|
+
return file.read()
|
|
23
|
+
|
|
24
|
+
return _load
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.fixture
|
|
28
|
+
def get_test_data_path(test_data_path):
|
|
29
|
+
"""Returns a function to get the path to a test data subfolder."""
|
|
30
|
+
|
|
31
|
+
def _get_path(subfolder_name):
|
|
32
|
+
return os.path.join(test_data_path, subfolder_name)
|
|
33
|
+
|
|
34
|
+
return _get_path
|