Python¶
Usage
use Python;
or
import Python;
Warning
The Python module’s interface is under active development and may change
Library for interfacing with Python from Chapel code.
This module provides a Chapel interface to a Python interpreter. It allows manipulating native Python objects and libraries with minimal wrapper code required.
Note
This module is implemented using the Python C API, and as such, it is not compatible with PyPy or other alternative Python implementations.
Compiling Chapel code¶
Compiling Chapel code that uses this module needs the Python.h
header file
and requires linking with the Python library. If python3
is installed,
this can be achieved with the following commands:
PYTHON_INCLUDE_DIR=$(python3 -c "import sysconfig; print(sysconfig.get_paths()['include'])")
PYTHON_LIB_DIR=$(python3 -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
PYTHON_LDVERSION=$(python3 -c "import sysconfig; print(sysconfig.get_config_var('LDVERSION'))")
chpl --ccflags -isystem$PYTHON_INCLUDE_DIR \
-L$PYTHON_LIB_DIR --ldflags -Wl,-rpath,$PYTHON_LIB_DIR \
-lpython$PYTHON_LDVERSION ...Chapel source files...
Parallel Execution¶
Running any Python code in parallel from Chapel requires special care. Before any parallel execution with Python code can occur, the thread state needs to be saved. After the parallel execution, the thread state must to be restored. Then for each thread, the Global Interpreter Lock (GIL) must be acquired and released. This is necessary to prevent segmentation faults and deadlocks in the Python interpreter.
The following demonstrates this when explicit tasks are introduced with a
coforall
:
use Python;
var Arr: [1..10] int = 1..10;
var interp = new Interpreter();
var func = new Function(interp, "lambda x,: x * x");
var ts = new threadState();
ts.save(); // save the thread state
coforall tid in 1..10 {
var gil = new GIL(); // acquire the GIL
Arr[tid] = func(int, tid);
// GIL is automatically released at the end of the block
}
ts.restore(); // restore the thread state
writeln(Arr);
When using a data-parallel forall
, the GIL should be acquired and released
as a task private variable.
use Python;
var Arr: [1..10] int = 1..10;
var interp = new Interpreter();
var func = new Function(interp, "lambda x,: x * x");
var ts = new threadState();
ts.save(); // save the thread state
forall tid in 1..10 with (var gil = new GIL()) {
Arr[tid] = func(int, tid);
}
ts.restore(); // restore the thread state
writeln(Arr);
In the examples above, because the GIL is being acquired and released for the entirety of each task, these examples will be no faster than running the tasks serially.
Note
Newer Python versions offer a free-threading mode that allows multiple threads concurrently, without the need for the GIL. In this mode, users can either remove the GIL acquisition code or not. Without the GIL, the GIL acquisition code will have no effect.
Note
In the future, it may be possible to achieve better parallelism with Python by using sub-interpreters. However, sub-interpreters are not yet supported in Chapel.
Using Python Modules With Distributed Code¶
Python has no built-in support for distributed memory, so each locale must create its own interpreter (and subsequent Python objects).
The following example demonstrates how to create a Python interpreter and run a Python function on each locale:
use Python, BlockDist;
config const n = 100;
var Arr = blockDist.createArray({1..n}, int);
Arr = 1..n;
coforall l in Arr.targetLocales() {
on l {
// each locale has its own interpreter
const interp = new Interpreter();
const func = new Function(interp, "lambda x,: x + 1");
var ts = new threadState();
ts.save();
forall i in Arr.localSubdomain() with (var gil = new GIL()) {
Arr[i] = func(Arr.eltType, Arr[i]);
}
ts.restore();
}
}
writeln(Arr);
In this example, interp
and func
only exist for the body of the
on
block,Python objects can be made to persist beyond the scope of a
given on
block by creating a distributed array of Python objects.
Defining Custom Types¶
To translate custom Chapel types to Python objects, users should define and
register custom TypeConverter
classes.
More Examples:¶
For more examples of using the Python module, see the test cases in $CHPL_HOME/test/library/packages/Python/examples.
- record NoneType¶
Represents the python NoneType
- proc str() : string¶
Returns the string representation of None.
Equivalent to calling
str(None)
in Python.
- const None = new NoneType()¶
Represents the python value ‘None’
- class Interpreter¶
Represents the python interpreter. All code using the Python module should create and maintain a single instance of this class.
Warning
Multiple/sub interpreters are not yet supported. Do not create more than one instance of this class.
- proc run(code: string) throws¶
Run a string of python code.
This function will just run the code, it cannot be passed arguments or return values.
- proc registerConverter(in cvt: owned TypeConverter)¶
Register a custom
TypeConverter
with the interpreter. This allows arbitrary Chapel types to be serialized/deserialized to and from Python objects.The registered converter will take precedence over the default converters, allowing users to override the default behavior.
- proc checkException() throws¶
Query to see if an Python exception has occurred. If there is an exception, the Python exception will be thrown as a
Exception
.Note
This method should be called after any Python API call that may fail. The wrapping types in this module will call this method automatically, most users should not need to call this method directly.
- proc toPython(const val: ?t) : PyObjectPtr throws¶
Convert a Chapel value to a python object. This clones the Chapel value.
Note
Most users should not need to call this directly, except when writing a
TypeConverter
.
- proc fromPython(type t, obj: PyObjectPtr) : t throws¶
Convert a Python object to a Chapel value. This clones the Python value.
Note
Most users should not need to call this directly, except when writing a
TypeConverter
.
- class Exception : Error¶
Represents a Python exception, either forwarded from Python (i.e.
Interpreter.checkException
) or thrown directly in Chapel code.- proc init(in message: string)¶
Creates a new exception with the given message.
- class PythonException : Exception¶
Represents an exception caused in the Python code, forwarded by Chapel code
- proc init(in message: string)¶
- class ChapelException : Exception¶
Represents an exception caused by code in the Chapel module, not forwarded from Python.
- proc init(in message: string)¶
- class TypeConverter¶
Base class for Chapel/Python type converters.
To create a custom type converter, subclass this class and implement the
handlesType
,toPython
, andfromPython
methods. Then register an instance of this class with the interpreter by callingregisterConverter
.- proc handlesType(type T) : bool¶
Check if the converter can handle the given Chapel type.
This method should return true if the converter can handle the given type, and false otherwise.
- proc toPython(interpreter: borrowed Interpreter, type T, const value: T) : PyObjectPtr throws¶
Convert a Chapel value to a Python object.
This method should convert the Chapel value to a Python object and return the
c_ptr
to the underlying Python object.The
toPython
method will call this method.
- proc fromPython(interpreter: borrowed Interpreter, type T, obj: PyObjectPtr) : T throws¶
Convert a Python object to a Chapel value.
This method should convert the Python object to a Chapel value and return the Chapel value.
The
fromPython
method will call this method.
- class Module¶
Represents a Python module.
- proc init(interpreter: borrowed Interpreter, in modName: string) throws¶
Import a Python module by name.
- proc interpreter¶
Get the interpreter associated with this module.
- proc str() : string throws¶
Returns the string representation of the object. This is the same as casting to a string.
Equivalent to calling
str(obj)
in Python.
- class Function¶
Represents a Python function.
- proc init(mod: borrowed Module, in fnName: string) throws¶
- proc init(in fnName: string, in fn: owned PyObject) throws
- proc init(interpreter: borrowed Interpreter, in lambdaFn: string) throws
- proc interpreter¶
Get the interpreter associated with this function.
- proc str() : string throws¶
Returns the string representation of the object. This is the same as casting to a string.
Equivalent to calling
str(obj)
in Python.
- proc this(type retType, const args ...) : retType throws¶
Call a python function with Chapel arguments and get a Chapel return value
- proc this(type retType) : retType throws
- proc this(type retType, const args ..., kwargs: ?t = none) : retType throws where kwargs.isAssociative()
- proc this(type retType, kwargs: ?t = none) : retType throws where kwargs.isAssociative()
- proc getAttr(type t, attr: string) : t throws¶
- class Class¶
Represents a Python class.
- var className : string¶
- var cls : owned PyObject¶
- proc init(mod: borrowed Module, in className: string) throws¶
- proc interpreter¶
Get the interpreter associated with this class.
- proc str() : string throws¶
Returns the string representation of the object. This is the same as casting to a string.
Equivalent to calling
str(obj)
in Python.
- proc newInstance(const args ...) : owned PyObject throws¶
Create a new instance of a python class
- proc this(const args ...) : owned ClassObject throws¶
Create a new instance of a python class
- proc this() : owned ClassObject throws
- class ClassObject¶
Represents a Python class object.
- proc init(cls: borrowed Class, const args ...) throws¶
- proc init(cls: borrowed Class) throws
- proc init(in obj: owned PyObject?) throws
- proc interpreter¶
Get the interpreter associated with this object.
- proc str() : string throws¶
Returns the string representation of the object. This is the same as casting to a string.
Equivalent to calling
str(obj)
in Python.
- proc getAttr(type t, attr: string) : t throws¶
- proc setAttr(attr: string, value) throws¶
- proc this(type retType, const args ...) : retType throws¶
- proc call(type retType, method: string, const args ...) : retType throws¶
- proc call(type retType, method: string) : retType throws
- record GIL¶
Represents the Global Interpreter Lock, this is used to ensure that only one thread is executing python code at a time. Each thread should have its own
GIL
instance.Warning
This is not thread safe, do not attempt to use the same instance from multiple threads. This may cause a segfault or deadlock.
- proc init(param acquire: bool = true)¶
Acquires the GIL on record creation by default. Set
acquire
to false to delay acquisition.
- proc ref acquire()¶
Acquire the GIL. If the GIL is already acquired, this is a no-op.
- proc ref release()¶
Release the GIL. If the GIL is not acquired, this is a no-op.
This method is called automatically when the record is destroyed.
- record threadState¶
Represents the current thread state. This saves and restores the current thread state.
Warning
This is not thread safe, do not attempt to use the same instance from multiple threads. This may cause a segfault or deadlock.
- proc init(param save: bool = false)¶
Saves the current thread state on record creation by default. Set
save
to true to save the thread state on object creation.
- proc ref save()¶
Saves the current thread state. If the state is already saved, this is a no-op.
- proc ref restore()¶
Restores the thread state. If the state is not saved, this is a no-op.
This method is called automatically when the record is destroyed.
- class PyObject¶
Represents a Python value, it handles reference counting and is owned by default.
Most users should not need to use this directly.
- var interpreter : borrowed Interpreter¶
The interpreter that this object is associated with.
- proc init(in interpreter: borrowed Interpreter, obj: PyObjectPtr, isOwned: bool = true)¶
Takes ownership of an existing Python object, pointed to by
obj
- Arguments:
interpreter – The interpreter that this object is associated with.
obj – The
c_ptr
to the existing object.isOwned – Whether this object owns the Python object. This is true by default.
- proc init(in interpreter: borrowed Interpreter, value: ?)
Creates a new Python object from a Chapel value.
- Arguments:
interpreter – The interpreter that this object is associated with.
value – The Chapel value to convert to a Python object.
- proc check() throws¶
- proc value(type value) throws¶
Returns the Chapel value of the object.
This is a shortcut for calling
fromPython
on this object.
- proc type release(in self: owned PyObject) : PyObjectPtr¶
- proc type release(in self: owned ClassObject) : PyObjectPtr
- proc str() : string throws¶
Returns the string representation of the object. This is the same as casting to a string.
Equivalent to calling
str(obj)
in Python.