Skip to content

Commit bc87517

Browse files
committed
use generic jlwrap Python types as fallback for Julia -> Python conversions, support bidirectional conversion of jlwrap types
1 parent afcb764 commit bc87517

File tree

2 files changed

+42
-7
lines changed

2 files changed

+42
-7
lines changed

src/conversions.jl

+7
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,14 @@ end
380380
pytype_query(o::PyObject) = pytype_query(o, PyObject)
381381

382382
function convert(::Type{PyAny}, o::PyObject)
383+
if (o.o == C_NULL)
384+
return o
385+
end
383386
try
387+
T = pytype_query(o)
388+
if T == PyObject && is_pyjlwrap(o)
389+
return unsafe_pyjlwrap_to_objref(o.o)
390+
end
384391
convert(pytype_query(o), o)
385392
catch
386393
pyerr_clear() # just in case

src/pytype.jl

+35-7
Original file line numberDiff line numberDiff line change
@@ -336,17 +336,37 @@ function pyjlwrap_repr(o::PyPtr)
336336
return oret
337337
end
338338

339-
# use this to create a new jlwrap type, with init to set up custom members
340-
function pyjlwrap_type(name::String, init::Function)
339+
jlWrapType = PyTypeObject()
340+
341+
function pyjlwrap_init()
341342
if pyversion() < v"2.6"
342343
error("Python version 2.6 or later required for T_PYSSIZET")
343344
end
344-
PyTypeObject(name, sizeof(Py_jlWrap),
345+
global jlWrapType
346+
if (jlWrapType::PyTypeObject).tp_name == C_NULL
347+
jlWrapType::PyTypeObject =
348+
PyTypeObject("PyCall.jlwrap", sizeof(Py_jlWrap),
349+
t::PyTypeObject -> begin
350+
t.tp_flags |= Py_TPFLAGS_BASETYPE
351+
t.tp_members = convert(Ptr{Void}, pyjlwrap_members);
352+
t.tp_dealloc = cfunction(pyjlwrap_dealloc,
353+
Void, (PyPtr,))
354+
t.tp_repr = cfunction(pyjlwrap_repr,
355+
PyPtr, (PyPtr,))
356+
end)
357+
end
358+
359+
end
360+
361+
# use this to create a new jlwrap type, with init to set up custom members
362+
function pyjlwrap_type(name::String, init::Function)
363+
pyjlwrap_init()
364+
PyTypeObject(name,
365+
sizeof(Py_jlWrap) + sizeof(PyPtr), # must be > base type
345366
t::PyTypeObject -> begin
346-
t.tp_members = convert(Ptr{Void}, pyjlwrap_members);
347-
t.tp_dealloc = cfunction(pyjlwrap_dealloc,
348-
Void, (PyPtr,))
349-
t.tp_repr = cfunction(pyjlwrap_repr, PyPtr, (PyPtr,))
367+
t.tp_base = ccall(:jl_value_ptr, Ptr{Void},
368+
(Ptr{PyTypeObject},),
369+
&(jlWrapType::PyTypeObject))
350370
init(t)
351371
end)
352372
end
@@ -365,5 +385,13 @@ function pyjlwrap_new(pyT::PyTypeObject, value::Any)
365385
return o
366386
end
367387

388+
is_pyjlwrap(o::PyObject) = (jlWrapType::PyTypeObject).tp_name != C_NULL && ccall(pyfunc(:PyObject_IsInstance), Cint, (PyPtr,Ptr{PyTypeObject}), o, &(jlWrapType::PyTypeObject)) == 1
389+
390+
################################################################
391+
# Fallback conversion: if we don't have a better conversion function,
392+
# just wrap the Julia object in a Python object
393+
394+
PyObject(x::Any) = begin pyjlwrap_init(); pyjlwrap_new(jlWrapType, x); end
395+
368396
################################################################
369397

0 commit comments

Comments
 (0)