@@ -61,17 +61,14 @@ def option(name, default=None, xkey=None, envkey=None):
61
61
v = os .getenv (k )
62
62
if v is not None :
63
63
return v , f'{ k } ={ v } '
64
- return default , f'<default>={ v } '
64
+ return default , f'<default>={ default } '
65
65
66
66
def choice (name , choices , default = None , ** kw ):
67
67
v , s = option (name , ** kw )
68
68
if v is None :
69
69
return default , s
70
70
if v in choices :
71
- if isinstance (choices , dict ):
72
- return choices [v ], s
73
- else :
74
- return v , s
71
+ return v , s
75
72
raise ValueError (
76
73
f'{ s } : expecting one of { ", " .join (choices )} ' )
77
74
@@ -113,7 +110,7 @@ def args_from_config():
113
110
return
114
111
115
112
# Parse some more options
116
- CONFIG ['opt_home' ] = path_option ('home' , check_exists = True , envkey = 'PYTHON_JULIACALL_BINDIR' )[0 ]
113
+ CONFIG ['opt_home' ] = bindir = path_option ('home' , check_exists = True , envkey = 'PYTHON_JULIACALL_BINDIR' )[0 ]
117
114
CONFIG ['opt_check_bounds' ] = choice ('check_bounds' , ['yes' , 'no' , 'auto' ])[0 ]
118
115
CONFIG ['opt_compile' ] = choice ('compile' , ['yes' , 'no' , 'all' , 'min' ])[0 ]
119
116
CONFIG ['opt_compiled_modules' ] = choice ('compiled_modules' , ['yes' , 'no' ])[0 ]
@@ -122,7 +119,7 @@ def args_from_config():
122
119
CONFIG ['opt_min_optlevel' ] = choice ('min_optlevel' , ['0' , '1' , '2' , '3' ])[0 ]
123
120
CONFIG ['opt_optimize' ] = choice ('optimize' , ['0' , '1' , '2' , '3' ])[0 ]
124
121
CONFIG ['opt_procs' ] = int_option ('procs' , accept_auto = True )[0 ]
125
- CONFIG ['opt_sysimage' ] = path_option ('sysimage' , check_exists = True )[0 ]
122
+ CONFIG ['opt_sysimage' ] = sysimg = path_option ('sysimage' , check_exists = True )[0 ]
126
123
CONFIG ['opt_threads' ] = int_option ('threads' , accept_auto = True )[0 ]
127
124
CONFIG ['opt_warn_overwrite' ] = choice ('warn_overwrite' , ['yes' , 'no' ])[0 ]
128
125
@@ -150,27 +147,44 @@ def args_from_config():
150
147
# Open the library
151
148
os .chdir (os .path .dirname (libpath ))
152
149
CONFIG ['lib' ] = lib = c .CDLL (libpath , mode = c .RTLD_GLOBAL )
153
- lib . jl_init__threading . argtypes = []
154
- lib . jl_init__threading . restype = None
150
+
151
+ # parse options
155
152
argc , argv = args_from_config ()
156
- lib .jl_parse_opts (c .pointer (argc ), c .pointer (argv ))
153
+ jl_parse_opts = lib .jl_parse_opts
154
+ jl_parse_opts .argtypes = [c .c_void_p , c .c_void_p ]
155
+ jl_parse_opts .restype = None
156
+ jl_parse_opts (c .pointer (argc ), c .pointer (argv ))
157
157
assert argc .value == 0
158
- lib .jl_init__threading ()
159
- lib .jl_eval_string .argtypes = [c .c_char_p ]
160
- lib .jl_eval_string .restype = c .c_void_p
161
- os .environ ['JULIA_PYTHONCALL_LIBPTR' ] = str (c .pythonapi ._handle )
162
- os .environ ['JULIA_PYTHONCALL_EXE' ] = sys .executable or ''
163
- os .environ ['JULIA_PYTHONCALL_PROJECT' ] = project
164
- os .environ ['JULIA_PYTHONCALL_INIT_JL' ] = os .path .join (os .path .dirname (__file__ ), 'init.jl' )
158
+
159
+ # initialise julia
160
+ try :
161
+ jl_init = lib .jl_init_with_image__threading
162
+ except AttributeError :
163
+ jl_init = lib .jl_init_with_image
164
+ jl_init .argtypes = [c .c_char_p , c .c_char_p ]
165
+ jl_init .restype = None
166
+ jl_init (
167
+ (os .path .dirname (exepath ) if bindir is None else bindir ).encode ('utf8' ),
168
+ None if sysimg is None else sysimg .encode ('utf8' ),
169
+ )
170
+
171
+ # initialise PythonCall
172
+ jl_eval = lib .jl_eval_string
173
+ jl_eval .argtypes = [c .c_char_p ]
174
+ jl_eval .restype = c .c_void_p
175
+ def jlstr (x ):
176
+ return 'raw"' + x .replace ('"' , '\\ "' ).replace ('\\ ' , '\\ \\ ' ) + '"'
165
177
script = '''
166
178
try
167
179
import Pkg
168
- Pkg.activate(ENV["JULIA_PYTHONCALL_PROJECT"], io=devnull)
180
+ ENV["JULIA_PYTHONCALL_LIBPTR"] = {}
181
+ ENV["JULIA_PYTHONCALL_EXE"] = {}
182
+ Pkg.activate({}, io=devnull)
169
183
import PythonCall
170
184
# This uses some internals, but Base._start() gets the state more like Julia
171
185
# is if you call the executable directly, in particular it creates workers when
172
186
# the --procs argument is given.
173
- push!(Core.ARGS, ENV["JULIA_PYTHONCALL_INIT_JL"] )
187
+ push!(Core.ARGS, {} )
174
188
Base._start()
175
189
@eval Base PROGRAM_FILE=""
176
190
catch err
@@ -179,8 +193,13 @@ def args_from_config():
179
193
flush(stderr)
180
194
rethrow()
181
195
end
182
- '''
183
- res = lib .jl_eval_string (script .encode ('utf8' ))
196
+ ''' .format (
197
+ jlstr (str (c .pythonapi ._handle )),
198
+ jlstr (sys .executable or '' ),
199
+ jlstr (project ),
200
+ jlstr (os .path .join (os .path .dirname (__file__ ), 'init.jl' )),
201
+ )
202
+ res = jl_eval (script .encode ('utf8' ))
184
203
if res is None :
185
204
raise Exception ('PythonCall.jl did not start properly' )
186
205
finally :
0 commit comments