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.

Files changed (49) hide show
  1. pdd/__init__.py +7 -1
  2. pdd/bug_main.py +21 -3
  3. pdd/bug_to_unit_test.py +16 -5
  4. pdd/change.py +2 -1
  5. pdd/change_main.py +407 -189
  6. pdd/cli.py +853 -301
  7. pdd/code_generator.py +2 -1
  8. pdd/conflicts_in_prompts.py +2 -1
  9. pdd/construct_paths.py +377 -222
  10. pdd/context_generator.py +2 -1
  11. pdd/continue_generation.py +3 -2
  12. pdd/crash_main.py +55 -20
  13. pdd/data/llm_model.csv +8 -8
  14. pdd/detect_change.py +2 -1
  15. pdd/fix_code_loop.py +465 -160
  16. pdd/fix_code_module_errors.py +7 -4
  17. pdd/fix_error_loop.py +9 -9
  18. pdd/fix_errors_from_unit_tests.py +207 -365
  19. pdd/fix_main.py +31 -4
  20. pdd/fix_verification_errors.py +285 -0
  21. pdd/fix_verification_errors_loop.py +975 -0
  22. pdd/fix_verification_main.py +412 -0
  23. pdd/generate_output_paths.py +427 -183
  24. pdd/generate_test.py +3 -2
  25. pdd/increase_tests.py +2 -2
  26. pdd/llm_invoke.py +18 -8
  27. pdd/pdd_completion.zsh +38 -1
  28. pdd/preprocess.py +3 -3
  29. pdd/process_csv_change.py +466 -154
  30. pdd/prompts/extract_prompt_split_LLM.prompt +7 -4
  31. pdd/prompts/extract_prompt_update_LLM.prompt +11 -5
  32. pdd/prompts/extract_unit_code_fix_LLM.prompt +2 -2
  33. pdd/prompts/find_verification_errors_LLM.prompt +25 -0
  34. pdd/prompts/fix_code_module_errors_LLM.prompt +29 -0
  35. pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +5 -5
  36. pdd/prompts/fix_verification_errors_LLM.prompt +20 -0
  37. pdd/prompts/generate_test_LLM.prompt +9 -3
  38. pdd/prompts/split_LLM.prompt +3 -3
  39. pdd/prompts/update_prompt_LLM.prompt +3 -3
  40. pdd/split.py +13 -12
  41. pdd/split_main.py +22 -13
  42. pdd/trace_main.py +7 -0
  43. pdd/xml_tagger.py +2 -1
  44. {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/METADATA +4 -4
  45. {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/RECORD +49 -44
  46. {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/WHEEL +1 -1
  47. {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/entry_points.txt +0 -0
  48. {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/licenses/LICENSE +0 -0
  49. {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/top_level.txt +0 -0
@@ -1,194 +1,438 @@
1
1
  import os
2
- from pathlib import Path
2
+ import logging
3
+ from typing import Dict, List, Optional
3
4
 
4
- def generate_output_paths(command, output_locations, basename, language, file_extension):
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 output filenames based on command, output_locations, basename, language, and file_extension.
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 (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").
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
- 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.
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
- 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)
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
- 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)
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
- # 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
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
- return default_filename
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=0.97,
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=.97,
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
- 0.97, # Using 0.97 to match the unit test expectation
82
+ EXTRACTION_STRENGTH, # Fixed strength for extraction
83
83
  temperature,
84
84
  verbose
85
85
  )