|
| 1 | +import base64 |
| 2 | +import io |
| 3 | +import os |
| 4 | +import sys |
| 5 | + |
| 6 | +from . import newmodule, Base |
| 7 | +from importlib.machinery import ModuleSpec, SourceFileLoader |
| 8 | + |
| 9 | +class Finder: |
| 10 | + def __init__(self, jlext='.jl', pyext='.py'): |
| 11 | + self.jlext = jlext |
| 12 | + self.pyext = pyext |
| 13 | + |
| 14 | + def find_spec(self, fullname, path, target=None): |
| 15 | + if path is None: |
| 16 | + path = sys.path |
| 17 | + if '.' in fullname: |
| 18 | + return |
| 19 | + name = fullname |
| 20 | + else: |
| 21 | + name = fullname.split('.')[-1] |
| 22 | + for root in path: |
| 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 | + buf = io.StringIO() |
| 40 | + pr = lambda x: print(x, file=buf) |
| 41 | + jl2 = jl.replace('\\', '\\\\').replace("'", "\\'") |
| 42 | + pr('# This file was automatically generated by juliacall.importer') |
| 43 | + pr('import juliacall.importer') |
| 44 | + pr('juliacall.importer.exec_module(__name__,') |
| 45 | + pr("'''"+jl2+"''')") |
| 46 | + return buf.getvalue() |
| 47 | + |
| 48 | +def gen_file(jl, py): |
| 49 | + with open(jl, encoding='utf-8') as fp: |
| 50 | + jlcode = fp.read() |
| 51 | + pycode = gen_code(jlcode) |
| 52 | + with open(py, 'w', encoding='utf-8') as fp: |
| 53 | + fp.write(pycode) |
| 54 | + |
| 55 | +def exec_module(name, code): |
| 56 | + pymod = sys.modules[name] |
| 57 | + jlmod = newmodule(name) |
| 58 | + jlmod.seval('begin\n' + code + '\nend') |
| 59 | + delattr(pymod, 'juliacall') |
| 60 | + setattr(pymod, '__jl_code__', code) |
| 61 | + setattr(pymod, '__jl_module__', jlmod) |
| 62 | + ks = [str(k) for k in Base.names(jlmod)] |
| 63 | + ks = [k for k in ks if k != name] |
| 64 | + if not ks: |
| 65 | + ks = [str(k) for k in Base.names(jlmod, all=True)] |
| 66 | + ks = [k for k in ks if not (k == name or k == 'include' or k == 'eval' or k.startswith('_') or '#' in k)] |
| 67 | + setattr(pymod, '__all__', ks) |
| 68 | + setattr(pymod, '__doc__', str(Base.Docs.doc(jlmod))) |
| 69 | + for k in ks: |
| 70 | + setattr(pymod, k, getattr(jlmod, k)) |
0 commit comments