11# This module gets modified by PythonCall when it is loaded, e.g. to include Core, Base
22# and Main modules.
33
4- __version__ = ' 0.9.24'
4+ __version__ = " 0.9.24"
55
66_newmodule = None
77
8+
89def newmodule (name ):
910 "A new module with the given name."
1011 global _newmodule
1112 if _newmodule is None :
12- _newmodule = Main .seval ("name -> (n1=Symbol(name); n2=gensym(n1); Main.@eval(module $n2; module $n1; end; end); Main.@eval $n2.$n1)" )
13+ _newmodule = Main .seval (
14+ "name -> (n1=Symbol(name); n2=gensym(n1); Main.@eval(module $n2; module $n1; end; end); Main.@eval $n2.$n1)"
15+ )
1316 return _newmodule (name )
1417
18+
1519_convert = None
1620
21+
1722def convert (T , x ):
1823 "Convert x to a Julia T."
1924 global _convert
2025 if _convert is None :
21- _convert = PythonCall .JlWrap .seval ("pyjlcallback((T,x)->pyjl(pyconvert(pyjlvalue(T)::Type,x)))" )
26+ _convert = PythonCall .Internals .JlWrap .seval (
27+ "pyjlcallback((T,x)->pyjl(pyconvert(pyjlvalue(T)::Type,x)))"
28+ )
2229 return _convert (T , x )
2330
31+
2432def interactive (enable = True ):
2533 "Allow the Julia event loop to run in the background of the Python REPL."
2634 if enable :
27- PythonCall .Compat ._set_python_input_hook ()
35+ PythonCall .Internals . Compat ._set_python_input_hook ()
2836 else :
29- PythonCall .Compat ._unset_python_input_hook ()
37+ PythonCall .Internals .Compat ._unset_python_input_hook ()
38+
3039
3140class JuliaError (Exception ):
3241 "An error arising in Julia code."
42+
3343 def __init__ (self , exception , backtrace = None ):
3444 super ().__init__ (exception , backtrace )
45+
3546 def __str__ (self ):
3647 e = self .exception
3748 b = self .backtrace
3849 if b is None :
3950 return Base .sprint (Base .showerror , e )
4051 else :
4152 return Base .sprint (Base .showerror , e , b )
53+
4254 @property
4355 def exception (self ):
4456 return self .args [0 ]
57+
4558 @property
4659 def backtrace (self ):
4760 return self .args [1 ]
4861
49- CONFIG = {'inited' : False }
62+
63+ CONFIG = {"inited" : False }
64+
5065
5166def init ():
5267 import atexit
@@ -70,30 +85,29 @@ def option(name, default=None, xkey=None, envkey=None):
7085 Options can be set as command line arguments '-X juliacall-{name}={value}' or as
7186 environment variables 'PYTHON_JULIACALL_{NAME}={value}'.
7287 """
73- k = xkey or ' juliacall-' + name .lower ().replace ('_' , '-' )
88+ k = xkey or " juliacall-" + name .lower ().replace ("_" , "-" )
7489 v = sys ._xoptions .get (k )
7590 if v is not None :
76- return v , f' -X{ k } ={ v } '
77- k = envkey or ' PYTHON_JULIACALL_' + name .upper ()
91+ return v , f" -X{ k } ={ v } "
92+ k = envkey or " PYTHON_JULIACALL_" + name .upper ()
7893 v = os .getenv (k )
7994 if v is not None :
80- return v , f' { k } ={ v } '
81- return default , f' <default>={ default } '
95+ return v , f" { k } ={ v } "
96+ return default , f" <default>={ default } "
8297
8398 def choice (name , choices , default = None , ** kw ):
8499 v , s = option (name , ** kw )
85100 if v is None :
86101 return default , s
87102 if v in choices :
88103 return v , s
89- raise ValueError (
90- f'{ s } : expecting one of { ", " .join (choices )} ' )
104+ raise ValueError (f"{ s } : expecting one of { ', ' .join (choices )} " )
91105
92106 def path_option (name , default = None , check_exists = False , ** kw ):
93107 path , s = option (name , ** kw )
94108 if path is not None :
95109 if check_exists and not os .path .exists (path ):
96- raise ValueError (f' { s } : path does not exist' )
110+ raise ValueError (f" { s } : path does not exist" )
97111 return os .path .abspath (path ), s
98112 return default , s
99113
@@ -107,18 +121,20 @@ def int_option(name, *, accept_auto=False, **kw):
107121 int (val )
108122 return val , s
109123 except ValueError :
110- raise ValueError (f'{ s } : expecting an int' + (' or auto' if accept_auto else "" ))
124+ raise ValueError (
125+ f"{ s } : expecting an int" + (" or auto" if accept_auto else "" )
126+ )
111127
112128 def args_from_config ():
113- argv = [CONFIG [' exepath' ]]
129+ argv = [CONFIG [" exepath" ]]
114130 for opt , val in CONFIG .items ():
115- if opt .startswith (' opt_' ):
131+ if opt .startswith (" opt_" ):
116132 if val is None :
117- if opt == ' opt_handle_signals' :
118- val = 'no'
133+ if opt == " opt_handle_signals" :
134+ val = "no"
119135 else :
120136 continue
121- argv .append ('--' + opt [4 :].replace ('_' , '-' ) + '=' + val )
137+ argv .append ("--" + opt [4 :].replace ("_" , "-" ) + "=" + val )
122138 argv = [s .encode ("utf-8" ) for s in argv ]
123139
124140 argc = len (argv )
@@ -127,58 +143,69 @@ def args_from_config():
127143 return argc , argv
128144
129145 # Determine if we should skip initialising.
130- CONFIG [' init' ] = choice (' init' , [' yes' , 'no' ], default = ' yes' )[0 ] == ' yes'
131- if not CONFIG [' init' ]:
146+ CONFIG [" init" ] = choice (" init" , [" yes" , "no" ], default = " yes" )[0 ] == " yes"
147+ if not CONFIG [" init" ]:
132148 return
133149
134150 # Parse some more options
135- CONFIG ['opt_home' ] = bindir = path_option ('home' , check_exists = True , envkey = 'PYTHON_JULIACALL_BINDIR' )[0 ]
136- CONFIG ['opt_check_bounds' ] = choice ('check_bounds' , ['yes' , 'no' , 'auto' ])[0 ]
137- CONFIG ['opt_compile' ] = choice ('compile' , ['yes' , 'no' , 'all' , 'min' ])[0 ]
138- CONFIG ['opt_compiled_modules' ] = choice ('compiled_modules' , ['yes' , 'no' ])[0 ]
139- CONFIG ['opt_depwarn' ] = choice ('depwarn' , ['yes' , 'no' , 'error' ])[0 ]
140- CONFIG ['opt_inline' ] = choice ('inline' , ['yes' , 'no' ])[0 ]
141- CONFIG ['opt_min_optlevel' ] = choice ('min_optlevel' , ['0' , '1' , '2' , '3' ])[0 ]
142- CONFIG ['opt_optimize' ] = choice ('optimize' , ['0' , '1' , '2' , '3' ])[0 ]
143- CONFIG ['opt_procs' ] = int_option ('procs' , accept_auto = True )[0 ]
144- CONFIG ['opt_sysimage' ] = sysimg = path_option ('sysimage' , check_exists = True )[0 ]
145- CONFIG ['opt_threads' ] = int_option ('threads' , accept_auto = True )[0 ]
146- CONFIG ['opt_warn_overwrite' ] = choice ('warn_overwrite' , ['yes' , 'no' ])[0 ]
147- CONFIG ['opt_handle_signals' ] = choice ('handle_signals' , ['yes' , 'no' ])[0 ]
148- CONFIG ['opt_startup_file' ] = choice ('startup_file' , ['yes' , 'no' ])[0 ]
151+ CONFIG ["opt_home" ] = bindir = path_option (
152+ "home" , check_exists = True , envkey = "PYTHON_JULIACALL_BINDIR"
153+ )[0 ]
154+ CONFIG ["opt_check_bounds" ] = choice ("check_bounds" , ["yes" , "no" , "auto" ])[0 ]
155+ CONFIG ["opt_compile" ] = choice ("compile" , ["yes" , "no" , "all" , "min" ])[0 ]
156+ CONFIG ["opt_compiled_modules" ] = choice ("compiled_modules" , ["yes" , "no" ])[0 ]
157+ CONFIG ["opt_depwarn" ] = choice ("depwarn" , ["yes" , "no" , "error" ])[0 ]
158+ CONFIG ["opt_inline" ] = choice ("inline" , ["yes" , "no" ])[0 ]
159+ CONFIG ["opt_min_optlevel" ] = choice ("min_optlevel" , ["0" , "1" , "2" , "3" ])[0 ]
160+ CONFIG ["opt_optimize" ] = choice ("optimize" , ["0" , "1" , "2" , "3" ])[0 ]
161+ CONFIG ["opt_procs" ] = int_option ("procs" , accept_auto = True )[0 ]
162+ CONFIG ["opt_sysimage" ] = sysimg = path_option ("sysimage" , check_exists = True )[0 ]
163+ CONFIG ["opt_threads" ] = int_option ("threads" , accept_auto = True )[0 ]
164+ CONFIG ["opt_warn_overwrite" ] = choice ("warn_overwrite" , ["yes" , "no" ])[0 ]
165+ CONFIG ["opt_handle_signals" ] = choice ("handle_signals" , ["yes" , "no" ])[0 ]
166+ CONFIG ["opt_startup_file" ] = choice ("startup_file" , ["yes" , "no" ])[0 ]
149167
150168 # Stop if we already initialised
151- if CONFIG [' inited' ]:
169+ if CONFIG [" inited" ]:
152170 return
153171
154172 # we don't import this at the top level because it is not required when juliacall is
155173 # loaded by PythonCall and won't be available
156174 import juliapkg
157175
158176 # Find the Julia executable and project
159- CONFIG [' exepath' ] = exepath = juliapkg .executable ()
160- CONFIG [' project' ] = project = juliapkg .project ()
177+ CONFIG [" exepath" ] = exepath = juliapkg .executable ()
178+ CONFIG [" project" ] = project = juliapkg .project ()
161179
162180 # Find the Julia library
163- cmd = [exepath , '--project=' + project , '--startup-file=no' , '-O0' , '--compile=min' ,
164- '-e' , 'import Libdl; print(abspath(Libdl.dlpath("libjulia")), "\\ 0", Sys.BINDIR)' ]
165- libpath , default_bindir = subprocess .run (cmd , check = True , capture_output = True , encoding = 'utf8' ).stdout .split ('\0 ' )
181+ cmd = [
182+ exepath ,
183+ "--project=" + project ,
184+ "--startup-file=no" ,
185+ "-O0" ,
186+ "--compile=min" ,
187+ "-e" ,
188+ 'import Libdl; print(abspath(Libdl.dlpath("libjulia")), "\\ 0", Sys.BINDIR)' ,
189+ ]
190+ libpath , default_bindir = subprocess .run (
191+ cmd , check = True , capture_output = True , encoding = "utf8"
192+ ).stdout .split ("\0 " )
166193 assert os .path .exists (libpath )
167194 assert os .path .exists (default_bindir )
168- CONFIG [' libpath' ] = libpath
195+ CONFIG [" libpath" ] = libpath
169196
170197 # Add the Julia library directory to the PATH on Windows so Julia's system libraries can
171198 # be found. They are normally found because they are in the same directory as julia.exe,
172199 # but python.exe is somewhere else!
173- if os .name == 'nt' :
200+ if os .name == "nt" :
174201 libdir = os .path .dirname (libpath )
175- if ' PATH' in os .environ :
176- os .environ [' PATH' ] = libdir + ';' + os .environ [' PATH' ]
202+ if " PATH" in os .environ :
203+ os .environ [" PATH" ] = libdir + ";" + os .environ [" PATH" ]
177204 else :
178- os .environ [' PATH' ] = libdir
205+ os .environ [" PATH" ] = libdir
179206
180207 # Open the library
181- CONFIG [' lib' ] = lib = c .PyDLL (libpath , mode = c .RTLD_GLOBAL )
208+ CONFIG [" lib" ] = lib = c .PyDLL (libpath , mode = c .RTLD_GLOBAL )
182209
183210 # parse options
184211 argc , argv = args_from_config ()
@@ -196,8 +223,8 @@ def args_from_config():
196223 jl_init .argtypes = [c .c_char_p , c .c_char_p ]
197224 jl_init .restype = None
198225 jl_init (
199- (default_bindir if bindir is None else bindir ).encode (' utf8' ),
200- None if sysimg is None else sysimg .encode (' utf8' ),
226+ (default_bindir if bindir is None else bindir ).encode (" utf8" ),
227+ None if sysimg is None else sysimg .encode (" utf8" ),
201228 )
202229
203230 # call jl_atexit_hook() when python exits to gracefully stop the julia runtime,
@@ -213,9 +240,11 @@ def at_jl_exit():
213240 jl_eval = lib .jl_eval_string
214241 jl_eval .argtypes = [c .c_char_p ]
215242 jl_eval .restype = c .c_void_p
243+
216244 def jlstr (x ):
217245 return 'raw"' + x + '"'
218- script = '''
246+
247+ script = """
219248 try
220249 Base.require(Main, :CompilerSupportLibraries_jll)
221250 import Pkg
@@ -229,18 +258,18 @@ def jlstr(x):
229258 flush(stderr)
230259 rethrow()
231260 end
232- ''' .format (
261+ """ .format (
233262 hex (c .pythonapi ._handle ),
234- jlstr (sys .executable or '' ),
263+ jlstr (sys .executable or "" ),
235264 jlstr (project ),
236265 )
237- res = jl_eval (script .encode (' utf8' ))
266+ res = jl_eval (script .encode (" utf8" ))
238267 if res is None :
239- raise Exception (' PythonCall.jl did not start properly' )
268+ raise Exception (" PythonCall.jl did not start properly" )
240269
241- CONFIG [' inited' ] = True
270+ CONFIG [" inited" ] = True
242271
243- if CONFIG [' opt_handle_signals' ] is None :
272+ if CONFIG [" opt_handle_signals" ] is None :
244273 if Base .Threads .nthreads () > 1 :
245274 # a warning to help multithreaded users
246275 # TODO: should we set PYTHON_JULIACALL_HANDLE_SIGNALS=yes whenever PYTHON_JULIACALL_THREADS != 1?
@@ -259,20 +288,22 @@ def jlstr(x):
259288 )
260289
261290 # Next, automatically load the juliacall extension if we are in IPython or Jupyter
262- CONFIG ['autoload_ipython_extension' ] = choice ('autoload_ipython_extension' , ['yes' , 'no' ])[0 ]
263- if CONFIG ['autoload_ipython_extension' ] in {'yes' , None }:
291+ CONFIG ["autoload_ipython_extension" ] = choice (
292+ "autoload_ipython_extension" , ["yes" , "no" ]
293+ )[0 ]
294+ if CONFIG ["autoload_ipython_extension" ] in {"yes" , None }:
264295 try :
265- get_ipython = sys .modules [' IPython' ].get_ipython
296+ get_ipython = sys .modules [" IPython" ].get_ipython
266297
267- if CONFIG [' autoload_ipython_extension' ] is None :
298+ if CONFIG [" autoload_ipython_extension" ] is None :
268299 # Only let the user know if it was not explicitly set
269300 print (
270301 "Detected IPython. Loading juliacall extension. See https://juliapy.github.io/PythonCall.jl/stable/compat/#IPython"
271302 )
272303
273304 load_ipython_extension (get_ipython ())
274305 except Exception as e :
275- if CONFIG [' autoload_ipython_extension' ] == ' yes' :
306+ if CONFIG [" autoload_ipython_extension" ] == " yes" :
276307 # Only warn if the user explicitly requested the extension to be loaded
277308 warnings .warn (
278309 "Could not load juliacall extension in Jupyter notebook: " + str (e )
@@ -282,6 +313,8 @@ def jlstr(x):
282313
283314def load_ipython_extension (ip ):
284315 import juliacall .ipython
316+
285317 juliacall .ipython .load_ipython_extension (ip )
286318
319+
287320init ()
0 commit comments