Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Fix subclass behaviors #30

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Call __init__ in initialize method for subclasses
  • Loading branch information
mrkn committed Sep 11, 2017
commit 662d7cbf2316f14ff51420f0e20e691c1a09dbe1
4 changes: 4 additions & 0 deletions lib/pycall/pyobject_wrapper.rb
Original file line number Diff line number Diff line change
@@ -26,6 +26,10 @@ def self.extend_object(obj)
:| => :__or__
}.freeze

def initialize(*args)
__init__(*args)
end

def method_missing(name, *args)
name_str = name.to_s if name.kind_of?(Symbol)
name_str.chop! if name_str.end_with?('=')
8 changes: 5 additions & 3 deletions lib/pycall/pytypeobject_wrapper.rb
Original file line number Diff line number Diff line change
@@ -20,12 +20,14 @@ def inherited(subclass)
subclass.instance_variable_set(:@__pyptr__, __pyptr__)
end

def new(*args)
wrap_pyptr(LibPython::Helpers.call_object(__pyptr__, *args))
def new(*args, &b)
wrap_pyptr(__new__(__pyptr__, *args)).tap do |obj|
obj.instance_eval { initialize(*args, &b) }
end
end

def wrap_pyptr(pyptr)
return pyptr if pyptr.kind_of? self
return pyptr if pyptr.class <= self
pyptr = pyptr.__pyptr__ if pyptr.kind_of? PyObjectWrapper
unless pyptr.kind_of? PyPtr
raise TypeError, "unexpected argument type #{pyptr.class} (expected PyCall::PyPtr)"
14 changes: 14 additions & 0 deletions spec/pycall/pytypeobject_wrapper_spec.rb
Original file line number Diff line number Diff line change
@@ -239,6 +239,20 @@ module PyCall
obj = extended_class.new
expect(obj.__pyptr__.__ob_type__).to eq(simple_class_wrapper)
end

it 'calls __init__ only once' do
test_class = PyCall.import_module('pycall.initialize_test').InitializeTest
obj = test_class.new(42)
expect(obj.values.to_a).to eq([42])
end

context 'when __new__ is redefined' do
it 'calls __init__ only once' do
test_class = PyCall.import_module('pycall.initialize_test').NewOverrideTest
obj = test_class.new(42)
expect(obj.values.to_a).to eq([42, 42])
end
end
end
end
end
4 changes: 4 additions & 0 deletions spec/pycall/subclass_spec.rb
Original file line number Diff line number Diff line change
@@ -13,6 +13,10 @@
Class.new(superclass_wrapper)
end

it 'is an instance of subclass' do
expect(subclass.new.class).to eq(subclass)
end

it 'calls __init__ of superclass' do
a = subclass.new(1, 2, 3)
expect(a.init_args.to_a).to eq([1, 2, 3])
11 changes: 11 additions & 0 deletions spec/python/pycall/initialize_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class InitializeTest(object):
def __init__(self, x):
if not hasattr(self, 'values'):
self.values = []
self.values.append(x)

class NewOverrideTest(InitializeTest):
def __new__(cls, x):
obj = super().__new__(cls)
obj.__init__(x)
return obj