Skip to content

Commit 3e2b3e6

Browse files
committed
Add PyCall::PyModuleWrapper module
- Extend module wrapper object by this new module - Add PyModuleWrapper#[] to obtain functions under the module
1 parent b40e92f commit 3e2b3e6

File tree

5 files changed

+75
-31
lines changed

5 files changed

+75
-31
lines changed

lib/pycall.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module PyCall
44
require 'pycall/pyerror'
55
require 'pycall/pyobject_wrapper'
66
require 'pycall/pytypeobject_wrapper'
7+
require 'pycall/pymodule_wrapper'
78
require 'pycall/init'
89

910
module_function

lib/pycall/pymodule_wrapper.rb

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
require 'pycall/pyobject_wrapper'
2+
3+
module PyCall
4+
module PyModuleWrapper
5+
include PyObjectWrapper
6+
7+
def [](*args)
8+
case args[0]
9+
when String, Symbol
10+
PyCall.getattr(self, args[0])
11+
else
12+
super
13+
end
14+
end
15+
end
16+
17+
module_function
18+
19+
class WrapperModuleCache < WrapperObjectCache
20+
def initialize
21+
super(LibPython::API::PyModule_Type)
22+
end
23+
24+
def check_wrapper_object(wrapper_object)
25+
unless wrapper_object.kind_of?(Module) && wrapper_object.kind_of?(PyObjectWrapper)
26+
raise TypeError, "unexpected type #{wrapper_object.class} (expected Module extended by PyObjectWrapper)"
27+
end
28+
end
29+
30+
def self.instance
31+
@instance ||= self.new
32+
end
33+
end
34+
35+
private_constant :WrapperModuleCache
36+
37+
def wrap_module(pymodptr)
38+
check_ismodule(pymodptr)
39+
WrapperModuleCache.instance.lookup(pymodptr) do
40+
Module.new do |mod|
41+
mod.instance_variable_set(:@__pyptr__, pymodptr)
42+
mod.extend PyModuleWrapper
43+
end
44+
end
45+
end
46+
end

lib/pycall/pyobject_wrapper.rb

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -170,32 +170,9 @@ def to_f
170170

171171
module_function
172172

173-
class WrapperModuleCache < WrapperObjectCache
174-
def initialize
175-
super(LibPython::API::PyModule_Type)
176-
end
177-
178-
def check_wrapper_object(wrapper_object)
179-
unless wrapper_object.kind_of?(Module) && wrapper_object.kind_of?(PyObjectWrapper)
180-
raise TypeError, "unexpected type #{wrapper_object.class} (expected Module extended by PyObjectWrapper)"
181-
end
182-
end
183-
184-
def self.instance
185-
@instance ||= self.new
186-
end
187-
end
188-
189-
private_constant :WrapperModuleCache
190-
191-
def wrap_module(pymodptr)
192-
check_ismodule(pymodptr)
193-
WrapperModuleCache.instance.lookup(pymodptr) do
194-
Module.new do |mod|
195-
mod.instance_variable_set(:@__pyptr__, pymodptr)
196-
mod.extend PyObjectWrapper
197-
end
198-
end
173+
def check_ismodule(pyptr)
174+
return if pyptr.kind_of? LibPython::API::PyModule_Type
175+
raise TypeError, "PyModule object is required"
199176
end
200177

201178
def check_isclass(pyptr)
@@ -204,9 +181,4 @@ def check_isclass(pyptr)
204181
return defined?(LibPython::API::PyClass_Type) && pyptr.kind_of?(LibPython::API::PyClass_Type)
205182
raise TypeError, "PyType object is required"
206183
end
207-
208-
def check_ismodule(pyptr)
209-
return if pyptr.kind_of? LibPython::API::PyModule_Type
210-
raise TypeError, "PyModule object is required"
211-
end
212184
end

spec/pycall/pymodule_wrapper_spec.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
require 'spec_helper'
2+
3+
::RSpec.describe PyCall::PyModuleWrapper do
4+
let(:simple_module) do
5+
PyCall.import_module('pycall.simple_module')
6+
end
7+
8+
specify do
9+
expect(simple_module).to be_an_instance_of(Module)
10+
expect(simple_module).to be_a(PyCall::PyModuleWrapper)
11+
expect(simple_module).to be_a(PyCall::PyObjectWrapper)
12+
end
13+
14+
describe '#[]' do
15+
specify do
16+
expect(simple_module[:double]).to be_a(PyCall::PyObjectWrapper)
17+
expect(simple_module[:double].call(2)).to eq(4)
18+
expect(simple_module[:answer]).to eq(42)
19+
end
20+
end
21+
end

spec/python/pycall/simple_module.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
def double(x):
2+
return 2 * x
3+
4+
answer = 42

0 commit comments

Comments
 (0)