lib/pycall/import.rb in pycall-0.1.0.alpha.20170502 vs lib/pycall/import.rb in pycall-0.1.0.alpha.20170711
- old
+ new
@@ -25,30 +25,63 @@
raise PyError.fetch unless mod
define_singleton_method(as) { mod }
end
+ # This function is implemented as a mimic of `import_from` function defined in `Python/ceval.c`.
def pyfrom(mod_name, import: nil)
raise ArgumentError, "missing identifiers to be imported" unless import
- mod = PyCall.import_module(mod_name)
- raise PyError.fetch unless mod
+ mod_name = mod_name.to_str if mod_name.respond_to? :to_str
+ mod_name = mod_name.to_s if mod_name.is_a? Symbol
- case import
- when Hash
- import.each do |attr, as|
- val = PyCall.getattr(mod, attr)
- define_name(as, val)
+ import = Array(import)
+ fromlist = LibPython.PyTuple_New(import.length)
+ import.each_with_index do |import_name, i|
+ name = case import_name
+ when assoc_array_matcher
+ import_name[0]
+ when Symbol, String
+ import_name
+ end
+ LibPython.PyTuple_SetItem(fromlist, i, Conversions.from_ruby(name))
+ end
+
+ main_dict = PyCall::Eval.__send__ :main_dict
+ globals = main_dict.__pyobj__ # FIXME: this should mimic to `import_name` function defined in `Python/ceval.c`.
+ locals = main_dict.__pyobj__ # FIXME: this should mimic to `import_name` function defined in `Python/ceval.c`.
+ level = 0 # TODO: support prefixed dots (#25)
+ mod = LibPython.PyImport_ImportModuleLevel(mod_name, globals, locals, fromlist, level)
+ raise PyError.fetch if mod.null?
+ mod = mod.to_ruby
+
+ import.each do |import_name|
+ case import_name
+ when assoc_array_matcher
+ name, asname = *import_name
+ when Symbol, String
+ name, asname = import_name, import_name
end
- when Array
- import.each do |attr|
- val = PyCall.getattr(mod, attr)
- define_name(attr, val)
+
+ if PyCall.hasattr?(mod, name)
+ pyobj = PyCall.getattr(mod, name)
+ define_name(asname, pyobj)
+ next
end
- when Symbol, String
- val = PyCall.getattr(mod, import)
- define_name(import, val)
+
+ if PyCall.hasattr?(mod, :__name__)
+ pkgname = PyCall.getattr(mod, :__name__)
+ fullname = "#{pkgname}.#{name}"
+ module_dict = LibPython.PyImport_GetModuleDict()
+ if PyCall.getattr(module_dict, fullname)
+ pyobj = PyCall.getattr(module_dict, fullname)
+ define_name(asname, pyobj)
+ next
+ end
+ end
+
+ raise ArgumentError, "cannot import name #{fullname}" unless pyobj
end
end
private
@@ -68,9 +101,15 @@
def check_valid_module_variable_name(mod_name, var_name)
var_name = var_name.to_s if var_name.kind_of? Symbol
if var_name.include?('.')
raise ArgumentError, "#{var_name} is not a valid module variable name, use pyimport #{mod_name}, as: <name>"
+ end
+ end
+
+ def assoc_array_matcher
+ @assoc_array_matcher ||= ->(ary) do
+ ary.is_a?(Array) && ary.length == 2
end
end
end
end