codeplain 0.3.0__py3-none-any.whl → 0.3.1__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.
- _version.py +1 -1
- cli_output/__init__.py +7 -0
- cli_output/dry_run.py +35 -0
- cli_output/render_summary.py +27 -0
- cli_output/status.py +160 -0
- {codeplain-0.3.0.dist-info → codeplain-0.3.1.dist-info}/METADATA +29 -4
- {codeplain-0.3.0.dist-info → codeplain-0.3.1.dist-info}/RECORD +39 -31
- codeplain_REST_api.py +8 -0
- memory_management.py +2 -2
- module_renderer.py +2 -5
- partial_rendering.py +10 -6
- plain2code.py +56 -41
- plain2code_arguments.py +32 -2
- plain2code_console.py +2 -0
- plain2code_logger.py +37 -3
- plain_modules.py +5 -6
- render_machine/actions/fix_conformance_test.py +27 -29
- render_machine/actions/fix_unit_tests.py +2 -6
- render_machine/actions/prepare_repositories.py +3 -6
- render_machine/actions/prepare_testing_environment.py +3 -5
- render_machine/actions/refactor_code.py +11 -15
- render_machine/actions/render_conformance_tests.py +34 -39
- render_machine/actions/render_functional_requirement.py +15 -20
- render_machine/actions/run_conformance_tests.py +7 -9
- render_machine/actions/run_unit_tests.py +3 -5
- render_machine/code_renderer.py +1 -1
- render_machine/conformance_tests.py +9 -13
- render_machine/render_context.py +5 -13
- render_machine/render_utils.py +42 -47
- render_machine/state_machine_config.py +39 -33
- tests/e2e/conftest.py +145 -0
- tests/e2e/test_hello_world_python.py +37 -0
- tests/e2e/test_hello_world_python_windows.py +64 -0
- tests/test_cli_output.py +411 -0
- tui/plain2code_tui.py +11 -0
- tui/plain_module_render_choice_tui.py +27 -9
- {codeplain-0.3.0.dist-info → codeplain-0.3.1.dist-info}/WHEEL +0 -0
- {codeplain-0.3.0.dist-info → codeplain-0.3.1.dist-info}/entry_points.txt +0 -0
- {codeplain-0.3.0.dist-info → codeplain-0.3.1.dist-info}/licenses/LICENSE +0 -0
_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.3.
|
|
1
|
+
__version__ = "0.3.1"
|
cli_output/__init__.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""CLI output formatting for non-interactive display."""
|
|
2
|
+
|
|
3
|
+
from cli_output.dry_run import print_dry_run_output
|
|
4
|
+
from cli_output.render_summary import print_exit_summary
|
|
5
|
+
from cli_output.status import print_status
|
|
6
|
+
|
|
7
|
+
__all__ = ["print_dry_run_output", "print_exit_summary", "print_status"]
|
cli_output/dry_run.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Dry run output display for --dry-run flag."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import plain_spec
|
|
6
|
+
from plain2code_console import console
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def print_dry_run_output(plain_source_tree: dict, render_range: Optional[list[str]]):
|
|
10
|
+
"""Print dry run output showing what would be rendered."""
|
|
11
|
+
frid = plain_spec.get_first_frid(plain_source_tree)
|
|
12
|
+
|
|
13
|
+
while frid is not None:
|
|
14
|
+
is_inside_range = render_range is None or frid in render_range
|
|
15
|
+
|
|
16
|
+
if is_inside_range:
|
|
17
|
+
specifications, _ = plain_spec.get_specifications_for_frid(plain_source_tree, frid)
|
|
18
|
+
functional_requirement_text = specifications[plain_spec.FUNCTIONAL_REQUIREMENTS][-1]
|
|
19
|
+
console.info(
|
|
20
|
+
"-------------------------------------\n"
|
|
21
|
+
f"Rendering functionality {frid}:\n"
|
|
22
|
+
f"{functional_requirement_text}\n"
|
|
23
|
+
"-------------------------------------\n"
|
|
24
|
+
)
|
|
25
|
+
if plain_spec.ACCEPTANCE_TESTS in specifications:
|
|
26
|
+
for i, acceptance_test in enumerate(specifications[plain_spec.ACCEPTANCE_TESTS], 1):
|
|
27
|
+
console.info(f"Generating acceptance test #{i}:\n\n{acceptance_test}\n")
|
|
28
|
+
else:
|
|
29
|
+
console.info(
|
|
30
|
+
"-------------------------------------\n"
|
|
31
|
+
f"Skipping rendering iteration: {frid}\n"
|
|
32
|
+
"-------------------------------------"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
frid = plain_spec.get_next_frid(plain_source_tree, frid)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Render completion summary display."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from plain2code_console import console
|
|
6
|
+
from plain2code_state import RunState
|
|
7
|
+
from plain2code_utils import format_duration_hms
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def print_exit_summary(
|
|
11
|
+
run_state: RunState,
|
|
12
|
+
spec_filename: str,
|
|
13
|
+
error_message: Optional[str] = None,
|
|
14
|
+
) -> None:
|
|
15
|
+
"""Print render outcome after the TUI exits (terminal restored)."""
|
|
16
|
+
console.quiet = False
|
|
17
|
+
|
|
18
|
+
msg = "\n[#79FC96]✓ rendering completed\n\n" if run_state.render_succeeded else "[#FF6B6B]✗ rendering failed\n\n"
|
|
19
|
+
msg += f" [#8E8F91]render id:\t\t\t[#FFFFFF]{run_state.render_id}\n"
|
|
20
|
+
msg += f" [#8E8F91]input file:\t\t\t[#FFFFFF]{spec_filename}\n"
|
|
21
|
+
msg += f" [#8E8F91]generated code folder:\t[#FFFFFF]{run_state.render_generated_code_path or '-'}\n\n"
|
|
22
|
+
msg += f"[#8E8F91]functionalities [#FFFFFF]{run_state.rendered_functionalities} [#8E8F91]used credits [#FFFFFF]{run_state.rendered_functionalities} [#8E8F91]render time [#FFFFFF]{format_duration_hms(run_state.render_time_accumulated)}\n"
|
|
23
|
+
console.print(msg)
|
|
24
|
+
|
|
25
|
+
if not run_state.render_succeeded and error_message:
|
|
26
|
+
console.error(error_message)
|
|
27
|
+
console.quiet = True
|
cli_output/status.py
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Status display for --status flag."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import codeplain_REST_api as codeplain_api
|
|
7
|
+
from plain2code_console import console
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _create_progress_bar(remaining: int, total: int, width: int = 30) -> str:
|
|
11
|
+
"""Create a Unicode progress bar."""
|
|
12
|
+
if total == 0:
|
|
13
|
+
filled = 0
|
|
14
|
+
else:
|
|
15
|
+
filled = int((remaining / total) * width)
|
|
16
|
+
|
|
17
|
+
empty = width - filled
|
|
18
|
+
return "█" * filled + "░" * empty
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _display_credit_line(plan_credits: dict) -> None:
|
|
22
|
+
"""Display a plan credit line with progress bar."""
|
|
23
|
+
plan_type = plan_credits["type"]
|
|
24
|
+
remaining = plan_credits["remaining"]
|
|
25
|
+
total = plan_credits["total"]
|
|
26
|
+
period_end = plan_credits["period_end"]
|
|
27
|
+
|
|
28
|
+
# Parse ISO-8601 timestamp and format as "Jun 1, 2026"
|
|
29
|
+
# Handle both with and without timezone info
|
|
30
|
+
dt_str = period_end.replace("Z", "+00:00")
|
|
31
|
+
dt = datetime.fromisoformat(dt_str)
|
|
32
|
+
# If naive datetime, assume UTC
|
|
33
|
+
if dt.tzinfo is None:
|
|
34
|
+
dt = dt.replace(tzinfo=timezone.utc)
|
|
35
|
+
formatted_date = dt.strftime("%b %-d, %Y")
|
|
36
|
+
|
|
37
|
+
# Check if expired
|
|
38
|
+
now = datetime.now(timezone.utc)
|
|
39
|
+
is_expired = dt < now
|
|
40
|
+
|
|
41
|
+
# Create progress bar (30 chars wide)
|
|
42
|
+
bar = _create_progress_bar(remaining, total, width=30)
|
|
43
|
+
|
|
44
|
+
# Format plan type label
|
|
45
|
+
plan_label = "Free trial" if plan_type == "free" else plan_type.upper() + " plan"
|
|
46
|
+
|
|
47
|
+
if is_expired:
|
|
48
|
+
console.print(f" {plan_label:10} {bar} expired {formatted_date}")
|
|
49
|
+
else:
|
|
50
|
+
console.print(f" {plan_label:10} {bar} {remaining:2} of {total} remaining expires {formatted_date}")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _display_purchased_credit_line(bucket: dict) -> None:
|
|
54
|
+
"""Display a purchased credit line with progress bar."""
|
|
55
|
+
remaining = bucket["remaining"]
|
|
56
|
+
total = bucket["total"]
|
|
57
|
+
expiry_date = bucket["expiry_date"]
|
|
58
|
+
|
|
59
|
+
# Parse ISO-8601 timestamp and handle both with and without timezone info
|
|
60
|
+
dt_str = expiry_date.replace("Z", "+00:00")
|
|
61
|
+
dt = datetime.fromisoformat(dt_str)
|
|
62
|
+
# If naive datetime, assume UTC
|
|
63
|
+
if dt.tzinfo is None:
|
|
64
|
+
dt = dt.replace(tzinfo=timezone.utc)
|
|
65
|
+
formatted_date = dt.strftime("%b %-d, %Y")
|
|
66
|
+
|
|
67
|
+
# Check if expired
|
|
68
|
+
now = datetime.now(timezone.utc)
|
|
69
|
+
is_expired = dt < now
|
|
70
|
+
|
|
71
|
+
bar = _create_progress_bar(remaining, total, width=30)
|
|
72
|
+
|
|
73
|
+
if is_expired:
|
|
74
|
+
console.print(f" Purchased {bar} expired {formatted_date}")
|
|
75
|
+
else:
|
|
76
|
+
console.print(f" Purchased {bar} {remaining:2} of {total} remaining expires {formatted_date}")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _display_status_message(plan_credits: Optional[dict], purchased_credits: list) -> None:
|
|
80
|
+
"""Display appropriate status message based on credit state."""
|
|
81
|
+
has_remaining = False
|
|
82
|
+
|
|
83
|
+
# Check if plan credits have remaining balance and are not expired
|
|
84
|
+
if plan_credits:
|
|
85
|
+
remaining = plan_credits["remaining"]
|
|
86
|
+
dt_str = plan_credits["period_end"].replace("Z", "+00:00")
|
|
87
|
+
period_end = datetime.fromisoformat(dt_str)
|
|
88
|
+
# If naive datetime, assume UTC
|
|
89
|
+
if period_end.tzinfo is None:
|
|
90
|
+
period_end = period_end.replace(tzinfo=timezone.utc)
|
|
91
|
+
now = datetime.now(timezone.utc)
|
|
92
|
+
|
|
93
|
+
if remaining > 0 and period_end > now:
|
|
94
|
+
has_remaining = True
|
|
95
|
+
|
|
96
|
+
# Check if any purchased credits have remaining balance and not expired
|
|
97
|
+
for bucket in purchased_credits:
|
|
98
|
+
dt_str = bucket["expiry_date"].replace("Z", "+00:00")
|
|
99
|
+
expiry_date = datetime.fromisoformat(dt_str)
|
|
100
|
+
# If naive datetime, assume UTC
|
|
101
|
+
if expiry_date.tzinfo is None:
|
|
102
|
+
expiry_date = expiry_date.replace(tzinfo=timezone.utc)
|
|
103
|
+
now = datetime.now(timezone.utc)
|
|
104
|
+
|
|
105
|
+
if bucket["remaining"] > 0 and expiry_date > now:
|
|
106
|
+
has_remaining = True
|
|
107
|
+
break
|
|
108
|
+
|
|
109
|
+
if not has_remaining:
|
|
110
|
+
console.print("\nNo rendering credits remaining. Upgrade to continue rendering.")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def print_status(api_key: str, api_url: str, client_version: str) -> None:
|
|
114
|
+
"""Display account status including user info and rendering credits."""
|
|
115
|
+
codeplainAPI = codeplain_api.CodeplainAPI(api_key, console)
|
|
116
|
+
codeplainAPI.api_url = api_url
|
|
117
|
+
|
|
118
|
+
# First check client version
|
|
119
|
+
version_check = codeplainAPI.connection_check(client_version)
|
|
120
|
+
client_version_valid = version_check.get("client_version_valid", False)
|
|
121
|
+
min_version = version_check.get("min_client_version", "unknown")
|
|
122
|
+
|
|
123
|
+
response = codeplainAPI.status()
|
|
124
|
+
|
|
125
|
+
user = response["user"]
|
|
126
|
+
api_key_label = response["api_key_label"]
|
|
127
|
+
org_owner = response.get("organization_owner_email")
|
|
128
|
+
plan_credits = response.get("plan_credits")
|
|
129
|
+
purchased_credits = response.get("purchased_credits", [])
|
|
130
|
+
|
|
131
|
+
# Display header information
|
|
132
|
+
if client_version_valid:
|
|
133
|
+
console.print(f"Version: {client_version}")
|
|
134
|
+
else:
|
|
135
|
+
from plain2code_console import Plain2CodeConsole
|
|
136
|
+
|
|
137
|
+
console.print(
|
|
138
|
+
f"Version: {client_version} (outdated — minimum required: {min_version})",
|
|
139
|
+
style=Plain2CodeConsole.ERROR_STYLE,
|
|
140
|
+
)
|
|
141
|
+
console.print("To update, run: uv tool upgrade codeplain\n", style=Plain2CodeConsole.ERROR_STYLE)
|
|
142
|
+
console.print(f"Name: {user['first_name']} {user['last_name']}")
|
|
143
|
+
console.print(f"User email: {user['email']}")
|
|
144
|
+
console.print(f"Organization owner: {org_owner or 'N/A'}")
|
|
145
|
+
console.print(f"API key label: {api_key_label}\n")
|
|
146
|
+
|
|
147
|
+
# Display rendering credits section
|
|
148
|
+
console.print("Rendering credits:")
|
|
149
|
+
|
|
150
|
+
# Display plan credits (free trial or subscription)
|
|
151
|
+
if plan_credits:
|
|
152
|
+
_display_credit_line(plan_credits)
|
|
153
|
+
|
|
154
|
+
# Display purchased credits
|
|
155
|
+
for bucket in purchased_credits:
|
|
156
|
+
_display_purchased_credit_line(bucket)
|
|
157
|
+
|
|
158
|
+
# Display status messages and management link
|
|
159
|
+
_display_status_message(plan_credits, purchased_credits)
|
|
160
|
+
console.print("\nTo manage your plan navigate to https://platform.codeplain.ai/plans")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codeplain
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Transform plain language specifications into working code
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Classifier: Environment :: Console
|
|
@@ -11,17 +11,17 @@ Requires-Python: ==3.11
|
|
|
11
11
|
Requires-Dist: gitpython==3.1.50
|
|
12
12
|
Requires-Dist: mistletoe==1.3.0
|
|
13
13
|
Requires-Dist: networkx==3.6.1
|
|
14
|
-
Requires-Dist: python-frontmatter==1.
|
|
14
|
+
Requires-Dist: python-frontmatter==1.3.0
|
|
15
15
|
Requires-Dist: python-liquid2==0.3.0
|
|
16
16
|
Requires-Dist: pyyaml==6.0.3
|
|
17
17
|
Requires-Dist: requests==2.34.0
|
|
18
|
-
Requires-Dist: rich==
|
|
18
|
+
Requires-Dist: rich==15.0.0
|
|
19
19
|
Requires-Dist: textual>=7.5.0
|
|
20
20
|
Requires-Dist: tiktoken==0.12.0
|
|
21
21
|
Requires-Dist: transitions==0.9.3
|
|
22
22
|
Provides-Extra: dev
|
|
23
23
|
Requires-Dist: black==26.3.1; extra == 'dev'
|
|
24
|
-
Requires-Dist: flake8==7.
|
|
24
|
+
Requires-Dist: flake8==7.3.0; extra == 'dev'
|
|
25
25
|
Requires-Dist: isort==5.13.2; extra == 'dev'
|
|
26
26
|
Requires-Dist: mypy==1.11.2; extra == 'dev'
|
|
27
27
|
Requires-Dist: pytest==8.3.5; extra == 'dev'
|
|
@@ -105,6 +105,31 @@ After completing the installation steps above, you can immediately test the syst
|
|
|
105
105
|
python hello_world.py
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
+
## Releasing
|
|
109
|
+
|
|
110
|
+
Releases are built and published with [uv](https://docs.astral.sh/uv/). The version is read from `_version.py`.
|
|
111
|
+
|
|
112
|
+
1. Bump the version in `_version.py` and commit/tag (`git tag v<version>`).
|
|
113
|
+
2. Build the distributions:
|
|
114
|
+
```bash
|
|
115
|
+
uv build
|
|
116
|
+
```
|
|
117
|
+
This produces `dist/codeplain-<version>-py3-none-any.whl` and `dist/codeplain-<version>.tar.gz`.
|
|
118
|
+
3. (Optional) Smoke-test the wheel:
|
|
119
|
+
```bash
|
|
120
|
+
uv run --with dist/codeplain-<version>-py3-none-any.whl --no-project -- codeplain --status
|
|
121
|
+
```
|
|
122
|
+
4. (Optional) Publish to TestPyPI first:
|
|
123
|
+
```bash
|
|
124
|
+
uv publish --publish-url https://test.pypi.org/legacy/ dist/codeplain-<version>*
|
|
125
|
+
```
|
|
126
|
+
5. Publish to PyPI:
|
|
127
|
+
```bash
|
|
128
|
+
uv publish dist/codeplain-<version>*
|
|
129
|
+
```
|
|
130
|
+
Authenticate with `UV_PUBLISH_TOKEN=pypi-...` (recommended), `--token pypi-...`, or `--username __token__ --password pypi-...`.
|
|
131
|
+
6. Push the tag: `git push origin v<version>`.
|
|
132
|
+
|
|
108
133
|
## Additional Resources
|
|
109
134
|
|
|
110
135
|
### Examples and Sample Projects
|
|
@@ -1,41 +1,45 @@
|
|
|
1
|
-
_version.py,sha256=
|
|
2
|
-
codeplain_REST_api.py,sha256=
|
|
1
|
+
_version.py,sha256=r4xAFihOf72W9TD-lpMi6ntWSTKTP2SlzKP1ytkjRbI,22
|
|
2
|
+
codeplain_REST_api.py,sha256=5O7-PgdxDZZZ95tq4tDyaYeouQdwedU3P6KBeJ0krwo,21550
|
|
3
3
|
concept_utils.py,sha256=VLHur80-XSJTveClLiHb-CMuqsXd8sIQAr0Ehe1Hid0,7930
|
|
4
4
|
diff_utils.py,sha256=AjiQlqo5pRos_8hVXZo5yBurl5BzSrTMGrQv4dCtRCg,1198
|
|
5
5
|
event_bus.py,sha256=g5XLwRfjrvTIcB6urjREuCJzZj5TA93hy8lKXLGXuCE,650
|
|
6
6
|
file_utils.py,sha256=eO_SHwyjJlkwT3wTlIjIEQ3t8y3k0i-fWKAn5_1SMkY,12597
|
|
7
7
|
git_utils.py,sha256=LQQnL5DAFpH5fDBQgUZX2WfjWY4YC5OEGBPIXryTmnY,16896
|
|
8
8
|
hash_key.py,sha256=lMKgKpOhPeC4UpFf9e7eCNK20FEaDsXTCJ8j3eCWidE,837
|
|
9
|
-
memory_management.py,sha256=
|
|
10
|
-
module_renderer.py,sha256=
|
|
11
|
-
partial_rendering.py,sha256=
|
|
12
|
-
plain2code.py,sha256=
|
|
13
|
-
plain2code_arguments.py,sha256=
|
|
14
|
-
plain2code_console.py,sha256=
|
|
9
|
+
memory_management.py,sha256=nHNudgaOqp5UGkIMi62TRCc2nUeFOM0w-I1FfxBFaQE,6120
|
|
10
|
+
module_renderer.py,sha256=pXMXKKGMhUwLLlSxppE_hpZlwpJ3WSHSfR9FQxt6rSI,6860
|
|
11
|
+
partial_rendering.py,sha256=prWEJo9m1TbF7SKzpNInbcefyTF0o3oXE7Qf1l4SmBs,8409
|
|
12
|
+
plain2code.py,sha256=eYmXKAsdvladjoG6ujLWpZCXIOq5FsIabBkCwZd2tDs,13767
|
|
13
|
+
plain2code_arguments.py,sha256=J05NwaY-O04rIWVF2yIXysNB_ofZS0wJFn0u1WaCCSA,15399
|
|
14
|
+
plain2code_console.py,sha256=YdE-Kz9qRAzIIAg7aYA1bnXRcwy_aTpbFtkR2zHbd-I,4918
|
|
15
15
|
plain2code_events.py,sha256=AM8KJS68uiVXRMLt861KaGhs2H4yzujlMB_xiYPfHQc,1478
|
|
16
16
|
plain2code_exceptions.py,sha256=g3wMOnjpQlk2pdKRvVarnuh9BlOsRV2AKm_CoNidmH4,1629
|
|
17
|
-
plain2code_logger.py,sha256=
|
|
17
|
+
plain2code_logger.py,sha256=kNKIfkS6Ydtut7Ptw5jmv5bFPgXlxB-_Ds5nd-j4d9o,4609
|
|
18
18
|
plain2code_nodes.py,sha256=IwjQqJxRSJKgP6eEnkYGy3VQHIyoazgkFxAEkxkjfJ8,4426
|
|
19
19
|
plain2code_read_config.py,sha256=D5CxnmTRjddupecWvstcUm0kIJWWzq5-Zmk6sU0wbIg,2235
|
|
20
20
|
plain2code_state.py,sha256=UN3iD3rfJkGK4QQx4RxueQrCy9ngHqExtzxiSEgrW2E,2117
|
|
21
21
|
plain2code_utils.py,sha256=CLvysMiwChAVaKdqJjkUUlDCQ8dGIFPz1NG7cLbFZuI,2236
|
|
22
22
|
plain_file.py,sha256=hiyFdB548sYG9T2NILhGM63dcSgbRzy_y5atX5YabUg,29172
|
|
23
|
-
plain_modules.py,sha256=
|
|
23
|
+
plain_modules.py,sha256=QwSjX2SC62bQBR-UZM8NSzlepwEs3uSPXgiCqdjoWy4,14281
|
|
24
24
|
plain_spec.py,sha256=E2Yp2eXMExE7kx7GPQ7v9boHN8XhFUcqprn1DGMaFMs,15669
|
|
25
25
|
system_config.py,sha256=DMyfiq_uzxWH_uXz5vMWNHkcRFPkIA-M8nr64SeVhPo,1350
|
|
26
|
+
cli_output/__init__.py,sha256=MBKl0YbVpWE-tBa3V5_aVbB7vbaqlIK2NsHTjRUZqis,284
|
|
27
|
+
cli_output/dry_run.py,sha256=6NKhNWPtD0CBK_QHSsSqIKLTzibTwxS9d8ltP9d1bgU,1473
|
|
28
|
+
cli_output/render_summary.py,sha256=X9wHvyaQa8niO87GR2gnzI0rwF6XU55OktwzgmMpJaQ,1186
|
|
29
|
+
cli_output/status.py,sha256=5jr9XFU1MWD3pN404qw7SNYCGdvqfA9j4xv9z1tZG4s,5890
|
|
26
30
|
config/__init__.py,sha256=beYSsJWmBNHDP5rYmVDouqgEeP3t1lkkepbXJ-oq0F8,37
|
|
27
31
|
config/system_config.yaml,sha256=of5R9vukSohU9AlkGJOcAVQA1UJgxYmDy6islU6iFuE,508
|
|
28
32
|
docs/generate_cli.py,sha256=0FHVhICbM8g7ahdInTNih3hNKpty1wbV5rdGECMJj48,656
|
|
29
33
|
examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py,sha256=dwTowrHiVKKbrDv21v8xJC30Q57AXZkQasdGOO5JsBE,470
|
|
30
34
|
render_machine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
-
render_machine/code_renderer.py,sha256=
|
|
35
|
+
render_machine/code_renderer.py,sha256=bLdoZcWaLGvuR0GygnWY9y9kycGySD-IEWY5DFGcGsg,3781
|
|
32
36
|
render_machine/conformance_test_helpers.py,sha256=6Ru7Dh24SLNIKWfz_sP5hE_EmWpvk6nfgN1T1yaCZus,2887
|
|
33
|
-
render_machine/conformance_tests.py,sha256=
|
|
37
|
+
render_machine/conformance_tests.py,sha256=MeEveEGJTClLGxWw04P4TR6U9kX9Qgz9qtxNrB9a8QI,7085
|
|
34
38
|
render_machine/implementation_code_helpers.py,sha256=LdHNLoKgVtrDaGH2APX8C9vjNjLBUhu2V7OAaJvm4rM,2009
|
|
35
|
-
render_machine/render_context.py,sha256=
|
|
39
|
+
render_machine/render_context.py,sha256=ke2HWKNTh3QoPLv_T3b-8ohrM2mzqsCtlP3lsk011uA,28921
|
|
36
40
|
render_machine/render_types.py,sha256=iqRd9MyrRnXasoA8rvssZbCN66BbVCVXH5uFA8QJVXY,9222
|
|
37
|
-
render_machine/render_utils.py,sha256=
|
|
38
|
-
render_machine/state_machine_config.py,sha256=
|
|
41
|
+
render_machine/render_utils.py,sha256=ao0e64VSOGYfb8hwJXIZlbqer5HjNMYJWHlLDoHnJyc,9123
|
|
42
|
+
render_machine/state_machine_config.py,sha256=uqrU9Pu4cAKxu_-e1eiuUQK-tZWxZko0U0Bfvl67v_c,28813
|
|
39
43
|
render_machine/states.py,sha256=niFXqayyA_rezCrlzo0hYeHAruErcPzQVF-BeIBGnL8,1968
|
|
40
44
|
render_machine/triggers.py,sha256=o1N5c9xC7fsKY6ZaWcWBtALT8i1acSSharAXKAqBu8E,1285
|
|
41
45
|
render_machine/actions/analyze_specification_ambiguity.py,sha256=SykZAozGvr1jySxbpKCgt11nMpZhOK0sN-J66M42T5Y,2847
|
|
@@ -45,15 +49,15 @@ render_machine/actions/commit_implementation_code_changes.py,sha256=yi51oAArLCgW
|
|
|
45
49
|
render_machine/actions/create_dist.py,sha256=xMPPyws7swVkaUSQg3dwMGScCi1BuII9y2C_XSP0N80,1067
|
|
46
50
|
render_machine/actions/exit_with_error.py,sha256=-LkQsFhmV-Nr741APTx38dqu473b6OSiIvKayFFsXxI,1270
|
|
47
51
|
render_machine/actions/finish_functional_requirement.py,sha256=tj9CzuxuHcbR-2-jMLcAM0gOAcbWpMLg9HIiyngI6gU,739
|
|
48
|
-
render_machine/actions/fix_conformance_test.py,sha256=
|
|
49
|
-
render_machine/actions/fix_unit_tests.py,sha256=
|
|
50
|
-
render_machine/actions/prepare_repositories.py,sha256=
|
|
51
|
-
render_machine/actions/prepare_testing_environment.py,sha256=
|
|
52
|
-
render_machine/actions/refactor_code.py,sha256=
|
|
53
|
-
render_machine/actions/render_conformance_tests.py,sha256=
|
|
54
|
-
render_machine/actions/render_functional_requirement.py,sha256=
|
|
55
|
-
render_machine/actions/run_conformance_tests.py,sha256=
|
|
56
|
-
render_machine/actions/run_unit_tests.py,sha256
|
|
52
|
+
render_machine/actions/fix_conformance_test.py,sha256=ePfxz9Xm0IXht0ch7H4tLPdRzoKnVdlbcDC9EgeDAAQ,8786
|
|
53
|
+
render_machine/actions/fix_unit_tests.py,sha256=hvwvCJDk_-8fHMpkNFyeBSG1IshIcufDpymF00ulPXY,2301
|
|
54
|
+
render_machine/actions/prepare_repositories.py,sha256=eE-uU6H_K5IQMraVWSRi4TKk_XPrnA878T_JwtI9cWo,3410
|
|
55
|
+
render_machine/actions/prepare_testing_environment.py,sha256=GQNVzc_Ap5n74OAmeQuAhXXHK2FVVY374Z0lutrN2UQ,1867
|
|
56
|
+
render_machine/actions/refactor_code.py,sha256=_1C16bQbpxdzJkEwl8jDhEKVyXcyGTd-5YYDNTq2vA8,1782
|
|
57
|
+
render_machine/actions/render_conformance_tests.py,sha256=5gOQn-G1T9UWEI8sDfALcVdArk0ln9DgUprOPjccS-U,9268
|
|
58
|
+
render_machine/actions/render_functional_requirement.py,sha256=2SbPGsLbrrQx3kasXpSpphzaMsq9GD8ASnSzvIdodT4,3748
|
|
59
|
+
render_machine/actions/run_conformance_tests.py,sha256=jmpB-yklUeUjywSpOfbOM0bFGOAiXBQkZYh13prwL6Q,3976
|
|
60
|
+
render_machine/actions/run_unit_tests.py,sha256=-X7IOrZ7d9fuy_pL7CiON5wU1mI4ccSLuMyq-768aD8,2093
|
|
57
61
|
render_machine/actions/summarize_conformance_tests.py,sha256=Vy1kRK8vyazK_BbsKuz1MLDN_TQWVxxzkwEEm-50byc,1639
|
|
58
62
|
standard_template_library/__init__.py,sha256=LtsHl0c3VV46DUInIqyOw4KKVoxKEMOx8dAZpMXtAXc,43
|
|
59
63
|
standard_template_library/golang-console-app-template.plain,sha256=JOusEjCj7jagnXUzaI-SdIr3hj1wTo2uShK017aNtVM,949
|
|
@@ -62,6 +66,7 @@ standard_template_library/typescript-react-app-boilerplate.plain,sha256=6LFxhEOz
|
|
|
62
66
|
standard_template_library/typescript-react-app-template.plain,sha256=DN5wEJcT8ZqQTf0vFKi9Z1isi9cin2UVNOZb3r28d3M,715
|
|
63
67
|
tests/__init__.py,sha256=Wk73Io62J15BtlLVIzxmASDWaaJkQLevS4BLK5LDAQg,16
|
|
64
68
|
tests/conftest.py,sha256=QZcp08htUlJGgmHDlRWFgsWXZ8o8IBWTD5QqJaUMlU8,790
|
|
69
|
+
tests/test_cli_output.py,sha256=Zh4-zWXnW5Znjoj7L33CUYUjNqYzXyFScvWhKPIRn4A,14504
|
|
65
70
|
tests/test_file_utils.py,sha256=-O5zImiFVz9JJ4xi8TbsUwNgPFQoQUOl9Frls4BHCBI,1358
|
|
66
71
|
tests/test_git_utils.py,sha256=h3rWhhs4XVRYqzVzdmj51siF_AYD-GkbZiefK2iGfWo,15614
|
|
67
72
|
tests/test_imports.py,sha256=EWYLUxGunUUdsG9iCiY_tts6T7DIVdhdB_MZlB1LsmU,2081
|
|
@@ -72,17 +77,20 @@ tests/test_plainfileparser.py,sha256=iVTAJWxQZbv96uHXe-qvGSgsC9uJk5Tu10Nod3kqflI
|
|
|
72
77
|
tests/test_plainspec.py,sha256=JrzjJ4VFYDmWTZDq-8WFyt2oMx76IEuO1CAUPQeGOsw,2404
|
|
73
78
|
tests/test_requires.py,sha256=6tnHYaKudxN-RiQjSFoi9nHe_x0ze3QF-f-j67zAE74,1250
|
|
74
79
|
tests/test_resolve_config_file.py,sha256=b87tDOvyzbsnE-QRWbZ97ou7NuyaAgskv-dbYBum31c,2830
|
|
80
|
+
tests/e2e/conftest.py,sha256=5Dm67UTOE-M6hMb-mqZvwa6Ek_wmZgsR7fUv9ZEqCwY,4164
|
|
81
|
+
tests/e2e/test_hello_world_python.py,sha256=PQy4elzB7WvpiWLKa6_HFO0K8HA6_6hGLaAqRi0J3OU,1627
|
|
82
|
+
tests/e2e/test_hello_world_python_windows.py,sha256=kJQZIuzj8OEEtgBVxnzFvyQJ_wvP2oBu9L-E9geg8sE,2010
|
|
75
83
|
tui/__init__.py,sha256=_fy7FowY0RkWdn4kC7XV2jgvQPCj-2gE8fNUb-Mny0A,60
|
|
76
84
|
tui/components.py,sha256=G6ktJx211WrYmj-1aZL3mFtnBTOE4WRF3hA1LG8J0jU,25810
|
|
77
85
|
tui/models.py,sha256=KMjlWubmPD41GA-BjgiqkaV9v7tLJ0fuWKBDPmZj4JA,1493
|
|
78
|
-
tui/plain2code_tui.py,sha256=
|
|
79
|
-
tui/plain_module_render_choice_tui.py,sha256=
|
|
86
|
+
tui/plain2code_tui.py,sha256=Migz-ZdylT8I5ilgvPXxIsTvF30EMC18jyMBGMdattI,13608
|
|
87
|
+
tui/plain_module_render_choice_tui.py,sha256=8aQBwjFmKoKOo-s_sCWuEs4ax1Ww0GKadbMiZAdpKSM,9366
|
|
80
88
|
tui/spinner.py,sha256=Ro6Gd9Przf-whuHqPRY6HwI0T57yJjyNPbhDbigZKZE,2471
|
|
81
89
|
tui/state_handlers.py,sha256=4r_6m5YMcprQtgiTP0De3XFfGAF8VzgaWXHxPweYPbQ,16325
|
|
82
90
|
tui/styles.css,sha256=9vI6V7n7p76i2Dn62KDyOkRYp__d3v2bCzYxO9PWnm8,6685
|
|
83
91
|
tui/widget_helpers.py,sha256=DdXCAJEvFVMgLM2GNBqE-yMtgoNnk7sHG6ehaEV3zdk,6577
|
|
84
|
-
codeplain-0.3.
|
|
85
|
-
codeplain-0.3.
|
|
86
|
-
codeplain-0.3.
|
|
87
|
-
codeplain-0.3.
|
|
88
|
-
codeplain-0.3.
|
|
92
|
+
codeplain-0.3.1.dist-info/METADATA,sha256=Rg-b_OM3ViTIsGXtcIk55V_ZXLoKw3lKhA1r3BaAFLw,5112
|
|
93
|
+
codeplain-0.3.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
94
|
+
codeplain-0.3.1.dist-info/entry_points.txt,sha256=oDZkBqu9WhtZApb_K6ia8-fn9aojwmAsgnKELceX5T4,46
|
|
95
|
+
codeplain-0.3.1.dist-info/licenses/LICENSE,sha256=pCeKgQ1mXE5OmNUuKOfOZh1T1vqkeCUxghE7N8qgnzc,11345
|
|
96
|
+
codeplain-0.3.1.dist-info/RECORD,,
|
codeplain_REST_api.py
CHANGED
|
@@ -161,6 +161,14 @@ class CodeplainAPI:
|
|
|
161
161
|
}
|
|
162
162
|
return self.post_request(endpoint_url, headers, payload, None, num_retries=0, silent=True)
|
|
163
163
|
|
|
164
|
+
def status(self):
|
|
165
|
+
endpoint_url = f"{self.api_url}/status"
|
|
166
|
+
headers = {"Content-Type": "application/json"}
|
|
167
|
+
payload = {
|
|
168
|
+
"api_key": self.api_key,
|
|
169
|
+
}
|
|
170
|
+
return self.post_request(endpoint_url, headers, payload, None, num_retries=0, silent=True)
|
|
171
|
+
|
|
164
172
|
def render_functional_requirement(
|
|
165
173
|
self,
|
|
166
174
|
frid: str,
|
memory_management.py
CHANGED
|
@@ -24,9 +24,9 @@ class MemoryManager:
|
|
|
24
24
|
console.debug(f"Loaded {len(memory_files_content)} memory files.")
|
|
25
25
|
return memory_files, memory_files_content
|
|
26
26
|
|
|
27
|
-
def __init__(self, codeplain_api,
|
|
27
|
+
def __init__(self, codeplain_api, module_name: str, conformance_tests_folder: str):
|
|
28
28
|
self.codeplain_api = codeplain_api
|
|
29
|
-
self.memory_folder = os.path.join(
|
|
29
|
+
self.memory_folder = os.path.join(conformance_tests_folder, module_name, CODEPLAIN_MEMORY_SUBFOLDER)
|
|
30
30
|
|
|
31
31
|
def create_conformance_tests_memory(
|
|
32
32
|
self, render_context: RenderContext, exit_code: int, conformance_tests_issue: str
|
module_renderer.py
CHANGED
|
@@ -60,7 +60,6 @@ class ModuleRenderer:
|
|
|
60
60
|
render_range=render_range,
|
|
61
61
|
render_conformance_tests=self.args.render_conformance_tests,
|
|
62
62
|
base_folder=self.args.base_folder,
|
|
63
|
-
verbose=self.args.verbose,
|
|
64
63
|
run_state=self.run_state,
|
|
65
64
|
event_bus=self.event_bus,
|
|
66
65
|
test_script_timeout=self.args.test_script_timeout,
|
|
@@ -116,10 +115,8 @@ class ModuleRenderer:
|
|
|
116
115
|
|
|
117
116
|
memory_manager = MemoryManager(
|
|
118
117
|
self.codeplainAPI,
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
plain_module.module_name,
|
|
122
|
-
),
|
|
118
|
+
plain_module.module_name,
|
|
119
|
+
self.args.conformance_tests_folder,
|
|
123
120
|
)
|
|
124
121
|
render_context = self._build_render_context_for_module(
|
|
125
122
|
plain_module,
|
partial_rendering.py
CHANGED
|
@@ -60,7 +60,6 @@ def module_comes_before_or_equal(
|
|
|
60
60
|
module1: PlainModule,
|
|
61
61
|
module2: PlainModule,
|
|
62
62
|
) -> bool:
|
|
63
|
-
|
|
64
63
|
for module in all_required_modules:
|
|
65
64
|
if module.module_name == module1.module_name:
|
|
66
65
|
return True
|
|
@@ -120,7 +119,7 @@ def get_all_affected_modules_from_change(
|
|
|
120
119
|
plain_module: PlainModule,
|
|
121
120
|
plain_module_render_state: PlainModuleRenderState,
|
|
122
121
|
) -> list[PlainModule]:
|
|
123
|
-
all_affected_modules =
|
|
122
|
+
all_affected_modules = dict[str, PlainModule]()
|
|
124
123
|
|
|
125
124
|
if plain_module_render_state.change_type == "spec_change":
|
|
126
125
|
start_module = plain_module_render_state.change
|
|
@@ -138,10 +137,10 @@ def get_all_affected_modules_from_change(
|
|
|
138
137
|
if module.module_name == start_module.module_name:
|
|
139
138
|
affected_module = True
|
|
140
139
|
|
|
141
|
-
if affected_module:
|
|
142
|
-
all_affected_modules.
|
|
140
|
+
if affected_module and module.module_name not in all_affected_modules:
|
|
141
|
+
all_affected_modules[module.module_name] = module
|
|
143
142
|
|
|
144
|
-
return all_affected_modules
|
|
143
|
+
return list(all_affected_modules.values())
|
|
145
144
|
|
|
146
145
|
|
|
147
146
|
def get_render_choices(
|
|
@@ -151,6 +150,7 @@ def get_render_choices(
|
|
|
151
150
|
) -> dict[str, RenderChoice]:
|
|
152
151
|
choices = dict[str, RenderChoice]()
|
|
153
152
|
choice_idx = 1
|
|
153
|
+
module_start_points = list[str]()
|
|
154
154
|
|
|
155
155
|
if plain_module_render_state.last_render_module.is_initial_module():
|
|
156
156
|
choices[str(choice_idx)] = RenderChoice(
|
|
@@ -190,12 +190,13 @@ def get_render_choices(
|
|
|
190
190
|
is_destructive=plain_module_render_state.last_render_module.module_name == plain_module.module_name,
|
|
191
191
|
choice_type="module_start",
|
|
192
192
|
)
|
|
193
|
+
module_start_points.append(next_module.module_name)
|
|
193
194
|
choice_idx += 1
|
|
194
195
|
|
|
195
196
|
if plain_module_render_state.change:
|
|
196
197
|
all_affected_modules = get_all_affected_modules_from_change(plain_module, plain_module_render_state)
|
|
197
198
|
|
|
198
|
-
if len(all_affected_modules) > 0:
|
|
199
|
+
if len(all_affected_modules) > 0 and all_affected_modules[0].module_name not in module_start_points:
|
|
199
200
|
choices[str(choice_idx)] = RenderChoice(
|
|
200
201
|
module=all_affected_modules[0],
|
|
201
202
|
render_range=None,
|
|
@@ -203,6 +204,7 @@ def get_render_choices(
|
|
|
203
204
|
wipe_later_modules=True,
|
|
204
205
|
is_destructive=True,
|
|
205
206
|
)
|
|
207
|
+
module_start_points.append(all_affected_modules[0].module_name)
|
|
206
208
|
choice_idx += 1
|
|
207
209
|
|
|
208
210
|
if len(plain_module.all_required_modules) > 0:
|
|
@@ -210,6 +212,7 @@ def get_render_choices(
|
|
|
210
212
|
if first_module.module_name != plain_module_render_state.last_render_module.module_name and (
|
|
211
213
|
plain_module_render_state.change is not None
|
|
212
214
|
and first_module.module_name != plain_module_render_state.change.module_name
|
|
215
|
+
and first_module.module_name not in module_start_points
|
|
213
216
|
):
|
|
214
217
|
choices[str(choice_idx)] = RenderChoice(
|
|
215
218
|
module=first_module,
|
|
@@ -218,6 +221,7 @@ def get_render_choices(
|
|
|
218
221
|
wipe_later_modules=True,
|
|
219
222
|
is_destructive=True,
|
|
220
223
|
)
|
|
224
|
+
module_start_points.append(first_module.module_name)
|
|
221
225
|
choice_idx += 1
|
|
222
226
|
|
|
223
227
|
choices[str(choice_idx)] = RenderChoice(module=None, render_range=None, choice_type="quit")
|