CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-bytedeco--cpython

JavaCPP bindings for CPython 3.13.5 enabling Java applications to embed Python interpreters and interact with Python objects through the Python C API

Pending
Overview
Eval results
Files

exceptions.mddocs/

Exception Handling

Complete Python exception system integration allowing Java applications to handle Python errors, set Python exceptions from Java code, and work with Python's warning system. This provides seamless error handling between Java and Python runtimes.

Capabilities

Exception State Management

Core functions for checking and managing Python exception state.

/**
 * Check if an exception is currently set
 * @return Exception object if set, NULL otherwise
 */
public static native PyObject PyErr_Occurred();

/**
 * Clear the current exception state
 */
public static native void PyErr_Clear();

/**
 * Check if exception matches specific type
 * @param exc - Exception to check
 * @param type - Exception type to match against
 * @return Non-zero if exception matches type
 */
public static native int PyErr_ExceptionMatches(PyObject exc);

/**
 * Check if current exception matches specific type
 * @param type - Exception type to check against
 * @return Non-zero if current exception matches type
 */
public static native int PyErr_GivenExceptionMatches(PyObject type);

Usage Example:

import static org.bytedeco.cpython.global.python.*;

// Call a Python function that might raise an exception
PyObject result = PyRun_SimpleString("1 / 0");  // Division by zero

// Check for exceptions
if (PyErr_Occurred() != null) {
    System.out.println("Python exception occurred!");
    
    // Check specific exception type
    if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError())) {
        System.out.println("Division by zero error");
    }
    
    // Clear the exception
    PyErr_Clear();
}

Setting Exceptions

Functions for setting Python exceptions from Java code.

/**
 * Set exception with no value (just the type)
 * @param exception - Exception type to set
 */
public static native void PyErr_SetNone(PyObject exception);

/**
 * Set exception with specific value object
 * @param exception - Exception type
 * @param value - Exception value object
 */
public static native void PyErr_SetObject(PyObject exception, PyObject value);

/**
 * Set exception with string message
 * @param exception - Exception type
 * @param message - Error message string
 */
public static native void PyErr_SetString(PyObject exception, String message);

/**
 * Set exception using formatted message
 * @param exception - Exception type
 * @param format - Printf-style format string
 * @param args - Format arguments
 */
public static native PyObject PyErr_Format(PyObject exception, String format, Object... args);

/**
 * Set MemoryError exception
 */
public static native PyObject PyErr_NoMemory();

/**
 * Set exception for bad argument to function
 */
public static native PyObject PyErr_BadArgument();

/**
 * Set exception for bad internal call
 */
public static native PyObject PyErr_BadInternalCall();

Usage Example:

// Set a custom exception
PyErr_SetString(PyExc_ValueError(), "Invalid input parameter");

// Set formatted exception
PyErr_Format(PyExc_TypeError(), "Expected %s, got %s", "int", "str");

// Set memory error
PyErr_NoMemory();

// Set exception with object value
PyObject errorDetails = PyDict_New();
PyDict_SetItemString(errorDetails, "code", PyLong_FromLong(404));
PyErr_SetObject(PyExc_RuntimeError(), errorDetails);

Exception Fetch and Restore

Advanced exception handling for preserving and restoring exception state.

/**
 * Fetch current exception info (clears current exception)
 * @param type - Pointer to receive exception type
 * @param value - Pointer to receive exception value
 * @param traceback - Pointer to receive traceback object
 */
public static native void PyErr_Fetch(PointerPointer type, PointerPointer value, PointerPointer traceback);

/**
 * Restore exception info (sets current exception)
 * @param type - Exception type (can be NULL)
 * @param value - Exception value (can be NULL)
 * @param traceback - Traceback object (can be NULL)
 */
public static native void PyErr_Restore(PyObject type, PyObject value, PyObject traceback);

/**
 * Normalize exception info (converts strings to proper exception objects)
 * @param type - Pointer to exception type (modified)
 * @param value - Pointer to exception value (modified)
 * @param traceback - Pointer to traceback (modified)
 */
public static native void PyErr_NormalizeException(PointerPointer type, PointerPointer value, PointerPointer traceback);

New Exception Handling (Python 3.12+)

Modern exception handling API introduced in Python 3.12.

/**
 * Get currently raised exception (new API)
 * @return Current exception object, or NULL if none
 */
public static native PyObject PyErr_GetRaisedException();

/**
 * Set currently raised exception (new API)
 * @param exc - Exception object to set (can be NULL to clear)
 */
public static native void PyErr_SetRaisedException(PyObject exc);

/**
 * Get currently handled exception
 * @return Currently handled exception, or NULL if none
 */
public static native PyObject PyErr_GetHandledException();

/**
 * Set currently handled exception
 * @param exc - Exception object to set as handled
 */
public static native void PyErr_SetHandledException(PyObject exc);

Usage Example:

// Modern exception handling pattern
PyObject exception = PyErr_GetRaisedException();
if (exception != null) {
    // Process the exception
    System.out.println("Handling exception: " + exception);
    
    // Optionally re-raise or clear
    PyErr_SetRaisedException(null); // Clear
    // or PyErr_SetRaisedException(exception); // Re-raise
}

Warning System

Python's warning system integration for handling warnings from Java.

/**
 * Issue a warning
 * @param category - Warning category (or NULL for default)
 * @param message - Warning message
 * @param stack_level - Stack level for warning location
 * @return 0 on success, -1 on error
 */
public static native int PyErr_WarnEx(PyObject category, String message, long stack_level);

/**
 * Issue a formatted warning
 * @param category - Warning category
 * @param stack_level - Stack level for warning location  
 * @param format - Printf-style format string
 * @param args - Format arguments
 * @return 0 on success, -1 on error
 */
public static native int PyErr_WarnFormat(PyObject category, long stack_level, String format, Object... args);

/**
 * Issue a resource warning
 * @param source - Source object causing the warning
 * @param stack_level - Stack level for warning location
 * @param format - Printf-style format string
 * @param args - Format arguments
 * @return 0 on success, -1 on error
 */
public static native int PyErr_ResourceWarning(PyObject source, long stack_level, String format, Object... args);

/**
 * Issue an explicit warning with full control
 * @param category - Warning category
 * @param message - Warning message
 * @param filename - Source filename
 * @param lineno - Line number
 * @param module - Module name
 * @param registry - Warning registry
 * @return 0 on success, -1 on error
 */
public static native int PyErr_WarnExplicit(PyObject category, String message, String filename,
                                          int lineno, String module, PyObject registry);

Usage Example:

// Issue a deprecation warning
int result = PyErr_WarnEx(PyExc_DeprecationWarning(), 
                         "This function is deprecated", 1);

if (result < 0) {
    // Warning caused an exception (warnings treated as errors)
    PyErr_Clear();
}

// Issue formatted warning
PyErr_WarnFormat(PyExc_UserWarning(), 2, 
                "Value %d is outside expected range", 150);

// Resource warning for unclosed file
PyErr_ResourceWarning(fileObject, 1, 
                     "unclosed file %s", filename);

Built-in Exception Types

Access to all standard Python exception types.

// Base exceptions
public static native PyObject PyExc_BaseException();
public static native PyObject PyExc_Exception();
public static native PyObject PyExc_ArithmeticError();
public static native PyObject PyExc_LookupError();

// Common exceptions
public static native PyObject PyExc_AttributeError();
public static native PyObject PyExc_EOFError();
public static native PyObject PyExc_ImportError();
public static native PyObject PyExc_IndexError();
public static native PyObject PyExc_KeyError();
public static native PyObject PyExc_KeyboardInterrupt();
public static native PyObject PyExc_MemoryError();
public static native PyObject PyExc_NameError();
public static native PyObject PyExc_OSError();
public static native PyObject PyExc_RuntimeError();
public static native PyObject PyExc_StopIteration();
public static native PyObject PyExc_SyntaxError();
public static native PyObject PyExc_SystemError();
public static native PyObject PyExc_SystemExit();
public static native PyObject PyExc_TypeError();
public static native PyObject PyExc_ValueError();
public static native PyObject PyExc_ZeroDivisionError();

// Warning categories
public static native PyObject PyExc_Warning();
public static native PyObject PyExc_UserWarning();
public static native PyObject PyExc_DeprecationWarning();
public static native PyObject PyExc_PendingDeprecationWarning();
public static native PyObject PyExc_SyntaxWarning();
public static native PyObject PyExc_RuntimeWarning();
public static native PyObject PyExc_FutureWarning();
public static native PyObject PyExc_ImportWarning();
public static native PyObject PyExc_UnicodeWarning();
public static native PyObject PyExc_BytesWarning();
public static native PyObject PyExc_ResourceWarning();

Exception Object Types

/**
 * Base exception object structure
 */
class PyBaseExceptionObject extends PyObject { }

/**
 * Attribute error exception
 */
class PyAttributeErrorObject extends PyBaseExceptionObject { }

/**
 * Import error exception  
 */
class PyImportErrorObject extends PyBaseExceptionObject { }

/**
 * Name error exception
 */
class PyNameErrorObject extends PyBaseExceptionObject { }

/**
 * OS error exception
 */
class PyOSErrorObject extends PyBaseExceptionObject { }

/**
 * Syntax error exception
 */
class PySyntaxErrorObject extends PyBaseExceptionObject { }

/**
 * System exit exception
 */
class PySystemExitObject extends PyBaseExceptionObject { }

/**
 * Unicode error exception
 */
class PyUnicodeErrorObject extends PyBaseExceptionObject { }

Advanced Exception Handling Patterns

Exception Context Preservation

// Save current exception state before calling risky operation
PointerPointer savedType = new PointerPointer(1);
PointerPointer savedValue = new PointerPointer(1);
PointerPointer savedTraceback = new PointerPointer(1);

PyErr_Fetch(savedType, savedValue, savedTraceback);

try {
    // Risky operation that might set different exception
    PyObject result = riskyPythonOperation();
    
    // If operation succeeded, restore original exception
    if (PyErr_Occurred() == null) {
        PyErr_Restore(new PyObject(savedType.get()),
                     new PyObject(savedValue.get()),
                     new PyObject(savedTraceback.get()));
    }
    
} catch (Exception e) {
    // Handle Java exception, but preserve Python exception
    PyErr_Restore(new PyObject(savedType.get()),
                 new PyObject(savedValue.get()),
                 new PyObject(savedTraceback.get()));
    throw e;
}

Custom Exception Classes

// Create custom exception type (typically done during module initialization)
public PyObject createCustomException(String name, String docstring) {
    // Create exception class
    PyObject exceptionClass = PyErr_NewException(name, PyExc_Exception(), null);
    
    if (exceptionClass != null && docstring != null) {
        // Set docstring
        PyObject doc = PyUnicode_FromString(docstring);
        PyObject_SetAttrString(exceptionClass, "__doc__", doc);
    }
    
    return exceptionClass;
}

Exception Chaining

// Demonstrate exception chaining (raise ... from ...)
try {
    // Original operation that fails
    PyObject result = PyLong_FromString("not_a_number", null, 10);
    
} catch (Exception e) {
    // Chain with new exception
    PyErr_SetString(PyExc_ValueError(), "Failed to process input");
    
    // The original exception becomes the __cause__
    // This is handled automatically by Python's exception system
}

Comprehensive Error Handling

public class PythonExceptionHandler {
    
    public static boolean handlePythonError() {
        if (PyErr_Occurred() == null) {
            return false; // No error
        }
        
        // Get exception information
        PointerPointer type = new PointerPointer(1);
        PointerPointer value = new PointerPointer(1);
        PointerPointer traceback = new PointerPointer(1);
        
        PyErr_Fetch(type, value, traceback);
        PyErr_NormalizeException(type, value, traceback);
        
        PyObject exceptionType = new PyObject(type.get());
        PyObject exceptionValue = new PyObject(value.get());
        PyObject exceptionTraceback = new PyObject(traceback.get());
        
        try {
            // Log exception details
            if (PyErr_GivenExceptionMatches(exceptionType, PyExc_ValueError())) {
                System.err.println("ValueError occurred");
            } else if (PyErr_GivenExceptionMatches(exceptionType, PyExc_TypeError())) {
                System.err.println("TypeError occurred");
            } else {
                System.err.println("Other exception occurred");
            }
            
            // Get exception message
            if (exceptionValue != null) {
                PyObject strRepr = PyObject_Str(exceptionValue);
                if (strRepr != null) {
                    // Convert to Java string and log
                    System.err.println("Exception message: " + strRepr);
                }
            }
            
            return true; // Exception handled
            
        } finally {
            // Clean up or re-raise if needed
            // PyErr_Restore(exceptionType, exceptionValue, exceptionTraceback);
        }
    }
}

Warning Configuration

// Configure warning behavior
public void configureWarnings() {
    // Import warnings module
    PyObject warningsModule = PyImport_ImportModule("warnings");
    
    if (warningsModule != null) {
        // Set warnings to be treated as errors
        PyObject filterwarnings = PyObject_GetAttrString(warningsModule, "filterwarnings");
        
        if (filterwarnings != null) {
            PyObject args = PyTuple_New(1);
            PyTuple_SetItem(args, 0, PyUnicode_FromString("error"));
            
            PyObject result = PyObject_CallObject(filterwarnings, args);
            
            if (result == null) {
                // Handle error in warning configuration
                PyErr_Clear();
            }
        }
    }
}

Integration with Java Exception Handling

Translating Python Exceptions to Java

public class PythonException extends RuntimeException {
    private final String pythonExceptionType;
    private final PyObject pythonException;
    
    public PythonException(String type, String message, PyObject exception) {
        super(message);
        this.pythonExceptionType = type;
        this.pythonException = exception;
    }
    
    public static PythonException fromPythonError() {
        if (PyErr_Occurred() == null) {
            return null;
        }
        
        // Extract exception details
        PyObject exception = PyErr_GetRaisedException();
        PyObject typeName = PyObject_GetAttrString(Py_TYPE(exception), "__name__");
        PyObject message = PyObject_Str(exception);
        
        String typeStr = (typeName != null) ? PyUnicode_AsUTF8(typeName) : "Unknown";
        String msgStr = (message != null) ? PyUnicode_AsUTF8(message) : "No message";
        
        return new PythonException(typeStr, msgStr, exception);
    }
}

// Usage
public void callPython() throws PythonException {
    PyRun_SimpleString("raise ValueError('Something went wrong')");
    
    PythonException pe = PythonException.fromPythonError();
    if (pe != null) {
        throw pe;
    }
}

Important Notes

Exception Ownership

When fetching exceptions with PyErr_Fetch(), the caller receives ownership of the exception objects and must manage their references appropriately.

Thread Safety

Exception state is thread-specific. Each thread has its own exception state that doesn't interfere with other threads.

Performance Considerations

  • Exception checking is fast when no exception is set
  • Avoid unnecessary exception fetching/restoration in performance-critical code
  • Clear exceptions promptly to avoid confusion

Error Propagation

Always check for Python exceptions after calling Python C API functions, especially when calling from Java code that doesn't expect Python exceptions.

Install with Tessl CLI

npx tessl i tessl/maven-org-bytedeco--cpython

docs

exceptions.md

index.md

initialization.md

memory-management.md

modules.md

objects.md

utilities.md

tile.json