pdd-cli 0.0.23__py3-none-any.whl → 0.0.25__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 +7 -1
- pdd/bug_main.py +21 -3
- pdd/bug_to_unit_test.py +16 -5
- pdd/change.py +2 -1
- pdd/change_main.py +407 -189
- pdd/cli.py +853 -301
- pdd/code_generator.py +2 -1
- pdd/conflicts_in_prompts.py +2 -1
- pdd/construct_paths.py +377 -222
- pdd/context_generator.py +2 -1
- pdd/continue_generation.py +3 -2
- pdd/crash_main.py +55 -20
- pdd/data/llm_model.csv +8 -8
- pdd/detect_change.py +2 -1
- pdd/fix_code_loop.py +465 -160
- pdd/fix_code_module_errors.py +7 -4
- pdd/fix_error_loop.py +9 -9
- pdd/fix_errors_from_unit_tests.py +207 -365
- pdd/fix_main.py +31 -4
- pdd/fix_verification_errors.py +285 -0
- pdd/fix_verification_errors_loop.py +975 -0
- pdd/fix_verification_main.py +412 -0
- pdd/generate_output_paths.py +427 -183
- pdd/generate_test.py +3 -2
- pdd/increase_tests.py +2 -2
- pdd/llm_invoke.py +18 -8
- pdd/pdd_completion.zsh +38 -1
- pdd/preprocess.py +3 -3
- pdd/process_csv_change.py +466 -154
- pdd/prompts/extract_prompt_split_LLM.prompt +7 -4
- pdd/prompts/extract_prompt_update_LLM.prompt +11 -5
- pdd/prompts/extract_unit_code_fix_LLM.prompt +2 -2
- pdd/prompts/find_verification_errors_LLM.prompt +25 -0
- pdd/prompts/fix_code_module_errors_LLM.prompt +29 -0
- pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +5 -5
- pdd/prompts/fix_verification_errors_LLM.prompt +20 -0
- pdd/prompts/generate_test_LLM.prompt +9 -3
- pdd/prompts/split_LLM.prompt +3 -3
- pdd/prompts/update_prompt_LLM.prompt +3 -3
- pdd/split.py +13 -12
- pdd/split_main.py +22 -13
- pdd/trace_main.py +7 -0
- pdd/xml_tagger.py +2 -1
- {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/METADATA +4 -4
- {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/RECORD +49 -44
- {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/WHEEL +1 -1
- {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/entry_points.txt +0 -0
- {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/licenses/LICENSE +0 -0
- {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/top_level.txt +0 -0
pdd/generate_output_paths.py
CHANGED
|
@@ -1,194 +1,438 @@
|
|
|
1
1
|
import os
|
|
2
|
-
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Dict, List, Optional
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
# Configure logging
|
|
6
|
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
# --- Configuration Data ---
|
|
10
|
+
|
|
11
|
+
# Define the expected output keys for each command
|
|
12
|
+
# Use underscores for keys as requested
|
|
13
|
+
COMMAND_OUTPUT_KEYS: Dict[str, List[str]] = {
|
|
14
|
+
'generate': ['output'],
|
|
15
|
+
'example': ['output'],
|
|
16
|
+
'test': ['output'],
|
|
17
|
+
'preprocess': ['output'],
|
|
18
|
+
'fix': ['output_test', 'output_code', 'output_results'],
|
|
19
|
+
'split': ['output_sub', 'output_modified'],
|
|
20
|
+
'change': ['output'],
|
|
21
|
+
'update': ['output'],
|
|
22
|
+
'detect': ['output'],
|
|
23
|
+
'conflicts': ['output'],
|
|
24
|
+
'crash': ['output', 'output_program'],
|
|
25
|
+
'trace': ['output'],
|
|
26
|
+
'bug': ['output'],
|
|
27
|
+
'auto-deps': ['output'],
|
|
28
|
+
'verify': ['output_results', 'output_code'],
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Define default filename patterns for each output key
|
|
32
|
+
# Placeholders: {basename}, {language}, {ext}
|
|
33
|
+
# Note: Patterns include the extension directly where it's fixed (e.g., .prompt, .log, .csv)
|
|
34
|
+
# or use {ext} where it depends on the language.
|
|
35
|
+
DEFAULT_FILENAMES: Dict[str, Dict[str, str]] = {
|
|
36
|
+
'generate': {'output': '{basename}{ext}'},
|
|
37
|
+
'example': {'output': '{basename}_example{ext}'},
|
|
38
|
+
'test': {'output': 'test_{basename}{ext}'},
|
|
39
|
+
'preprocess': {'output': '{basename}_{language}_preprocessed.prompt'},
|
|
40
|
+
'fix': {
|
|
41
|
+
'output_test': 'test_{basename}_fixed{ext}',
|
|
42
|
+
'output_code': '{basename}_fixed{ext}',
|
|
43
|
+
'output_results': '{basename}_fix_results.log',
|
|
44
|
+
},
|
|
45
|
+
'split': {
|
|
46
|
+
'output_sub': 'sub_{basename}.prompt',
|
|
47
|
+
'output_modified': 'modified_{basename}.prompt',
|
|
48
|
+
},
|
|
49
|
+
'change': {'output': 'modified_{basename}.prompt'},
|
|
50
|
+
'update': {'output': 'modified_{basename}.prompt'}, # Consistent with change/split default
|
|
51
|
+
'detect': {'output': '{basename}_detect.csv'}, # Using basename as change_file_basename isn't available here
|
|
52
|
+
'conflicts': {'output': '{basename}_conflict.csv'}, # Using basename as prompt1/2 basenames aren't available
|
|
53
|
+
'crash': {
|
|
54
|
+
'output': '{basename}_fixed{ext}',
|
|
55
|
+
# Using basename as program_basename isn't available here
|
|
56
|
+
'output_program': '{basename}_program_fixed{ext}',
|
|
57
|
+
},
|
|
58
|
+
'trace': {'output': '{basename}_trace_results.log'},
|
|
59
|
+
'bug': {'output': 'test_{basename}_bug{ext}'},
|
|
60
|
+
'auto-deps': {'output': '{basename}_with_deps.prompt'},
|
|
61
|
+
'verify': {
|
|
62
|
+
'output_results': '{basename}_verify_results.log',
|
|
63
|
+
'output_code': '{basename}_verified{ext}',
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# Define the mapping from command/output key to environment variables
|
|
68
|
+
ENV_VAR_MAP: Dict[str, Dict[str, str]] = {
|
|
69
|
+
'generate': {'output': 'PDD_GENERATE_OUTPUT_PATH'},
|
|
70
|
+
'example': {'output': 'PDD_EXAMPLE_OUTPUT_PATH'},
|
|
71
|
+
'test': {'output': 'PDD_TEST_OUTPUT_PATH'},
|
|
72
|
+
'preprocess': {'output': 'PDD_PREPROCESS_OUTPUT_PATH'},
|
|
73
|
+
'fix': {
|
|
74
|
+
'output_test': 'PDD_FIX_TEST_OUTPUT_PATH',
|
|
75
|
+
'output_code': 'PDD_FIX_CODE_OUTPUT_PATH',
|
|
76
|
+
'output_results': 'PDD_FIX_RESULTS_OUTPUT_PATH',
|
|
77
|
+
},
|
|
78
|
+
'split': {
|
|
79
|
+
'output_sub': 'PDD_SPLIT_SUB_PROMPT_OUTPUT_PATH',
|
|
80
|
+
'output_modified': 'PDD_SPLIT_MODIFIED_PROMPT_OUTPUT_PATH',
|
|
81
|
+
},
|
|
82
|
+
'change': {'output': 'PDD_CHANGE_OUTPUT_PATH'},
|
|
83
|
+
'update': {'output': 'PDD_UPDATE_OUTPUT_PATH'},
|
|
84
|
+
'detect': {'output': 'PDD_DETECT_OUTPUT_PATH'},
|
|
85
|
+
'conflicts': {'output': 'PDD_CONFLICTS_OUTPUT_PATH'},
|
|
86
|
+
'crash': {
|
|
87
|
+
'output': 'PDD_CRASH_OUTPUT_PATH',
|
|
88
|
+
'output_program': 'PDD_CRASH_PROGRAM_OUTPUT_PATH',
|
|
89
|
+
},
|
|
90
|
+
'trace': {'output': 'PDD_TRACE_OUTPUT_PATH'},
|
|
91
|
+
'bug': {'output': 'PDD_BUG_OUTPUT_PATH'},
|
|
92
|
+
'auto-deps': {'output': 'PDD_AUTO_DEPS_OUTPUT_PATH'},
|
|
93
|
+
'verify': {
|
|
94
|
+
'output_results': 'PDD_VERIFY_RESULTS_OUTPUT_PATH',
|
|
95
|
+
'output_code': 'PDD_VERIFY_CODE_OUTPUT_PATH',
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# --- Helper Function ---
|
|
100
|
+
|
|
101
|
+
def _get_default_filename(command: str, output_key: str, basename: str, language: str, file_extension: str) -> str:
|
|
102
|
+
"""Generates the default filename based on the command and output key."""
|
|
103
|
+
try:
|
|
104
|
+
pattern = DEFAULT_FILENAMES[command][output_key]
|
|
105
|
+
# Use specific extension if in pattern, otherwise use language extension
|
|
106
|
+
if '{ext}' in pattern:
|
|
107
|
+
# Ensure file_extension starts with '.' if not empty
|
|
108
|
+
effective_extension = file_extension if file_extension.startswith('.') or not file_extension else '.' + file_extension
|
|
109
|
+
return pattern.format(basename=basename, language=language, ext=effective_extension)
|
|
110
|
+
else:
|
|
111
|
+
# Pattern already contains the full extension (e.g., .prompt, .log, .csv)
|
|
112
|
+
return pattern.format(basename=basename, language=language) # ext might not be needed
|
|
113
|
+
except KeyError:
|
|
114
|
+
logger.error(f"Default filename pattern not found for command '{command}', output key '{output_key}'.")
|
|
115
|
+
# Fallback or raise error - returning a basic fallback for now
|
|
116
|
+
return f"{basename}_{output_key}_default{file_extension}"
|
|
117
|
+
except Exception as e:
|
|
118
|
+
logger.error(f"Error formatting default filename for {command}/{output_key}: {e}")
|
|
119
|
+
return f"{basename}_{output_key}_error{file_extension}"
|
|
120
|
+
|
|
121
|
+
# --- Main Function ---
|
|
122
|
+
|
|
123
|
+
def generate_output_paths(
|
|
124
|
+
command: str,
|
|
125
|
+
output_locations: Dict[str, Optional[str]],
|
|
126
|
+
basename: str,
|
|
127
|
+
language: str,
|
|
128
|
+
file_extension: str
|
|
129
|
+
) -> Dict[str, str]:
|
|
5
130
|
"""
|
|
6
|
-
Generates
|
|
131
|
+
Generates the full, absolute output paths for a given PDD command.
|
|
132
|
+
|
|
133
|
+
It prioritizes user-specified paths (--output options), then environment
|
|
134
|
+
variables, and finally falls back to default naming conventions in the
|
|
135
|
+
current working directory.
|
|
7
136
|
|
|
8
137
|
Args:
|
|
9
|
-
command
|
|
10
|
-
output_locations
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
138
|
+
command: The PDD command being executed (e.g., 'generate', 'fix').
|
|
139
|
+
output_locations: Dictionary of user-specified output locations from
|
|
140
|
+
command-line options (e.g., {'output': 'path/to/file',
|
|
141
|
+
'output_test': 'dir/'}). Keys use underscores.
|
|
142
|
+
Values can be None if the option wasn't provided.
|
|
143
|
+
basename: The base name derived from the input prompt file.
|
|
144
|
+
language: The programming language associated with the operation.
|
|
145
|
+
file_extension: The file extension (including '.') for the language,
|
|
146
|
+
used when default patterns require it.
|
|
14
147
|
|
|
15
148
|
Returns:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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.
|
|
149
|
+
A dictionary where keys are the standardized output identifiers
|
|
150
|
+
(e.g., 'output', 'output_test') and values are the full, absolute
|
|
151
|
+
paths to the determined output files. Returns an empty dictionary
|
|
152
|
+
if the command is unknown.
|
|
153
153
|
"""
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
154
|
+
logger.debug(f"Generating output paths for command: {command}")
|
|
155
|
+
logger.debug(f"User output locations: {output_locations}")
|
|
156
|
+
logger.debug(f"Basename: {basename}, Language: {language}, Extension: {file_extension}")
|
|
157
|
+
|
|
158
|
+
result_paths: Dict[str, str] = {}
|
|
159
|
+
|
|
160
|
+
if not basename:
|
|
161
|
+
logger.error("Basename is required but was not provided.")
|
|
162
|
+
return {} # Cannot generate paths without a basename
|
|
163
|
+
|
|
164
|
+
# Ensure file_extension starts with '.' if provided
|
|
165
|
+
if file_extension and not file_extension.startswith('.'):
|
|
166
|
+
file_extension = '.' + file_extension
|
|
167
|
+
logger.debug(f"Adjusted file extension to: {file_extension}")
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
expected_output_keys = COMMAND_OUTPUT_KEYS.get(command)
|
|
171
|
+
if not expected_output_keys:
|
|
172
|
+
logger.error(f"Unknown command '{command}' provided.")
|
|
173
|
+
return {}
|
|
174
|
+
|
|
175
|
+
# Ensure the input output_locations dictionary uses underscores
|
|
176
|
+
# (This should ideally be handled by the argument parser, but double-check)
|
|
177
|
+
processed_output_locations = {k.replace('-', '_'): v for k, v in output_locations.items()}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
for output_key in expected_output_keys:
|
|
181
|
+
logger.debug(f"Processing output key: {output_key}")
|
|
182
|
+
|
|
183
|
+
user_path: Optional[str] = processed_output_locations.get(output_key)
|
|
184
|
+
env_var_name: Optional[str] = ENV_VAR_MAP.get(command, {}).get(output_key)
|
|
185
|
+
env_path: Optional[str] = os.environ.get(env_var_name) if env_var_name else None
|
|
186
|
+
|
|
187
|
+
# Generate the default filename for this specific output key
|
|
188
|
+
default_filename = _get_default_filename(command, output_key, basename, language, file_extension)
|
|
189
|
+
logger.debug(f"Default filename for {output_key}: {default_filename}")
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
final_path: Optional[str] = None
|
|
193
|
+
source: str = "default" # Track where the path came from
|
|
194
|
+
|
|
195
|
+
# 1. Check User-Specified Path (--output option)
|
|
196
|
+
if user_path:
|
|
197
|
+
source = "user"
|
|
198
|
+
# Check if the user provided a directory path
|
|
199
|
+
# Ends with separator OR is an existing directory
|
|
200
|
+
is_dir = user_path.endswith(os.path.sep)
|
|
201
|
+
if not is_dir:
|
|
202
|
+
try:
|
|
203
|
+
# Check if it exists and is a directory, suppressing errors if it doesn't exist yet
|
|
204
|
+
if os.path.exists(user_path) and os.path.isdir(user_path):
|
|
205
|
+
is_dir = True
|
|
206
|
+
except Exception as e:
|
|
207
|
+
logger.warning(f"Could not check if user path '{user_path}' is a directory: {e}")
|
|
208
|
+
|
|
209
|
+
if is_dir:
|
|
210
|
+
logger.debug(f"User path '{user_path}' identified as a directory.")
|
|
211
|
+
final_path = os.path.join(user_path, default_filename)
|
|
212
|
+
else:
|
|
213
|
+
logger.debug(f"User path '{user_path}' identified as a specific file path.")
|
|
214
|
+
final_path = user_path # Assume it's a full path or filename
|
|
215
|
+
|
|
216
|
+
# 2. Check Environment Variable Path
|
|
217
|
+
elif env_path:
|
|
218
|
+
source = "environment"
|
|
219
|
+
# Check if the environment variable points to a directory
|
|
220
|
+
is_dir = env_path.endswith(os.path.sep)
|
|
221
|
+
if not is_dir:
|
|
222
|
+
try:
|
|
223
|
+
if os.path.exists(env_path) and os.path.isdir(env_path):
|
|
224
|
+
is_dir = True
|
|
225
|
+
except Exception as e:
|
|
226
|
+
logger.warning(f"Could not check if env path '{env_path}' is a directory: {e}")
|
|
227
|
+
|
|
228
|
+
if is_dir:
|
|
229
|
+
logger.debug(f"Env path '{env_path}' identified as a directory.")
|
|
230
|
+
final_path = os.path.join(env_path, default_filename)
|
|
231
|
+
else:
|
|
232
|
+
logger.debug(f"Env path '{env_path}' identified as a specific file path.")
|
|
233
|
+
final_path = env_path # Assume it's a full path or filename
|
|
234
|
+
|
|
235
|
+
# 3. Use Default Naming Convention in CWD
|
|
170
236
|
else:
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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)
|
|
237
|
+
source = "default"
|
|
238
|
+
logger.debug(f"Using default filename '{default_filename}' in current directory.")
|
|
239
|
+
final_path = default_filename # Relative to CWD initially
|
|
240
|
+
|
|
241
|
+
# Resolve to absolute path
|
|
242
|
+
if final_path:
|
|
186
243
|
try:
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
244
|
+
absolute_path = os.path.abspath(final_path)
|
|
245
|
+
result_paths[output_key] = absolute_path
|
|
246
|
+
logger.info(f"Determined path for '{output_key}' ({source}): {absolute_path}")
|
|
247
|
+
except Exception as e:
|
|
248
|
+
logger.error(f"Failed to resolve path '{final_path}' to absolute path: {e}")
|
|
249
|
+
# Decide how to handle: skip, use relative, raise error? Using relative for now.
|
|
250
|
+
result_paths[output_key] = final_path
|
|
251
|
+
logger.warning(f"Using relative path for '{output_key}' due to error: {final_path}")
|
|
252
|
+
|
|
193
253
|
else:
|
|
194
|
-
|
|
254
|
+
logger.error(f"Could not determine a final path for output key '{output_key}' for command '{command}'.")
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
logger.debug(f"Final generated paths: {result_paths}")
|
|
258
|
+
return result_paths
|
|
259
|
+
|
|
260
|
+
# --- Example Usage (for testing) ---
|
|
261
|
+
if __name__ == '__main__':
|
|
262
|
+
# Mock inputs
|
|
263
|
+
mock_basename = "my_module"
|
|
264
|
+
mock_language = "python"
|
|
265
|
+
mock_extension = ".py"
|
|
266
|
+
|
|
267
|
+
# --- Test Case 1: Generate command, no user/env input ---
|
|
268
|
+
print("\n--- Test Case 1: Generate (Defaults) ---")
|
|
269
|
+
paths1 = generate_output_paths(
|
|
270
|
+
command='generate',
|
|
271
|
+
output_locations={}, # No user input
|
|
272
|
+
basename=mock_basename,
|
|
273
|
+
language=mock_language,
|
|
274
|
+
file_extension=mock_extension
|
|
275
|
+
)
|
|
276
|
+
print(f"Result: {paths1}")
|
|
277
|
+
# Expected: {'output': '/path/to/cwd/my_module.py'}
|
|
278
|
+
|
|
279
|
+
# --- Test Case 2: Generate command, user specifies filename ---
|
|
280
|
+
print("\n--- Test Case 2: Generate (User Filename) ---")
|
|
281
|
+
paths2 = generate_output_paths(
|
|
282
|
+
command='generate',
|
|
283
|
+
output_locations={'output': 'generated_code.py'},
|
|
284
|
+
basename=mock_basename,
|
|
285
|
+
language=mock_language,
|
|
286
|
+
file_extension=mock_extension
|
|
287
|
+
)
|
|
288
|
+
print(f"Result: {paths2}")
|
|
289
|
+
# Expected: {'output': '/path/to/cwd/generated_code.py'}
|
|
290
|
+
|
|
291
|
+
# --- Test Case 3: Generate command, user specifies directory ---
|
|
292
|
+
print("\n--- Test Case 3: Generate (User Directory) ---")
|
|
293
|
+
# Create a dummy directory for testing
|
|
294
|
+
test_dir_gen = "temp_gen_output"
|
|
295
|
+
os.makedirs(test_dir_gen, exist_ok=True)
|
|
296
|
+
paths3 = generate_output_paths(
|
|
297
|
+
command='generate',
|
|
298
|
+
output_locations={'output': test_dir_gen + os.path.sep}, # Explicit directory
|
|
299
|
+
basename=mock_basename,
|
|
300
|
+
language=mock_language,
|
|
301
|
+
file_extension=mock_extension
|
|
302
|
+
)
|
|
303
|
+
print(f"Result: {paths3}")
|
|
304
|
+
# Expected: {'output': '/path/to/cwd/temp_gen_output/my_module.py'}
|
|
305
|
+
os.rmdir(test_dir_gen) # Clean up
|
|
306
|
+
|
|
307
|
+
# --- Test Case 4: Fix command, mixed user input (dir and file) ---
|
|
308
|
+
print("\n--- Test Case 4: Fix (Mixed User Input) ---")
|
|
309
|
+
test_dir_fix = "temp_fix_tests"
|
|
310
|
+
os.makedirs(test_dir_fix, exist_ok=True)
|
|
311
|
+
paths4 = generate_output_paths(
|
|
312
|
+
command='fix',
|
|
313
|
+
output_locations={
|
|
314
|
+
'output_test': test_dir_fix, # Directory
|
|
315
|
+
'output_code': 'src/fixed_code.py', # Specific file
|
|
316
|
+
'output_results': None # Use default/env
|
|
317
|
+
},
|
|
318
|
+
basename=mock_basename,
|
|
319
|
+
language=mock_language,
|
|
320
|
+
file_extension=mock_extension
|
|
321
|
+
)
|
|
322
|
+
print(f"Result: {paths4}")
|
|
323
|
+
# Expected: {
|
|
324
|
+
# 'output_test': '/path/to/cwd/temp_fix_tests/test_my_module_fixed.py',
|
|
325
|
+
# 'output_code': '/path/to/cwd/src/fixed_code.py',
|
|
326
|
+
# 'output_results': '/path/to/cwd/my_module_fix_results.log'
|
|
327
|
+
# }
|
|
328
|
+
os.rmdir(test_dir_fix) # Clean up
|
|
329
|
+
|
|
330
|
+
# --- Test Case 5: Fix command, using environment variables ---
|
|
331
|
+
print("\n--- Test Case 5: Fix (Environment Variables) ---")
|
|
332
|
+
test_dir_env_code = "env_fixed_code_dir"
|
|
333
|
+
test_dir_env_results = "env_results_dir"
|
|
334
|
+
os.makedirs(test_dir_env_code, exist_ok=True)
|
|
335
|
+
os.makedirs(test_dir_env_results, exist_ok=True)
|
|
336
|
+
# Set mock environment variables
|
|
337
|
+
os.environ['PDD_FIX_CODE_OUTPUT_PATH'] = test_dir_env_code + os.path.sep # Directory
|
|
338
|
+
os.environ['PDD_FIX_RESULTS_OUTPUT_PATH'] = os.path.join(test_dir_env_results, "custom_fix_log.txt") # Specific file
|
|
339
|
+
|
|
340
|
+
paths5 = generate_output_paths(
|
|
341
|
+
command='fix',
|
|
342
|
+
output_locations={}, # No user input
|
|
343
|
+
basename=mock_basename,
|
|
344
|
+
language=mock_language,
|
|
345
|
+
file_extension=mock_extension
|
|
346
|
+
)
|
|
347
|
+
print(f"Result: {paths5}")
|
|
348
|
+
# Expected: {
|
|
349
|
+
# 'output_test': '/path/to/cwd/test_my_module_fixed.py', # Default
|
|
350
|
+
# 'output_code': '/path/to/cwd/env_fixed_code_dir/my_module_fixed.py', # Env Dir
|
|
351
|
+
# 'output_results': '/path/to/cwd/env_results_dir/custom_fix_log.txt' # Env File
|
|
352
|
+
# }
|
|
353
|
+
# Clean up env vars and dirs
|
|
354
|
+
del os.environ['PDD_FIX_CODE_OUTPUT_PATH']
|
|
355
|
+
del os.environ['PDD_FIX_RESULTS_OUTPUT_PATH']
|
|
356
|
+
os.rmdir(test_dir_env_code)
|
|
357
|
+
os.rmdir(test_dir_env_results)
|
|
358
|
+
|
|
359
|
+
# --- Test Case 6: Preprocess command (fixed extension) ---
|
|
360
|
+
print("\n--- Test Case 6: Preprocess (Fixed Extension) ---")
|
|
361
|
+
paths6 = generate_output_paths(
|
|
362
|
+
command='preprocess',
|
|
363
|
+
output_locations={},
|
|
364
|
+
basename=mock_basename,
|
|
365
|
+
language=mock_language,
|
|
366
|
+
file_extension=mock_extension # This extension is ignored for preprocess default
|
|
367
|
+
)
|
|
368
|
+
print(f"Result: {paths6}")
|
|
369
|
+
# Expected: {'output': '/path/to/cwd/my_module_python_preprocessed.prompt'}
|
|
370
|
+
|
|
371
|
+
# --- Test Case 7: Unknown command ---
|
|
372
|
+
print("\n--- Test Case 7: Unknown Command ---")
|
|
373
|
+
paths7 = generate_output_paths(
|
|
374
|
+
command='nonexistent',
|
|
375
|
+
output_locations={},
|
|
376
|
+
basename=mock_basename,
|
|
377
|
+
language=mock_language,
|
|
378
|
+
file_extension=mock_extension
|
|
379
|
+
)
|
|
380
|
+
print(f"Result: {paths7}")
|
|
381
|
+
# Expected: {}
|
|
382
|
+
|
|
383
|
+
# --- Test Case 8: Split command defaults ---
|
|
384
|
+
print("\n--- Test Case 8: Split (Defaults) ---")
|
|
385
|
+
paths8 = generate_output_paths(
|
|
386
|
+
command='split',
|
|
387
|
+
output_locations={},
|
|
388
|
+
basename="complex_prompt",
|
|
389
|
+
language="javascript",
|
|
390
|
+
file_extension=".js" # Ignored for split defaults
|
|
391
|
+
)
|
|
392
|
+
print(f"Result: {paths8}")
|
|
393
|
+
# Expected: {
|
|
394
|
+
# 'output_sub': '/path/to/cwd/sub_complex_prompt.prompt',
|
|
395
|
+
# 'output_modified': '/path/to/cwd/modified_complex_prompt.prompt'
|
|
396
|
+
# }
|
|
397
|
+
|
|
398
|
+
# --- Test Case 9: Detect command default (using basename) ---
|
|
399
|
+
print("\n--- Test Case 9: Detect (Default) ---")
|
|
400
|
+
paths9 = generate_output_paths(
|
|
401
|
+
command='detect',
|
|
402
|
+
output_locations={},
|
|
403
|
+
basename="feature_analysis", # Used instead of change_file_basename
|
|
404
|
+
language="", # Not relevant for detect default
|
|
405
|
+
file_extension="" # Not relevant for detect default
|
|
406
|
+
)
|
|
407
|
+
print(f"Result: {paths9}")
|
|
408
|
+
# Expected: {'output': '/path/to/cwd/feature_analysis_detect.csv'}
|
|
409
|
+
|
|
410
|
+
# --- Test Case 10: Crash command defaults (using basename) ---
|
|
411
|
+
print("\n--- Test Case 10: Crash (Defaults) ---")
|
|
412
|
+
paths10 = generate_output_paths(
|
|
413
|
+
command='crash',
|
|
414
|
+
output_locations={},
|
|
415
|
+
basename="crashed_module", # Used for both code and program defaults
|
|
416
|
+
language="java",
|
|
417
|
+
file_extension=".java"
|
|
418
|
+
)
|
|
419
|
+
print(f"Result: {paths10}")
|
|
420
|
+
# Expected: {
|
|
421
|
+
# 'output': '/path/to/cwd/crashed_module_fixed.java',
|
|
422
|
+
# 'output_program': '/path/to/cwd/crashed_module_program_fixed.java'
|
|
423
|
+
# }
|
|
424
|
+
|
|
425
|
+
# --- Test Case 11: Verify command defaults ---
|
|
426
|
+
print("\n--- Test Case 11: Verify (Defaults) ---")
|
|
427
|
+
paths11 = generate_output_paths(
|
|
428
|
+
command='verify',
|
|
429
|
+
output_locations={},
|
|
430
|
+
basename="module_to_verify",
|
|
431
|
+
language="python",
|
|
432
|
+
file_extension=".py"
|
|
433
|
+
)
|
|
434
|
+
print(f"Result: {paths11}")
|
|
435
|
+
# Expected: {
|
|
436
|
+
# 'output_results': '/path/to/cwd/module_to_verify_verify_results.log',
|
|
437
|
+
# 'output_code': '/path/to/cwd/module_to_verify_verified.py'
|
|
438
|
+
# }
|
pdd/generate_test.py
CHANGED
|
@@ -2,6 +2,7 @@ from typing import Tuple, Optional
|
|
|
2
2
|
from rich import print
|
|
3
3
|
from rich.markdown import Markdown
|
|
4
4
|
from rich.console import Console
|
|
5
|
+
from . import EXTRACTION_STRENGTH
|
|
5
6
|
from .load_prompt_template import load_prompt_template
|
|
6
7
|
from .preprocess import preprocess
|
|
7
8
|
from .llm_invoke import llm_invoke
|
|
@@ -76,7 +77,7 @@ def generate_test(
|
|
|
76
77
|
last_600_chars = result[-600:] if len(result) > 600 else result
|
|
77
78
|
reasoning, is_finished, check_cost, check_model = unfinished_prompt(
|
|
78
79
|
prompt_text=last_600_chars,
|
|
79
|
-
strength=
|
|
80
|
+
strength=strength,
|
|
80
81
|
temperature=temperature,
|
|
81
82
|
verbose=verbose
|
|
82
83
|
)
|
|
@@ -101,7 +102,7 @@ def generate_test(
|
|
|
101
102
|
processed_result, post_cost, post_model = postprocess(
|
|
102
103
|
result,
|
|
103
104
|
language=language,
|
|
104
|
-
strength
|
|
105
|
+
strength=EXTRACTION_STRENGTH,
|
|
105
106
|
temperature=temperature,
|
|
106
107
|
verbose=verbose
|
|
107
108
|
)
|
pdd/increase_tests.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Tuple
|
|
2
2
|
from rich.console import Console
|
|
3
|
-
|
|
3
|
+
from . import EXTRACTION_STRENGTH
|
|
4
4
|
from .load_prompt_template import load_prompt_template
|
|
5
5
|
from .llm_invoke import llm_invoke
|
|
6
6
|
from .postprocess import postprocess
|
|
@@ -79,7 +79,7 @@ def increase_tests(
|
|
|
79
79
|
increase_test_function, total_cost, model_name = postprocess(
|
|
80
80
|
llm_response['result'],
|
|
81
81
|
language,
|
|
82
|
-
|
|
82
|
+
EXTRACTION_STRENGTH, # Fixed strength for extraction
|
|
83
83
|
temperature,
|
|
84
84
|
verbose
|
|
85
85
|
)
|