0
# Error Handling
1
2
Exception hierarchy for handling various error conditions during code analysis and refactoring operations. Rope provides specific exception types for different failure scenarios to enable appropriate error handling and user feedback.
3
4
## Exception Hierarchy
5
6
All rope exceptions inherit from the base `RopeError` class, providing a consistent error handling interface.
7
8
```python { .api }
9
class RopeError(Exception):
10
"""
11
Base exception class for all rope errors.
12
All rope-specific exceptions inherit from this class.
13
"""
14
pass
15
```
16
17
## Capabilities
18
19
### Refactoring Errors
20
21
Errors that occur during refactoring operations due to code structure or safety constraints.
22
23
```python { .api }
24
class RefactoringError(RopeError):
25
"""
26
General refactoring error for operations that cannot be completed safely.
27
Raised when a refactoring violates safety constraints or encounters
28
unsupported code patterns.
29
"""
30
pass
31
32
class InterruptedTaskError(RopeError):
33
"""
34
Raised when a refactoring task is cancelled or interrupted.
35
Can occur when using TaskHandle to monitor long-running operations.
36
"""
37
pass
38
```
39
40
### Resource Errors
41
42
Errors related to file system operations and resource management.
43
44
```python { .api }
45
class ResourceNotFoundError(RopeError):
46
"""
47
Raised when attempting to access a resource that doesn't exist.
48
Common when using project.get_resource() with invalid paths.
49
"""
50
pass
51
```
52
53
### Module and Import Errors
54
55
Errors related to Python module loading and import resolution.
56
57
```python { .api }
58
class ModuleNotFoundError(RopeError):
59
"""
60
Raised when a Python module cannot be found or loaded.
61
Occurs during module resolution in project.get_module() operations.
62
"""
63
pass
64
65
class AttributeNotFoundError(RopeError):
66
"""
67
Raised when attempting to access a non-existent attribute.
68
Can occur during code analysis and refactoring operations.
69
"""
70
pass
71
72
class NameNotFoundError(RopeError):
73
"""
74
Raised when name resolution fails during code analysis.
75
Indicates that a referenced identifier cannot be resolved.
76
"""
77
pass
78
```
79
80
### Syntax and Validation Errors
81
82
Errors related to code syntax and identifier validation.
83
84
```python { .api }
85
class BadIdentifierError(RopeError):
86
"""
87
Raised when an invalid identifier is provided for refactoring.
88
Common in rename operations with non-Python identifiers.
89
"""
90
pass
91
92
class ModuleSyntaxError(RopeError):
93
"""
94
Raised when a Python module contains syntax errors.
95
Can occur during parsing and analysis operations.
96
"""
97
pass
98
99
class ModuleDecodeError(RopeError):
100
"""
101
Raised when a Python file cannot be decoded due to encoding issues.
102
Occurs when reading files with invalid or unsupported encodings.
103
"""
104
pass
105
```
106
107
### History and State Errors
108
109
Errors related to project history and state management.
110
111
```python { .api }
112
class HistoryError(RopeError):
113
"""
114
Raised when history operations fail.
115
Can occur during undo/redo operations or history corruption.
116
"""
117
pass
118
```
119
120
## Error Handling Patterns
121
122
### Basic Exception Handling
123
124
```python
125
from rope.base.project import Project
126
from rope.base.exceptions import RopeError, ResourceNotFoundError, RefactoringError
127
from rope.refactor.rename import Rename
128
129
project = Project('/path/to/project')
130
131
try:
132
# Attempt to get a resource
133
try:
134
myfile = project.get_resource('nonexistent.py')
135
except ResourceNotFoundError:
136
print("File not found, creating new file")
137
myfile = project.get_file('nonexistent.py')
138
myfile.write('# New file\n')
139
140
# Attempt refactoring with error handling
141
try:
142
renamer = Rename(project, myfile, 50)
143
old_name = renamer.get_old_name()
144
changes = renamer.get_changes('new_name')
145
project.do(changes)
146
print(f"Successfully renamed '{old_name}' to 'new_name'")
147
148
except RefactoringError as e:
149
print(f"Refactoring failed: {e}")
150
# Handle refactoring-specific errors
151
152
except BadIdentifierError as e:
153
print(f"Invalid identifier: {e}")
154
# Handle identifier validation errors
155
156
except RopeError as e:
157
print(f"Rope error occurred: {e}")
158
# Handle any rope-specific error
159
160
except Exception as e:
161
print(f"Unexpected error: {e}")
162
# Handle unexpected errors
163
164
finally:
165
project.close()
166
```
167
168
### Module Loading Error Handling
169
170
```python
171
from rope.base.project import Project
172
from rope.base.exceptions import ModuleNotFoundError, ModuleSyntaxError, ModuleDecodeError
173
174
project = Project('/path/to/project')
175
176
try:
177
# Handle various module loading errors
178
try:
179
module = project.get_module('mymodule')
180
print(f"Module loaded: {module}")
181
182
except ModuleNotFoundError:
183
print("Module not found in project or Python path")
184
# Try alternative module names or create module
185
186
except ModuleSyntaxError as e:
187
print(f"Module has syntax errors: {e}")
188
# Report syntax issues to user
189
190
except ModuleDecodeError as e:
191
print(f"Cannot decode module file: {e}")
192
# Handle encoding issues
193
194
finally:
195
project.close()
196
```
197
198
### Task Interruption Handling
199
200
```python
201
from rope.base.project import Project
202
from rope.base.taskhandle import TaskHandle
203
from rope.base.exceptions import InterruptedTaskError
204
from rope.refactor.rename import Rename
205
206
def cancel_callback():
207
# Custom cancellation logic
208
return user_requested_cancel()
209
210
project = Project('/path/to/project')
211
212
try:
213
# Create task handle with cancellation support
214
task_handle = TaskHandle("Rename operation", cancel_callback)
215
216
try:
217
myfile = project.get_resource('mymodule.py')
218
renamer = Rename(project, myfile, 100)
219
changes = renamer.get_changes('new_name', task_handle=task_handle)
220
project.do(changes, task_handle)
221
print("Refactoring completed successfully")
222
223
except InterruptedTaskError:
224
print("Operation was cancelled by user")
225
# Clean up partial changes if necessary
226
227
finally:
228
project.close()
229
```
230
231
### Comprehensive Error Handling
232
233
```python
234
from rope.base.project import Project
235
from rope.base.exceptions import *
236
from rope.refactor.extract import ExtractMethod
237
238
def safe_refactor(project_path, file_path, start_offset, end_offset, method_name):
239
"""
240
Safely perform extract method refactoring with comprehensive error handling.
241
"""
242
project = None
243
try:
244
project = Project(project_path)
245
246
# Resource access with error handling
247
try:
248
resource = project.get_resource(file_path)
249
except ResourceNotFoundError:
250
return {"error": f"File not found: {file_path}"}
251
252
# Refactoring with error handling
253
try:
254
extractor = ExtractMethod(project, resource, start_offset, end_offset)
255
changes = extractor.get_changes(method_name)
256
257
# Validate changes before applying
258
description = changes.get_description()
259
print(f"About to apply: {description}")
260
261
project.do(changes)
262
return {"success": f"Extracted method '{method_name}'"}
263
264
except RefactoringError as e:
265
return {"error": f"Refactoring failed: {e}"}
266
267
except BadIdentifierError as e:
268
return {"error": f"Invalid method name '{method_name}': {e}"}
269
270
except InterruptedTaskError:
271
return {"error": "Operation was cancelled"}
272
273
except ModuleSyntaxError as e:
274
return {"error": f"Syntax error in file: {e}"}
275
276
except RopeError as e:
277
return {"error": f"Rope error: {e}"}
278
279
except Exception as e:
280
return {"error": f"Unexpected error: {e}"}
281
282
finally:
283
if project:
284
project.close()
285
286
# Usage
287
result = safe_refactor(
288
"/path/to/project",
289
"mymodule.py",
290
200, 350,
291
"extracted_method"
292
)
293
294
if "error" in result:
295
print(f"Error: {result['error']}")
296
else:
297
print(f"Success: {result['success']}")
298
```
299
300
### Error Recovery Patterns
301
302
```python
303
from rope.base.project import Project
304
from rope.base.exceptions import *
305
306
def robust_rename(project_path, file_path, offset, new_name, max_retries=3):
307
"""
308
Perform rename with automatic retry and error recovery.
309
"""
310
project = Project(project_path)
311
312
try:
313
resource = project.get_resource(file_path)
314
315
for attempt in range(max_retries + 1):
316
try:
317
from rope.refactor.rename import Rename
318
renamer = Rename(project, resource, offset)
319
320
# Validate before proceeding
321
try:
322
old_name = renamer.get_old_name()
323
print(f"Attempt {attempt + 1}: Renaming '{old_name}' to '{new_name}'")
324
except AttributeNotFoundError:
325
print("No identifier found at offset")
326
return False
327
328
changes = renamer.get_changes(new_name)
329
project.do(changes)
330
print("Rename successful")
331
return True
332
333
except BadIdentifierError as e:
334
print(f"Invalid identifier on attempt {attempt + 1}: {e}")
335
if attempt == max_retries:
336
print("All attempts failed - invalid identifier")
337
return False
338
# Could try with modified identifier
339
340
except RefactoringError as e:
341
print(f"Refactoring error on attempt {attempt + 1}: {e}")
342
if attempt == max_retries:
343
print("All attempts failed - refactoring error")
344
return False
345
# Could try with different parameters
346
347
except InterruptedTaskError:
348
print("Operation cancelled")
349
return False
350
351
except ResourceNotFoundError:
352
print(f"File not found: {file_path}")
353
return False
354
355
finally:
356
project.close()
357
358
return False
359
```
360
361
## Best Practices
362
363
### Exception Handling Guidelines
364
365
1. **Catch Specific Exceptions**: Always catch the most specific exception type first
366
2. **Resource Cleanup**: Use try/finally or context managers to ensure projects are closed
367
3. **User Feedback**: Provide meaningful error messages for different exception types
368
4. **Graceful Degradation**: Handle errors gracefully and provide fallback options
369
5. **Logging**: Log errors with sufficient context for debugging
370
371
### Common Error Scenarios
372
373
- **ResourceNotFoundError**: Check file existence before operations
374
- **RefactoringError**: Validate code structure before complex refactorings
375
- **BadIdentifierError**: Validate identifier names before rename operations
376
- **ModuleSyntaxError**: Parse and validate syntax before analysis
377
- **InterruptedTaskError**: Handle user cancellation in long operations