pdd-cli 0.0.2__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.
Potentially problematic release.
This version of pdd-cli might be problematic. Click here for more details.
- pdd/__init__.py +0 -0
- pdd/auto_deps_main.py +98 -0
- pdd/auto_include.py +175 -0
- pdd/auto_update.py +73 -0
- pdd/bug_main.py +99 -0
- pdd/bug_to_unit_test.py +159 -0
- pdd/change.py +141 -0
- pdd/change_main.py +240 -0
- pdd/cli.py +607 -0
- pdd/cmd_test_main.py +155 -0
- pdd/code_generator.py +117 -0
- pdd/code_generator_main.py +66 -0
- pdd/comment_line.py +35 -0
- pdd/conflicts_in_prompts.py +143 -0
- pdd/conflicts_main.py +90 -0
- pdd/construct_paths.py +251 -0
- pdd/context_generator.py +133 -0
- pdd/context_generator_main.py +73 -0
- pdd/continue_generation.py +140 -0
- pdd/crash_main.py +127 -0
- pdd/data/language_format.csv +61 -0
- pdd/data/llm_model.csv +15 -0
- pdd/detect_change.py +142 -0
- pdd/detect_change_main.py +100 -0
- pdd/find_section.py +28 -0
- pdd/fix_code_loop.py +212 -0
- pdd/fix_code_module_errors.py +143 -0
- pdd/fix_error_loop.py +216 -0
- pdd/fix_errors_from_unit_tests.py +240 -0
- pdd/fix_main.py +138 -0
- pdd/generate_output_paths.py +194 -0
- pdd/generate_test.py +140 -0
- pdd/get_comment.py +55 -0
- pdd/get_extension.py +52 -0
- pdd/get_language.py +41 -0
- pdd/git_update.py +84 -0
- pdd/increase_tests.py +93 -0
- pdd/insert_includes.py +150 -0
- pdd/llm_invoke.py +304 -0
- pdd/load_prompt_template.py +59 -0
- pdd/pdd_completion.fish +72 -0
- pdd/pdd_completion.sh +141 -0
- pdd/pdd_completion.zsh +418 -0
- pdd/postprocess.py +121 -0
- pdd/postprocess_0.py +52 -0
- pdd/preprocess.py +199 -0
- pdd/preprocess_main.py +72 -0
- pdd/process_csv_change.py +182 -0
- pdd/prompts/auto_include_LLM.prompt +230 -0
- pdd/prompts/bug_to_unit_test_LLM.prompt +17 -0
- pdd/prompts/change_LLM.prompt +34 -0
- pdd/prompts/conflict_LLM.prompt +23 -0
- pdd/prompts/continue_generation_LLM.prompt +3 -0
- pdd/prompts/detect_change_LLM.prompt +65 -0
- pdd/prompts/example_generator_LLM.prompt +10 -0
- pdd/prompts/extract_auto_include_LLM.prompt +6 -0
- pdd/prompts/extract_code_LLM.prompt +22 -0
- pdd/prompts/extract_conflict_LLM.prompt +19 -0
- pdd/prompts/extract_detect_change_LLM.prompt +19 -0
- pdd/prompts/extract_program_code_fix_LLM.prompt +16 -0
- pdd/prompts/extract_prompt_change_LLM.prompt +7 -0
- pdd/prompts/extract_prompt_split_LLM.prompt +9 -0
- pdd/prompts/extract_prompt_update_LLM.prompt +8 -0
- pdd/prompts/extract_promptline_LLM.prompt +11 -0
- pdd/prompts/extract_unit_code_fix_LLM.prompt +332 -0
- pdd/prompts/extract_xml_LLM.prompt +7 -0
- pdd/prompts/fix_code_module_errors_LLM.prompt +17 -0
- pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +62 -0
- pdd/prompts/generate_test_LLM.prompt +12 -0
- pdd/prompts/increase_tests_LLM.prompt +16 -0
- pdd/prompts/insert_includes_LLM.prompt +30 -0
- pdd/prompts/split_LLM.prompt +94 -0
- pdd/prompts/summarize_file_LLM.prompt +11 -0
- pdd/prompts/trace_LLM.prompt +30 -0
- pdd/prompts/trim_results_LLM.prompt +83 -0
- pdd/prompts/trim_results_start_LLM.prompt +45 -0
- pdd/prompts/unfinished_prompt_LLM.prompt +18 -0
- pdd/prompts/update_prompt_LLM.prompt +19 -0
- pdd/prompts/xml_convertor_LLM.prompt +54 -0
- pdd/split.py +119 -0
- pdd/split_main.py +103 -0
- pdd/summarize_directory.py +212 -0
- pdd/trace.py +135 -0
- pdd/trace_main.py +108 -0
- pdd/track_cost.py +102 -0
- pdd/unfinished_prompt.py +114 -0
- pdd/update_main.py +96 -0
- pdd/update_prompt.py +115 -0
- pdd/xml_tagger.py +122 -0
- pdd_cli-0.0.2.dist-info/LICENSE +7 -0
- pdd_cli-0.0.2.dist-info/METADATA +225 -0
- pdd_cli-0.0.2.dist-info/RECORD +95 -0
- pdd_cli-0.0.2.dist-info/WHEEL +5 -0
- pdd_cli-0.0.2.dist-info/entry_points.txt +2 -0
- pdd_cli-0.0.2.dist-info/top_level.txt +1 -0
pdd/fix_main.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Tuple, Optional
|
|
3
|
+
import click
|
|
4
|
+
from rich import print as rprint
|
|
5
|
+
|
|
6
|
+
from .construct_paths import construct_paths
|
|
7
|
+
from .fix_errors_from_unit_tests import fix_errors_from_unit_tests
|
|
8
|
+
from .fix_error_loop import fix_error_loop
|
|
9
|
+
|
|
10
|
+
def fix_main(
|
|
11
|
+
ctx: click.Context,
|
|
12
|
+
prompt_file: str,
|
|
13
|
+
code_file: str,
|
|
14
|
+
unit_test_file: str,
|
|
15
|
+
error_file: str,
|
|
16
|
+
output_test: Optional[str],
|
|
17
|
+
output_code: Optional[str],
|
|
18
|
+
output_results: Optional[str],
|
|
19
|
+
loop: bool,
|
|
20
|
+
verification_program: Optional[str],
|
|
21
|
+
max_attempts: int,
|
|
22
|
+
budget: float,
|
|
23
|
+
auto_submit: bool
|
|
24
|
+
) -> Tuple[bool, str, str, int, float, str]:
|
|
25
|
+
"""
|
|
26
|
+
Main function to fix errors in code and unit tests.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
ctx: Click context containing command-line parameters
|
|
30
|
+
prompt_file: Path to the prompt file that generated the code
|
|
31
|
+
code_file: Path to the code file to be fixed
|
|
32
|
+
unit_test_file: Path to the unit test file
|
|
33
|
+
error_file: Path to the error log file
|
|
34
|
+
output_test: Path to save the fixed unit test file
|
|
35
|
+
output_code: Path to save the fixed code file
|
|
36
|
+
output_results: Path to save the fix results
|
|
37
|
+
loop: Whether to use iterative fixing process
|
|
38
|
+
verification_program: Path to program that verifies code correctness
|
|
39
|
+
max_attempts: Maximum number of fix attempts
|
|
40
|
+
budget: Maximum cost allowed for fixing
|
|
41
|
+
auto_submit: Whether to auto-submit example if tests pass
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Tuple containing:
|
|
45
|
+
- Success status (bool)
|
|
46
|
+
- Fixed unit test code (str)
|
|
47
|
+
- Fixed source code (str)
|
|
48
|
+
- Total number of fix attempts (int)
|
|
49
|
+
- Total cost of operation (float)
|
|
50
|
+
- Name of model used (str)
|
|
51
|
+
"""
|
|
52
|
+
# Check verification program requirement before any file operations
|
|
53
|
+
if loop and not verification_program:
|
|
54
|
+
raise click.UsageError("--verification-program is required when using --loop")
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
# Construct file paths
|
|
58
|
+
input_file_paths = {
|
|
59
|
+
"prompt_file": prompt_file,
|
|
60
|
+
"code_file": code_file,
|
|
61
|
+
"unit_test_file": unit_test_file
|
|
62
|
+
}
|
|
63
|
+
if not loop:
|
|
64
|
+
input_file_paths["error_file"] = error_file
|
|
65
|
+
|
|
66
|
+
command_options = {
|
|
67
|
+
"output_test": output_test,
|
|
68
|
+
"output_code": output_code,
|
|
69
|
+
"output_results": output_results
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
input_strings, output_file_paths, _ = construct_paths(
|
|
73
|
+
input_file_paths=input_file_paths,
|
|
74
|
+
force=ctx.obj.get('force', False),
|
|
75
|
+
quiet=ctx.obj.get('quiet', False),
|
|
76
|
+
command="fix",
|
|
77
|
+
command_options=command_options
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Get parameters from context
|
|
81
|
+
strength = ctx.obj.get('strength', 0.9)
|
|
82
|
+
temperature = ctx.obj.get('temperature', 0)
|
|
83
|
+
|
|
84
|
+
if loop:
|
|
85
|
+
# Use fix_error_loop for iterative fixing
|
|
86
|
+
success, fixed_unit_test, fixed_code, attempts, total_cost, model_name = fix_error_loop(
|
|
87
|
+
unit_test_file=unit_test_file,
|
|
88
|
+
code_file=code_file,
|
|
89
|
+
prompt=input_strings["prompt_file"],
|
|
90
|
+
verification_program=verification_program,
|
|
91
|
+
strength=strength,
|
|
92
|
+
temperature=temperature,
|
|
93
|
+
max_attempts=max_attempts,
|
|
94
|
+
budget=budget,
|
|
95
|
+
error_log_file=output_file_paths.get("output_results")
|
|
96
|
+
)
|
|
97
|
+
else:
|
|
98
|
+
# Use fix_errors_from_unit_tests for single-pass fixing
|
|
99
|
+
update_unit_test, update_code, fixed_unit_test, fixed_code, total_cost, model_name = fix_errors_from_unit_tests(
|
|
100
|
+
unit_test=input_strings["unit_test_file"],
|
|
101
|
+
code=input_strings["code_file"],
|
|
102
|
+
prompt=input_strings["prompt_file"],
|
|
103
|
+
error=input_strings["error_file"],
|
|
104
|
+
error_file=output_file_paths.get("output_results"),
|
|
105
|
+
strength=strength,
|
|
106
|
+
temperature=temperature
|
|
107
|
+
)
|
|
108
|
+
success = update_unit_test or update_code
|
|
109
|
+
attempts = 1
|
|
110
|
+
|
|
111
|
+
# Save fixed files
|
|
112
|
+
if fixed_unit_test:
|
|
113
|
+
with open(output_file_paths["output_test"], 'w') as f:
|
|
114
|
+
f.write(fixed_unit_test)
|
|
115
|
+
|
|
116
|
+
if fixed_code:
|
|
117
|
+
with open(output_file_paths["output_code"], 'w') as f:
|
|
118
|
+
f.write(fixed_code)
|
|
119
|
+
|
|
120
|
+
# Provide user feedback
|
|
121
|
+
if not ctx.obj.get('quiet', False):
|
|
122
|
+
rprint(f"[bold]{'Success' if success else 'Failed'} to fix errors[/bold]")
|
|
123
|
+
rprint(f"[bold]Total attempts:[/bold] {attempts}")
|
|
124
|
+
rprint(f"[bold]Total cost:[/bold] ${total_cost:.6f}")
|
|
125
|
+
rprint(f"[bold]Model used:[/bold] {model_name}")
|
|
126
|
+
if success:
|
|
127
|
+
rprint("[bold green]Fixed files saved:[/bold green]")
|
|
128
|
+
rprint(f" Test file: {output_file_paths['output_test']}")
|
|
129
|
+
rprint(f" Code file: {output_file_paths['output_code']}")
|
|
130
|
+
if output_file_paths.get("output_results"):
|
|
131
|
+
rprint(f" Results file: {output_file_paths['output_results']}")
|
|
132
|
+
|
|
133
|
+
return success, fixed_unit_test, fixed_code, attempts, total_cost, model_name
|
|
134
|
+
|
|
135
|
+
except Exception as e:
|
|
136
|
+
if not ctx.obj.get('quiet', False):
|
|
137
|
+
rprint(f"[bold red]Error:[/bold red] {str(e)}")
|
|
138
|
+
sys.exit(1)
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
def generate_output_paths(command, output_locations, basename, language, file_extension):
|
|
5
|
+
"""
|
|
6
|
+
Generates output filenames based on command, output_locations, basename, language, and file_extension.
|
|
7
|
+
|
|
8
|
+
Args:
|
|
9
|
+
command (str): The command being executed.
|
|
10
|
+
output_locations (dict): Dictionary of output locations specified by the user.
|
|
11
|
+
basename (str): The base name of the file.
|
|
12
|
+
language (str): The programming language.
|
|
13
|
+
file_extension (str): The file extension, including the leading dot (e.g., ".py").
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
dict: A dictionary containing the generated output filenames with full paths.
|
|
17
|
+
"""
|
|
18
|
+
output_paths = {}
|
|
19
|
+
default_keys = {
|
|
20
|
+
'generate': ['output'],
|
|
21
|
+
'example': ['output'],
|
|
22
|
+
'test': ['output'],
|
|
23
|
+
'preprocess': ['output'],
|
|
24
|
+
'fix': ['output_test', 'output_code', 'output_results'],
|
|
25
|
+
'split': ['output_sub', 'output_modified'],
|
|
26
|
+
'change': ['output'],
|
|
27
|
+
'update': ['output'],
|
|
28
|
+
'detect': ['output'],
|
|
29
|
+
'conflicts': ['output'],
|
|
30
|
+
'crash': ['output', 'output_program'],
|
|
31
|
+
'trace': ['output'],
|
|
32
|
+
'bug': ['output'],
|
|
33
|
+
'auto-deps': ['output']
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Ensure output_locations has all necessary keys for the given command
|
|
37
|
+
for key in default_keys.get(command, []):
|
|
38
|
+
if key not in output_locations:
|
|
39
|
+
output_locations[key] = None
|
|
40
|
+
|
|
41
|
+
if command == 'generate':
|
|
42
|
+
output_paths['output'] = get_output_path(
|
|
43
|
+
output_locations.get('output'),
|
|
44
|
+
'PDD_GENERATE_OUTPUT_PATH',
|
|
45
|
+
f"{basename}{file_extension}"
|
|
46
|
+
)
|
|
47
|
+
elif command == 'example':
|
|
48
|
+
output_paths['output'] = get_output_path(
|
|
49
|
+
output_locations.get('output'),
|
|
50
|
+
'PDD_EXAMPLE_OUTPUT_PATH',
|
|
51
|
+
f"{basename}_example{file_extension}"
|
|
52
|
+
)
|
|
53
|
+
elif command == 'test':
|
|
54
|
+
output_paths['output'] = get_output_path(
|
|
55
|
+
output_locations.get('output'),
|
|
56
|
+
'PDD_TEST_OUTPUT_PATH',
|
|
57
|
+
f"test_{basename}{file_extension}"
|
|
58
|
+
)
|
|
59
|
+
elif command == 'preprocess':
|
|
60
|
+
output_paths['output'] = get_output_path(
|
|
61
|
+
output_locations.get('output'),
|
|
62
|
+
'PDD_PREPROCESS_OUTPUT_PATH',
|
|
63
|
+
f"{basename}_{language}_preprocessed.prompt"
|
|
64
|
+
)
|
|
65
|
+
elif command == 'fix':
|
|
66
|
+
output_paths['output_test'] = get_output_path(
|
|
67
|
+
output_locations.get('output_test'),
|
|
68
|
+
'PDD_FIX_TEST_OUTPUT_PATH',
|
|
69
|
+
f"test_{basename}_fixed{file_extension}"
|
|
70
|
+
)
|
|
71
|
+
output_paths['output_code'] = get_output_path(
|
|
72
|
+
output_locations.get('output_code'),
|
|
73
|
+
'PDD_FIX_CODE_OUTPUT_PATH',
|
|
74
|
+
f"{basename}_fixed{file_extension}"
|
|
75
|
+
)
|
|
76
|
+
output_paths['output_results'] = get_output_path(
|
|
77
|
+
output_locations.get('output_results'),
|
|
78
|
+
'PDD_FIX_RESULTS_OUTPUT_PATH',
|
|
79
|
+
f"{basename}_fix_results.log"
|
|
80
|
+
)
|
|
81
|
+
elif command == 'split':
|
|
82
|
+
output_paths['output_sub'] = get_output_path(
|
|
83
|
+
output_locations.get('output_sub'),
|
|
84
|
+
'PDD_SPLIT_SUB_PROMPT_OUTPUT_PATH',
|
|
85
|
+
f"sub_{basename}.prompt"
|
|
86
|
+
)
|
|
87
|
+
output_paths['output_modified'] = get_output_path(
|
|
88
|
+
output_locations.get('output_modified'),
|
|
89
|
+
'PDD_SPLIT_MODIFIED_PROMPT_OUTPUT_PATH',
|
|
90
|
+
f"modified_{basename}.prompt"
|
|
91
|
+
)
|
|
92
|
+
elif command == 'change':
|
|
93
|
+
output_paths['output'] = get_output_path(
|
|
94
|
+
output_locations.get('output'),
|
|
95
|
+
'PDD_CHANGE_OUTPUT_PATH',
|
|
96
|
+
f"modified_{basename}.prompt"
|
|
97
|
+
)
|
|
98
|
+
elif command == 'update':
|
|
99
|
+
output_paths['output'] = get_output_path(
|
|
100
|
+
output_locations.get('output'),
|
|
101
|
+
'PDD_UPDATE_OUTPUT_PATH',
|
|
102
|
+
f"modified_{basename}.prompt"
|
|
103
|
+
)
|
|
104
|
+
elif command == 'detect':
|
|
105
|
+
output_paths['output'] = get_output_path(
|
|
106
|
+
output_locations.get('output'),
|
|
107
|
+
'PDD_DETECT_OUTPUT_PATH',
|
|
108
|
+
f"{basename}_detect.csv"
|
|
109
|
+
)
|
|
110
|
+
elif command == 'conflicts':
|
|
111
|
+
output_paths['output'] = get_output_path(
|
|
112
|
+
output_locations.get('output'),
|
|
113
|
+
'PDD_CONFLICTS_OUTPUT_PATH',
|
|
114
|
+
f"{basename}_conflict.csv"
|
|
115
|
+
)
|
|
116
|
+
elif command == 'crash':
|
|
117
|
+
output_paths['output'] = get_output_path(
|
|
118
|
+
output_locations.get('output'),
|
|
119
|
+
'PDD_CRASH_OUTPUT_PATH',
|
|
120
|
+
f"{basename}_fixed{file_extension}"
|
|
121
|
+
)
|
|
122
|
+
output_paths['output_program'] = get_output_path(
|
|
123
|
+
output_locations.get('output_program'),
|
|
124
|
+
'PDD_CRASH_PROGRAM_OUTPUT_PATH',
|
|
125
|
+
f"{basename}_fixed{file_extension}"
|
|
126
|
+
)
|
|
127
|
+
elif command == 'trace':
|
|
128
|
+
output_paths['output'] = get_output_path(
|
|
129
|
+
output_locations.get('output'),
|
|
130
|
+
'PDD_TRACE_OUTPUT_PATH',
|
|
131
|
+
f"{basename}_trace_results.log"
|
|
132
|
+
)
|
|
133
|
+
elif command == 'bug':
|
|
134
|
+
output_paths['output'] = get_output_path(
|
|
135
|
+
output_locations.get('output'),
|
|
136
|
+
'PDD_BUG_OUTPUT_PATH',
|
|
137
|
+
f"test_{basename}_bug{file_extension}"
|
|
138
|
+
)
|
|
139
|
+
elif command == 'auto-deps':
|
|
140
|
+
output_paths['output'] = get_output_path(
|
|
141
|
+
output_locations.get('output'),
|
|
142
|
+
'PDD_AUTO_DEPS_OUTPUT_PATH',
|
|
143
|
+
f"{basename}_with_deps.prompt"
|
|
144
|
+
)
|
|
145
|
+
else:
|
|
146
|
+
raise ValueError(f"Invalid command: {command}")
|
|
147
|
+
|
|
148
|
+
return output_paths
|
|
149
|
+
|
|
150
|
+
def get_output_path(user_path, env_var, default_filename):
|
|
151
|
+
"""
|
|
152
|
+
Determines the output path based on user input, environment variables, and default behavior.
|
|
153
|
+
"""
|
|
154
|
+
if user_path:
|
|
155
|
+
# Check if user_path is a directory
|
|
156
|
+
try:
|
|
157
|
+
# A path is considered a directory if:
|
|
158
|
+
# 1. It ends with a separator
|
|
159
|
+
# 2. It exists and is a directory
|
|
160
|
+
# 3. It doesn't contain a file extension
|
|
161
|
+
is_dir = (user_path.endswith(os.sep) or
|
|
162
|
+
(os.path.exists(user_path) and os.path.isdir(user_path)) or
|
|
163
|
+
not os.path.splitext(user_path)[1])
|
|
164
|
+
except (TypeError, ValueError):
|
|
165
|
+
is_dir = user_path.endswith(os.sep)
|
|
166
|
+
|
|
167
|
+
# If it's a directory, join with default filename
|
|
168
|
+
if is_dir:
|
|
169
|
+
path = os.path.join(user_path.rstrip(os.sep), default_filename)
|
|
170
|
+
else:
|
|
171
|
+
path = user_path
|
|
172
|
+
|
|
173
|
+
# Create parent directory if needed
|
|
174
|
+
try:
|
|
175
|
+
parent_dir = os.path.dirname(path)
|
|
176
|
+
if parent_dir:
|
|
177
|
+
Path(parent_dir).mkdir(parents=True, exist_ok=True)
|
|
178
|
+
except (OSError, PermissionError):
|
|
179
|
+
# If we can't create the directory, just return the path
|
|
180
|
+
pass
|
|
181
|
+
return path
|
|
182
|
+
else:
|
|
183
|
+
env_path = os.environ.get(env_var)
|
|
184
|
+
if env_path:
|
|
185
|
+
path = os.path.join(env_path, default_filename)
|
|
186
|
+
try:
|
|
187
|
+
# Create parent directory if needed
|
|
188
|
+
Path(env_path).mkdir(parents=True, exist_ok=True)
|
|
189
|
+
except (OSError, PermissionError):
|
|
190
|
+
# If we can't create the directory, just return the path
|
|
191
|
+
pass
|
|
192
|
+
return path
|
|
193
|
+
else:
|
|
194
|
+
return default_filename
|
pdd/generate_test.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from typing import Tuple, Optional
|
|
2
|
+
from rich import print
|
|
3
|
+
from rich.markdown import Markdown
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from .load_prompt_template import load_prompt_template
|
|
6
|
+
from .preprocess import preprocess
|
|
7
|
+
from .llm_invoke import llm_invoke
|
|
8
|
+
from .unfinished_prompt import unfinished_prompt
|
|
9
|
+
from .continue_generation import continue_generation
|
|
10
|
+
from .postprocess import postprocess
|
|
11
|
+
|
|
12
|
+
console = Console()
|
|
13
|
+
|
|
14
|
+
def generate_test(
|
|
15
|
+
prompt: str,
|
|
16
|
+
code: str,
|
|
17
|
+
strength: float,
|
|
18
|
+
temperature: float,
|
|
19
|
+
language: str,
|
|
20
|
+
verbose: bool = False
|
|
21
|
+
) -> Tuple[str, float, str]:
|
|
22
|
+
"""
|
|
23
|
+
Generate a unit test from a code file using LLM.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
prompt (str): The prompt that generated the code file.
|
|
27
|
+
code (str): The code to generate a unit test from.
|
|
28
|
+
strength (float): The strength of the LLM model (0-1).
|
|
29
|
+
temperature (float): The temperature of the LLM model.
|
|
30
|
+
language (str): The programming language for the unit test.
|
|
31
|
+
verbose (bool): Whether to print detailed information.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Tuple[str, float, str]: (unit_test, total_cost, model_name)
|
|
35
|
+
"""
|
|
36
|
+
total_cost = 0.0
|
|
37
|
+
model_name = ""
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
# Step 1: Load prompt template
|
|
41
|
+
template = load_prompt_template("generate_test_LLM")
|
|
42
|
+
if not template:
|
|
43
|
+
raise ValueError("Failed to load generate_test_LLM prompt template")
|
|
44
|
+
|
|
45
|
+
# Step 2: Preprocess template
|
|
46
|
+
processed_template = preprocess(template, recursive=False, double_curly_brackets=False)
|
|
47
|
+
processed_prompt = preprocess(prompt, recursive=False, double_curly_brackets=False)
|
|
48
|
+
|
|
49
|
+
# Step 3: Run through LLM
|
|
50
|
+
input_json = {
|
|
51
|
+
"prompt_that_generated_code": processed_prompt,
|
|
52
|
+
"code": code,
|
|
53
|
+
"language": language
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if verbose:
|
|
57
|
+
console.print("[bold blue]Generating unit test...[/bold blue]")
|
|
58
|
+
|
|
59
|
+
response = llm_invoke(
|
|
60
|
+
prompt=processed_template,
|
|
61
|
+
input_json=input_json,
|
|
62
|
+
strength=strength,
|
|
63
|
+
temperature=temperature,
|
|
64
|
+
verbose=verbose
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
total_cost += response['cost']
|
|
68
|
+
model_name = response['model_name']
|
|
69
|
+
result = response['result']
|
|
70
|
+
|
|
71
|
+
if verbose:
|
|
72
|
+
console.print(Markdown(result))
|
|
73
|
+
console.print(f"[bold green]Initial generation cost: ${total_cost:.6f}[/bold green]")
|
|
74
|
+
|
|
75
|
+
# Step 4: Check if generation is complete
|
|
76
|
+
last_600_chars = result[-600:] if len(result) > 600 else result
|
|
77
|
+
reasoning, is_finished, check_cost, check_model = unfinished_prompt(
|
|
78
|
+
prompt_text=last_600_chars,
|
|
79
|
+
strength=0.895,
|
|
80
|
+
temperature=temperature,
|
|
81
|
+
verbose=verbose
|
|
82
|
+
)
|
|
83
|
+
total_cost += check_cost
|
|
84
|
+
|
|
85
|
+
if not is_finished:
|
|
86
|
+
if verbose:
|
|
87
|
+
console.print("[bold yellow]Generation incomplete. Continuing...[/bold yellow]")
|
|
88
|
+
|
|
89
|
+
continued_result, continue_cost, continue_model = continue_generation(
|
|
90
|
+
formatted_input_prompt=processed_template,
|
|
91
|
+
llm_output=result,
|
|
92
|
+
strength=strength,
|
|
93
|
+
temperature=temperature,
|
|
94
|
+
verbose=verbose
|
|
95
|
+
)
|
|
96
|
+
total_cost += continue_cost
|
|
97
|
+
result = continued_result
|
|
98
|
+
model_name = continue_model
|
|
99
|
+
|
|
100
|
+
# Process the final result
|
|
101
|
+
processed_result, post_cost, post_model = postprocess(
|
|
102
|
+
result,
|
|
103
|
+
language=language,
|
|
104
|
+
strength=0.895,
|
|
105
|
+
temperature=temperature,
|
|
106
|
+
verbose=verbose
|
|
107
|
+
)
|
|
108
|
+
total_cost += post_cost
|
|
109
|
+
|
|
110
|
+
# Step 5: Print total cost if verbose
|
|
111
|
+
if verbose:
|
|
112
|
+
console.print(f"[bold green]Total cost: ${total_cost:.6f}[/bold green]")
|
|
113
|
+
console.print(f"[bold blue]Final model used: {model_name}[/bold blue]")
|
|
114
|
+
|
|
115
|
+
# Step 6: Return results
|
|
116
|
+
return processed_result, total_cost, model_name
|
|
117
|
+
|
|
118
|
+
except Exception as e:
|
|
119
|
+
console.print(f"[bold red]Error: {str(e)}[/bold red]")
|
|
120
|
+
raise
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _validate_inputs(
|
|
124
|
+
prompt: str,
|
|
125
|
+
code: str,
|
|
126
|
+
strength: float,
|
|
127
|
+
temperature: float,
|
|
128
|
+
language: str
|
|
129
|
+
) -> None:
|
|
130
|
+
"""Validate input parameters."""
|
|
131
|
+
if not prompt or not isinstance(prompt, str):
|
|
132
|
+
raise ValueError("Prompt must be a non-empty string")
|
|
133
|
+
if not code or not isinstance(code, str):
|
|
134
|
+
raise ValueError("Code must be a non-empty string")
|
|
135
|
+
if not isinstance(strength, float) or not 0 <= strength <= 1:
|
|
136
|
+
raise ValueError("Strength must be a float between 0 and 1")
|
|
137
|
+
if not isinstance(temperature, float):
|
|
138
|
+
raise ValueError("Temperature must be a float")
|
|
139
|
+
if not language or not isinstance(language, str):
|
|
140
|
+
raise ValueError("Language must be a non-empty string")
|
pdd/get_comment.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# To achieve the task of writing a Python function `get_comment` that returns the comment character(s) associated with a given programming language, we need to follow the steps outlined in your description. Here's how you can implement this:
|
|
2
|
+
|
|
3
|
+
# ```python
|
|
4
|
+
import os
|
|
5
|
+
import csv
|
|
6
|
+
|
|
7
|
+
def get_comment(language):
|
|
8
|
+
# Step 1: Load environment variables to get the path to the CSV file
|
|
9
|
+
pdd_path = os.getenv('PDD_PATH')
|
|
10
|
+
if not pdd_path:
|
|
11
|
+
return 'del' # Return 'del' if the environment variable is not set
|
|
12
|
+
|
|
13
|
+
csv_file_path = os.path.join(pdd_path, 'data', 'language_format.csv')
|
|
14
|
+
|
|
15
|
+
# Step 2: Lower case the language string
|
|
16
|
+
language = language.lower()
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
# Step 3: Open the CSV file and look up the comment character(s)
|
|
20
|
+
with open(csv_file_path, mode='r', newline='') as csvfile:
|
|
21
|
+
reader = csv.DictReader(csvfile)
|
|
22
|
+
for row in reader:
|
|
23
|
+
if row['language'].lower() == language:
|
|
24
|
+
comment = row['comment']
|
|
25
|
+
# Step 4: Check if the comment character(s) is valid
|
|
26
|
+
if comment:
|
|
27
|
+
return comment
|
|
28
|
+
else:
|
|
29
|
+
return 'del'
|
|
30
|
+
except FileNotFoundError:
|
|
31
|
+
return 'del' # Return 'del' if the file is not found
|
|
32
|
+
except Exception as e:
|
|
33
|
+
return 'del' # Return 'del' for any other exceptions
|
|
34
|
+
|
|
35
|
+
return 'del' # Return 'del' if the language is not found
|
|
36
|
+
|
|
37
|
+
# Example usage:
|
|
38
|
+
# Assuming the environment variable PDD_PATH is set correctly
|
|
39
|
+
# print(get_comment('Python')) # Output: #
|
|
40
|
+
# print(get_comment('Java')) # Output: //
|
|
41
|
+
# ```
|
|
42
|
+
|
|
43
|
+
# ### Explanation:
|
|
44
|
+
|
|
45
|
+
# 1. **Environment Variable**: The function first retrieves the `PDD_PATH` environment variable to locate the CSV file. If the environment variable is not set, it returns `'del'`.
|
|
46
|
+
|
|
47
|
+
# 2. **Case Insensitivity**: The input language string is converted to lowercase to ensure case-insensitive comparison.
|
|
48
|
+
|
|
49
|
+
# 3. **CSV Reading**: The function reads the CSV file using Python's `csv.DictReader`, which allows accessing each row as a dictionary. It checks if the lowercase version of the language matches any entry in the CSV.
|
|
50
|
+
|
|
51
|
+
# 4. **Validation**: If a match is found, it checks if the comment character(s) is valid (i.e., not an empty string). If valid, it returns the comment character(s); otherwise, it returns `'del'`.
|
|
52
|
+
|
|
53
|
+
# 5. **Error Handling**: The function handles potential errors such as file not found or other exceptions by returning `'del'`.
|
|
54
|
+
|
|
55
|
+
# This implementation assumes that the CSV file is correctly formatted and that the environment variable `PDD_PATH` is set to the correct path.
|
pdd/get_extension.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# To implement the `get_extension` function as described, we will follow the steps outlined in your request. We'll use the `pandas` library to read the CSV file, and we'll handle the environment variable for the file path. Here's how you can implement this function:
|
|
2
|
+
|
|
3
|
+
# ```python
|
|
4
|
+
import os
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
def get_extension(language):
|
|
8
|
+
# Step 1: Load the environment variable PDD_PATH
|
|
9
|
+
pdd_path = os.getenv('PDD_PATH')
|
|
10
|
+
if not pdd_path:
|
|
11
|
+
raise ValueError("Environment variable PDD_PATH is not set.")
|
|
12
|
+
|
|
13
|
+
# Construct the full path to the CSV file
|
|
14
|
+
csv_file_path = os.path.join(pdd_path, 'data', 'language_format.csv')
|
|
15
|
+
|
|
16
|
+
# Step 2: Lower case the language string
|
|
17
|
+
language_lower = language.lower()
|
|
18
|
+
|
|
19
|
+
# Step 3: Load the CSV file and look up the file extension
|
|
20
|
+
try:
|
|
21
|
+
df = pd.read_csv(csv_file_path)
|
|
22
|
+
except FileNotFoundError:
|
|
23
|
+
raise FileNotFoundError(f"The file {csv_file_path} does not exist.")
|
|
24
|
+
|
|
25
|
+
# Check if the language exists in the DataFrame
|
|
26
|
+
row = df[df['language'].str.lower() == language_lower]
|
|
27
|
+
|
|
28
|
+
# Step 4: Return the file extension or an empty string if not found
|
|
29
|
+
if not row.empty:
|
|
30
|
+
extension = row['extension'].values[0]
|
|
31
|
+
return extension if isinstance(extension, str) and extension else ''
|
|
32
|
+
|
|
33
|
+
return ''
|
|
34
|
+
|
|
35
|
+
# Example usage:
|
|
36
|
+
# Assuming the environment variable PDD_PATH is set correctly
|
|
37
|
+
# print(get_extension('Python')) # Output: .py
|
|
38
|
+
# ```
|
|
39
|
+
|
|
40
|
+
# ### Explanation of the Code:
|
|
41
|
+
# 1. **Environment Variable**: We use `os.getenv` to retrieve the `PDD_PATH` environment variable. If it's not set, we raise a `ValueError`.
|
|
42
|
+
# 2. **Lowercase Language**: The input language string is converted to lowercase to ensure case-insensitive comparison.
|
|
43
|
+
# 3. **Load CSV**: We use `pandas` to read the CSV file. If the file is not found, we raise a `FileNotFoundError`.
|
|
44
|
+
# 4. **Lookup**: We filter the DataFrame to find the row corresponding to the given language. If found, we check if the extension is a valid string and return it; otherwise, we return an empty string.
|
|
45
|
+
# 5. **Return Value**: If the language is not found, we return an empty string.
|
|
46
|
+
|
|
47
|
+
# ### Note:
|
|
48
|
+
# - Make sure to have the `pandas` library installed in your Python environment. You can install it using pip:
|
|
49
|
+
# ```bash
|
|
50
|
+
# pip install pandas
|
|
51
|
+
# ```
|
|
52
|
+
# - Ensure that the CSV file is structured correctly and located at the specified path.
|
pdd/get_language.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import csv
|
|
3
|
+
|
|
4
|
+
def get_language(extension: str) -> str:
|
|
5
|
+
"""
|
|
6
|
+
Determines the programming language associated with a given file extension.
|
|
7
|
+
|
|
8
|
+
Args:
|
|
9
|
+
extension (str): The file extension to look up.
|
|
10
|
+
|
|
11
|
+
Returns:
|
|
12
|
+
str: The name of the programming language or an empty string if not found.
|
|
13
|
+
|
|
14
|
+
Raises:
|
|
15
|
+
ValueError: If PDD_PATH environment variable is not set.
|
|
16
|
+
"""
|
|
17
|
+
# Step 1: Load environment variable PDD_PATH
|
|
18
|
+
pdd_path = os.environ.get('PDD_PATH')
|
|
19
|
+
if not pdd_path:
|
|
20
|
+
raise ValueError("PDD_PATH environment variable is not set")
|
|
21
|
+
|
|
22
|
+
# Step 2: Ensure the extension starts with a dot and convert to lowercase
|
|
23
|
+
if not extension.startswith('.'):
|
|
24
|
+
extension = '.' + extension
|
|
25
|
+
extension = extension.lower()
|
|
26
|
+
|
|
27
|
+
# Step 3 & 4: Look up the language name and handle exceptions
|
|
28
|
+
csv_path = os.path.join(pdd_path, 'data', 'language_format.csv')
|
|
29
|
+
try:
|
|
30
|
+
with open(csv_path, 'r') as csvfile:
|
|
31
|
+
reader = csv.DictReader(csvfile)
|
|
32
|
+
for row in reader:
|
|
33
|
+
if row['extension'].lower() == extension:
|
|
34
|
+
language = row['language'].strip()
|
|
35
|
+
return language if language else ''
|
|
36
|
+
except FileNotFoundError:
|
|
37
|
+
print(f"CSV file not found at {csv_path}")
|
|
38
|
+
except csv.Error as e:
|
|
39
|
+
print(f"Error reading CSV file: {e}")
|
|
40
|
+
|
|
41
|
+
return '' # Return empty string if extension not found or any error occurs
|