-
Notifications
You must be signed in to change notification settings - Fork 189
/
pyinit.jl
157 lines (133 loc) · 6.28 KB
/
pyinit.jl
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# Initializing Python (surprisingly complicated; see also deps/build.jl)
#########################################################################
# Base.with_env in Julia 0.3, withenv in Julia 0.4 (#10914)
if VERSION >= v"0.4.0-dev+4392"
with_env(f::Function, key::AbstractString, val) = withenv(f, key=>val)
else
const with_env = Base.with_env
end
#########################################################################
# global constants, initialized to NULL and then overwritten in __init__
# (eventually, the ability to define global const in __init__ may go away,
# and in any case this is better for type inference during precompilation)
const inspect = PyNULL()
const builtin = PyNULL()
const BuiltinFunctionType = PyNULL()
const TypeType = PyNULL()
const MethodType = PyNULL()
const MethodWrapperType = PyNULL()
const ufuncType = PyNULL()
const format_traceback = PyNULL()
#########################################################################
function __init__()
# issue #189
Libdl.dlopen(libpython, Libdl.RTLD_LAZY|Libdl.RTLD_DEEPBIND|Libdl.RTLD_GLOBAL)
already_inited = 0 != ccall((@pysym :Py_IsInitialized), Cint, ())
if !already_inited
if !isempty(PYTHONHOME)
if pyversion_build.major < 3
ccall((@pysym :Py_SetPythonHome), Void, (Cstring,), PYTHONHOME)
else
ccall((@pysym :Py_SetPythonHome), Void, (Cwstring,), PYTHONHOME)
end
end
if !isempty(pyprogramname)
if pyversion_build.major < 3
ccall((@pysym :Py_SetProgramName), Void, (Cstring,), pyprogramname)
else
ccall((@pysym :Py_SetProgramName), Void, (Cwstring,), pyprogramname)
end
end
ccall((@pysym :Py_InitializeEx), Void, (Cint,), 0)
end
# cache the Python version as a Julia VersionNumber
global const pyversion = convert(VersionNumber,
split(bytestring(ccall(@pysym(:Py_GetVersion),
Ptr{UInt8}, ())))[1])
if pyversion_build.major != pyversion.major
error("PyCall built with Python $pyversion_build, but now using Python $pyversion; ",
"you need to relaunch Julia and re-run Pkg.build(\"PyCall\")")
end
copy!(inspect, pyimport("inspect"))
copy!(builtin, pyimport(pyversion.major < 3 ? "__builtin__" : "builtins"))
pyexc_initialize() # mappings from Julia Exception types to Python exceptions
types = pyimport("types")
copy!(TypeType, pybuiltin("type")) # for pytypeof
if VERSION < v"0.4.0-dev+1246" # no call overloading
# Python has zillions of types that a function be, in addition
# to the FunctionType in the C API. We have to obtain these
# at runtime and cache them in globals
copy!(BuiltinFunctionType, types["BuiltinFunctionType"])
copy!(MethodType, types["MethodType"])
copy!(MethodWrapperType, pytypeof(PyObject(PyObject[])["__add__"]))
try # may fail if numpy not installed
copy!(ufuncType, pyimport("numpy")["ufunc"])
end
end
# cache Python None -- PyPtr, not PyObject, to prevent it from
# being finalized prematurely on exit
global const pynothing = @pyglobalobj(:_Py_NoneStruct)
# xrange type (or range in Python 3)
global const pyxrange = @pyglobalobj(:PyRange_Type)
# cache ctypes.c_void_p type and function if available
vpt, pvp = try
(pyimport("ctypes")["c_void_p"],
p::Ptr -> pycall(c_void_p_Type, PyObject, @compat UInt(p)))
catch # fallback to CObject
(@pyglobalobj(:PyCObject_FromVoidPtr),
p::Ptr -> PyObject(ccall(pycobject_new, PyPtr, (Ptr{Void}, Ptr{Void}), p, C_NULL)))
end
global const c_void_p_Type = vpt
global const py_void_p = pvp
# traceback.format_tb function, for show(PyError)
copy!(format_traceback, pyimport("traceback")["format_tb"])
# all cfunctions must be compiled at runtime
global const jl_Function_call_ptr =
cfunction(jl_Function_call, PyPtr, (PyPtr,PyPtr,PyPtr))
global const pyio_repr_ptr = cfunction(pyio_repr, PyPtr, (PyPtr,))
global const pyjlwrap_dealloc_ptr = cfunction(pyjlwrap_dealloc, Void, (PyPtr,))
global const pyjlwrap_repr_ptr = cfunction(pyjlwrap_repr, PyPtr, (PyPtr,))
global const pyjlwrap_hash_ptr = cfunction(pyjlwrap_hash, UInt, (PyPtr,))
global const pyjlwrap_hash32_ptr = cfunction(pyjlwrap_hash32, UInt32, (PyPtr,))
# similarly, any MethodDef calls involve cfunctions
global const jl_TextIO_methods = make_io_methods(true)
global const jl_IO_methods = make_io_methods(false)
global const jl_IO_getset = PyGetSetDef[
PyGetSetDef("closed", jl_IO_closed)
PyGetSetDef("encoding", jl_IO_encoding)
PyGetSetDef()
]
# PyMemberDef stores explicit pointers, hence must be initialized in __init__
global const pyjlwrap_members =
PyMemberDef[ PyMemberDef(pyjlwrap_membername,
T_PYSSIZET, sizeof_PyObject_HEAD, READONLY,
pyjlwrap_doc),
PyMemberDef(C_NULL,0,0,0,C_NULL) ]
init_datetime()
pyjlwrap_init()
global const jl_FunctionType = pyjlwrap_type("PyCall.jl_Function",
t -> t.tp_call =
jl_Function_call_ptr)
if !already_inited
# some modules (e.g. IPython) expect sys.argv to be set
if pyversion.major < 3
argv_s = bytestring("")
argv = unsafe_convert(Ptr{UInt8}, argv_s)
ccall(@pysym(:PySys_SetArgvEx), Void, (Cint,Ptr{Ptr{UInt8}},Cint), 1, &argv, 0)
else
argv_s = Cwchar_t[0]
argv = unsafe_convert(Ptr{Cwchar_t}, argv_s)
ccall(@pysym(:PySys_SetArgvEx), Void, (Cint, Ptr{Ptr{Cwchar_t}}, Cint), 1, &argv, 0)
end
# Some Python code checks sys.ps1 to see if it is running
# interactively, and refuses to be interactive otherwise.
# (e.g. Matplotlib: see PyPlot#79)
if isinteractive()
let sys = pyimport("sys")
if !haskey(sys, "ps1")
sys["ps1"] = ">>> "
end
end
end
end
end