1
- __version__ = '0.5.1'
1
+ # This module gets modified by PythonCall when it is loaded, e.g. to include Core, Base
2
+ # and Main modules.
2
3
3
- CONFIG = {}
4
+ __version__ = '0.5.1'
4
5
5
6
def newmodule (name ):
6
7
"A new module with the given name."
7
- from . import Base
8
8
return Base .Module (Base .Symbol (name ))
9
9
10
10
class As :
11
11
"Interpret 'value' as type 'type' when converting to Julia."
12
12
__slots__ = ("value" , "type" )
13
- __module__ = "juliacall"
14
13
def __init__ (self , value , type ):
15
14
self .value = value
16
15
self .type = type
@@ -19,24 +18,84 @@ def __repr__(self):
19
18
20
19
class JuliaError (Exception ):
21
20
"An error arising in Julia code."
22
- __module__ = "juliacall"
23
21
def __init__ (self , exception , stacktrace = None ):
24
22
super ().__init__ (exception , stacktrace )
25
23
def __str__ (self ):
26
24
e = self .exception
27
- if isinstance (e , str ):
28
- return e
25
+ b = self .stacktrace
26
+ if b is None :
27
+ return Base .sprint (Base .showerror , e )
29
28
else :
30
- from . import Base
31
- io = Base .IOBuffer ()
32
- Base .showerror (io , e )
33
- return str (Base .String (Base .take_b (io )))
29
+ return Base .sprint (Base .showerror , e , b )
34
30
@property
35
31
def exception (self ):
36
32
return self .args [0 ]
37
33
@property
38
34
def stacktrace (self ):
39
35
return self .args [1 ]
40
36
41
- from .init import init
37
+ CONFIG = {'inited' : False }
38
+
39
+ def init ():
40
+ import os
41
+ import ctypes as c
42
+ import sys
43
+ import subprocess
44
+
45
+ # Determine if we should skip initialising.
46
+ CONFIG ['noinit' ] = os .getenv ('PYTHON_JULIACALL_NOINIT' , '' ) == 'yes'
47
+ if CONFIG ['noinit' ]:
48
+ return
49
+
50
+ # Stop if we already initialised
51
+ if CONFIG ['inited' ]:
52
+ return
53
+
54
+ # we don't import this at the top level because it is not required when juliacall is
55
+ # loaded by PythonCall and won't be available
56
+ import juliapkg
57
+
58
+ # Find the Julia executable and project
59
+ CONFIG ['exepath' ] = exepath = juliapkg .executable ()
60
+ CONFIG ['project' ] = project = juliapkg .project ()
61
+
62
+ # Find the Julia library
63
+ cmd = [exepath , '--project=' + project , '--startup-file=no' , '-O0' , '--compile=min' , '-e' , 'import Libdl; print(abspath(Libdl.dlpath("libjulia")))' ]
64
+ CONFIG ['libpath' ] = libpath = subprocess .run (cmd , check = True , capture_output = True , encoding = 'utf8' ).stdout
65
+ assert os .path .exists (libpath )
66
+
67
+ # Initialise Julia
68
+ d = os .getcwd ()
69
+ try :
70
+ # Open the library
71
+ os .chdir (os .path .dirname (libpath ))
72
+ CONFIG ['lib' ] = lib = c .CDLL (libpath )
73
+ lib .jl_init__threading .argtypes = []
74
+ lib .jl_init__threading .restype = None
75
+ lib .jl_init__threading ()
76
+ lib .jl_eval_string .argtypes = [c .c_char_p ]
77
+ lib .jl_eval_string .restype = c .c_void_p
78
+ os .environ ['JULIA_PYTHONCALL_LIBPTR' ] = str (c .pythonapi ._handle )
79
+ os .environ ['JULIA_PYTHONCALL_EXE' ] = sys .executable or ''
80
+ os .environ ['JULIA_PYTHONCALL_PROJECT' ] = project
81
+ script = '''
82
+ try
83
+ import Pkg
84
+ Pkg.activate(ENV["JULIA_PYTHONCALL_PROJECT"], io=devnull)
85
+ import PythonCall
86
+ catch err
87
+ print(stderr, "ERROR: ")
88
+ showerror(stderr, err, catch_backtrace())
89
+ flush(stderr)
90
+ rethrow()
91
+ end
92
+ '''
93
+ res = lib .jl_eval_string (script .encode ('utf8' ))
94
+ if res is None :
95
+ raise Exception ('PythonCall.jl did not start properly' )
96
+ finally :
97
+ os .chdir (d )
98
+
99
+ CONFIG ['inited' ] = True
100
+
42
101
init ()
0 commit comments