Skip to content

Commit 8616711

Browse files
author
Christopher Doris
committed
rewrite importer
1 parent cff4ca0 commit 8616711

File tree

1 file changed

+58
-26
lines changed

1 file changed

+58
-26
lines changed

pysrc/juliacall/importer.py

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
import base64
2+
import io
13
import os
24
import sys
35

46
from . import newmodule, Base
5-
from importlib.machinery import ModuleSpec
7+
from importlib.machinery import ModuleSpec, SourceFileLoader
68

79
class Finder:
10+
def __init__(self, jlext='.jl', pyext='.py'):
11+
self.jlext = jlext
12+
self.pyext = pyext
13+
814
def find_spec(self, fullname, path, target=None):
915
if path is None:
1016
path = sys.path
@@ -14,28 +20,54 @@ def find_spec(self, fullname, path, target=None):
1420
else:
1521
name = fullname.split('.')[-1]
1622
for root in path:
17-
origin = os.path.join(root, name + '.py.jl')
18-
if os.path.isfile(origin):
19-
origin = os.path.realpath(origin)
20-
return ModuleSpec(fullname, Loader(), origin=origin)
21-
22-
class Loader:
23-
def create_module(self, spec):
24-
return None
25-
26-
def exec_module(self, module):
27-
spec = module.__spec__
28-
name = spec.name
29-
m = module.__jl_module__ = newmodule(name)
30-
with open(spec.origin) as fp:
31-
src = fp.read()
32-
m.seval("begin;]\n" + src + "\nend")
33-
ks = [str(k) for k in Base.names(m)]
34-
ks = [k for k in ks if k != name]
35-
if not ks:
36-
ks = [str(k) for k in Base.names(m, all=True)]
37-
ks = [k for k in ks if not (k == name or k.startswith('_') or '#' in k)]
38-
for k in ks:
39-
module.__dict__[k] = getattr(m, k)
40-
41-
sys.meta_path.append(Finder())
23+
jlfile = os.path.join(root, name + self.jlext)
24+
if os.path.isfile(jlfile):
25+
jlfile = os.path.realpath(jlfile)
26+
pyfile = os.path.join(root, name + self.pyext)
27+
gen_file(jlfile, pyfile)
28+
return ModuleSpec(fullname, SourceFileLoader(fullname, pyfile), origin=jlfile)
29+
30+
def install(**kw):
31+
finder = Finder(**kw)
32+
sys.meta_path.insert(0, finder)
33+
return finder
34+
35+
def uninstall(finder):
36+
sys.meta_path.remove(finder)
37+
38+
def gen_code(jl):
39+
jlb = base64.b64encode(jl.encode('utf8')).decode('ascii')
40+
buf = io.StringIO()
41+
pr = lambda x: print(x, file=buf)
42+
pr('# This file was automatically generated by juliacall.importer')
43+
pr('import juliacall.importer')
44+
pr('juliacall.importer.exec_module(__name__, """')
45+
for i in range(0, len(jlb), 80):
46+
pr(jlb[i:i+80])
47+
pr('""")')
48+
return buf.getvalue()
49+
50+
def gen_file(jl, py):
51+
with open(jl) as fp:
52+
jlcode = fp.read()
53+
pycode = gen_code(jlcode)
54+
with open(py, 'w') as fp:
55+
fp.write(pycode)
56+
57+
def exec_module(name, code):
58+
pymod = sys.modules[name]
59+
code = base64.b64decode(code.encode('ascii')).decode('utf8')
60+
jlmod = newmodule(name)
61+
jlmod.seval('begin\n' + code + '\nend')
62+
delattr(pymod, 'juliacall')
63+
setattr(pymod, '__jl_code__', code)
64+
setattr(pymod, '__jl_module__', jlmod)
65+
ks = [str(k) for k in Base.names(jlmod)]
66+
ks = [k for k in ks if k != name]
67+
if not ks:
68+
ks = [str(k) for k in Base.names(jlmod, all=True)]
69+
ks = [k for k in ks if not (k == name or k == 'include' or k == 'eval' or k.startswith('_') or '#' in k)]
70+
setattr(pymod, '__all__', ks)
71+
setattr(pymod, '__doc__', str(Base.Docs.doc(jlmod)))
72+
for k in ks:
73+
setattr(pymod, k, getattr(jlmod, k))

0 commit comments

Comments
 (0)