0
# Exception Handling
1
2
Jython provides comprehensive exception handling that bridges Python and Java exception systems, allowing seamless error handling across both platforms.
3
4
## PyException Class
5
6
The main exception class that represents Python exceptions in Java.
7
8
```java { .api }
9
public class PyException extends RuntimeException {
10
public PyObject type; // Exception type (e.g., ValueError, TypeError)
11
public PyObject value; // Exception value/message
12
public PyTraceback traceback; // Python traceback information
13
14
// Constructors
15
public PyException();
16
public PyException(PyObject type);
17
public PyException(PyObject type, String value);
18
public PyException(PyObject type, PyObject value);
19
public PyException(PyObject type, PyObject value, PyTraceback traceback);
20
21
// Exception matching and handling
22
public boolean match(PyObject exc);
23
public boolean match(PyObject[] excs);
24
public void normalize();
25
public PyObject getCause();
26
public void setCause(PyObject cause);
27
28
// Traceback handling
29
public void setTraceback(PyTraceback traceback);
30
public void tracebackHere(PyFrame frame);
31
public void tracebackHere(PyFrame frame, boolean isFinally);
32
33
// String representation
34
public String toString();
35
}
36
```
37
38
## Python Exception Types
39
40
All standard Python exceptions are available as static fields in the `Py` class.
41
42
```java { .api }
43
public final class Py {
44
// Base exceptions
45
public static final PyObject Exception;
46
public static final PyObject BaseException;
47
public static final PyObject SystemExit;
48
public static final PyObject KeyboardInterrupt;
49
public static final PyObject GeneratorExit;
50
51
// Common exceptions
52
public static final PyObject TypeError;
53
public static final PyObject ValueError;
54
public static final PyObject RuntimeError;
55
public static final PyObject AttributeError;
56
public static final PyObject KeyError;
57
public static final PyObject IndexError;
58
public static final PyObject NameError;
59
public static final PyObject ImportError;
60
public static final PyObject IOError;
61
public static final PyObject OSError;
62
public static final PyObject SyntaxError;
63
public static final PyObject IndentationError;
64
public static final PyObject SystemError;
65
public static final PyObject MemoryError;
66
public static final PyObject OverflowError;
67
public static final PyObject ZeroDivisionError;
68
public static final PyObject AssertionError;
69
public static final PyObject LookupError;
70
public static final PyObject StopIteration;
71
72
// Warning types
73
public static final PyObject Warning;
74
public static final PyObject UserWarning;
75
public static final PyObject DeprecationWarning;
76
public static final PyObject SyntaxWarning;
77
public static final PyObject RuntimeWarning;
78
public static final PyObject FutureWarning;
79
public static final PyObject ImportWarning;
80
public static final PyObject UnicodeWarning;
81
public static final PyObject BytesWarning;
82
public static final PyObject ResourceWarning;
83
}
84
```
85
86
## Exception Factory Methods
87
88
Convenient factory methods for creating Python exceptions.
89
90
```java { .api }
91
public final class Py {
92
// Exception creation
93
public static PyException TypeError(String message);
94
public static PyException ValueError(String message);
95
public static PyException RuntimeError(String message);
96
public static PyException AttributeError(String message);
97
public static PyException KeyError(String message);
98
public static PyException IndexError(String message);
99
public static PyException NameError(String message);
100
public static PyException ImportError(String message);
101
public static PyException IOError(String message);
102
public static PyException OSError(String message);
103
public static PyException SyntaxError(String message);
104
public static PyException SystemError(String message);
105
public static PyException MemoryError(String message);
106
public static PyException OverflowError(String message);
107
public static PyException ZeroDivisionError(String message);
108
public static PyException AssertionError(String message);
109
public static PyException StopIteration();
110
public static PyException StopIteration(String message);
111
112
// Exception creation with custom value
113
public static PyException makeException(PyObject type, PyObject value);
114
public static PyException makeException(PyObject type, PyObject value, PyTraceback traceback);
115
}
116
```
117
118
## Traceback Information
119
120
Python traceback information for debugging.
121
122
```java { .api }
123
public class PyTraceback extends PyObject {
124
public PyTraceback tb_next; // Next traceback frame
125
public PyFrame tb_frame; // Frame object
126
public int tb_lineno; // Line number
127
128
public PyTraceback(PyFrame frame);
129
public PyTraceback(PyTraceback next, PyFrame frame);
130
131
// Traceback manipulation
132
public void dumpStack();
133
public void dumpStack(StringBuilder buffer);
134
}
135
```
136
137
## Exception Handling Examples
138
139
### Catching Python Exceptions in Java
140
141
```java
142
import org.python.core.*;
143
import org.python.util.PythonInterpreter;
144
145
PythonInterpreter interp = new PythonInterpreter();
146
147
try {
148
interp.exec("raise ValueError('Something went wrong')");
149
} catch (PyException e) {
150
// Check exception type
151
if (e.match(Py.ValueError)) {
152
System.out.println("Caught ValueError: " + e.value);
153
} else if (e.match(Py.TypeError)) {
154
System.out.println("Caught TypeError: " + e.value);
155
} else {
156
System.out.println("Caught other exception: " + e.type + " - " + e.value);
157
}
158
159
// Print Python traceback
160
if (e.traceback != null) {
161
e.traceback.dumpStack();
162
}
163
}
164
165
interp.close();
166
```
167
168
### Multiple Exception Types
169
170
```java
171
try {
172
interp.exec("undefined_variable + 1");
173
} catch (PyException e) {
174
// Check against multiple exception types
175
PyObject[] commonExceptions = {Py.NameError, Py.TypeError, Py.ValueError};
176
177
if (e.match(commonExceptions)) {
178
System.out.println("Caught common exception: " + e.type);
179
} else {
180
System.out.println("Caught unexpected exception: " + e.type);
181
throw e; // Re-raise if not handled
182
}
183
}
184
```
185
186
### Accessing Exception Details
187
188
```java
189
try {
190
interp.exec("""
191
try:
192
x = 10 / 0
193
except ZeroDivisionError as e:
194
raise ValueError("Custom message") from e
195
""");
196
} catch (PyException e) {
197
System.out.println("Exception type: " + e.type);
198
System.out.println("Exception value: " + e.value);
199
200
// Get the original cause if available
201
PyObject cause = e.getCause();
202
if (cause != null && cause != Py.None) {
203
System.out.println("Caused by: " + cause);
204
}
205
206
// Print full traceback
207
System.out.println("Full traceback:");
208
System.out.println(e.toString());
209
}
210
```
211
212
## Raising Python Exceptions from Java
213
214
### Using Factory Methods
215
216
```java
217
// Raise exceptions from Java code
218
PythonInterpreter interp = new PythonInterpreter();
219
220
// Set up Python function that calls Java
221
interp.exec("""
222
def test_function(value):
223
return java_function(value)
224
""");
225
226
// Define Java function that can raise Python exceptions
227
interp.set("java_function", new PyObject() {
228
public PyObject __call__(PyObject[] args, String[] keywords) {
229
if (args.length == 0) {
230
throw Py.TypeError("java_function() missing required argument");
231
}
232
233
PyObject arg = args[0];
234
if (arg instanceof PyInteger) {
235
int value = ((PyInteger) arg).getValue();
236
if (value < 0) {
237
throw Py.ValueError("value must be non-negative");
238
}
239
if (value == 0) {
240
throw Py.ZeroDivisionError("cannot divide by zero");
241
}
242
return Py.newInteger(100 / value);
243
} else {
244
throw Py.TypeError("expected integer argument");
245
}
246
}
247
});
248
249
// Test the exception handling
250
try {
251
interp.exec("result = test_function(-5)");
252
} catch (PyException e) {
253
if (e.match(Py.ValueError)) {
254
System.out.println("Validation error: " + e.value);
255
}
256
}
257
```
258
259
### Custom Exception Classes
260
261
```java
262
// Create custom Python exception class from Java
263
interp.exec("""
264
class CustomError(Exception):
265
def __init__(self, message, error_code=None):
266
super().__init__(message)
267
self.error_code = error_code
268
""");
269
270
// Get the custom exception class
271
PyObject customErrorClass = interp.get("CustomError");
272
273
// Raise custom exception from Java
274
PyObject[] args = {Py.newString("Custom error occurred"), Py.newInteger(404)};
275
PyException customException = new PyException(customErrorClass,
276
customErrorClass.__call__(args));
277
278
throw customException;
279
```
280
281
## Java Exception Integration
282
283
### Java Exceptions in Python Code
284
285
```java
286
// Java method that throws checked exception
287
class FileProcessor {
288
public static String readFile(String filename) throws IOException {
289
if (!new File(filename).exists()) {
290
throw new IOException("File not found: " + filename);
291
}
292
return Files.readString(Paths.get(filename));
293
}
294
}
295
296
PythonInterpreter interp = new PythonInterpreter();
297
interp.set("FileProcessor", FileProcessor.class);
298
299
interp.exec("""
300
try:
301
content = FileProcessor.readFile("nonexistent.txt")
302
except Exception as e:
303
print("Caught Java exception:", type(e).__name__)
304
print("Message:", str(e))
305
306
# Java exceptions appear as Python exceptions
307
import traceback
308
traceback.print_exc()
309
""");
310
```
311
312
### Converting Java Exceptions to Python
313
314
```java
315
// Automatic conversion of Java exceptions
316
try {
317
interp.exec("""
318
from java.lang import Integer
319
# This will throw NumberFormatException
320
num = Integer.parseInt("not_a_number")
321
""");
322
} catch (PyException e) {
323
// Java NumberFormatException becomes Python exception
324
System.out.println("Java exception as Python: " + e.type);
325
System.out.println("Message: " + e.value);
326
}
327
```
328
329
## Exception Configuration
330
331
### Controlling Exception Display
332
333
```java
334
import org.python.core.Options;
335
336
// Show Java stack traces in Python exceptions
337
Options.showJavaExceptions = true;
338
339
// Include Java stack traces in Python tracebacks
340
Options.includeJavaStackInExceptions = true;
341
342
// Show Python proxy exceptions
343
Options.showPythonProxyExceptions = true;
344
345
PythonInterpreter interp = new PythonInterpreter();
346
347
try {
348
interp.exec("""
349
from java.util import ArrayList
350
list = ArrayList()
351
# This will show Java stack trace if enabled
352
list.get(10) # IndexOutOfBoundsException
353
""");
354
} catch (PyException e) {
355
System.out.println("Exception with Java details: " + e);
356
}
357
358
interp.close();
359
```
360
361
## Advanced Exception Patterns
362
363
### Exception Context Managers
364
365
```java
366
// Exception handling with context managers
367
interp.exec("""
368
class ExceptionHandler:
369
def __enter__(self):
370
print("Entering exception context")
371
return self
372
373
def __exit__(self, exc_type, exc_val, exc_tb):
374
if exc_type:
375
print(f"Handling {exc_type.__name__}: {exc_val}")
376
return True # Suppress exception
377
print("Exiting normally")
378
return False
379
""");
380
381
// Use the context manager
382
interp.exec("""
383
with ExceptionHandler():
384
raise ValueError("This will be suppressed")
385
386
print("Execution continues after context manager")
387
""");
388
```
389
390
### Exception Chaining
391
392
```java
393
// Python-style exception chaining
394
try {
395
interp.exec("""
396
def inner_function():
397
raise ValueError("Original error")
398
399
def outer_function():
400
try:
401
inner_function()
402
except ValueError as e:
403
raise RuntimeError("Wrapper error") from e
404
405
outer_function()
406
""");
407
} catch (PyException e) {
408
System.out.println("Main exception: " + e.type + " - " + e.value);
409
410
// Check for chained exception
411
PyObject cause = e.getCause();
412
if (cause != null && cause != Py.None) {
413
System.out.println("Caused by: " + cause);
414
}
415
}
416
```
417
418
### Custom Exception Handler
419
420
```java
421
public class JythonExceptionHandler {
422
private PythonInterpreter interp;
423
424
public JythonExceptionHandler(PythonInterpreter interp) {
425
this.interp = interp;
426
}
427
428
public Object safeExecute(String code) {
429
try {
430
return interp.eval(code);
431
} catch (PyException e) {
432
return handlePythonException(e);
433
} catch (Exception e) {
434
return handleJavaException(e);
435
}
436
}
437
438
private Object handlePythonException(PyException e) {
439
if (e.match(Py.SyntaxError)) {
440
System.err.println("Syntax error in Python code: " + e.value);
441
return null;
442
} else if (e.match(Py.NameError)) {
443
System.err.println("Undefined variable: " + e.value);
444
return null;
445
} else if (e.match(Py.TypeError)) {
446
System.err.println("Type error: " + e.value);
447
return null;
448
} else {
449
System.err.println("Unhandled Python exception: " + e.type + " - " + e.value);
450
e.printStackTrace();
451
return null;
452
}
453
}
454
455
private Object handleJavaException(Exception e) {
456
System.err.println("Java exception: " + e.getMessage());
457
e.printStackTrace();
458
return null;
459
}
460
}
461
462
// Usage:
463
JythonExceptionHandler handler = new JythonExceptionHandler(interp);
464
Object result = handler.safeExecute("undefined_variable");
465
```
466
467
## Error Recovery Patterns
468
469
### Graceful Degradation
470
471
```java
472
public class RobustJythonService {
473
private PythonInterpreter interp;
474
475
public String processData(String data) {
476
String fallbackResult = "Error processing data";
477
478
try {
479
interp.set("input_data", data);
480
PyObject result = interp.eval("process_input(input_data)");
481
return result.toString();
482
} catch (PyException e) {
483
if (e.match(Py.ImportError)) {
484
// Module not available, use Java fallback
485
return processDataFallback(data);
486
} else if (e.match(Py.ValueError)) {
487
// Invalid data, return error message
488
return "Invalid input: " + e.value;
489
} else {
490
// Log error and return fallback
491
System.err.println("Python processing failed: " + e);
492
return fallbackResult;
493
}
494
}
495
}
496
497
private String processDataFallback(String data) {
498
// Java implementation as fallback
499
return "Processed by Java: " + data.toUpperCase();
500
}
501
}
502
```
503
504
### Retry with Different Approaches
505
506
```java
507
public class RetryingJythonExecutor {
508
private PythonInterpreter interp;
509
510
public Object executeWithRetry(String primaryCode, String fallbackCode) {
511
// Try primary approach
512
try {
513
return interp.eval(primaryCode);
514
} catch (PyException e) {
515
System.out.println("Primary approach failed: " + e.value);
516
517
// Try fallback approach
518
try {
519
return interp.eval(fallbackCode);
520
} catch (PyException fallbackError) {
521
System.err.println("Both approaches failed");
522
System.err.println("Primary: " + e.value);
523
System.err.println("Fallback: " + fallbackError.value);
524
throw fallbackError;
525
}
526
}
527
}
528
}
529
```
530
531
## Debugging Exception Information
532
533
### Detailed Exception Analysis
534
535
```java
536
public class ExceptionAnalyzer {
537
public static void analyzeException(PyException e) {
538
System.out.println("=== Exception Analysis ===");
539
System.out.println("Type: " + e.type);
540
System.out.println("Value: " + e.value);
541
System.out.println("Message: " + e.getMessage());
542
543
// Java stack trace
544
System.out.println("\nJava Stack Trace:");
545
e.printStackTrace();
546
547
// Python traceback
548
if (e.traceback != null) {
549
System.out.println("\nPython Traceback:");
550
e.traceback.dumpStack();
551
}
552
553
// Exception cause chain
554
Throwable cause = e.getCause();
555
int level = 1;
556
while (cause != null) {
557
System.out.println("\nCause Level " + level + ": " + cause.getMessage());
558
cause = cause.getCause();
559
level++;
560
}
561
562
System.out.println("=== End Analysis ===");
563
}
564
}
565
566
// Usage:
567
try {
568
interp.exec("complex_operation()");
569
} catch (PyException e) {
570
ExceptionAnalyzer.analyzeException(e);
571
}
572
```