1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
# This file contains a recursive version of the pywrap() function from PyCall:
# it will generate nested Julia Modules for nested Python modules.
# This extends to recursive or infinitely looping modules. For example, the
# Python "os" module goes infinitely deep:
#
# os.path.genericpath.os.path.genericpath.os.path.genericpath.os.path...
#
# It was created for PyX.jl because PyX has deeply nested modules (eg,
# pyx.graph.graphxy), which are not handled by the generic pywrap() from
# PyCall.
_pyrecwrap_cache = Dict{PyObject,Module}()
function pyrecwrap(o::PyObject, mname::Symbol=:__anon__)
members = convert(Vector{Tuple{AbstractString,PyObject}},
pycall(PyCall.inspect["getmembers"], PyObject, o))
if PyCall.pyversion >= v"3"
# Blacklist the "inspect" module under Python3; fail if called on it, and filter it
# out of recursive imports.
# See also: https://github.com/stevengj/PyCall.jl/issues/252
if o == PyCall.inspect
error("Wrapping the 'inspect' module under Python3 causes a hang")
end
filter!(m -> !(m[1] == PyCall.inspect), members)
end
filter!(m -> !(m[1] in PyCall.reserved), members)
m = Module(mname, false)
# Preload module cache with this (so far empty) module
_pyrecwrap_cache[o] = m
consts = Expr[]
for (ms, mo) in members # ms is Symbol, mo is PyObject)
if pyisinstance(mo, PyCall.@pyglobalobj :PyModule_Type) ||
pyisinstance(mo, PyCall.@pyglobalobj :PyType_Type)
if mo == PyCall.inspect
continue
end
# Before recursing, check if we've seen this python module before
if !haskey(_pyrecwrap_cache, mo)
_pyrecwrap_cache[mo] = pyrecwrap(mo)
end
mm = _pyrecwrap_cache[mo]
push!(consts, Expr(:const, Expr(:(=), symbol(ms), mm)))
else
push!(consts, Expr(:const, Expr(:(=), symbol(ms), convert(PyAny, mo))))
end
end
exports = try
convert(Vector{Symbol}, o["__all__"])
catch
[symbol(x[1]) for x in filter(x -> x[1][1] != '_', members)]
end
eval(m, Expr(:toplevel, consts..., :(pymember(s) = $(getindex)($(o), s)),
Expr(:export, exports...)))
m
end
|