lib/pycall/import.rb in pycall-0.1.0.alpha.20170711 vs lib/pycall/import.rb in pycall-1.0.0

- old
+ new

@@ -1,81 +1,72 @@ require 'pycall' module PyCall module Import - def self.main_object - @main_object + class << self + attr_reader :main_object end end end -main_object = self -PyCall::Import.class_eval { @main_object = main_object } +PyCall::Import.instance_variable_set(:@main_object, self) module PyCall module Import def pyimport(mod_name, as: nil) - case as - when nil - as = mod_name - end - + as = mod_name unless as check_valid_module_variable_name(mod_name, as) - mod = PyCall.import_module(mod_name) - 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 + raise ArgumentError, "missing identifier(s) to be imported" unless import 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 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)) + fromlist = import.map.with_index do |import_name, i| + case import_name + when assoc_array_matcher + import_name[0] + when Symbol, String + import_name + else + raise ArgumentError, "wrong type of import name #{import_name.class} (expected String or Symbol)" + end end + from_list = PyCall.tuple(from_list) - 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`. + main_dict_ptr = PyCall.import_module('__main__').__dict__.__pyptr__ + globals = main_dict_ptr # FIXME: this should mimic to `import_name` function defined in `Python/ceval.c`. + locals = main_dict_ptr # 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 + mod = LibPython::Helpers.import_module(mod_name, globals, locals, fromlist, level) 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 - if PyCall.hasattr?(mod, name) - pyobj = PyCall.getattr(mod, name) + if PyCall::LibPython::Helpers.hasattr?(mod.__pyptr__, name) + pyobj = PyCall::LibPython::Helpers.getattr(mod.__pyptr__, name) define_name(asname, pyobj) next end - if PyCall.hasattr?(mod, :__name__) - pkgname = PyCall.getattr(mod, :__name__) + if mod.respond_to? :__name__ + pkgname = mod.__name__ fullname = "#{pkgname}.#{name}" - module_dict = LibPython.PyImport_GetModuleDict() - if PyCall.getattr(module_dict, fullname) - pyobj = PyCall.getattr(module_dict, fullname) + sys_modules = PyCall.import_module('sys').modules + if sys_modules.has_key?(fullname) + pyobj = module_dict[fullname] define_name(asname, pyobj) next end end @@ -84,16 +75,22 @@ end private def define_name(name, pyobj) - if constant_name?(name) - context = self - context = (self == PyCall::Import.main_object) ? Object : self - context.module_eval { const_set(name, pyobj) } + if callable?(pyobj) && !type_object?(pyobj) + define_singleton_method(name) do |*args| + LibPython::Helpers.call_object(pyobj.__pyptr__, *args) + end else - define_singleton_method(name) { pyobj } + if constant_name?(name) + context = self + context = (self == PyCall::Import.main_object) ? Object : self + context.module_eval { const_set(name, pyobj) } + else + define_singleton_method(name) { pyobj } + end end end def constant_name?(name) name =~ /\A[A-Z]/ @@ -108,8 +105,16 @@ def assoc_array_matcher @assoc_array_matcher ||= ->(ary) do ary.is_a?(Array) && ary.length == 2 end + end + + def callable?(pyobj) + LibPython::Helpers.callable?(pyobj.__pyptr__) + end + + def type_object?(pyobj) + pyobj.__pyptr__.kind_of? PyTypePtr end end end