@@ -45,8 +45,50 @@ class JuliaError(Exception):
4545 pass
4646
4747
48+ def jl_name (name ):
49+ if name .endswith ('_b' ):
50+ return name [:- 2 ] + '!'
51+ return name
52+
53+
4854class JuliaModule (ModuleType ):
49- pass
55+
56+ def __init__ (self , loader , * args , ** kwargs ):
57+ super (JuliaModule , self ).__init__ (* args , ** kwargs )
58+ self ._julia = loader .julia
59+ self .__loader__ = loader
60+
61+ def __getattr__ (self , name ):
62+ try :
63+ return self .__try_getattr (name )
64+ except AttributeError :
65+ if name .endswith ("_b" ):
66+ try :
67+ return self .__try_getattr (jl_name (name ))
68+ except AttributeError :
69+ pass
70+ raise
71+
72+ def __try_getattr (self , name ):
73+ juliapath = self .__name__ .lstrip ("julia." )
74+ try :
75+ module_path = "." .join ((juliapath , name ))
76+ is_module = self ._julia .eval ("isa({}, Module)" .format (module_path ))
77+ if is_module :
78+ # TODO: find a better way to handle submodules
79+ split_path = module_path .split ("." )
80+ is_base = split_path [- 1 ] == "Base"
81+ recur_module = split_path [- 1 ] == split_path [- 2 ]
82+ if not is_base and not recur_module :
83+ newpath = "." .join ((self .__name__ , name ))
84+ return self .__loader__ .load_module (newpath )
85+ return self ._julia .eval (module_path )
86+ except Exception :
87+ if isafunction (self ._julia , name , mod_name = juliapath ):
88+ func = "{}.{}" .format (juliapath , name )
89+ return self ._julia .eval (func )
90+
91+ raise AttributeError (name )
5092
5193
5294
@@ -72,38 +114,7 @@ def __init__(self, julia):
72114 def load_module (self , fullname ):
73115 juliapath = fullname .lstrip ("julia." )
74116 if isamodule (self .julia , juliapath ):
75- mod = sys .modules .setdefault (fullname , JuliaModule (fullname ))
76- mod .__loader__ = self
77- names = self .julia .eval ("names({}, true, false)" .format (juliapath ))
78- for name in names :
79- if (ismacro (name ) or
80- isoperator (name ) or
81- isprotected (name ) or
82- notascii (name )):
83- continue
84- attrname = name
85- if name .endswith ("!" ):
86- attrname = name .replace ("!" , "_b" )
87- if keyword .iskeyword (name ):
88- attrname = "jl" .join (name )
89- try :
90- module_path = "." .join ((juliapath , name ))
91- module_obj = self .julia .eval (module_path )
92- is_module = self .julia .eval ("isa({}, Module)"
93- .format (module_path ))
94- if is_module :
95- split_path = module_path .split ("." )
96- is_base = split_path [- 1 ] == "Base"
97- recur_module = split_path [- 1 ] == split_path [- 2 ]
98- if is_module and not is_base and not recur_module :
99- newpath = "." .join ((fullname , name ))
100- module_obj = self .load_module (newpath )
101- setattr (mod , attrname , module_obj )
102- except Exception :
103- if isafunction (self .julia , name , mod_name = juliapath ):
104- func = "{}.{}" .format (juliapath , name )
105- setattr (mod , name , self .julia .eval (func ))
106- return mod
117+ return sys .modules .setdefault (fullname , JuliaModule (self , fullname ))
107118 elif isafunction (self .julia , juliapath ):
108119 return getattr (self .julia , juliapath )
109120 else :
0 commit comments