pankaj mishra
pankaj mishra

Reputation: 2615

calling python functions of same name from diffrent classes in robotframe work

I have a python class , which inherits multiple classes, and have test_func() with same name

parent.py

class parent:
    def __init__(self, **kwargs):
        self.ip = kwargs.get('ip')
        self.name = kwargs.get('name')
        self.local = kwargs.get('local')

class child1(parent):
        def __init__(self,**kwargs):
            parent.__init__(self,**kwargs)

        def test_func(self):
            print 'When local =true'
            return self.name

class child2(parent):
        def __init__(self,**kwargs):
            parent.__init__(self,**kwargs)
        def test_func(self):
            print ("When local =False")
            return self.ip


class child3(parent,child1,child2):
    def __init__(self, **kwargs):
        parent.__init__(self, **kwargs)

There is an environment file , where i am initializing the class

from parent import parent
from child2 import child2
from child1 import child1

from parent import child3
server=child3(
ip = '10.20.11.10',
name ='pankaj',
local = False
)

I have a robotfile (Test.robot) which calls the method test_func

*** Settings ***
Library  parent.child3  WITH NAME  wireshark_test
*** Variables ***
*** Test Cases ***
This is first
    Invoking methods
*** Keywords ***
Invoking methods
    log to console  wireshark_test.test_func

i am executing this via command

pybot -V envSI.py Test.robot

I am always getting test_func of child1 class

Expectation:

When local=True test_func of child1 class Else test_func of child2 class

Could anyone please guide me how can i do this?

Upvotes: 3

Views: 187

Answers (2)

A. Kootstra
A. Kootstra

Reputation: 6971

Building on the above answer by @todor. What I observed was that there was no logic determine how to instantiate the right class. Normally this logic would reside in some factory class but assuming there is a simple logic for determining the class then the following example will allow you to do what you want using dynamic class names.

robot_suite.robot

*** Test Cases ***
TC - false
    Import Library    child3    
    ...    ip=10.20.11.10    
    ...    name=pankaj    
    ...    local=false    
    ...    WITH NAME    i_false

    ${result}    i_false.Test Func    
    Should Be Equal As Strings   ${result}    10.20.11.10    

TC - true
    Import Library    child3    
    ...    ip=10.20.11.10    
    ...    name=pankaj    
    ...    local=true    
    ...    WITH NAME    i_true

    ${result}    i_true.Test Func    
    Should Be Equal As Strings   ${result}    pankaj

As the instantiation of a library can only be done once, I'm using the WITH NAME construct to load the same lib twice.

child3.py

class child3(object):

    def __init__(self, **kwargs):
        self.child = globals()["child_" + kwargs.get('local', 'true')](**kwargs)

    def get_keyword_names(self):
        return ['test func']

    def run_keyword(self, name, args):
        return getattr(self.child, name.lower().replace(' ', '_'))()


class parent:
    def __init__(self, **kwargs):
        self.ip = kwargs.get('ip', 'Default')
        self.name = kwargs.get('name', 'Default')
        self.local = kwargs.get('local', 'Default')


class child_true(parent):
        def __init__(self,**kwargs):
            parent.__init__(self,**kwargs)

        def test_func(self):
            return self.name


class child_false(parent):
        def __init__(self,**kwargs):
            parent.__init__(self,**kwargs)

        def test_func(self):
            return self.ip

Upvotes: 2

Todor Minakov
Todor Minakov

Reputation: 20067

I am always getting test_func of child1 class

That is so because of the Method Resolution Order in multiple inheritance in python; another read is https://www.python.org/download/releases/2.3/mro/ (don't mind the old version in the url).

In short, when there's a multiple inheritance - like in your example, class child3(parent,child1,child2), when there's an access to an attribute python will look in the parent classes from left to right, until a match is found (and raise an exception, if there isn't such).
When you called test_func(), the resolution started from "parent" - not found, then went to "child1" - and as it has this method, it got picked and executed. And thus for objects created from "child3", it's always going to be the implementation in "child1".

Can you change the MRO? Hardly (and, you really don't want to do that, if you are not 101% certain what you're doing). You can change the inheritance patterns of the class; or you can have different classes objects - "child1" and "child2", and call the corresponding one depending on your condition.

Upvotes: 3

Related Questions