Skip to content

Commit 383e366

Browse files
author
Christopher Doris
committed
simplify juliacall further
1 parent d193f56 commit 383e366

File tree

3 files changed

+71
-74
lines changed

3 files changed

+71
-74
lines changed

python/juliacall/__init__.py

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
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.
23

3-
CONFIG = {}
4+
__version__ = '0.5.1'
45

56
def newmodule(name):
67
"A new module with the given name."
7-
from . import Base
88
return Base.Module(Base.Symbol(name))
99

1010
class As:
1111
"Interpret 'value' as type 'type' when converting to Julia."
1212
__slots__ = ("value", "type")
13-
__module__ = "juliacall"
1413
def __init__(self, value, type):
1514
self.value = value
1615
self.type = type
@@ -19,24 +18,84 @@ def __repr__(self):
1918

2019
class JuliaError(Exception):
2120
"An error arising in Julia code."
22-
__module__ = "juliacall"
2321
def __init__(self, exception, stacktrace=None):
2422
super().__init__(exception, stacktrace)
2523
def __str__(self):
2624
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)
2928
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)
3430
@property
3531
def exception(self):
3632
return self.args[0]
3733
@property
3834
def stacktrace(self):
3935
return self.args[1]
4036

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+
42101
init()

python/juliacall/init.py

Lines changed: 0 additions & 62 deletions
This file was deleted.

python/juliacall/utils.py

Whitespace-only changes.

0 commit comments

Comments
 (0)