Conversion to Julia
Conversion Rules
The following table specifies the conversion rules used whenever converting a Python object to a Julia object. If the initial Python type matches the "From" column and the desired type T
intersects with the "To" column, then that conversion is attempted. Conversions are tried in priority order, then in specificity order.
From Julia, one can convert Python objects to a desired type using pyconvert(T, x)
for example.
From Python, the arguments to a Julia function will be converted according to these rules with T=Any
.
From | To |
---|---|
Top priority (wrapped values). | |
juliacall.AnyValue | Any |
Very high priority (arrays). | |
Objects satisfying the buffer or array interface (inc. bytes , bytearray , array.array , numpy.ndarray ) | PyArray |
High priority (canonical conversions). | |
None | Nothing |
bool | Bool |
numbers.Integral (inc. int ) | Integer (prefers Int , or BigInt on overflow) |
float | Float64 |
complex | Complex{Float64} |
range | StepRange |
str | String |
tuple | Tuple |
collections.abc.Mapping (inc. dict ) | PyDict |
collections.abc.Sequence (inc. list ) | PyList |
collections.abc.Set (inc. set , frozenset ) | PySet |
io.IOBase (includes open files) | PyIO |
BaseException | PyException |
datetime.date /datetime.time /datetime.datetime | Date /Time /DateTime |
datetime.timedelta | Microsecond (or Millisecond or Second on overflow) |
numpy.intXX /numpy.uintXX /numpy.floatXX | IntXX /UIntXX /FloatXX |
Standard priority (other reasonable conversions). | |
None | Missing |
bytes | Vector{UInt8} , Vector{Int8} , String |
str | String , Symbol , Char , Vector{UInt8} , Vector{Int8} |
range | UnitRange |
collections.abc.Mapping | Dict |
collections.abc.Iterable | Vector , Set , Tuple , NamedTuple , Pair |
datetime.timedelta | Dates.CompoundPeriod |
numbers.Integral | Integer , Rational , Real , Number |
numbers.Real | AbstractFloat , Number , Missing /Nothing (if NaN) |
numbers.Complex | Complex , Number |
ctypes.c_int and other integers | Integer , Rational , Real , Number |
ctypes.c_float /ctypes.c_double | Cfloat /Cdouble , AbstractFloat , Real , Number |
ctypes.c_voidp | Ptr{Cvoid} , Ptr |
ctypes.c_char_p | Cstring , Ptr{Cchar} , Ptr |
ctypes.c_wchar_p | Cwstring , Ptr{Cwchar} , Ptr |
numpy.intXX /numpy.uintXX /numpy.floatXX | Integer , Rational , Real , Number |
Objects satisfying the buffer or array interface | Array , AbstractArray |
Low priority (fallback to Py ). | |
Anything | Py |
Bottom priority (must be explicitly specified by excluding Py ). | |
Objects satisfying the buffer interface | PyBuffer |
Anything | PyRef |
See below for an explanation of the Py*
types (PyList
, PyIO
, etc).
Custom rules
To add a custom conversion rule, you must define a function to do the conversion and call pyconvert_add_rule
to register it.
You must not do this while precompiling, so these calls will normally be in the __init__
function of your module.
PythonCall.pyconvert_add_rule
— Functionpyconvert_add_rule(tname::String, T::Type, func::Function, priority::PyConvertPriority=PYCONVERT_PRIORITY_NORMAL)
Add a new conversion rule for pyconvert
.
Arguments
tname
is a string of the form"__module__:__qualname__"
identifying a Python typet
, such as"builtins:dict"
. This rule only applies to Python objects of this type.T
is a Julia type, such that this rule only applies when the target type intersects withT
.func
is the function implementing the rule.priority
determines whether to prioritise this rule above others.
When pyconvert(R, x)
is called, all rules such that typeintersect(T, R) != Union{}
and pyisinstance(x, t)
are considered. These rules are sorted first by priority, then by the specificity of t
(e.g. bool
is more specific than int
is more specific than object
) then by the order they were added. The rules are tried in turn until one succeeds.
Implemeting func
func
is called as func(S, x::Py)
for some S <: T
.
It must return one of:
pyconvert_return(ans)
whereans
is the result of the conversion (and must be anS
).pyconvert_unconverted()
if the conversion was not possible (e.g. converting alist
toVector{Int}
might fail if some of the list items are not integers).
The target type S
is never a union or the empty type, i.e. it is always a data type or union-all.
Priority
Most rules should have priority PYCONVERT_PRIORITY_NORMAL
(the default) which is for any reasonable conversion rule.
Use priority PYCONVERT_PRIORITY_CANONICAL
for canonical conversion rules. Immutable objects may be canonically converted to their corresponding Julia type, such as int
to Integer
. Mutable objects must be converted to a wrapper type, such that the original Python object can be retrieved. For example a list
is canonically converted to PyList
and not to a Vector
. There should not be more than one canonical conversion rule for a given Python type.
Other priorities are reserved for internal use.
Optional optimization (for experts)
The func
is given the only reference to x
. This means it may call pydel!(x)
when done with x
provided x
is not referenced anywhere else, such as in the return value. See pydel!
.
If you are returning a wrapper type, such as PyList(x)
, then the object x
should be duplicated first, as in Py(x)
. It is recommended to force this in the inner constructor of the wrapper type.
Wrapper types
The following types wrap a Python object, giving it the semantics of a Julia object. For example PyList(x)
interprets the Python sequence x
as a Julia abstract vector.
Apart from a few fundamental immutable types, conversion from Python to Julia Any
will return a wrapper type such as one of these, or simply Py
if no wrapper type is suitable.
PythonCall.PyList
— TypePyList{T=Py}([x])
Wraps the Python list x
(or anything satisfying the sequence interface) as an AbstractVector{T}
.
If x
is not a Python object, it is converted to one using pylist
.
PythonCall.PySet
— TypePySet{T=Py}([x])
Wraps the Python set x
(or anything satisfying the set interface) as an AbstractSet{T}
.
If x
is not a Python object, it is converted to one using pyset
.
PythonCall.PyDict
— TypePyDict{K=Py,V=Py}([x])
Wraps the Python dict x
(or anything satisfying the mapping interface) as an AbstractDict{K,V}
.
If x
is not a Python object, it is converted to one using pydict
.
PythonCall.PyIterable
— TypePyIterable{T=Py}(x)
This object iterates over iterable Python object x
, yielding values of type T
.
PythonCall.PyArray
— TypePyArray{T,N,M,L,R}(x; copy=true, array=true, buffer=true)
Wrap the Python array x
as a Julia AbstractArray{T,N}
.
The input x
can be bytes
, bytearray
, array.array
, numpy.ndarray
or anything satisfying the buffer protocol (if buffer=true
) or the numpy array interface (if array=true
).
If copy=false
then the resulting array is guaranteed to directly wrap the data in x
. If copy=true
then a copy is taken if necessary to produce an array.
The type parameters are all optional, and are:
T
: The element type.N
: The number of dimensions.M
: True if the array is mutable.L
: True if the array supports fast linear indexing.R
: The element type of the underlying buffer. Equal toT
for scalar numeric types.
PythonCall.PyIO
— TypePyIO(x; own=false, text=missing, buflen=4096)
Wrap the Python IO stream x
as a Julia IO stream.
When this goes out of scope and is finalized, it is automatically flushed. If own=true
then it is also closed.
If text=false
then x
must be a binary stream and arbitrary binary I/O is possible. If text=true
then x
must be a text stream and only UTF-8 must be written (i.e. use print
not write
). If text
is not specified then it is chosen automatically. If x
is a text stream and you really need a binary stream, then often PyIO(x.buffer)
will work.
For efficiency, reads and writes are buffered before being sent to x
. The size of the buffers is buflen
. The buffers are cleared using flush
.
PythonCall.PyTable
— TypePyTable
Abstract type for Python wrappers which may be interpretable as Tables.jl-compatible tables.
If pyconvert(PyTable, x::Py)
is a table, then x
is also a table.
PythonCall.PyPandasDataFrame
— TypePyPandasDataFrame(x; indexname=nothing, columntypes=())
Wraps the pandas DataFrame x
as a Tables.jl-compatible table.
indexname
is the name of the column to contain the index. It may be nothing
to exclude the index.
columntypes
is a mapping of column names to column element types, in case automatic deduction does not work.
PythonCall.PyObjectArray
— TypePyObjectArray(undef, dims...)
PyObjectArray(array)
An array of Py
s which supports the Python buffer protocol.
Internally, the objects are stored as an array of pointers.
PythonCall.PyException
— TypePyException(x)
Wraps the Python exception x
as a Julia Exception
.
Custom wrappers
Here is a minimal example of defining a wrapper type. You may add methods, fields and a supertype to the type to specialise its behaviour. See any of the above wrapper types for examples.
# The new type with a field for the Python object being wrapped.
struct MyType
py::Py
end
# Says that the object is a wrapper.
ispy(x::MyType) = true
# Says how to access the underlying Python object.
getpy(x::MyType) = x.py