JavaCPP bindings for CPython 3.13.5 enabling Java applications to embed Python interpreters and interact with Python objects through the Python C API
—
Additional utilities including buffer protocol, callable objects, threading and GIL management, type system operations, and various helper functions for advanced Python integration scenarios.
Python's buffer protocol for efficient access to memory buffers and array-like objects.
/**
* Get buffer view of an object
* @param obj - Object to get buffer from
* @param view - Buffer view structure to fill
* @param flags - Buffer access flags
* @return 0 on success, -1 on error
*/
public static native int PyObject_GetBuffer(PyObject obj, Py_buffer view, int flags);
/**
* Release buffer view
* @param view - Buffer view to release
*/
public static native void PyBuffer_Release(Py_buffer view);
/**
* Get pointer to specific location in buffer
* @param view - Buffer view
* @param indices - Index array for multidimensional access
* @return Pointer to buffer location
*/
public static native Pointer PyBuffer_GetPointer(Py_buffer view, SizeTPointer indices);
/**
* Copy buffer data to contiguous memory
* @param buf - Destination buffer
* @param view - Source buffer view
* @param len - Number of bytes to copy
* @param order - Memory order ('C' or 'F')
* @return 0 on success, -1 on error
*/
public static native int PyBuffer_ToContiguous(Pointer buf, Py_buffer view, long len, char order);
/**
* Copy contiguous data to buffer
* @param view - Destination buffer view
* @param buf - Source buffer
* @param len - Number of bytes to copy
* @param order - Memory order ('C' or 'F')
* @return 0 on success, -1 on error
*/
public static native int PyBuffer_FromContiguous(Py_buffer view, Pointer buf, long len, char order);
/**
* Check if buffer is contiguous
* @param view - Buffer view
* @param order - Memory order to check ('C', 'F', or 'A')
* @return 1 if contiguous, 0 otherwise
*/
public static native int PyBuffer_IsContiguous(Py_buffer view, char order);
/**
* Fill buffer info structure
* @param view - Buffer view to fill
* @param obj - Object owning the buffer
* @param buf - Buffer pointer
* @param len - Buffer length
* @param readonly - 1 if read-only, 0 if writable
* @param flags - Buffer flags
* @return 0 on success, -1 on error
*/
public static native int PyBuffer_FillInfo(Py_buffer view, PyObject obj, Pointer buf,
long len, int readonly, int flags);Usage Example:
import static org.bytedeco.cpython.global.python.*;
// Get buffer from bytes object
PyObject bytesObj = PyBytes_FromString("Hello World");
Py_buffer buffer = new Py_buffer();
int result = PyObject_GetBuffer(bytesObj, buffer, PyBUF_SIMPLE);
if (result == 0) {
try {
// Access buffer data
Pointer data = buffer.buf();
long length = buffer.len();
System.out.println("Buffer length: " + length);
// Copy to contiguous memory
Pointer contiguous = PyMem_Malloc(length);
PyBuffer_ToContiguous(contiguous, buffer, length, 'C');
// Use contiguous data...
PyMem_Free(contiguous);
} finally {
// Always release buffer
PyBuffer_Release(buffer);
}
}Essential functions for executing Python code, evaluating expressions, and compiling Python source code from Java applications.
/**
* Execute Python source code string (equivalent to exec())
* @param command - Python code string to execute
* @return 0 on success, -1 on error
*/
public static native int PyRun_SimpleString(String command);
/**
* Execute Python source with error checking
* @param command - Python code string to execute
* @return 0 on success, -1 on error (with exception set)
*/
public static native int PyRun_SimpleStringFlags(String command, PyCompilerFlags flags);
/**
* Execute Python source code in specified namespace
* @param str - Python code string
* @param start - Start symbol (Py_eval_input, Py_single_input, or Py_file_input)
* @param globals - Global namespace dictionary
* @param locals - Local namespace dictionary
* @return Result object, or NULL on error
*/
public static native PyObject PyRun_String(String str, int start, PyObject globals, PyObject locals);
/**
* Execute Python source code with compiler flags
* @param str - Python code string
* @param start - Start symbol
* @param globals - Global namespace dictionary
* @param locals - Local namespace dictionary
* @param flags - Compiler flags
* @return Result object, or NULL on error
*/
public static native PyObject PyRun_StringFlags(String str, int start, PyObject globals,
PyObject locals, PyCompilerFlags flags);
/**
* Execute Python file from FILE pointer
* @param file - Open FILE pointer to Python source
* @param filename - Filename for error reporting
* @param start - Start symbol
* @param globals - Global namespace dictionary
* @param locals - Local namespace dictionary
* @return Result object, or NULL on error
*/
public static native PyObject PyRun_File(Pointer file, String filename, int start,
PyObject globals, PyObject locals);
/**
* Compile Python source code to code object
* @param str - Python source code string
* @param filename - Filename for error reporting
* @param start - Start symbol (Py_eval_input, Py_single_input, or Py_file_input)
* @return Compiled code object, or NULL on error
*/
public static native PyObject Py_CompileString(String str, String filename, int start);
/**
* Compile Python source with compiler flags
* @param str - Python source code string
* @param filename - Filename for error reporting
* @param start - Start symbol
* @param flags - Compiler flags
* @return Compiled code object, or NULL on error
*/
public static native PyObject Py_CompileStringFlags(String str, String filename, int start,
PyCompilerFlags flags);
/**
* Evaluate compiled code object
* @param code - Compiled code object
* @param globals - Global namespace dictionary
* @param locals - Local namespace dictionary
* @return Result object, or NULL on error
*/
public static native PyObject PyEval_EvalCode(PyObject code, PyObject globals, PyObject locals);
/**
* Evaluate code object with additional parameters
* @param code - Compiled code object
* @param globals - Global namespace dictionary
* @param locals - Local namespace dictionary
* @param args - Positional arguments array
* @param argcount - Number of positional arguments
* @param kwds - Keyword arguments array
* @param kwdcount - Number of keyword arguments
* @param defs - Default argument values
* @param defcount - Number of default values
* @param closure - Closure tuple for nested functions
* @return Result object, or NULL on error
*/
public static native PyObject PyEval_EvalCodeEx(PyObject code, PyObject globals, PyObject locals,
PointerPointer args, int argcount,
PointerPointer kwds, int kwdcount,
PointerPointer defs, int defcount,
PyObject closure);Execution Start Symbols:
// Execution mode constants
public static final int Py_single_input = 256; // Single interactive statement
public static final int Py_file_input = 257; // Complete Python file
public static final int Py_eval_input = 258; // Single expression for evaluationUsage Examples:
import static org.bytedeco.cpython.global.python.*;
// Simple code execution
PyRun_SimpleString("print('Hello from Python!')");
PyRun_SimpleString("x = 42; print(f'The answer is {x}')");
// Execute code with result capture
PyObject globals = PyDict_New();
PyObject locals = PyDict_New();
// Execute statements
PyRun_String("x = 10; y = 20", Py_file_input, globals, locals);
// Evaluate expression
PyObject result = PyRun_String("x + y", Py_eval_input, globals, locals);
long sum = PyLong_AsLong(result); // 30
// Compile and execute separately
PyObject code = Py_CompileString("result = x * y", "calculation", Py_file_input);
if (code != null) {
PyEval_EvalCode(code, globals, locals);
// Get result from locals
PyObject pyResult = PyDict_GetItemString(locals, "result");
long product = PyLong_AsLong(pyResult); // 200
}
// Execute Python file content
String pythonScript = """
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
result = fibonacci(10)
""";
PyRun_String(pythonScript, Py_file_input, globals, locals);
PyObject fibResult = PyDict_GetItemString(locals, "result");
System.out.println("Fibonacci(10) = " + PyLong_AsLong(fibResult)); // 55Functions for working with callable Python objects and function calls.
/**
* Check if object is callable
* @param obj - Object to check
* @return 1 if callable, 0 otherwise
*/
public static native int PyCallable_Check(PyObject obj);
/**
* Call callable object with arguments and keywords
* @param callable - Callable object
* @param args - Tuple of positional arguments
* @param kwargs - Dictionary of keyword arguments (or NULL)
* @return Result of call, or NULL on error
*/
public static native PyObject PyObject_Call(PyObject callable, PyObject args, PyObject kwargs);
/**
* Call callable object with tuple of arguments
* @param callable - Callable object
* @param args - Tuple of arguments (or NULL for no args)
* @return Result of call, or NULL on error
*/
public static native PyObject PyObject_CallObject(PyObject callable, PyObject args);
/**
* Call callable with formatted arguments
* @param callable - Callable object
* @param format - Argument format string
* @param args - Arguments matching format
* @return Result of call, or NULL on error
*/
public static native PyObject PyObject_CallFunction(PyObject callable, String format, Object... args);
/**
* Call method on object with formatted arguments
* @param obj - Object to call method on
* @param method - Method name
* @param format - Argument format string
* @param args - Arguments matching format
* @return Result of call, or NULL on error
*/
public static native PyObject PyObject_CallMethod(PyObject obj, String method, String format, Object... args);High-performance calling protocol introduced in Python 3.8+.
/**
* Call using vectorcall protocol
* @param callable - Callable object
* @param args - Array of argument objects
* @param nargsf - Number of arguments (with flags)
* @param kwnames - Tuple of keyword names (or NULL)
* @return Result of call, or NULL on error
*/
public static native PyObject PyObject_Vectorcall(PyObject callable, PointerPointer args,
long nargsf, PyObject kwnames);
/**
* Call using vectorcall with dictionary keywords
* @param callable - Callable object
* @param args - Array of argument objects
* @param nargsf - Number of arguments (with flags)
* @param kwargs - Dictionary of keyword arguments
* @return Result of call, or NULL on error
*/
public static native PyObject PyObject_VectorcallDict(PyObject callable, PointerPointer args,
long nargsf, PyObject kwargs);
/**
* Check if object supports vectorcall
* @param callable - Object to check
* @return 1 if supports vectorcall, 0 otherwise
*/
public static native int PyVectorcall_NARGS(long nargsf);Usage Example:
// Call a Python function
PyObject func = PyObject_GetAttrString(module, "my_function");
if (PyCallable_Check(func) != 0) {
// Create arguments tuple
PyObject args = PyTuple_New(2);
PyTuple_SetItem(args, 0, PyLong_FromLong(10));
PyTuple_SetItem(args, 1, PyUnicode_FromString("test"));
// Call function
PyObject result = PyObject_CallObject(func, args);
if (result != null) {
// Process result
System.out.println("Function returned: " + result);
} else {
PyErr_Clear();
}
}
// Call method on object
PyObject obj = getMyObject();
PyObject methodResult = PyObject_CallMethod(obj, "process", "si", "data", 42);Functions for managing Python's Global Interpreter Lock (GIL) and thread state.
/**
* Get thread state for current thread
* @return Thread state for this thread, or NULL if no Python thread state
*/
public static native PyThreadState PyGILState_GetThisThreadState();
/**
* Check if current thread holds the GIL
* @return 1 if GIL is held, 0 otherwise
*/
public static native int PyGILState_Check();
/**
* Ensure current thread has the GIL
* @return GIL state token (must be passed to PyGILState_Release)
*/
public static native @Cast("PyGILState_STATE") int PyGILState_Ensure();
/**
* Release GIL acquired with PyGILState_Ensure
* @param state - State token from PyGILState_Ensure
*/
public static native void PyGILState_Release(@Cast("PyGILState_STATE") int state);
/**
* Create new thread state for interpreter
* @param interp - Interpreter state
* @return New thread state
*/
public static native PyThreadState PyThreadState_New(PyInterpreterState interp);
/**
* Clear thread state (prepare for deletion)
* @param tstate - Thread state to clear
*/
public static native void PyThreadState_Clear(PyThreadState tstate);
/**
* Delete thread state
* @param tstate - Thread state to delete
*/
public static native void PyThreadState_Delete(PyThreadState tstate);
/**
* Get current thread state
* @return Current thread state
*/
public static native PyThreadState PyThreadState_Get();
/**
* Swap thread state (make different thread state current)
* @param tstate - New thread state (or NULL)
* @return Previous thread state
*/
public static native PyThreadState PyThreadState_Swap(PyThreadState tstate);Usage Example:
// Proper GIL management from Java thread
public class PythonWorker {
public void doWorkInPython() {
// Acquire GIL
int gilState = PyGILState_Ensure();
try {
// Now safe to call Python API
PyObject result = PyRun_SimpleString("print('Hello from Java thread')");
// More Python operations...
} finally {
// Always release GIL
PyGILState_Release(gilState);
}
}
public void longRunningTask() {
int gilState = PyGILState_Ensure();
try {
// Do some Python setup
PyObject data = PyList_New(1000000);
// Release GIL for long computation
PyGILState_Release(gilState);
gilState = null;
// Do Java computation without holding GIL
doExpensiveJavaComputation();
// Re-acquire GIL for Python work
gilState = PyGILState_Ensure();
// Continue with Python operations
PyList_Append(data, PyUnicode_FromString("done"));
} finally {
if (gilState != 0) {
PyGILState_Release(gilState);
}
}
}
private void doExpensiveJavaComputation() {
// Long-running Java code that doesn't need Python
// Good to release GIL during this
}
}Advanced type system functions for working with Python types and classes.
/**
* Prepare type object for use (must be called before using custom types)
* @param type - Type object to prepare
* @return 0 on success, -1 on error
*/
public static native int PyType_Ready(PyTypeObject type);
/**
* Create type from specification
* @param spec - Type specification structure
* @return New type object, or NULL on error
*/
public static native PyTypeObject PyType_FromSpec(PyType_Spec spec);
/**
* Create type from specification with base classes
* @param spec - Type specification
* @param bases - Tuple of base classes
* @return New type object, or NULL on error
*/
public static native PyTypeObject PyType_FromSpecWithBases(PyType_Spec spec, PyObject bases);
/**
* Create type from specification with module association
* @param module - Module to associate type with
* @param spec - Type specification
* @param bases - Tuple of base classes
* @return New type object, or NULL on error
*/
public static native PyTypeObject PyType_FromModuleAndSpec(PyObject module, PyType_Spec spec, PyObject bases);
/**
* Check if one type is subtype of another
* @param a - Potential subtype
* @param b - Potential base type
* @return 1 if a is subtype of b, 0 otherwise
*/
public static native int PyType_IsSubtype(PyTypeObject a, PyTypeObject b);
/**
* Check if object is instance of class
* @param obj - Object to check
* @param cls - Class to check against
* @return 1 if instance, 0 if not, -1 on error
*/
public static native int PyObject_IsInstance(PyObject obj, PyObject cls);
/**
* Check if one class is subclass of another
* @param derived - Potential subclass
* @param cls - Potential base class
* @return 1 if subclass, 0 if not, -1 on error
*/
public static native int PyObject_IsSubclass(PyObject derived, PyObject cls);/**
* Get size of type-specific data
* @param cls - Type object
* @return Size of type data in bytes
*/
public static native long PyType_GetTypeDataSize(PyTypeObject cls);
/**
* Get pointer to type-specific data
* @param cls - Type object
* @param base - Base type that defines the data
* @return Pointer to type data
*/
public static native Pointer PyType_GetTypeData(PyTypeObject cls, PyTypeObject base);Usage Example:
// Check types and inheritance
PyObject obj = getMyObject();
PyObject listType = PyList_Type(); // Assuming this exists
// Check if object is a list
if (PyObject_IsInstance(obj, listType) == 1) {
System.out.println("Object is a list");
}
// Check type inheritance
PyTypeObject customType = getCustomType();
if (PyType_IsSubtype(customType, listType) == 1) {
System.out.println("Custom type inherits from list");
}Important constants for mathematical operations and system limits.
/**
* Mathematical constants
*/
public static final double Py_MATH_PI = 3.14159265358979323846;
public static final double Py_MATH_E = 2.7182818284590452354;
public static final double Py_MATH_TAU = 6.2831853071795864769252867665590057683943;
/**
* Get positive infinity value
* @return Positive infinity as double
*/
public static native double Py_INFINITY();
/**
* Build and version constants
*/
public static final int Py_ENABLE_SHARED = 1;
public static final int Py_CAN_START_THREADS = 1;Additional object manipulation and introspection functions.
/**
* Get object's string representation
* @param obj - Object to get representation of
* @return String representation, or NULL on error
*/
public static native PyObject PyObject_Str(PyObject obj);
/**
* Get object's printable representation
* @param obj - Object to get representation of
* @return Printable representation, or NULL on error
*/
public static native PyObject PyObject_Repr(PyObject obj);
/**
* Get object's ASCII representation
* @param obj - Object to get representation of
* @return ASCII representation, or NULL on error
*/
public static native PyObject PyObject_ASCII(PyObject obj);
/**
* Get object's bytes representation
* @param obj - Object to convert to bytes
* @return Bytes object, or NULL on error
*/
public static native PyObject PyObject_Bytes(PyObject obj);
/**
* Check if object is true in boolean context
* @param obj - Object to check
* @return 1 if true, 0 if false, -1 on error
*/
public static native int PyObject_IsTrue(PyObject obj);
/**
* Check if object is false in boolean context
* @param obj - Object to check
* @return 1 if false, 0 if true, -1 on error
*/
public static native int PyObject_IsFalse(PyObject obj);
/**
* Get length of object
* @param obj - Object to get length of
* @return Length, or -1 on error
*/
public static native long PyObject_Length(PyObject obj);/**
* Buffer view structure for buffer protocol
*/
class Py_buffer extends Pointer {
// Contains:
// - buf: pointer to buffer data
// - len: length in bytes
// - readonly: read-only flag
// - format: format string
// - ndim: number of dimensions
// - shape: array of dimension sizes
// - strides: array of strides
// - suboffsets: suboffsets array
}
/**
* Type specification for creating new types
*/
class PyType_Spec extends Pointer {
// Contains:
// - name: type name
// - basicsize: basic instance size
// - itemsize: variable part size
// - flags: type flags
// - slots: array of slot definitions
}
/**
* GIL state enumeration (returned as int)
*/
public static final int PyGILState_STATE = 0; // Enum value cast to int
/**
* Thread state object
*/
class PyThreadState extends Pointer { }
/**
* Interpreter state object
*/
class PyInterpreterState extends Pointer { }public class BufferOperations {
public static void processLargeArray(PyObject arrayObj) {
Py_buffer buffer = new Py_buffer();
if (PyObject_GetBuffer(arrayObj, buffer, PyBUF_C_CONTIGUOUS) == 0) {
try {
long itemCount = buffer.len() / buffer.itemsize();
// Check if contiguous for fast access
if (PyBuffer_IsContiguous(buffer, 'C') == 1) {
// Direct memory access for maximum performance
Pointer data = buffer.buf();
// Process data directly in native code
processNativeBuffer(data, itemCount);
} else {
// Copy to contiguous buffer first
Pointer contiguous = PyMem_Malloc(buffer.len());
PyBuffer_ToContiguous(contiguous, buffer, buffer.len(), 'C');
processNativeBuffer(contiguous, itemCount);
// Copy back if buffer is writable
if (buffer.readonly() == 0) {
PyBuffer_FromContiguous(buffer, contiguous, buffer.len(), 'C');
}
PyMem_Free(contiguous);
}
} finally {
PyBuffer_Release(buffer);
}
}
}
private static native void processNativeBuffer(Pointer data, long count);
}public class PythonThreadPool {
private final ExecutorService executor;
public PythonThreadPool(int threadCount) {
this.executor = Executors.newFixedThreadPool(threadCount);
}
public CompletableFuture<PyObject> submitPythonTask(String pythonCode) {
return CompletableFuture.supplyAsync(() -> {
int gilState = PyGILState_Ensure();
try {
return PyRun_SimpleString(pythonCode);
} finally {
PyGILState_Release(gilState);
}
}, executor);
}
public void shutdown() {
executor.shutdown();
}
}public class CustomTypeBuilder {
public static PyTypeObject createCustomListType() {
// This is a simplified example - real type creation
// requires more detailed slot filling
PyType_Spec spec = new PyType_Spec();
// Fill spec with type information
// spec.name = "CustomList"
// spec.basicsize = sizeof(CustomListObject)
// spec.flags = Py_TPFLAGS_DEFAULT
PyTypeObject newType = PyType_FromSpec(spec);
if (newType != null) {
// Prepare the type for use
if (PyType_Ready(newType) < 0) {
return null;
}
}
return newType;
}
}// Use vectorcall for better performance when available
if (supportsVectorcall(func)) {
PointerPointer args = new PointerPointer(argArray);
PyObject result = PyObject_Vectorcall(func, args, argCount, null);
} else {
// Fall back to traditional calling
PyObject argTuple = createArgTuple(argArray);
PyObject result = PyObject_CallObject(func, argTuple);
}// Request specific buffer format for optimal performance
int flags = PyBUF_C_CONTIGUOUS | PyBUF_FORMAT;
if (PyObject_GetBuffer(obj, buffer, flags) == 0) {
// Got optimal buffer format
} else {
// Fall back to simple buffer
PyErr_Clear();
PyObject_GetBuffer(obj, buffer, PyBUF_SIMPLE);
}// Minimize GIL hold time
int gilState = PyGILState_Ensure();
PyObject data = extractPythonData(); // Quick Python operation
PyGILState_Release(gilState);
// Do heavy computation without GIL
Object processedData = processInJava(data);
// Re-acquire GIL for final Python operations
gilState = PyGILState_Ensure();
storePythonResult(processedData);
PyGILState_Release(gilState);PyBuffer_Release()PyGILState_Release()Most utility functions follow standard Python C API error conventions - check return values and PyErr_Occurred() for error detection.
Install with Tessl CLI
npx tessl i tessl/maven-org-bytedeco--cpython