pycall 1.0.1-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.travis.yml +41 -0
- data/CHANGES.md +39 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +91 -0
- data/Rakefile +29 -0
- data/appveyor.yml +138 -0
- data/bin/console +10 -0
- data/bin/guard +17 -0
- data/bin/rspec +17 -0
- data/bin/runner +6 -0
- data/bin/setup +8 -0
- data/config/Guardfile +30 -0
- data/docker/Dockerfile +191 -0
- data/docker/Gemfile +12 -0
- data/docker/README.md +22 -0
- data/examples/classifier_comparison.rb +135 -0
- data/examples/datascience_rb_20170519.ipynb +4836 -0
- data/examples/hist.rb +32 -0
- data/examples/notebooks/classifier_comparison.ipynb +226 -0
- data/examples/notebooks/forest_importances.ipynb +238 -0
- data/examples/notebooks/iruby_integration.ipynb +183 -0
- data/examples/notebooks/lorenz_attractor.ipynb +214 -0
- data/examples/notebooks/polar_axes.ipynb +209 -0
- data/examples/notebooks/sum_benchmarking.ipynb +374 -0
- data/examples/notebooks/xkcd_style.ipynb +149 -0
- data/examples/plot_forest_importances_faces.rb +46 -0
- data/examples/sum_benchmarking.rb +49 -0
- data/ext/pycall/extconf.rb +3 -0
- data/ext/pycall/gc.c +74 -0
- data/ext/pycall/libpython.c +217 -0
- data/ext/pycall/pycall.c +2184 -0
- data/ext/pycall/pycall_internal.h +700 -0
- data/ext/pycall/range.c +69 -0
- data/ext/pycall/ruby_wrapper.c +432 -0
- data/lib/pycall.rb +91 -0
- data/lib/pycall/conversion.rb +173 -0
- data/lib/pycall/dict.rb +48 -0
- data/lib/pycall/error.rb +10 -0
- data/lib/pycall/gc_guard.rb +84 -0
- data/lib/pycall/import.rb +120 -0
- data/lib/pycall/init.rb +55 -0
- data/lib/pycall/iruby_helper.rb +40 -0
- data/lib/pycall/libpython.rb +12 -0
- data/lib/pycall/libpython/finder.rb +170 -0
- data/lib/pycall/libpython/pyobject_struct.rb +30 -0
- data/lib/pycall/libpython/pytypeobject_struct.rb +273 -0
- data/lib/pycall/list.rb +45 -0
- data/lib/pycall/pretty_print.rb +9 -0
- data/lib/pycall/pyerror.rb +30 -0
- data/lib/pycall/pyobject_wrapper.rb +212 -0
- data/lib/pycall/python/PyCall/__init__.py +1 -0
- data/lib/pycall/python/PyCall/six.py +23 -0
- data/lib/pycall/python/investigator.py +7 -0
- data/lib/pycall/pytypeobject_wrapper.rb +90 -0
- data/lib/pycall/set.rb +19 -0
- data/lib/pycall/slice.rb +8 -0
- data/lib/pycall/tuple.rb +46 -0
- data/lib/pycall/version.rb +3 -0
- data/lib/pycall/wrapper_object_cache.rb +61 -0
- data/pycall.gemspec +40 -0
- data/tasks/docker.rake +21 -0
- data/tasks/pycall.rake +7 -0
- metadata +228 -0
data/lib/pycall.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
module PyCall
|
2
|
+
require 'pycall/version'
|
3
|
+
require 'pycall/libpython'
|
4
|
+
require 'pycall/pyerror'
|
5
|
+
require 'pycall/pyobject_wrapper'
|
6
|
+
require 'pycall/pytypeobject_wrapper'
|
7
|
+
require 'pycall/init'
|
8
|
+
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def builtins
|
12
|
+
@builtins ||= wrap_module(LibPython::API.builtins_module_ptr)
|
13
|
+
end
|
14
|
+
|
15
|
+
def callable?(obj)
|
16
|
+
case obj
|
17
|
+
when PyObjectWrapper
|
18
|
+
builtins.callable(obj.__pyptr__)
|
19
|
+
when PyPtr
|
20
|
+
builtins.callable(obj)
|
21
|
+
else
|
22
|
+
raise TypeError, "unexpected argument type #{obj.class} (expected PyCall::PyPtr or its wrapper)"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def dir(obj)
|
27
|
+
case obj
|
28
|
+
when PyObjectWrapper
|
29
|
+
builtins.dir(obj.__pyptr__)
|
30
|
+
when PyPtr
|
31
|
+
builtins.dir(obj)
|
32
|
+
else
|
33
|
+
raise TypeError, "unexpected argument type #{obj.class} (expected PyCall::PyPtr or its wrapper)"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def eval(expr, globals: nil, locals: nil)
|
38
|
+
globals ||= import_module(:__main__).__dict__
|
39
|
+
builtins.eval(expr, globals, locals)
|
40
|
+
end
|
41
|
+
|
42
|
+
def exec(code, globals: nil, locals: nil)
|
43
|
+
globals ||= import_module(:__main__).__dict__
|
44
|
+
if PYTHON_VERSION >= '3'
|
45
|
+
builtins.exec(code, globals, locals)
|
46
|
+
else
|
47
|
+
import_module('PyCall.six').exec_(code, globals, locals)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def import_module(name)
|
52
|
+
LibPython::Helpers.import_module(name)
|
53
|
+
end
|
54
|
+
|
55
|
+
def len(obj)
|
56
|
+
case obj
|
57
|
+
when PyObjectWrapper
|
58
|
+
builtins.len(obj.__pyptr__)
|
59
|
+
when PyPtr
|
60
|
+
builtins.len(obj)
|
61
|
+
else
|
62
|
+
raise TypeError, "unexpected argument type #{obj.class} (expected PyCall::PyPtr or its wrapper)"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def sys
|
67
|
+
@sys ||= import_module('sys')
|
68
|
+
end
|
69
|
+
|
70
|
+
def tuple(iterable=nil)
|
71
|
+
pyptr = if iterable
|
72
|
+
builtins.tuple.(iterable)
|
73
|
+
else
|
74
|
+
builtins.tuple.()
|
75
|
+
end
|
76
|
+
Tuple.wrap_pyptr(pyptr)
|
77
|
+
end
|
78
|
+
|
79
|
+
def with(ctx)
|
80
|
+
begin
|
81
|
+
yield ctx.__enter__
|
82
|
+
rescue PyError => err
|
83
|
+
raise err unless ctx.__exit__(err.type, err.value, err.traceback)
|
84
|
+
rescue Exception => err
|
85
|
+
# TODO: support telling what exception has been catched
|
86
|
+
raise err unless ctx.__exit__(err.class, err, err.backtrace_locations)
|
87
|
+
else
|
88
|
+
ctx.__exit__(nil, nil, nil)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
module PyCall
|
2
|
+
module Conversions
|
3
|
+
@python_type_map = []
|
4
|
+
|
5
|
+
class TypePair < Struct.new(:pytype, :rbtype)
|
6
|
+
def to_a
|
7
|
+
[pytype, rbtype]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.each_type_pair
|
12
|
+
i, n = 1, @python_type_map.length
|
13
|
+
while i <= n
|
14
|
+
yield @python_type_map[n - i]
|
15
|
+
i += 1
|
16
|
+
end
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.python_type_mapping(pytype, rbtype)
|
21
|
+
each_type_pair do |type_pair|
|
22
|
+
next unless pytype == type_pair.pytype
|
23
|
+
type_pair.rbtype = rbtype
|
24
|
+
return
|
25
|
+
end
|
26
|
+
@python_type_map << TypePair.new(pytype, rbtype)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Convert a PyCall::PyObjectStruct object to a Ruby object
|
30
|
+
#
|
31
|
+
# @param [PyCall::PyObjectStruct] pyptr a PyObjectStruct object.
|
32
|
+
#
|
33
|
+
# @return a Ruby object converted from `pyptr`.
|
34
|
+
def self.to_ruby(pyptr)
|
35
|
+
return nil if pyptr.null? || PyCall.none?(pyptr)
|
36
|
+
|
37
|
+
case
|
38
|
+
when PyCall::Types.pyisinstance(pyptr, LibPython.PyType_Type)
|
39
|
+
return TypeObject.new(pyptr)
|
40
|
+
|
41
|
+
when PyCall::Types.pyisinstance(pyptr, LibPython.PyBool_Type)
|
42
|
+
return Conversions.convert_to_boolean(pyptr)
|
43
|
+
|
44
|
+
when PyCall::Types.pyisinstance(pyptr, LibPython.PyInt_Type)
|
45
|
+
return Conversions.convert_to_integer(pyptr)
|
46
|
+
|
47
|
+
when PyCall::Types.pyisinstance(pyptr, LibPython.PyLong_Type)
|
48
|
+
# TODO: should make Bignum
|
49
|
+
|
50
|
+
when PyCall::Types.pyisinstance(pyptr, LibPython.PyFloat_Type)
|
51
|
+
return Conversions.convert_to_float(pyptr)
|
52
|
+
|
53
|
+
when PyCall::Types.pyisinstance(pyptr, LibPython.PyComplex_Type)
|
54
|
+
return Conversions.convert_to_complex(pyptr)
|
55
|
+
|
56
|
+
when PyCall::Types.pyisinstance(pyptr, LibPython.PyString_Type)
|
57
|
+
return Conversions.convert_to_string(pyptr)
|
58
|
+
|
59
|
+
when PyCall::Types.pyisinstance(pyptr, LibPython.PyUnicode_Type)
|
60
|
+
py_str_ptr = LibPython.PyUnicode_AsUTF8String(pyptr)
|
61
|
+
return Conversions.convert_to_string(py_str_ptr).force_encoding(Encoding::UTF_8)
|
62
|
+
|
63
|
+
when PyCall::Types.pyisinstance(pyptr, LibPython.PyList_Type)
|
64
|
+
return PyCall::List.new(pyptr)
|
65
|
+
|
66
|
+
when PyCall::Types.pyisinstance(pyptr, LibPython.PyTuple_Type)
|
67
|
+
return Conversions.convert_to_tuple(pyptr)
|
68
|
+
|
69
|
+
when PyCall::Types.pyisinstance(pyptr, LibPython.PyDict_Type)
|
70
|
+
return PyCall::Dict.new(pyptr)
|
71
|
+
|
72
|
+
when PyCall::Types.pyisinstance(pyptr, LibPython.PySet_Type)
|
73
|
+
return PyCall::Set.new(pyptr)
|
74
|
+
end
|
75
|
+
|
76
|
+
pyobj = PyObject.new(pyptr)
|
77
|
+
each_type_pair do |tp|
|
78
|
+
pytype, rbtype = tp.to_a
|
79
|
+
next unless pyobj.kind_of?(pytype)
|
80
|
+
case
|
81
|
+
when rbtype.kind_of?(Proc)
|
82
|
+
return rbtype.(pyobj)
|
83
|
+
when rbtype.respond_to?(:from_python)
|
84
|
+
return rbtype.from_python(pyobj)
|
85
|
+
else
|
86
|
+
return rbtype.new(pyobj)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
pyobj
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.from_ruby(obj)
|
93
|
+
case obj
|
94
|
+
when LibPython::PyObjectStruct
|
95
|
+
obj
|
96
|
+
when PyObject, PyObjectWrapper
|
97
|
+
obj.__pyobj__
|
98
|
+
when TrueClass, FalseClass
|
99
|
+
LibPython.PyBool_FromLong(obj ? 1 : 0)
|
100
|
+
when Integer
|
101
|
+
LibPython.PyInt_FromSsize_t(obj)
|
102
|
+
when Float
|
103
|
+
LibPython.PyFloat_FromDouble(obj)
|
104
|
+
when String
|
105
|
+
if obj.encoding != Encoding::BINARY && (PyCall.unicode_literals? || !obj.ascii_only?)
|
106
|
+
obj = obj.encode(Encoding::UTF_8) if obj.encoding != Encoding::UTF_8
|
107
|
+
return LibPython.PyUnicode_DecodeUTF8(obj, obj.bytesize, nil)
|
108
|
+
end
|
109
|
+
LibPython.PyString_FromStringAndSize(obj, obj.bytesize)
|
110
|
+
when Symbol
|
111
|
+
from_ruby(obj.to_s)
|
112
|
+
when Array
|
113
|
+
PyCall::List.new(obj).__pyobj__
|
114
|
+
when Hash
|
115
|
+
PyCall::Dict.new(obj).__pyobj__
|
116
|
+
when Proc
|
117
|
+
PyCall.wrap_ruby_callable(obj)
|
118
|
+
else
|
119
|
+
PyCall.None
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.convert_to_boolean(py_obj)
|
124
|
+
0 != LibPython.PyInt_AsSsize_t(py_obj)
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.convert_to_integer(py_obj)
|
128
|
+
LibPython.PyInt_AsSsize_t(py_obj)
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.convert_to_float(py_obj)
|
132
|
+
LibPython.PyFloat_AsDouble(py_obj)
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.convert_to_complex(py_obj)
|
136
|
+
real = LibPython.PyComplex_RealAsDouble(py_obj)
|
137
|
+
imag = LibPython.PyComplex_ImagAsDouble(py_obj)
|
138
|
+
Complex(real, imag)
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.convert_to_string(py_obj)
|
142
|
+
FFI::MemoryPointer.new(:string) do |str_ptr|
|
143
|
+
FFI::MemoryPointer.new(:int) do |len_ptr|
|
144
|
+
res = LibPython.PyString_AsStringAndSize(py_obj, str_ptr, len_ptr)
|
145
|
+
return nil if res == -1 # FIXME: error
|
146
|
+
|
147
|
+
len = len_ptr.get(:int, 0)
|
148
|
+
return str_ptr.get_pointer(0).read_string(len)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.convert_to_array(py_obj, force_list: true, array_class: Array)
|
154
|
+
case
|
155
|
+
when force_list || py_obj.kind_of?(LibPython.PyList_Type)
|
156
|
+
len = LibPython.PySequence_Size(py_obj)
|
157
|
+
array_class.new(len) do |i|
|
158
|
+
LibPython.PySequence_GetItem(py_obj, i).to_ruby
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.convert_to_tuple(py_obj)
|
164
|
+
PyCall::Tuple.new(py_obj)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class LibPython::PyObjectStruct
|
169
|
+
def to_ruby
|
170
|
+
Conversions.to_ruby(self)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
data/lib/pycall/dict.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module PyCall
|
2
|
+
Dict = builtins.dict
|
3
|
+
class Dict
|
4
|
+
register_python_type_mapping
|
5
|
+
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def self.new(h)
|
9
|
+
super(h, {})
|
10
|
+
end
|
11
|
+
|
12
|
+
def length
|
13
|
+
PyCall.len(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def has_key?(key)
|
17
|
+
LibPython::Helpers.dict_contains(__pyptr__, key)
|
18
|
+
end
|
19
|
+
|
20
|
+
alias include? has_key?
|
21
|
+
alias key? has_key?
|
22
|
+
alias member? has_key?
|
23
|
+
|
24
|
+
def [](key)
|
25
|
+
super
|
26
|
+
rescue PyError
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete(key)
|
31
|
+
v = self[key]
|
32
|
+
LibPython::Helpers.delitem(__pyptr__, key)
|
33
|
+
v
|
34
|
+
end
|
35
|
+
|
36
|
+
def each
|
37
|
+
return enum_for unless block_given?
|
38
|
+
LibPython::Helpers.dict_each(__pyptr__, &proc)
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_h
|
43
|
+
inject({}) do |h, (k, v)|
|
44
|
+
h.update(k => v)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/pycall/error.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'pycall'
|
2
|
+
|
3
|
+
module PyCall
|
4
|
+
module GCGuard
|
5
|
+
@gc_guard = {}
|
6
|
+
|
7
|
+
class Key < Struct.new(:pyptr)
|
8
|
+
def initialize(pyptr)
|
9
|
+
self.pyptr = check_pyptr(pyptr)
|
10
|
+
# LibPython.Py_IncRef(pyptr)
|
11
|
+
end
|
12
|
+
|
13
|
+
def release
|
14
|
+
# LibPython.Py_DecRef(pyptr)
|
15
|
+
self.pyptr = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def ==(other)
|
19
|
+
case other
|
20
|
+
when Key
|
21
|
+
pyptr.pointer == other.pyptr.pointer
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
alias :eql? :==
|
28
|
+
|
29
|
+
def hash
|
30
|
+
pyptr.pointer.address
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def check_pyptr(pyptr)
|
36
|
+
pyptr = pyptr.__pyobj__ if pyptr.respond_to? :__pyobj__
|
37
|
+
return pyptr if pyptr.kind_of? LibPython::PyObjectStruct
|
38
|
+
raise TypeError, "The argument must be a Python object"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.register(pyobj, obj)
|
43
|
+
key = Key.new(pyobj)
|
44
|
+
@gc_guard[key] ||= []
|
45
|
+
@gc_guard[key] << obj
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.unregister(pyobj)
|
49
|
+
key = Key.new(pyobj)
|
50
|
+
@gc_guard.delete(key).tap { key.release }
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.guarded_object_count
|
54
|
+
@gc_guard.length
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.embed(pyobj, obj)
|
58
|
+
pyptr = pyobj.respond_to?(:__pyobj__) ? pyobj.__pyobj__ : pyobj
|
59
|
+
raise TypeError, "The argument must be a Python object" unless pyptr.kind_of? LibPython::PyObjectStruct
|
60
|
+
wo = LibPython.PyWeakref_NewRef(pyptr, weakref_callback)
|
61
|
+
register(wo, obj)
|
62
|
+
pyobj
|
63
|
+
end
|
64
|
+
|
65
|
+
private_class_method def self.weakref_callback
|
66
|
+
unless @weakref_callback
|
67
|
+
@weakref_callback_func = FFI::Function.new(
|
68
|
+
LibPython::PyObjectStruct.ptr,
|
69
|
+
[LibPython::PyObjectStruct.ptr, LibPython::PyObjectStruct.ptr]
|
70
|
+
) do |callback, pyptr|
|
71
|
+
GCGuard.unregister(pyptr)
|
72
|
+
# LibPython.Py_DecRef(pyptr)
|
73
|
+
# LibPython.Py_IncRef(PyCall.None)
|
74
|
+
next PyCall.None
|
75
|
+
end
|
76
|
+
method_def = LibPython::PyMethodDef.new("weakref_callback", @weakref_callback_func, LibPython::METH_O, nil)
|
77
|
+
@weakref_callback = LibPython.PyCFunction_NewEx(method_def, nil, nil).tap {|po| LibPython.Py_IncRef(po) }
|
78
|
+
end
|
79
|
+
@weakref_callback
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private_constant :GCGuard
|
84
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'pycall'
|
2
|
+
|
3
|
+
module PyCall
|
4
|
+
module Import
|
5
|
+
class << self
|
6
|
+
attr_reader :main_object
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
PyCall::Import.instance_variable_set(:@main_object, self)
|
12
|
+
|
13
|
+
module PyCall
|
14
|
+
module Import
|
15
|
+
def pyimport(mod_name, as: nil)
|
16
|
+
as = mod_name unless as
|
17
|
+
check_valid_module_variable_name(mod_name, as)
|
18
|
+
mod = PyCall.import_module(mod_name)
|
19
|
+
define_singleton_method(as) { mod }
|
20
|
+
end
|
21
|
+
|
22
|
+
# This function is implemented as a mimic of `import_from` function defined in `Python/ceval.c`.
|
23
|
+
def pyfrom(mod_name, import: nil)
|
24
|
+
raise ArgumentError, "missing identifier(s) to be imported" unless import
|
25
|
+
|
26
|
+
mod_name = mod_name.to_str if mod_name.respond_to? :to_str
|
27
|
+
mod_name = mod_name.to_s if mod_name.is_a? Symbol
|
28
|
+
|
29
|
+
import = Array(import)
|
30
|
+
fromlist = import.map.with_index do |import_name, i|
|
31
|
+
case import_name
|
32
|
+
when assoc_array_matcher
|
33
|
+
import_name[0]
|
34
|
+
when Symbol, String
|
35
|
+
import_name
|
36
|
+
else
|
37
|
+
raise ArgumentError, "wrong type of import name #{import_name.class} (expected String or Symbol)"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
from_list = PyCall.tuple(from_list)
|
41
|
+
|
42
|
+
main_dict_ptr = PyCall.import_module('__main__').__dict__.__pyptr__
|
43
|
+
globals = main_dict_ptr # FIXME: this should mimic to `import_name` function defined in `Python/ceval.c`.
|
44
|
+
locals = main_dict_ptr # FIXME: this should mimic to `import_name` function defined in `Python/ceval.c`.
|
45
|
+
level = 0 # TODO: support prefixed dots (#25)
|
46
|
+
mod = LibPython::Helpers.import_module(mod_name, globals, locals, fromlist, level)
|
47
|
+
|
48
|
+
import.each do |import_name|
|
49
|
+
case import_name
|
50
|
+
when assoc_array_matcher
|
51
|
+
name, asname = *import_name
|
52
|
+
when Symbol, String
|
53
|
+
name, asname = import_name, import_name
|
54
|
+
end
|
55
|
+
|
56
|
+
if PyCall::LibPython::Helpers.hasattr?(mod.__pyptr__, name)
|
57
|
+
pyobj = PyCall::LibPython::Helpers.getattr(mod.__pyptr__, name)
|
58
|
+
define_name(asname, pyobj)
|
59
|
+
next
|
60
|
+
end
|
61
|
+
|
62
|
+
if mod.respond_to? :__name__
|
63
|
+
pkgname = mod.__name__
|
64
|
+
fullname = "#{pkgname}.#{name}"
|
65
|
+
sys_modules = PyCall.import_module('sys').modules
|
66
|
+
if sys_modules.has_key?(fullname)
|
67
|
+
pyobj = module_dict[fullname]
|
68
|
+
define_name(asname, pyobj)
|
69
|
+
next
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
raise ArgumentError, "cannot import name #{fullname}" unless pyobj
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def define_name(name, pyobj)
|
80
|
+
if callable?(pyobj) && !type_object?(pyobj)
|
81
|
+
define_singleton_method(name) do |*args|
|
82
|
+
LibPython::Helpers.call_object(pyobj.__pyptr__, *args)
|
83
|
+
end
|
84
|
+
else
|
85
|
+
if constant_name?(name)
|
86
|
+
context = self
|
87
|
+
context = (self == PyCall::Import.main_object) ? Object : self
|
88
|
+
context.module_eval { const_set(name, pyobj) }
|
89
|
+
else
|
90
|
+
define_singleton_method(name) { pyobj }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def constant_name?(name)
|
96
|
+
name =~ /\A[A-Z]/
|
97
|
+
end
|
98
|
+
|
99
|
+
def check_valid_module_variable_name(mod_name, var_name)
|
100
|
+
var_name = var_name.to_s if var_name.kind_of? Symbol
|
101
|
+
if var_name.include?('.')
|
102
|
+
raise ArgumentError, "#{var_name} is not a valid module variable name, use pyimport #{mod_name}, as: <name>"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def assoc_array_matcher
|
107
|
+
@assoc_array_matcher ||= ->(ary) do
|
108
|
+
ary.is_a?(Array) && ary.length == 2
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def callable?(pyobj)
|
113
|
+
LibPython::Helpers.callable?(pyobj.__pyptr__)
|
114
|
+
end
|
115
|
+
|
116
|
+
def type_object?(pyobj)
|
117
|
+
pyobj.__pyptr__.kind_of? PyTypePtr
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|