forked from JuliaPy/PyCall.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
depsutils.jl
116 lines (109 loc) · 4.46 KB
/
depsutils.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
import Compat.Libdl
hassym(lib, sym) = Libdl.dlsym_e(lib, sym) != C_NULL
# call dlsym_e on a sequence of symbols and return the symbol that gives
# the first non-null result
function findsym(lib, syms...)
for sym in syms
if hassym(lib, sym)
return sym
end
end
error("no symbol found from: ", syms)
end
# Need to set PythonHome before calling GetVersion to avoid warning (#299).
# Unfortunately, this poses something of a chicken-and-egg problem because
# we need to know the Python version to set PythonHome via the API. Note
# that the string (or array) passed to Py_SetPythonHome needs to be a
# constant that lasts for the lifetime of the program, which is why we
# can't use Cwstring here (since that creates a temporary copy).
function Py_SetPythonHome(libpy, PYTHONHOME, wPYTHONHOME, pyversion)
if !isempty(PYTHONHOME)
if pyversion.major < 3
ccall(Libdl.dlsym(libpy, :Py_SetPythonHome), Cvoid, (Cstring,), PYTHONHOME)
else
ccall(Libdl.dlsym(libpy, :Py_SetPythonHome), Cvoid, (Ptr{Cwchar_t},), wPYTHONHOME)
end
end
end
# need to be able to get the version before Python is initialized
Py_GetVersion(libpy) = unsafe_string(ccall(Libdl.dlsym(libpy, :Py_GetVersion), Ptr{UInt8}, ()))
# Fix the environment for running `python`, and setts IO encoding to UTF-8.
# If cmd is the Conda python, then additionally removes all PYTHON* and
# CONDA* environment variables.
function pythonenv(cmd::Cmd)
env = copy(ENV)
if dirname(cmd.exec[1]) == abspath(Conda.PYTHONDIR)
pythonvars = String[]
for var in keys(env)
if startswith(var, "CONDA") || startswith(var, "PYTHON")
push!(pythonvars, var)
end
end
for var in pythonvars
pop!(env, var)
end
end
# set PYTHONIOENCODING when running python executable, so that
# we get UTF-8 encoded text as output (this is not the default on Windows).
env["PYTHONIOENCODING"] = "UTF-8"
setenv(cmd, env)
end
function pythonhome_of(pyprogramname::AbstractString)
if Compat.Sys.iswindows()
# PYTHONHOME tells python where to look for both pure python
# and binary modules. When it is set, it replaces both
# `prefix` and `exec_prefix` and we thus need to set it to
# both in case they differ. This is also what the
# documentation recommends. However, they are documented
# to always be the same on Windows, where it causes
# problems if we try to include both.
script = """
import sys
if hasattr(sys, "base_exec_prefix"):
sys.stdout.write(sys.base_exec_prefix)
else:
sys.stdout.write(sys.exec_prefix)
"""
else
script = """
import sys
if hasattr(sys, "base_exec_prefix"):
sys.stdout.write(sys.base_prefix)
sys.stdout.write(":")
sys.stdout.write(sys.base_exec_prefix)
else:
sys.stdout.write(sys.prefix)
sys.stdout.write(":")
sys.stdout.write(sys.exec_prefix)
"""
# https://docs.python.org/3/using/cmdline.html#envvar-PYTHONHOME
end
return read(pythonenv(`$pyprogramname -c $script`), String)
end
# To support `venv` standard library (as well as `virtualenv`), we
# need to use `sys.base_prefix` and `sys.base_exec_prefix` here.
# Otherwise, initializing Python in `__init__` below fails with
# unrecoverable error:
#
# Fatal Python error: initfsencoding: unable to load the file system codec
# ModuleNotFoundError: No module named 'encodings'
#
# This is because `venv` does not symlink standard libraries like
# `virtualenv`. For example, `lib/python3.X/encodings` does not
# exist. Rather, `venv` relies on the behavior of Python runtime:
#
# If a file named "pyvenv.cfg" exists one directory above
# sys.executable, sys.prefix and sys.exec_prefix are set to that
# directory and it is also checked for site-packages
# --- https://docs.python.org/3/library/venv.html
#
# Thus, we need point `PYTHONHOME` to `sys.base_prefix` and
# `sys.base_exec_prefix`. If the virtual environment is created by
# `virtualenv`, those `sys.base_*` paths point to the virtual
# environment. Thus, above code supports both use cases.
#
# See also:
# * https://docs.python.org/3/library/venv.html
# * https://docs.python.org/3/library/site.html
# * https://docs.python.org/3/library/sys.html#sys.base_exec_prefix
# * https://github.com/JuliaPy/PyCall.jl/issues/410