Adding methods from one class to another, dynamically

O

Oltmans

Hello Python gurus,

I'm quite new when it comes to Python so I will appreciate any help.
Here is what I'm trying to do. I've two classes like below

import new
import unittest

class test(unittest.TestCase):
def test_first(self):
print 'first test'
def test_second(self):
print 'second test'
def test_third(self):
print 'third test'

class tee(unittest.TestCase):
pass

and I want to attach all test methods of 'test'(i.e. test_first(),
test_second() and test_third()) class to 'tee' class. So I'm trying to
do something like

if __name__=="__main__":
for name,func in inspect.getmembers(test,inspect.ismethod):
if name.find('test_')!= -1:
tee.name = new.instancemethod(func,None,tee)

after doing above when I run this statement
print dirs(tee)
I don't see test_first(), test_second() and test_third() attached to
class 'tee'. Any ideas, on how can I attach methods of class 'test' to
class 'tee' dynamically? Any help is highly appreciated.

Many thanks and I look forward to any help.
 
C

Chris Rebert

Hello Python gurus,

I'm quite new when it comes to Python so I will appreciate any help.
Here is what I'm trying to do. I've two classes like below

import new
import unittest

class test(unittest.TestCase):
   def test_first(self):
       print 'first test'
   def test_second(self):
       print 'second test'
   def test_third(self):
       print 'third test'

class tee(unittest.TestCase):
   pass

and I want to attach all test methods of 'test'(i.e. test_first(),
test_second() and test_third()) class to 'tee' class. So I'm trying to
do something like

if __name__=="__main__":
   for name,func in inspect.getmembers(test,inspect.ismethod):
       if name.find('test_')!= -1:
           tee.name = new.instancemethod(func,None,tee)

This ends up repeatedly assigning to the attribute "name" of tee; if
you check dir(tee), you'll see the string "name" as an entry. It does
*not* assign to the attribute named by the string in the variable
`name`.
You want setattr(): http://docs.python.org/library/functions.html#setattr
Assuming the rest of your code chunk is correct:

setattr(tee, name, new.instancemethod(func,None,tee))

Cheers,
Chris
 
C

Carl Banks

Hello Python gurus,

I'm quite new when it comes to Python so I will appreciate any help.
Here is what I'm trying to do. I've two classes like below

import new
import unittest

class test(unittest.TestCase):
    def test_first(self):
        print 'first test'
    def test_second(self):
        print 'second test'
    def test_third(self):
        print 'third test'

class tee(unittest.TestCase):
    pass

and I want to attach all test methods of 'test'(i.e. test_first(),
test_second() and test_third()) class to 'tee' class.


Simplest way:

class tee(test):
pass


To do it dynamically the following might work:

class tee(unittest.TestCase):
pass

tee.__bases__ = (test,)
tee.__bases__ = (test2,) # dynamically reassign base

So I'm trying to
do something like

if __name__=="__main__":
    for name,func in inspect.getmembers(test,inspect.ismethod):
        if name.find('test_')!= -1:
            tee.name = new.instancemethod(func,None,tee)

after doing above when I run this statement
print dirs(tee)
I don't see test_first(), test_second() and test_third() attached to
class 'tee'. Any ideas, on how can I attach methods of class 'test' to
class 'tee' dynamically? Any help is highly appreciated.

If you want to do it this way--and I recommend regular inheritance if
you can--this is how:

for x in dir(test): # or inspect.getmembers
if x.startswith('test_'):
method = getattr(test,x)
function = method.im_func
setattr(tee,x,function)

The business with method.im_func is because in Python 2.x the getattr
on a class will actually returns an unbound method, so you have to get
at the actual function object with im_func. In Python 3 this is not
necessary.

Carl Banks
 
G

Gerald Britton

Or you could just do a mixin:

tee.__class__.__bases__ = (test,) + tee.__class__.__bases__
 
O

Oltmans

Thank you for your help, Chris. Looks like I can now attach methods to
class 'tee'. However, after attaching methods to 'tee' when I try to
run them using suite.run() I don't see any of the methods running, I'm
sorry but I've no clue what's failing this. Any insights will be
highly appreciated. Here is the sample code
filename: check.py
---
import inspect
import unittest


class result(unittest.TestResult):

def addSuccess(self,test):
print str(test) + ' succeeded'
def addError(self,test,err):
print 'An error occured while running the test ' + str(test) +
' and error is = ' + str(err)
def addFailure(self,test,err):
print str(test) + " failed with an error =" + str(err)



class test(unittest.TestCase):
def test_first(self):
print 'first test'
def test_second(self):
print 'second test'
def test_third(self):
print 'third test'

import new
class tee(unittest.TestCase):
pass

if __name__=="__main__":
r = result()
for name,func in inspect.getmembers(test,inspect.ismethod):
if name.find('test_')!= -1:

setattr(tee, name, new.instancemethod(func,None,tee))

suite = unittest.defaultTestLoader.loadTestsFromName('check.tee')
suite.run(r)
---

Then line suite.run(r) should have run the methods that we just
attached, but it's not. I must be missing something here. Please
enlighten me.

Thanks.
 
S

Steve Holden

Oltmans said:
Thank you for your help, Chris. Looks like I can now attach methods to
class 'tee'. However, after attaching methods to 'tee' when I try to
run them using suite.run() I don't see any of the methods running, I'm
sorry but I've no clue what's failing this. Any insights will be
highly appreciated. Here is the sample code
filename: check.py
---
import inspect
import unittest


class result(unittest.TestResult):

def addSuccess(self,test):
print str(test) + ' succeeded'
def addError(self,test,err):
print 'An error occured while running the test ' + str(test) +
' and error is = ' + str(err)
def addFailure(self,test,err):
print str(test) + " failed with an error =" + str(err)



class test(unittest.TestCase):
def test_first(self):
print 'first test'
def test_second(self):
print 'second test'
def test_third(self):
print 'third test'

import new
class tee(unittest.TestCase):
pass

if __name__=="__main__":
r = result()
for name,func in inspect.getmembers(test,inspect.ismethod):
if name.find('test_')!= -1:

setattr(tee, name, new.instancemethod(func,None,tee))

suite = unittest.defaultTestLoader.loadTestsFromName('check.tee')
suite.run(r)
---

Then line suite.run(r) should have run the methods that we just
attached, but it's not. I must be missing something here. Please
enlighten me.
Should not tee be subclassing test, not unittest.TestCase?

regards
Steve
 
M

Michele Simionato

Wanting the same methods to be attached to different classes often is
a code smell (perhaps it is not your case and then use setattr as
others said). Perhaps you can just leave such methods outside any
class. I would suggest you to use a testing framework not based on
inheritance (i.e. use nose or py.test). Perhaps your problem can be
solved with generative tests.
 
O

Oltmans

Should not tee be subclassing test, not unittest.TestCase?

Thank you, Steve. This worked, but I've not clue why? Can you please
enlighten me why sub-classing 'test' made it happen? Please. Thanks
again.
 
S

Steve Holden

Oltmans said:
Thank you, Steve. This worked, but I've not clue why? Can you please
enlighten me why sub-classing 'test' made it happen? Please. Thanks
again.

unittest.TestCase doesn't have any test* methods (methods whose names
begin with "test"). So neither do your subclasses.

When you subclass test, however, test has everything that
unittest.TestCase does (because it subclasses unittest.TestCase) and it
also has three test* methods. So your subclass of test also has those
three methods as well.

regards
Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,262
Messages
2,571,056
Members
48,769
Latest member
Clifft

Latest Threads

Top