0

I followed the solution as given here and added a method to extend functionality to my Device class. How to inherit from MonkeyDevice?

I get an error object has no attribute 'test'. Looks like my Class instance is of type MonkeyDevice. What am I doing wrong?

from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage

class Device(MonkeyDevice):

    def __new__(self):
        return MonkeyRunner.waitForConnection(10) 
    def __init__(self):
        MonkeyDevice.__init__(self)
    def test():
        print "this is test"

device = Device()
device.test(self)
Community
  • 1
  • 1

2 Answers2

1

You are doing a lot of things wrong. Unfortunately I don't use monkeyrunner so I can't help you with the details related to the library itself.

What your code does is something like the following:

>>> class MonkeyRunner(object): pass
... 
>>> class Device(MonkeyRunner):
...     def __new__(self):
...             return MonkeyRunner()
...     def __init__(self):
...             super(Device, self).__init__()
...     def test():
...             print "This is test"
... 
>>> device = Device()
>>> device.test(self)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MonkeyRunner' object has no attribute 'test'
>>> device
<__main__.MonkeyRunner object at 0xb743fb0c>
>>> isinstance(device, Device)
False

Note how device is not a Device instance. The reason is the your __new__ method is not returning a Device instance, but a MonkeyRunner instance. The answer that you linked in your question states:

Anyway to achieve what you want you should create a class with custom __new__ rather than __init__, get your MonkeyDevice instance from the factory and inject your stuff into the instance or it's class/bases/etc.

Which means you should have done something like:

>>> class Device(MonkeyRunner):
...     def __new__(self):
...             inst = MonkeyRunner()
...             inst.test = Device.test
...             return inst
...     @staticmethod
...     def test():
...             print "I'm test"
... 
>>> device = Device()
>>> device.test()
I'm test

However this isn't useful at all, since the Device could simply be a function:

>>> def Device():
...     def test():
...             print "I'm test"
...     inst = MonkeyRunner()
...     inst.test = test
...     return inst
... 
>>> device = Device()
>>> device.test()
I'm test

AFAIK you cannot subclass MonkeyRunner and create the instance from its waitForConnection method, at least if waitForConnection is a staticmethod.

What I'd do is to use delegation:

class Device(object):
    def __init__(self):
        self._device = MonkeyRunner.waitForConnection(10)
    def __getattr__(self, attr):
        return getattr(self._device, attr)
    def test(self):
        print "I'm test"
Bakuriu
  • 98,325
  • 22
  • 197
  • 231
1

__new__ is the method used to actually instantiate the object. Because you've overridden it and explicitly returned whatever MonkeyRunner.waitForConnection returns, device is not actually an instance of class Device.

It's rare to need to override __new__.

edited OK, I see from the linked answer that this is a case where you need to do that. Bakuriu's answers show some ways to work with the need to use the special constructor to instantiate the object, as do the docs for __new__: Python docs

As a minor note, by convention the first argument to __new__ is cls rather than self, because it's actually the class object itself rather than an instance.

Peter DeGlopper
  • 36,326
  • 7
  • 90
  • 83