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.
- codeplain-0.1.0.dist-info/METADATA +142 -0
- codeplain-0.1.0.dist-info/RECORD +51 -0
- codeplain-0.1.0.dist-info/WHEEL +5 -0
- codeplain-0.1.0.dist-info/entry_points.txt +2 -0
- codeplain-0.1.0.dist-info/licenses/LICENSE +21 -0
- codeplain-0.1.0.dist-info/top_level.txt +36 -0
- codeplain_REST_api.py +370 -0
- config/__init__.py +2 -0
- config/system_config.yaml +27 -0
- file_utils.py +316 -0
- git_utils.py +304 -0
- hash_key.py +29 -0
- plain2code.py +218 -0
- plain2code_arguments.py +286 -0
- plain2code_console.py +107 -0
- plain2code_exceptions.py +45 -0
- plain2code_nodes.py +108 -0
- plain2code_read_config.py +74 -0
- plain2code_state.py +75 -0
- plain2code_utils.py +56 -0
- plain_spec.py +360 -0
- render_machine/actions/analyze_specification_ambiguity.py +50 -0
- render_machine/actions/base_action.py +19 -0
- render_machine/actions/commit_conformance_tests_changes.py +46 -0
- render_machine/actions/commit_implementation_code_changes.py +22 -0
- render_machine/actions/create_dist.py +26 -0
- render_machine/actions/exit_with_error.py +22 -0
- render_machine/actions/fix_conformance_test.py +121 -0
- render_machine/actions/fix_unit_tests.py +57 -0
- render_machine/actions/prepare_repositories.py +50 -0
- render_machine/actions/prepare_testing_environment.py +30 -0
- render_machine/actions/refactor_code.py +48 -0
- render_machine/actions/render_conformance_tests.py +169 -0
- render_machine/actions/render_functional_requirement.py +69 -0
- render_machine/actions/run_conformance_tests.py +44 -0
- render_machine/actions/run_unit_tests.py +38 -0
- render_machine/actions/summarize_conformance_tests.py +34 -0
- render_machine/code_renderer.py +50 -0
- render_machine/conformance_test_helpers.py +68 -0
- render_machine/implementation_code_helpers.py +20 -0
- render_machine/render_context.py +280 -0
- render_machine/render_types.py +36 -0
- render_machine/render_utils.py +92 -0
- render_machine/state_machine_config.py +408 -0
- render_machine/states.py +52 -0
- render_machine/triggers.py +27 -0
- standard_template_library/__init__.py +1 -0
- standard_template_library/golang-console-app-template.plain +36 -0
- standard_template_library/python-console-app-template.plain +32 -0
- standard_template_library/typescript-react-app-template.plain +22 -0
- system_config.py +49 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codeplain
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Transform plain language specifications into working code
|
|
5
|
+
Classifier: Environment :: Console
|
|
6
|
+
Classifier: Intended Audience :: Developers
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
12
|
+
Requires-Python: >=3.11
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: python-liquid2==0.3.0
|
|
16
|
+
Requires-Dist: mistletoe==1.3.0
|
|
17
|
+
Requires-Dist: langchain==1.0.8
|
|
18
|
+
Requires-Dist: langchain-core==1.2.3
|
|
19
|
+
Requires-Dist: langchain-openai==1.0.3
|
|
20
|
+
Requires-Dist: langchain-anthropic==1.1.0
|
|
21
|
+
Requires-Dist: langchain-aws==1.0.0
|
|
22
|
+
Requires-Dist: langchain-cerebras==0.8.0
|
|
23
|
+
Requires-Dist: langchain-google-genai==4.1.2
|
|
24
|
+
Requires-Dist: langchain-ollama==1.0.0
|
|
25
|
+
Requires-Dist: requests==2.32.3
|
|
26
|
+
Requires-Dist: langsmith==0.4.4
|
|
27
|
+
Requires-Dist: rich==14.2.0
|
|
28
|
+
Requires-Dist: tiktoken==0.12.0
|
|
29
|
+
Requires-Dist: PyYAML==6.0.2
|
|
30
|
+
Requires-Dist: gitpython==3.1.42
|
|
31
|
+
Requires-Dist: lizard==1.18.0
|
|
32
|
+
Requires-Dist: textual==1.0.0
|
|
33
|
+
Requires-Dist: SQLAlchemy==2.0.36
|
|
34
|
+
Requires-Dist: psycopg2==2.9.10
|
|
35
|
+
Requires-Dist: python-dotenv==1.1.0
|
|
36
|
+
Requires-Dist: transitions==0.9.3
|
|
37
|
+
Requires-Dist: cryptography==46.0.1
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: pytest==8.3.5; extra == "dev"
|
|
40
|
+
Requires-Dist: flake8==7.0.0; extra == "dev"
|
|
41
|
+
Requires-Dist: black==24.2.0; extra == "dev"
|
|
42
|
+
Requires-Dist: isort==5.13.2; extra == "dev"
|
|
43
|
+
Requires-Dist: flake8-bugbear==24.12.12; extra == "dev"
|
|
44
|
+
Requires-Dist: flake8-unused-arguments==0.0.13; extra == "dev"
|
|
45
|
+
Requires-Dist: flake8-eradicate==1.5.0; extra == "dev"
|
|
46
|
+
Requires-Dist: pep8-naming==0.15.1; extra == "dev"
|
|
47
|
+
Requires-Dist: mypy==1.11.2; extra == "dev"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
# Codeplain plain2code renderer
|
|
51
|
+
|
|
52
|
+
Render ***plain source to software code using the Codeplain API.
|
|
53
|
+
|
|
54
|
+
## Codeplain.ai - Code Generation as a Service
|
|
55
|
+
|
|
56
|
+
Codeplain is a platform that generates software code using large language models based on requirements you specify in ***plain specification language.
|
|
57
|
+
|
|
58
|
+
Schematic overview of the Codeplain's code generation service
|
|
59
|
+
|
|
60
|
+
<img src="resources/codeplain_overview.png">
|
|
61
|
+
|
|
62
|
+
### Abstracting Away Code Generation Complexity with ***plain
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
***plain is a novel specification language that helps abstracting away complexity of using large language models for code generation.
|
|
66
|
+
|
|
67
|
+
An example application in ***plain
|
|
68
|
+
|
|
69
|
+
<img src="resources/plain_example.png" width="70%" height="70%">
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
## Getting started
|
|
73
|
+
|
|
74
|
+
### Prerequisites
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
#### System requirements
|
|
78
|
+
|
|
79
|
+
To run the plain2code client, you need Python 3.11 or a later version.
|
|
80
|
+
|
|
81
|
+
**Windows users:** Please install WSL (Windows Subsystem for Linux) as this is currently the supported environment for running plain code on Windows.
|
|
82
|
+
|
|
83
|
+
#### Authorization - Codeplain API Key
|
|
84
|
+
|
|
85
|
+
We are using Codeplain API Key to authorize requests to the Codeplain API. To get your Codeplain API Key, please contact Codeplain.ai support at support@codeplain.ai.
|
|
86
|
+
|
|
87
|
+
In order to generate code, you need to export the following environment variable:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
export CODEPLAIN_API_KEY="your_actual_api_key_here"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Installation Steps
|
|
94
|
+
|
|
95
|
+
1. Clone this repository
|
|
96
|
+
2. Set your Codeplain API key as an environment variable:
|
|
97
|
+
```
|
|
98
|
+
export CODEPLAIN_API_KEY=your_api_key_here
|
|
99
|
+
```
|
|
100
|
+
3. (Recommended) Create and activate a virtual environment:
|
|
101
|
+
```bash
|
|
102
|
+
python -m venv .venv
|
|
103
|
+
source .venv/bin/activate
|
|
104
|
+
```
|
|
105
|
+
4. Install required libraries
|
|
106
|
+
```
|
|
107
|
+
pip install -r requirements.txt
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Quick Start
|
|
111
|
+
|
|
112
|
+
After completing the installation steps above, you can immediately test the system with a simple "Hello World" example:
|
|
113
|
+
|
|
114
|
+
- Change to the example folder and run the example:
|
|
115
|
+
```
|
|
116
|
+
cd examples/example_hello_world_python
|
|
117
|
+
python ../../plain2code.py hello_world_python.plain
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
*Note: Rendering will take a few minutes to complete.*
|
|
121
|
+
|
|
122
|
+
- The system will generate a Python application in the `build` directory. You can run it with:
|
|
123
|
+
```
|
|
124
|
+
cd build
|
|
125
|
+
python hello_world.py
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Additional Resources
|
|
129
|
+
|
|
130
|
+
### Examples and Sample Projects
|
|
131
|
+
|
|
132
|
+
- See the [examples](examples) folder for sample projects in Golang, Python, and React.
|
|
133
|
+
- For example application how to implement task manager in ***plain see [example-task-manager](https://github.com/Codeplain-ai/example-task-manager) repository.
|
|
134
|
+
- For example application how to implement SaaS connectors in ***plain see [example-saas-connectors](https://github.com/Codeplain-ai/example-saas-connectors) repository.
|
|
135
|
+
|
|
136
|
+
### Documentation
|
|
137
|
+
|
|
138
|
+
- For more details on the ***plain format, see the [***plain language specification](docs/plain_language_specification.md).
|
|
139
|
+
- For step-by-step instructions for creating your first ***plain project see the [Kickstart your ***plain project](docs/starting_a_plain_project_from_scratch.md).
|
|
140
|
+
- For complete CLI documentation and usage examples, see [plain2code CLI documentation](docs/plain2code_cli.md).
|
|
141
|
+
|
|
142
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
codeplain_REST_api.py,sha256=C0PoV3xgXXH4GUBJYMq-dKnxtt3eKSykPgND31TNATo,14781
|
|
2
|
+
file_utils.py,sha256=MaHDvn-a5fB2_D0kvAk1MGxqs5Povke2NIA-WLjdo_s,11387
|
|
3
|
+
git_utils.py,sha256=vLDVRek9nhYdAR4IRp_M8WNn-pyYjVjrIxNfEXEij2E,10153
|
|
4
|
+
hash_key.py,sha256=lMKgKpOhPeC4UpFf9e7eCNK20FEaDsXTCJ8j3eCWidE,837
|
|
5
|
+
plain2code.py,sha256=rvP0-GDgr9F05dyAsYTelgn2kza3pLK9ODSWG9PE5kw,8098
|
|
6
|
+
plain2code_arguments.py,sha256=wMIbDVjzXZnrkXnbhBWc9Vz7ddQCPIm_wg56Wp_aado,11040
|
|
7
|
+
plain2code_console.py,sha256=08TWADO9bmwmN6oMfLsjDKF54EIPc3mPlipFGy3Gwsk,3778
|
|
8
|
+
plain2code_exceptions.py,sha256=UTFovKObkYuIOfknZcEISL06_V5JavnAJsR4rcTubsI,717
|
|
9
|
+
plain2code_nodes.py,sha256=Om624mfb5MB1Z09c0Zqtb9G1gGkUY9x-v2hzAf3A2gw,3818
|
|
10
|
+
plain2code_read_config.py,sha256=QnpbW_Bi9LzDIOubM5x7fVXH1HgiFL3-5Oa_O1EUoE4,2449
|
|
11
|
+
plain2code_state.py,sha256=K1U9EoaGHboWEf5SVhSx3sN-ZvCEcAztV0q9dpj-2Zw,2570
|
|
12
|
+
plain2code_utils.py,sha256=gxH8i-XHK-K9s9reBNose0UKYrH7oLjSsaEKMpLS1g0,2471
|
|
13
|
+
plain_spec.py,sha256=SwjhdYuMJzwtF70ti7r5tVXogGbzvutu4U42u0AuKdU,13457
|
|
14
|
+
system_config.py,sha256=mgHLn-CRHLO9Y9vKyI_eFBreY_YhFad-ctZgBYp-rIg,1777
|
|
15
|
+
codeplain-0.1.0.dist-info/licenses/LICENSE,sha256=wsFi5dpbJurnRNfBj8q2RCcF3ryrmdRIfxc3lPcmc4c,1069
|
|
16
|
+
config/__init__.py,sha256=iHrUksORYKKYsPhE2D_zvZ5tV7mfFAp16c_Cp38hT7A,38
|
|
17
|
+
config/system_config.yaml,sha256=bB5Th5jxgXFyaIvceUPID1ReebMMXsyMibV4gtu9sWQ,1148
|
|
18
|
+
render_machine/code_renderer.py,sha256=kHS_8uZEgQhygGvw0GBoA-V2nW8lIpoF1GJgyRw8oNk,2072
|
|
19
|
+
render_machine/conformance_test_helpers.py,sha256=6Ru7Dh24SLNIKWfz_sP5hE_EmWpvk6nfgN1T1yaCZus,2887
|
|
20
|
+
render_machine/implementation_code_helpers.py,sha256=XhjbQRn2mhfIXs1QioqFlopRfzUrY3U9DsFq38IFvic,816
|
|
21
|
+
render_machine/render_context.py,sha256=OTlSwIqgt7UzMytSjQqqpAZTwjUE0l-eyCXJRpjii8E,13944
|
|
22
|
+
render_machine/render_types.py,sha256=Ke1LzVXAY5XvJwMcY97C7gZniuRAgJRSCv4Flcfn-ig,1156
|
|
23
|
+
render_machine/render_utils.py,sha256=ImqoIcGy9s4y3IF6BuAFOWZ4_10UB2CKBE6zf_pLd2M,4302
|
|
24
|
+
render_machine/state_machine_config.py,sha256=9aQOcWesI-fQ9_BpicpQ3flzSTln18QBVsr_ZHi_3T0,26109
|
|
25
|
+
render_machine/states.py,sha256=GvjGMYKYURKzTS7W2B8HOeDGt43z2AoKPcUv3FDnK9Q,1973
|
|
26
|
+
render_machine/triggers.py,sha256=GarwIYPY6ZZzVdRF7yXLB54tofr08NpFZfp5DH6AOuI,1331
|
|
27
|
+
render_machine/actions/analyze_specification_ambiguity.py,sha256=UsDQeOZI4l58rwZ9yjPtgB5-erz55HJvcjMrjMObV2I,2608
|
|
28
|
+
render_machine/actions/base_action.py,sha256=vVzMp-LanrZyq-jamHyWaQxpRl-pLqtTdtiEzUBhfyE,534
|
|
29
|
+
render_machine/actions/commit_conformance_tests_changes.py,sha256=3W-AnUFoukbN5U70PqsRwiL_wIoFwqsz6lM2TDoSy6k,2265
|
|
30
|
+
render_machine/actions/commit_implementation_code_changes.py,sha256=5A55hESZGs-XXEZSPk7KvTeUmJWTOyG9IOIiuDEsv4Y,791
|
|
31
|
+
render_machine/actions/create_dist.py,sha256=1t-DIZhtbajaLdtF05vsv4-MEuZpOxhBMX0EJ-TeCe0,1019
|
|
32
|
+
render_machine/actions/exit_with_error.py,sha256=R0J1HPQtgHrVr8U5_r5uckXYzcuBFmsras5Avjh1Ra4,854
|
|
33
|
+
render_machine/actions/fix_conformance_test.py,sha256=X8HWjMp8b0J2thB1rWqAefZkDTsViBUJi5BA65uui5A,6158
|
|
34
|
+
render_machine/actions/fix_unit_tests.py,sha256=muabQEaWwzCoONjfGCMbODKZt5-xPLhfAAMD3O2AIs8,2448
|
|
35
|
+
render_machine/actions/prepare_repositories.py,sha256=kjc12Q6FArn3Wg_r-SYioW6sZSbN0LSbpI_b4pFMXQY,2109
|
|
36
|
+
render_machine/actions/prepare_testing_environment.py,sha256=J6GMclP07k7LuHrp5P7LOb4UJ7M3PAT1EWWLgKnAtHQ,1236
|
|
37
|
+
render_machine/actions/refactor_code.py,sha256=NoPv04RWedFL0gehiOnBSGD-cy6DFEz0smeRO23f_Ts,2116
|
|
38
|
+
render_machine/actions/render_conformance_tests.py,sha256=AvzdM6yV79kSLAV6m3VB3JYrBnOS0OXsV3G9SXK8Uw4,8034
|
|
39
|
+
render_machine/actions/render_functional_requirement.py,sha256=Yq4r_LLmHLT1_SSK5uCuNWQV9baHzHA_bxNQJqNe58w,3389
|
|
40
|
+
render_machine/actions/run_conformance_tests.py,sha256=DslNg5i4utlEkd4bmtDmTNxDye11n3juWzf6E95afMI,1900
|
|
41
|
+
render_machine/actions/run_unit_tests.py,sha256=7xMiMrjW1yOJavI97huA4dj5hpNroxDZh2ASx4rcIoI,1561
|
|
42
|
+
render_machine/actions/summarize_conformance_tests.py,sha256=mFU-GhOBGqhwDIMYlQtPUi4aUr-GJYPNXHeiK9U561g,1611
|
|
43
|
+
standard_template_library/__init__.py,sha256=LtsHl0c3VV46DUInIqyOw4KKVoxKEMOx8dAZpMXtAXc,43
|
|
44
|
+
standard_template_library/golang-console-app-template.plain,sha256=aPg2uhoNUFryVXzs0a2QjY82-uzftOgtrXNjDBAM8WU,1396
|
|
45
|
+
standard_template_library/python-console-app-template.plain,sha256=5kqK5kErQ-Pa46iT3LVIYyBw68B8__CS-S4MoXkBx7Q,1432
|
|
46
|
+
standard_template_library/typescript-react-app-template.plain,sha256=6JXLqQja17M7NbDEmk6pRltaD2m00OoDo6pJxuiv1Do,465
|
|
47
|
+
codeplain-0.1.0.dist-info/METADATA,sha256=rJvrDgTtVlE6PoSfj7fCkdr9oGcOxJQC8jYJ-Y6WOfw,4974
|
|
48
|
+
codeplain-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
49
|
+
codeplain-0.1.0.dist-info/entry_points.txt,sha256=oDZkBqu9WhtZApb_K6ia8-fn9aojwmAsgnKELceX5T4,46
|
|
50
|
+
codeplain-0.1.0.dist-info/top_level.txt,sha256=wNGviii6Ojj3wNiGASr-QbTS8Xkiyux_nMeQJGL_OTE,536
|
|
51
|
+
codeplain-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Codeplain.ai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
code_complexity
|
|
2
|
+
codeplain
|
|
3
|
+
codeplain_REST_api
|
|
4
|
+
codeplain_constants
|
|
5
|
+
codeplain_local_api
|
|
6
|
+
codeplain_models
|
|
7
|
+
codeplain_types
|
|
8
|
+
codeplain_utils
|
|
9
|
+
config
|
|
10
|
+
content_extractor
|
|
11
|
+
event_bus
|
|
12
|
+
file_utils
|
|
13
|
+
git_utils
|
|
14
|
+
hash_key
|
|
15
|
+
llm
|
|
16
|
+
llm_exceptions
|
|
17
|
+
llm_handler
|
|
18
|
+
llm_selector
|
|
19
|
+
plain2code
|
|
20
|
+
plain2code_arguments
|
|
21
|
+
plain2code_console
|
|
22
|
+
plain2code_events
|
|
23
|
+
plain2code_exceptions
|
|
24
|
+
plain2code_nodes
|
|
25
|
+
plain2code_read_config
|
|
26
|
+
plain2code_state
|
|
27
|
+
plain2code_tui
|
|
28
|
+
plain2code_utils
|
|
29
|
+
plain_file
|
|
30
|
+
plain_spec
|
|
31
|
+
render_cache
|
|
32
|
+
render_machine
|
|
33
|
+
spinner
|
|
34
|
+
standard_template_library
|
|
35
|
+
system_config
|
|
36
|
+
tui_components
|
codeplain_REST_api.py
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
from requests.exceptions import ConnectionError, RequestException, Timeout
|
|
6
|
+
|
|
7
|
+
import plain2code_exceptions
|
|
8
|
+
from plain2code_state import RunState
|
|
9
|
+
|
|
10
|
+
MAX_RETRIES = 4
|
|
11
|
+
RETRY_DELAY = 3
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CodeplainAPI:
|
|
15
|
+
|
|
16
|
+
def __init__(self, api_key, console):
|
|
17
|
+
self.api_key = api_key
|
|
18
|
+
self.console = console
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def api_url(self):
|
|
22
|
+
return self._api_url
|
|
23
|
+
|
|
24
|
+
@api_url.setter
|
|
25
|
+
def api_url(self, value):
|
|
26
|
+
self._api_url = value
|
|
27
|
+
|
|
28
|
+
def _extend_payload_with_run_state(self, payload: dict, run_state: RunState):
|
|
29
|
+
run_state.increment_call_count()
|
|
30
|
+
payload["render_state"] = run_state.to_dict()
|
|
31
|
+
|
|
32
|
+
def post_request(self, endpoint_url, headers, payload, run_state: Optional[RunState]): # noqa: C901
|
|
33
|
+
if run_state is not None:
|
|
34
|
+
self._extend_payload_with_run_state(payload, run_state)
|
|
35
|
+
|
|
36
|
+
retry_delay = RETRY_DELAY
|
|
37
|
+
for attempt in range(MAX_RETRIES + 1):
|
|
38
|
+
try:
|
|
39
|
+
response = requests.post(endpoint_url, headers=headers, json=payload)
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
response_json = response.json()
|
|
43
|
+
except requests.exceptions.JSONDecodeError as e:
|
|
44
|
+
print(f"Failed to decode JSON response: {e}. Response text: {response.text}")
|
|
45
|
+
raise
|
|
46
|
+
|
|
47
|
+
if response.status_code == requests.codes.bad_request and "error_code" in response_json:
|
|
48
|
+
if response_json["error_code"] == "FunctionalRequirementTooComplex":
|
|
49
|
+
raise plain2code_exceptions.FunctionalRequirementTooComplex(
|
|
50
|
+
response_json["message"], response_json.get("proposed_breakdown")
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if response_json["error_code"] == "ConflictingRequirements":
|
|
54
|
+
raise plain2code_exceptions.ConflictingRequirements(response_json["message"])
|
|
55
|
+
|
|
56
|
+
if response_json["error_code"] == "CreditBalanceTooLow":
|
|
57
|
+
raise plain2code_exceptions.CreditBalanceTooLow(response_json["message"])
|
|
58
|
+
|
|
59
|
+
if response_json["error_code"] == "LLMInternalError":
|
|
60
|
+
raise plain2code_exceptions.LLMInternalError(response_json["message"])
|
|
61
|
+
|
|
62
|
+
if response_json["error_code"] == "MissingResource":
|
|
63
|
+
raise plain2code_exceptions.MissingResource(response_json["message"])
|
|
64
|
+
|
|
65
|
+
if response_json["error_code"] == "PlainSyntaxError":
|
|
66
|
+
raise plain2code_exceptions.PlainSyntaxError(response_json["message"])
|
|
67
|
+
|
|
68
|
+
if response_json["error_code"] == "OnlyRelativeLinksAllowed":
|
|
69
|
+
raise plain2code_exceptions.OnlyRelativeLinksAllowed(response_json["message"])
|
|
70
|
+
|
|
71
|
+
if response_json["error_code"] == "LinkMustHaveTextSpecified":
|
|
72
|
+
raise plain2code_exceptions.LinkMustHaveTextSpecified(response_json["message"])
|
|
73
|
+
|
|
74
|
+
if response_json["error_code"] == "NoRenderFound":
|
|
75
|
+
raise plain2code_exceptions.NoRenderFound(response_json["message"])
|
|
76
|
+
|
|
77
|
+
if response_json["error_code"] == "MultipleRendersFound":
|
|
78
|
+
raise plain2code_exceptions.MultipleRendersFound(response_json["message"])
|
|
79
|
+
|
|
80
|
+
response.raise_for_status()
|
|
81
|
+
return response_json
|
|
82
|
+
|
|
83
|
+
except (ConnectionError, Timeout, RequestException) as e:
|
|
84
|
+
if attempt < MAX_RETRIES:
|
|
85
|
+
self.console.info(f"Connection error on attempt {attempt + 1}/{MAX_RETRIES + 1}: {e}")
|
|
86
|
+
self.console.info(f"Retrying in {retry_delay} seconds...")
|
|
87
|
+
time.sleep(retry_delay)
|
|
88
|
+
# Exponential backoff
|
|
89
|
+
retry_delay *= 2
|
|
90
|
+
else:
|
|
91
|
+
self.console.error(f"Max retries ({MAX_RETRIES}) exceeded. Last error: {e}")
|
|
92
|
+
raise RequestException(
|
|
93
|
+
f"Connection error: Unable to reach the Codeplain API at {self.api_url}. Please try again or contact support."
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def get_plain_source_tree(self, plain_source, loaded_templates, run_state: RunState):
|
|
97
|
+
"""
|
|
98
|
+
Builds plain source tree from the given plain text source in Markdown format.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
plain_source (str): A string containing the plain text source to be parsed.
|
|
102
|
+
loaded_templates (dict): A dictionary containing the loaded templates.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
dict: A plain source tree.
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
Exception: If parsing of plain_source fails.
|
|
109
|
+
"""
|
|
110
|
+
endpoint_url = f"{self.api_url}/plain_source_tree"
|
|
111
|
+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
112
|
+
|
|
113
|
+
payload = {"plain_source": plain_source, "loaded_templates": loaded_templates}
|
|
114
|
+
|
|
115
|
+
return self.post_request(endpoint_url, headers, payload, run_state)
|
|
116
|
+
|
|
117
|
+
def render_functional_requirement(
|
|
118
|
+
self,
|
|
119
|
+
frid,
|
|
120
|
+
plain_source_tree,
|
|
121
|
+
linked_resources,
|
|
122
|
+
existing_files_content,
|
|
123
|
+
run_state: RunState,
|
|
124
|
+
):
|
|
125
|
+
"""
|
|
126
|
+
Renders the content of a functional requirement based on the provided ID,
|
|
127
|
+
plain source tree, and existing files' content.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
frid (str): The unique identifier for the functional requirement to be rendered.
|
|
131
|
+
plain_source_tree (dict): A dictionary containing the plain source tree.
|
|
132
|
+
linked_resources (dict): A dictionary where the keys represent resource names
|
|
133
|
+
and the values are the content of those resources.
|
|
134
|
+
existing_files_content (dict): A dictionary where the keys represent code base
|
|
135
|
+
filenames and the values are the content of those files.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
str: A string containing the rendered functional requirement, formatted
|
|
139
|
+
appropriately based on the inputs.
|
|
140
|
+
|
|
141
|
+
Raises:
|
|
142
|
+
ValueError: If the frid is invalid or the necessary plain source tree is not valid.
|
|
143
|
+
"""
|
|
144
|
+
endpoint_url = f"{self.api_url}/render_functional_requirement"
|
|
145
|
+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
146
|
+
|
|
147
|
+
payload = {
|
|
148
|
+
"frid": frid,
|
|
149
|
+
"plain_source_tree": plain_source_tree,
|
|
150
|
+
"linked_resources": linked_resources,
|
|
151
|
+
"existing_files_content": existing_files_content,
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return self.post_request(endpoint_url, headers, payload, run_state)
|
|
155
|
+
|
|
156
|
+
def fix_unittests_issue(
|
|
157
|
+
self,
|
|
158
|
+
frid,
|
|
159
|
+
plain_source_tree,
|
|
160
|
+
linked_resources,
|
|
161
|
+
existing_files_content,
|
|
162
|
+
unittests_issue,
|
|
163
|
+
run_state: RunState,
|
|
164
|
+
):
|
|
165
|
+
endpoint_url = f"{self.api_url}/fix_unittests_issue"
|
|
166
|
+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
167
|
+
|
|
168
|
+
payload = {
|
|
169
|
+
"frid": frid,
|
|
170
|
+
"plain_source_tree": plain_source_tree,
|
|
171
|
+
"linked_resources": linked_resources,
|
|
172
|
+
"existing_files_content": existing_files_content,
|
|
173
|
+
"unittests_issue": unittests_issue,
|
|
174
|
+
"unittest_batch_id": run_state.unittest_batch_id,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return self.post_request(endpoint_url, headers, payload, run_state)
|
|
178
|
+
|
|
179
|
+
def refactor_source_files_if_needed(self, frid, files_to_check, existing_files_content, run_state: RunState):
|
|
180
|
+
endpoint_url = f"{self.api_url}/refactor_source_files_if_needed"
|
|
181
|
+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
182
|
+
|
|
183
|
+
payload = {
|
|
184
|
+
"frid": frid,
|
|
185
|
+
"files_to_check": list(files_to_check),
|
|
186
|
+
"existing_files_content": existing_files_content,
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return self.post_request(endpoint_url, headers, payload, run_state)
|
|
190
|
+
|
|
191
|
+
def render_conformance_tests(
|
|
192
|
+
self,
|
|
193
|
+
frid,
|
|
194
|
+
functional_requirement_id,
|
|
195
|
+
plain_source_tree,
|
|
196
|
+
linked_resources,
|
|
197
|
+
existing_files_content,
|
|
198
|
+
conformance_tests_folder_name,
|
|
199
|
+
conformance_tests_json,
|
|
200
|
+
all_acceptance_tests,
|
|
201
|
+
run_state: RunState,
|
|
202
|
+
):
|
|
203
|
+
endpoint_url = f"{self.api_url}/render_conformance_tests"
|
|
204
|
+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
205
|
+
|
|
206
|
+
payload = {
|
|
207
|
+
"frid": frid,
|
|
208
|
+
"functional_requirement_id": functional_requirement_id,
|
|
209
|
+
"plain_source_tree": plain_source_tree,
|
|
210
|
+
"linked_resources": linked_resources,
|
|
211
|
+
"existing_files_content": existing_files_content,
|
|
212
|
+
"conformance_tests_folder_name": conformance_tests_folder_name,
|
|
213
|
+
"conformance_tests_json": conformance_tests_json,
|
|
214
|
+
"all_acceptance_tests": all_acceptance_tests,
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
response = self.post_request(endpoint_url, headers, payload, run_state)
|
|
218
|
+
return response["patched_response_files"], response["conformance_tests_plan_summary_string"]
|
|
219
|
+
|
|
220
|
+
def generate_folder_name_from_functional_requirement(
|
|
221
|
+
self,
|
|
222
|
+
frid,
|
|
223
|
+
functional_requirement,
|
|
224
|
+
existing_folder_names,
|
|
225
|
+
run_state: RunState,
|
|
226
|
+
):
|
|
227
|
+
endpoint_url = f"{self.api_url}/generate_folder_name_from_functional_requirement"
|
|
228
|
+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
229
|
+
|
|
230
|
+
payload = {
|
|
231
|
+
"frid": frid,
|
|
232
|
+
"functional_requirement": functional_requirement,
|
|
233
|
+
"existing_folder_names": existing_folder_names,
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return self.post_request(endpoint_url, headers, payload, run_state)
|
|
237
|
+
|
|
238
|
+
def fix_conformance_tests_issue(
|
|
239
|
+
self,
|
|
240
|
+
frid,
|
|
241
|
+
functional_requirement_id,
|
|
242
|
+
plain_source_tree,
|
|
243
|
+
linked_resources,
|
|
244
|
+
existing_files_content,
|
|
245
|
+
code_diff,
|
|
246
|
+
conformance_tests_files,
|
|
247
|
+
acceptance_tests,
|
|
248
|
+
conformance_tests_issue,
|
|
249
|
+
implementation_fix_count,
|
|
250
|
+
conformance_tests_folder_name,
|
|
251
|
+
current_testing_frid_high_level_implementation_plan: Optional[str],
|
|
252
|
+
run_state: RunState,
|
|
253
|
+
):
|
|
254
|
+
endpoint_url = f"{self.api_url}/fix_conformance_tests_issue"
|
|
255
|
+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
256
|
+
|
|
257
|
+
payload = {
|
|
258
|
+
"frid": frid,
|
|
259
|
+
"functional_requirement_id": functional_requirement_id,
|
|
260
|
+
"plain_source_tree": plain_source_tree,
|
|
261
|
+
"linked_resources": linked_resources,
|
|
262
|
+
"existing_files_content": existing_files_content,
|
|
263
|
+
"code_diff": code_diff,
|
|
264
|
+
"conformance_tests_files": conformance_tests_files,
|
|
265
|
+
"conformance_tests_issue": conformance_tests_issue,
|
|
266
|
+
"implementation_fix_count": implementation_fix_count,
|
|
267
|
+
"conformance_tests_folder_name": conformance_tests_folder_name,
|
|
268
|
+
"current_testing_frid_high_level_implementation_plan": current_testing_frid_high_level_implementation_plan,
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if acceptance_tests is not None:
|
|
272
|
+
payload["acceptance_tests"] = acceptance_tests
|
|
273
|
+
|
|
274
|
+
return self.post_request(endpoint_url, headers, payload, run_state)
|
|
275
|
+
|
|
276
|
+
def render_acceptance_tests(
|
|
277
|
+
self,
|
|
278
|
+
frid,
|
|
279
|
+
plain_source_tree,
|
|
280
|
+
linked_resources,
|
|
281
|
+
existing_files_content,
|
|
282
|
+
conformance_tests_files,
|
|
283
|
+
acceptance_test,
|
|
284
|
+
run_state: RunState,
|
|
285
|
+
):
|
|
286
|
+
"""
|
|
287
|
+
Renders acceptance tests based on the provided parameters.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
frid (str): The unique identifier for the functional requirement.
|
|
291
|
+
plain_source_tree (dict): A dictionary containing the plain source tree.
|
|
292
|
+
linked_resources (dict): A dictionary where the keys represent resource names
|
|
293
|
+
and the values are the content of those resources.
|
|
294
|
+
existing_files_content (dict): A dictionary where the keys represent code base
|
|
295
|
+
filenames and the values are the content of those files.
|
|
296
|
+
conformance_tests_files (dict): A dictionary containing conformance test files.
|
|
297
|
+
acceptance_test (dict): A dictionary containing acceptance test information.
|
|
298
|
+
|
|
299
|
+
Returns:
|
|
300
|
+
dict: The rendered acceptance tests.
|
|
301
|
+
|
|
302
|
+
Raises:
|
|
303
|
+
Exception: If the request fails or returns an error.
|
|
304
|
+
"""
|
|
305
|
+
endpoint_url = f"{self.api_url}/render_acceptance_tests"
|
|
306
|
+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
307
|
+
|
|
308
|
+
payload = {
|
|
309
|
+
"frid": frid,
|
|
310
|
+
"plain_source_tree": plain_source_tree,
|
|
311
|
+
"linked_resources": linked_resources,
|
|
312
|
+
"existing_files_content": existing_files_content,
|
|
313
|
+
"conformance_tests_files": conformance_tests_files,
|
|
314
|
+
"acceptance_test": acceptance_test,
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return self.post_request(endpoint_url, headers, payload, run_state)
|
|
318
|
+
|
|
319
|
+
def analyze_rendering(
|
|
320
|
+
self,
|
|
321
|
+
frid,
|
|
322
|
+
plain_source_tree,
|
|
323
|
+
linked_resources,
|
|
324
|
+
existing_files_content,
|
|
325
|
+
implementation_code_diff,
|
|
326
|
+
fixed_implementation_code_diff,
|
|
327
|
+
run_state: RunState,
|
|
328
|
+
):
|
|
329
|
+
endpoint_url = f"{self.api_url}/analyze_rendering"
|
|
330
|
+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
331
|
+
|
|
332
|
+
payload = {
|
|
333
|
+
"frid": frid,
|
|
334
|
+
"plain_source_tree": plain_source_tree,
|
|
335
|
+
"linked_resources": linked_resources,
|
|
336
|
+
"existing_files_content": existing_files_content,
|
|
337
|
+
"implementation_code_diff": implementation_code_diff,
|
|
338
|
+
"fixed_implementation_code_diff": fixed_implementation_code_diff,
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return self.post_request(endpoint_url, headers, payload, run_state)
|
|
342
|
+
|
|
343
|
+
def finish_functional_requirement(self, frid, run_state: RunState):
|
|
344
|
+
endpoint_url = f"{self.api_url}/finish_functional_requirement"
|
|
345
|
+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
346
|
+
|
|
347
|
+
payload = {
|
|
348
|
+
"frid": frid,
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return self.post_request(endpoint_url, headers, payload, run_state)
|
|
352
|
+
|
|
353
|
+
def summarize_finished_conformance_tests(
|
|
354
|
+
self,
|
|
355
|
+
frid,
|
|
356
|
+
plain_source_tree,
|
|
357
|
+
linked_resources,
|
|
358
|
+
conformance_test_files_content,
|
|
359
|
+
run_state: RunState,
|
|
360
|
+
):
|
|
361
|
+
endpoint_url = f"{self.api_url}/summarize_finished_conformance_tests"
|
|
362
|
+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
363
|
+
payload = {
|
|
364
|
+
"frid": frid,
|
|
365
|
+
"plain_source_tree": plain_source_tree,
|
|
366
|
+
"linked_resources": linked_resources,
|
|
367
|
+
"conformance_test_files_content": conformance_test_files_content,
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return self.post_request(endpoint_url, headers, payload, run_state)
|
config/__init__.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
system_requirements:
|
|
2
|
+
timeout:
|
|
3
|
+
command: timeout
|
|
4
|
+
error_message: |
|
|
5
|
+
Error: Required system command 'timeout' is not available.
|
|
6
|
+
This command is needed to enforce time limits on test execution.
|
|
7
|
+
|
|
8
|
+
To install the timeout command:
|
|
9
|
+
- On Linux: Install coreutils package
|
|
10
|
+
- Debian/Ubuntu: sudo apt-get install coreutils
|
|
11
|
+
- CentOS/RHEL: sudo yum install coreutils
|
|
12
|
+
- Fedora: sudo dnf install coreutils
|
|
13
|
+
- On macOS:
|
|
14
|
+
- Using Homebrew: brew install coreutils
|
|
15
|
+
- Using MacPorts: port install coreutils
|
|
16
|
+
- On Windows: Use Windows Subsystem for Linux (WSL), Cygwin, or Git Bash
|
|
17
|
+
|
|
18
|
+
error_messages:
|
|
19
|
+
template_not_found:
|
|
20
|
+
message: |
|
|
21
|
+
The required template could not be found. Templates are searched in the following order (highest to lowest precedence):
|
|
22
|
+
|
|
23
|
+
1. The directory containing your .plain file
|
|
24
|
+
2. The directory specified by --template-dir (if provided)
|
|
25
|
+
3. The built-in 'standard_template_library' directory
|
|
26
|
+
|
|
27
|
+
Please ensure that the missing template exists in one of these locations, or specify the correct --template-dir if using custom templates.
|