auto-coder 0.1.327__py3-none-any.whl → 0.1.328__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 auto-coder might be problematic. Click here for more details.
- {auto_coder-0.1.327.dist-info → auto_coder-0.1.328.dist-info}/METADATA +1 -1
- {auto_coder-0.1.327.dist-info → auto_coder-0.1.328.dist-info}/RECORD +26 -14
- autocoder/common/__init__.py +5 -0
- autocoder/common/auto_coder_lang.py +16 -0
- autocoder/common/stream_out_type.py +3 -0
- autocoder/common/v2/code_editblock_manager.py +92 -8
- autocoder/compilers/__init__.py +51 -0
- autocoder/compilers/base_compiler.py +107 -0
- autocoder/compilers/compiler_config_api.py +365 -0
- autocoder/compilers/compiler_config_manager.py +305 -0
- autocoder/compilers/compiler_factory.py +271 -0
- autocoder/compilers/java_compiler.py +680 -0
- autocoder/compilers/models.py +210 -0
- autocoder/compilers/provided_compiler.py +343 -0
- autocoder/compilers/python_compiler.py +413 -0
- autocoder/compilers/reactjs_compiler.py +491 -0
- autocoder/compilers/shadow_compiler.py +42 -0
- autocoder/compilers/vue_compiler.py +548 -0
- autocoder/memory/active_context_manager.py +3 -3
- autocoder/memory/active_package.py +2 -2
- autocoder/shadows/shadow_manager.py +251 -4
- autocoder/version.py +1 -1
- {auto_coder-0.1.327.dist-info → auto_coder-0.1.328.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.327.dist-info → auto_coder-0.1.328.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.327.dist-info → auto_coder-0.1.328.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.327.dist-info → auto_coder-0.1.328.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for compiling/checking Python code.
|
|
3
|
+
This module provides functionality to check Python code syntax and imports.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
import subprocess
|
|
9
|
+
import tempfile
|
|
10
|
+
import time
|
|
11
|
+
import re
|
|
12
|
+
from typing import Dict, List, Any, Optional, Tuple
|
|
13
|
+
|
|
14
|
+
from autocoder.compilers.base_compiler import BaseCompiler
|
|
15
|
+
from autocoder.compilers.models import (
|
|
16
|
+
CompilationError,
|
|
17
|
+
FileCompilationResult,
|
|
18
|
+
ProjectCompilationResult,
|
|
19
|
+
CompilationErrorPosition,
|
|
20
|
+
CompilationErrorSeverity
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
class PythonCompiler(BaseCompiler):
|
|
24
|
+
"""
|
|
25
|
+
A class that provides compilation/checking functionality for Python code.
|
|
26
|
+
For Python, "compilation" means checking syntax and imports.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, verbose: bool = False):
|
|
30
|
+
"""
|
|
31
|
+
Initialize the PythonCompiler.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
verbose (bool): Whether to display verbose output.
|
|
35
|
+
"""
|
|
36
|
+
super().__init__(verbose)
|
|
37
|
+
|
|
38
|
+
def get_supported_extensions(self) -> List[str]:
|
|
39
|
+
"""
|
|
40
|
+
Get the list of file extensions supported by this compiler.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
List[str]: List of supported file extensions.
|
|
44
|
+
"""
|
|
45
|
+
return ['.py']
|
|
46
|
+
|
|
47
|
+
def _check_dependencies(self) -> bool:
|
|
48
|
+
"""
|
|
49
|
+
Check if required dependencies are installed.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
bool: True if all dependencies are available, False otherwise.
|
|
53
|
+
"""
|
|
54
|
+
try:
|
|
55
|
+
# Check if python is installed
|
|
56
|
+
subprocess.run([sys.executable, "--version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
57
|
+
return True
|
|
58
|
+
except (subprocess.SubprocessError, FileNotFoundError):
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
def _check_syntax(self, file_path: str) -> Dict[str, Any]:
|
|
62
|
+
"""
|
|
63
|
+
Check Python file syntax without executing the code.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
file_path (str): Path to the file to check.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Dict[str, Any]: Dictionary containing syntax check results.
|
|
70
|
+
"""
|
|
71
|
+
result = {
|
|
72
|
+
'success': True,
|
|
73
|
+
'errors': [],
|
|
74
|
+
'error_count': 0,
|
|
75
|
+
'warning_count': 0
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
# Use Python's built-in compiler to check syntax
|
|
80
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
81
|
+
source = f.read()
|
|
82
|
+
|
|
83
|
+
# Check syntax using compile
|
|
84
|
+
try:
|
|
85
|
+
compile(source, file_path, 'exec')
|
|
86
|
+
except SyntaxError as e:
|
|
87
|
+
# Create error details
|
|
88
|
+
error = CompilationError(
|
|
89
|
+
message=str(e),
|
|
90
|
+
severity=CompilationErrorSeverity.ERROR,
|
|
91
|
+
position=CompilationErrorPosition(
|
|
92
|
+
line=e.lineno if e.lineno is not None else 1,
|
|
93
|
+
column=e.offset if e.offset is not None else 1
|
|
94
|
+
),
|
|
95
|
+
file_path=file_path,
|
|
96
|
+
code="syntax-error"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Try to get the source line
|
|
100
|
+
if e.text:
|
|
101
|
+
error.source = e.text
|
|
102
|
+
|
|
103
|
+
result['errors'].append(error)
|
|
104
|
+
result['error_count'] += 1
|
|
105
|
+
result['success'] = False
|
|
106
|
+
|
|
107
|
+
except Exception as e:
|
|
108
|
+
# Handle file reading errors
|
|
109
|
+
result['success'] = False
|
|
110
|
+
result['error_message'] = f"Error reading file: {str(e)}"
|
|
111
|
+
|
|
112
|
+
return result
|
|
113
|
+
|
|
114
|
+
def _check_imports(self, file_path: str) -> Dict[str, Any]:
|
|
115
|
+
"""
|
|
116
|
+
Check if all imports in the Python file can be resolved.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
file_path (str): Path to the file to check.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Dict[str, Any]: Dictionary containing import check results.
|
|
123
|
+
"""
|
|
124
|
+
result = {
|
|
125
|
+
'success': True,
|
|
126
|
+
'errors': [],
|
|
127
|
+
'error_count': 0,
|
|
128
|
+
'warning_count': 0
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
# Use a temporary directory for PYTHONPATH to avoid polluting the real environment
|
|
133
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
134
|
+
# Get the directory of the file to check
|
|
135
|
+
file_dir = os.path.dirname(os.path.abspath(file_path))
|
|
136
|
+
|
|
137
|
+
# Create a temporary file to check imports
|
|
138
|
+
temp_file = os.path.join(temp_dir, "import_checker.py")
|
|
139
|
+
with open(temp_file, 'w', encoding='utf-8') as f:
|
|
140
|
+
f.write(f"""
|
|
141
|
+
import sys
|
|
142
|
+
import os
|
|
143
|
+
import importlib.util
|
|
144
|
+
import re
|
|
145
|
+
|
|
146
|
+
# Add file directory to path
|
|
147
|
+
sys.path.insert(0, "{file_dir}")
|
|
148
|
+
|
|
149
|
+
# Try to extract imports from the file
|
|
150
|
+
with open("{file_path}", "r", encoding="utf-8") as source_file:
|
|
151
|
+
source = source_file.read()
|
|
152
|
+
|
|
153
|
+
# Regular expressions to match import statements
|
|
154
|
+
import_patterns = [
|
|
155
|
+
r'^\\s*import\\s+([\\w\\.]+)', # import module
|
|
156
|
+
r'^\\s*from\\s+([\\w\\.]+)\\s+import', # from module import ...
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
# Find all imports
|
|
160
|
+
imports = []
|
|
161
|
+
for line in source.split('\\n'):
|
|
162
|
+
for pattern in import_patterns:
|
|
163
|
+
match = re.match(pattern, line)
|
|
164
|
+
if match:
|
|
165
|
+
module_name = match.group(1)
|
|
166
|
+
# Handle relative imports
|
|
167
|
+
if module_name.startswith('.'):
|
|
168
|
+
continue # Skip relative imports
|
|
169
|
+
# Get the top-level package
|
|
170
|
+
top_package = module_name.split('.')[0]
|
|
171
|
+
if top_package not in imports:
|
|
172
|
+
imports.append(top_package)
|
|
173
|
+
|
|
174
|
+
# Check each import
|
|
175
|
+
for module_name in imports:
|
|
176
|
+
try:
|
|
177
|
+
importlib.import_module(module_name)
|
|
178
|
+
print(f"SUCCESS: {{module_name}}")
|
|
179
|
+
except ImportError as e:
|
|
180
|
+
print(f"ERROR: {{module_name}} - {{str(e)}}")
|
|
181
|
+
""")
|
|
182
|
+
|
|
183
|
+
# Run the import checker
|
|
184
|
+
cmd = [sys.executable, temp_file]
|
|
185
|
+
process = subprocess.run(
|
|
186
|
+
cmd,
|
|
187
|
+
stdout=subprocess.PIPE,
|
|
188
|
+
stderr=subprocess.PIPE,
|
|
189
|
+
text=True
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Parse the output to find import errors
|
|
193
|
+
line_num = 1 # Default line number for import errors
|
|
194
|
+
for line in process.stdout.splitlines():
|
|
195
|
+
if line.startswith("ERROR:"):
|
|
196
|
+
# Extract module name and error message
|
|
197
|
+
_, module_info = line.split(":", 1)
|
|
198
|
+
module_name, error_msg = module_info.strip().split(" - ", 1)
|
|
199
|
+
|
|
200
|
+
# Try to find the line number for this import
|
|
201
|
+
import_line = self._find_import_line(file_path, module_name)
|
|
202
|
+
if import_line > 0:
|
|
203
|
+
line_num = import_line
|
|
204
|
+
|
|
205
|
+
# Create error details
|
|
206
|
+
error = CompilationError(
|
|
207
|
+
message=f"Import error for module '{module_name}': {error_msg}",
|
|
208
|
+
severity=CompilationErrorSeverity.ERROR,
|
|
209
|
+
position=CompilationErrorPosition(line=line_num),
|
|
210
|
+
file_path=file_path,
|
|
211
|
+
code="import-error"
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
result['errors'].append(error)
|
|
215
|
+
result['error_count'] += 1
|
|
216
|
+
|
|
217
|
+
# Check if there were any errors
|
|
218
|
+
if result['error_count'] > 0:
|
|
219
|
+
result['success'] = False
|
|
220
|
+
|
|
221
|
+
except Exception as e:
|
|
222
|
+
# Handle any other errors
|
|
223
|
+
result['success'] = False
|
|
224
|
+
result['error_message'] = f"Error checking imports: {str(e)}"
|
|
225
|
+
|
|
226
|
+
return result
|
|
227
|
+
|
|
228
|
+
def _find_import_line(self, file_path: str, module_name: str) -> int:
|
|
229
|
+
"""
|
|
230
|
+
Find the line number where a module is imported.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
file_path (str): Path to the file.
|
|
234
|
+
module_name (str): Name of the module to find.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
int: Line number (1-based) or 0 if not found.
|
|
238
|
+
"""
|
|
239
|
+
try:
|
|
240
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
241
|
+
for i, line in enumerate(f, 1):
|
|
242
|
+
if re.search(r'^\s*import\s+' + re.escape(module_name), line) or \
|
|
243
|
+
re.search(r'^\s*from\s+' + re.escape(module_name) + r'\s+import', line):
|
|
244
|
+
return i
|
|
245
|
+
return 0
|
|
246
|
+
except Exception:
|
|
247
|
+
return 0
|
|
248
|
+
|
|
249
|
+
def compile_file(self, file_path: str) -> Dict[str, Any]:
|
|
250
|
+
"""
|
|
251
|
+
Compile (check) a single Python file.
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
file_path (str): Path to the file to compile.
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
Dict[str, Any]: Compilation results.
|
|
258
|
+
"""
|
|
259
|
+
if not os.path.exists(file_path):
|
|
260
|
+
return FileCompilationResult(
|
|
261
|
+
file_path=file_path,
|
|
262
|
+
success=False,
|
|
263
|
+
language="python",
|
|
264
|
+
error_message=f"File not found: {file_path}"
|
|
265
|
+
).model_dump()
|
|
266
|
+
|
|
267
|
+
if not self.is_supported_file(file_path):
|
|
268
|
+
return FileCompilationResult(
|
|
269
|
+
file_path=file_path,
|
|
270
|
+
success=False,
|
|
271
|
+
language="python",
|
|
272
|
+
error_message=f"Unsupported file type: {file_path}"
|
|
273
|
+
).model_dump()
|
|
274
|
+
|
|
275
|
+
start_time = time.time()
|
|
276
|
+
|
|
277
|
+
# First check syntax
|
|
278
|
+
syntax_result = self._check_syntax(file_path)
|
|
279
|
+
|
|
280
|
+
# Then check imports if syntax is correct
|
|
281
|
+
import_result = {'errors': [], 'error_count': 0, 'warning_count': 0}
|
|
282
|
+
if syntax_result['success']:
|
|
283
|
+
import_result = self._check_imports(file_path)
|
|
284
|
+
|
|
285
|
+
# Combine results
|
|
286
|
+
all_errors = syntax_result['errors'] + import_result['errors']
|
|
287
|
+
error_count = syntax_result['error_count'] + import_result['error_count']
|
|
288
|
+
warning_count = syntax_result['warning_count'] + import_result['warning_count']
|
|
289
|
+
|
|
290
|
+
# Calculate execution time
|
|
291
|
+
execution_time_ms = int((time.time() - start_time) * 1000)
|
|
292
|
+
|
|
293
|
+
# Create the final result
|
|
294
|
+
result = FileCompilationResult(
|
|
295
|
+
file_path=file_path,
|
|
296
|
+
success=(error_count == 0),
|
|
297
|
+
language="python",
|
|
298
|
+
errors=all_errors,
|
|
299
|
+
error_count=error_count,
|
|
300
|
+
warning_count=warning_count,
|
|
301
|
+
info_count=0,
|
|
302
|
+
execution_time_ms=execution_time_ms
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
return result.model_dump()
|
|
306
|
+
|
|
307
|
+
def compile_project(self, project_path: str) -> Dict[str, Any]:
|
|
308
|
+
"""
|
|
309
|
+
Compile (check) a Python project.
|
|
310
|
+
|
|
311
|
+
Args:
|
|
312
|
+
project_path (str): Path to the project directory.
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
Dict[str, Any]: Compilation results.
|
|
316
|
+
"""
|
|
317
|
+
if not os.path.exists(project_path):
|
|
318
|
+
return ProjectCompilationResult(
|
|
319
|
+
project_path=project_path,
|
|
320
|
+
success=False,
|
|
321
|
+
total_files=0,
|
|
322
|
+
error_message=f"Project directory not found: {project_path}"
|
|
323
|
+
).model_dump()
|
|
324
|
+
|
|
325
|
+
# Find all Python files
|
|
326
|
+
python_files = []
|
|
327
|
+
for root, _, files in os.walk(project_path):
|
|
328
|
+
for file in files:
|
|
329
|
+
if file.endswith('.py'):
|
|
330
|
+
python_files.append(os.path.join(root, file))
|
|
331
|
+
|
|
332
|
+
if not python_files:
|
|
333
|
+
return ProjectCompilationResult(
|
|
334
|
+
project_path=project_path,
|
|
335
|
+
success=True,
|
|
336
|
+
total_files=0,
|
|
337
|
+
file_results={}
|
|
338
|
+
).model_dump()
|
|
339
|
+
|
|
340
|
+
# Compile each file
|
|
341
|
+
file_results = {}
|
|
342
|
+
total_errors = 0
|
|
343
|
+
total_warnings = 0
|
|
344
|
+
files_with_errors = 0
|
|
345
|
+
|
|
346
|
+
for file_path in python_files:
|
|
347
|
+
file_result = self.compile_file(file_path)
|
|
348
|
+
file_results[file_path] = file_result
|
|
349
|
+
|
|
350
|
+
if file_result['error_count'] > 0:
|
|
351
|
+
files_with_errors += 1
|
|
352
|
+
total_errors += file_result['error_count']
|
|
353
|
+
|
|
354
|
+
total_warnings += file_result['warning_count']
|
|
355
|
+
|
|
356
|
+
# Create the project result
|
|
357
|
+
result = ProjectCompilationResult(
|
|
358
|
+
project_path=project_path,
|
|
359
|
+
success=(total_errors == 0),
|
|
360
|
+
total_files=len(python_files),
|
|
361
|
+
files_with_errors=files_with_errors,
|
|
362
|
+
total_errors=total_errors,
|
|
363
|
+
total_warnings=total_warnings,
|
|
364
|
+
total_infos=0,
|
|
365
|
+
file_results={p: FileCompilationResult(**r) for p, r in file_results.items()}
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
return result.model_dump()
|
|
369
|
+
|
|
370
|
+
def format_compile_result(self, compile_result: Dict[str, Any]) -> str:
|
|
371
|
+
"""
|
|
372
|
+
Format compilation results into a human-readable string.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
compile_result (Dict[str, Any]): The compilation result dictionary.
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
str: A formatted string representation of the compilation results.
|
|
379
|
+
"""
|
|
380
|
+
if 'project_path' in compile_result:
|
|
381
|
+
# This is a project result
|
|
382
|
+
return ProjectCompilationResult(**compile_result).to_str()
|
|
383
|
+
else:
|
|
384
|
+
# This is a file result
|
|
385
|
+
return FileCompilationResult(**compile_result).to_str()
|
|
386
|
+
|
|
387
|
+
def compile_python_file(file_path: str, verbose: bool = False) -> Dict[str, Any]:
|
|
388
|
+
"""
|
|
389
|
+
Utility function to compile a single Python file.
|
|
390
|
+
|
|
391
|
+
Args:
|
|
392
|
+
file_path (str): Path to the file to compile.
|
|
393
|
+
verbose (bool): Whether to display verbose output.
|
|
394
|
+
|
|
395
|
+
Returns:
|
|
396
|
+
Dict[str, Any]: A dictionary containing compilation results.
|
|
397
|
+
"""
|
|
398
|
+
compiler = PythonCompiler(verbose=verbose)
|
|
399
|
+
return compiler.compile_file(file_path)
|
|
400
|
+
|
|
401
|
+
def compile_python_project(project_path: str, verbose: bool = False) -> Dict[str, Any]:
|
|
402
|
+
"""
|
|
403
|
+
Utility function to compile a Python project.
|
|
404
|
+
|
|
405
|
+
Args:
|
|
406
|
+
project_path (str): Path to the project directory.
|
|
407
|
+
verbose (bool): Whether to display verbose output.
|
|
408
|
+
|
|
409
|
+
Returns:
|
|
410
|
+
Dict[str, Any]: A dictionary containing compilation results.
|
|
411
|
+
"""
|
|
412
|
+
compiler = PythonCompiler(verbose=verbose)
|
|
413
|
+
return compiler.compile_project(project_path)
|