When mocking a class object I can't access it's attributes.
I've read a lot of documentation but I'm new to mocking and don't see the problem with this code. I expect x and y to return the same value 1e-15
class test_user_data:
scale = 1e-15
class test_signal(unittest.TestCase):
#patch('xx.user_data', autospec=test_user_data, spec_set=True)
def test_data(self, mock_user_data):
x = xx.user_data()
y = test_user_data()
print(x.scale)
print(y.scale)
but I get
<NonCallableMagicMock name='user_data().timescale' spec_set='float' id='47213638195072'>
1e-15
autospec and spec'ing in general is used to define an API. When using a Mock, you can pretty much call or access any attribute on it and it'll just let you. It will return another mock object though.
See something like this:
>>> my_mock = Mock()
>>> my_mock.stuff
<Mock name='mock.stuff' id='139870989908344'>
>>> my_mock.junk()
<Mock name='mock.junk()' id='139870987197912'>
If I define a spec, it says you can't access things that don't actually exist on the real class. Like so:
>>> my_mock = Mock(spec=xx.user_data)
>>> my_mock.stuff
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python3.4/unittest/mock.py", line 574, in __getattr__
raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'stuff'
>>> my_mock.scale
<Mock name='mock.scale' id='139871128095264'>
So the above shows you can't access an attribute on the Mock that isn't defined in the actual user_data class because I've used spec.
That explains how autospec works, but what you actually want is the return_value arg. Go ahead and add it to your patch decorator and you should be all set. It should look like this:
#patch('xx.user_data', autospec=test_user_data, spec_set=True, return_value=test_user_data)
Related
I would like to store a bunch of variables under a Python namespace without creating a separate module. I notice that the result of ArgumentParser's parse_args() is a argparse.Namespace object. You can access the arguments through dot-syntax.
from argparse import ArgumentParser
parser = ArgumentParser()
# some arg definitions here...
args = parser.parse_args() # returns a `argparse.Namespace` object
How can I create the equivalent of an argparse.Namespace? I know I can do something similar with a dict but I would like to use dot-syntax. Is there any built-in class that just lets you assign arbitrary attributes?
Starting with python3.3 you can use types.SimpleNamespace.
However an alternative is simply:
class Namespace(object):
pass
namespaceA = Namespace()
namespaceA.x = 1
The full code for SimpleNamespace isn't much longer.
Note that you cannot simply use an object instance:
>>> o = object()
>>> o.x = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'x'
This is because instances of object do not have a __dict__ attribute:
>>> vars(object())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: vars() argument must have __dict__ attribute
Which means you cannot set the attributes of an instance of object.
Any object subclass that does not have the __slots__ attribute set does have the __dict__ which is used (by default) to store/retrieve attributes:
>>> class Namespace(object):
... pass
...
>>> a = Namespace()
>>> a.x = 1 # same as as.__dict__['a'] = 1
>>> a.__dict__
{'x': 1}
For further information about attribute setting/lookup you should learn about descriptors.
A class can be used as a namespace, where the variables are class members:
class Namespace1:
foo = 'a'
bar = 5
To prevent callers from trying to instantiate, you can use a baseclass like:
class objectless(object):
def __new__(cls, *args, **kwargs):
raise RuntimeError('%s should not be instantiated' % cls)
And use it like:
class Namespace1(objectless):
...
It sounds like you want a python class. See the docs.
Depending on what you want exactly, you can define a bunch of variables as attributes of a class (either a variable of an instance or of the class itself) and access them that way.
If you want "the equivalent of an argparse.Namespace", use argparse.Namespace:
from argparse import Namespace
ns = Namespace(a=1)
print ns.a
If I'm understanding correctly, you want to dynamically add attributes to it. For example, a class parses command-line flags you access them directly like args.verbose, right? If so, you may be thinking of setattr() that lets you add arbitrary attributes.
class Foo(object):
pass
foo = Foo()
setattr(foo, 'ack', 'bar')
print(foo.ack) # prints 'bar'
I am attempting to do the following:
def test_fn(self):
cool_dict = {}
blah = Mock(spec=DictField, wraps=cool_dict)
blah['key'] = 'val'
print(cool_dict))
return False
Basically, I want to ensure that anything which happens to blah is allowed for a DictField, but I want anything that happens to blah to actually happen to cool_dict, so I can see assert that it has a certain state.
How can I do this? The above code fails:
FAILED (errors=1)
Error
Traceback (most recent call last):
File "C:\Program Files\Python 3.5\Lib\unittest\case.py", line 59, in testPartExecutor
yield
File "C:\Program Files\Python 3.5\Lib\unittest\case.py", line 605, in run
testMethod()
File "C:\Users\danie01.AD\PycharmProjects\component\component\Default\Functional\pam_team_management\test\test_team_create.py", line 23, in test_populate_info_page
blah['key'] = 'val'
TypeError: 'Mock' object does not support item assignment
I also tried it with a MagicMock:
def test_populate_info_page(self):
cool_dict = {}
blah = MagicMock(spec=DictField, wraps=cool_dict)
blah['key'] = 'val'
print(cool_dict)
return False
Which didn't fail, but cool_dict was still {}
In Python, you can also make use of magic methods which are the built-in methods on classes. For dict objects, you would want to override the __getitem__() and __setitem__() magic methods.
As an example, when you make the statement blah['key'] = 'var', it's actually calling blah.__setitem__('key', 'var'). So you'll want to mock those two magic methods, and then check on the status of those mocked methods.
Here's an example of how I might try what you're talking about:
>>> cool_dict = {'key': 'val'}
>>> blah = Mock()
>>> blah.__getitem__ = Mock()
>>> blah.__getitem__.side_effect = cool_dict.__getitem__
>>> blah['key']
'val'
>>> blah.__getitem__.assert_called() # No assertion raised, which means that it was called
>>>
So in this example, the __getitem__() method of the 'blah' object is the thing you're going to be using a Mock() to mock, and then you create a side effect: it triggers the same __getitem__() function on the cool_dict. After it's been called, you can inspect that Mock afterward to see whether it was called and what it was called with. See Mocking Magic Methods for more context.
ctypes has a classmethod from_buffer. I'm trying to add some custom processing to from_buffer() in a subclass, but I'm having trouble calling super(). Here is an example:
from ctypes import c_char, Structure
class Works(Structure):
_fields_ = [
("char", c_char),
]
class DoesntWork(Works):
#classmethod
def from_buffer(cls, buf):
print "do some extra stuff"
return super(DoesntWork, cls).from_buffer(buf)
print Works.from_buffer(bytearray('c')).char
print DoesntWork.from_buffer(bytearray('c')).char
This results in the error:
c
do some extra stuff
Traceback (most recent call last):
File "superctypes.py", line 18, in <module>
print DoesntWork.from_buffer(bytearray('c')).char
File "superctypes.py", line 14, in from_buffer
return super(DoesntWork, cls).from_buffer(buf)
AttributeError: 'super' object has no attribute 'from_buffer'
What am I missing? Why doesn't super work here?
from_buffer is not actually a class method on Structure; it is a method on Structure's type (that is, its metaclass). As such, it can't be overridden in the usual fashion: it's like asking to override a normal method for a single object, not a class.
Calling type(cls).from_buffer(cls,buf) works. It's pretty terrible, but I don't immediately see another option.
In the documentation on instance methods it states that:
Methods also support accessing (but not setting) the arbitrary function attributes on the underlying function object.
But I can't seem to be able to verify that restriction. I tried setting both an arbitrary value and one of the "Special Attributes" of functions:
class cls:
def foo(self):
f = self.foo.__func__
f.a = "some value" # arbitrary value
f.__doc__ = "Documentation"
print(f.a, f.__doc__)
When executed, no errors are produced and the output is as expected:
cls().foo() # prints out f.a, f.__doc__
What is it that I'm misunderstanding with the documentation?
You are misunderstanding what is being said. It says that you can access but not set the attributes of the underlying function object from the method!
>>> class Foo:
... def foo(self):
... self.foo.__func__.a = 1
... print(self.foo.a)
... self.foo.a = 2
...
>>> Foo().foo()
1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in foo
AttributeError: 'method' object has no attribute 'a'
Note how foo.a is updated when you set it on the __func__ value, but you cannot set it directly using self.foo.a = value.
So the function object can be modified as you please, the method wrapper only provides read-only access to the attributes on the underlying function.
Can I dynamically add attributes to instances of a new-style class (one that derives from object)?
Details:
I'm working with an instance of sqlite3.Connection. Simply extending the class isn't an option because I don't get the instance by calling a constructor; I get it by calling sqlite3.connect().
Building a wrapper doesn't save me much of the bulk for the code I'm writing.
Python 2.7.1
Edit
Right answers all. But I still am not reaching my goal; instances of sqlite3.Connection bar my attempts to set attributes in the following ways (as do instances of object itself). I always get an AttributeError:
> conn = sqlite3.connect([filepath])
> conn.a = 'foo'
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
conn.a = 'foo'
AttributeError: 'object' object has no attribute 'a'
> conn.__setattr__('a','foo')
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
conn.__setattr__('a','foo')
AttributeError: 'object' object has no attribute 'a'
Help?
Yes, unless the class is using __slots__ or preventing attribute writing by overriding __setattr__, or an internal Python class, or a Python class implemented natively (usually in C).
You can always try setting an attribute. Except for seriously weird __setattr__ implementations, assigning an attribute to an instance of a class of one of the types mentioned above should raise an AttributeError.
In these cases, you'll have to use a wrapper, like this:
class AttrWrapper(object):
def __init__(self, wrapped):
self._wrapped = wrapped
def __getattr__(self, n):
return getattr(self._wrapped, n)
conn = AttrWrapper(sqlite3.connect(filepath))
Simple experimentation:
In []: class Tst(object): pass
..:
In []: t= Tst()
In []: t.attr= 'is this valid?'
In []: t.attr
Out[]: 'is this valid?'
So, indeed it seems to be possible to do that.
Update:
But from the documentation: SQLite is a C library that ..., so it seems that you really need to wrap it.
conn.a = 'foo',
or any dynamic assignment is valid, if conn is
<type 'classobj'>.
Things like:
c=object()
c.e=1
will raise an Attribute error. On the otherhand: Python allows you to do fantastic Metaclass programming:
>>>from new import classobj
>>>Foo2 = classobj('Foo2',(Foo,),{'bar':lambda self:'bar'})
>>>Foo2().bar()
>>>'bar'
>>>Foo2().say_foo()
>>>foo