AttributeError: 'function' object has no attribute ''index" - python

In python, I'm trying to get a depth of recursion(dor). Before adding all the dor things into my code, it worked ~fine, but after adding the dor stuff, I received an attribute error concerning my code. Here is the function where I'm receiving the error
def parse(json,dor=0):
parse.index[dor]=0
parse.keyList[dor]=[]
parse.jsonDict[dor]=dict()
parse.json[dor]=remove_white(json)

Disclaimer: what you are doing is most likely The Wrong Thing To Do
Your code worked before because (I assume) you were setting an attribute on a function object:
def foo():
foo.bar = 4
When run, the function object sets an attribute bar on itself. However, when you added the __setitem__ (with the square brackets):
def foo():
foo.bar[dor] = 4
You're now saying that you want to modify foo.bar, but foo.bar doesn't exist yet! You can "fix" this by setting up the object manually, before you run it for the first time:
def foo():
foo.bar[dor] = 4
foo.bar = {}
foo()
Most likely, you want to avoid this whole mess altogether by using a separate object to keep track of the recursion depth in your code. Just because you can do something doesn't mean you should.
EDIT: Looking at your code, it seems like you should be using a class instead of a function for parse. Using a class makes sense because you're encapsulating mutable state with a set of methods that act on it. Of course, I'm also obligated to point you to the standard library JSON module.

Related

How to dynamically return Object attributes in python, including attributes of objects that are attributes

I am trying to write a testing program for a python program that takes data, does calculations on it, then puts the output in a class instance object. This object contains several other objects, each with their own attributes. I'm trying to access all the attributes and sub-attributes dynamically with a one size fits all solution, corresponding to elements in a dictionary I wrote to cycle through and get all those attributes for printing onto a test output file.
Edit: this may not be clear from the above but I have a list of the attributes I want, so using something to actually get those attributes is not a problem, although I'm aware python has methods that accomplish this. What I need to do is to be able to get all of those attributes with the same function call, regardless of whether they are top level object attributes or attributes of object attributes.
Python is having some trouble with this - first I tried doing something like this:
for string in attr_dictionary:
...
outputFile.print(outputclass.string)
...
But Python did not like this, and returned an AttributeError
After checking SE, I learned that this is a supposed solution:
for string in attr_dictionary:
...
outputFile.print(getattr(outputclass, string))
...
The only problem is - I want to dynamically access the attributes of objects that are attributes of outputclass. So ideally it would be something like outputclass.objectAttribute.attribute, but this does not work in python. When I use getattr(outputclass, objectAttribute.string), python returns an AttributeError
Any good solution here?
One thing I have thought of trying is creating methods to return those sub-attributes, something like:
class outputObject:
...
def attributeIWant(self,...):
return self.subObject.attributeIWant
...
Even then, it seems like getattr() will return an error because attributeIWant() is supposed to be a function call, it's not actually an attribute. I'm not certain that this is even within the capabilities of Python to make this happen.
Thank you in advance for reading and/or responding, if anyone is familiar with a way to do this it would save me a bunch of refactoring or additional code.
edit: Additional Clarification
The class for example is outputData, and inside that class you could have and instance of the class furtherData, which has the attribute dataIWant:
class outputData:
example: furtherData
example = furtherData()
example.dataIWant = someData
...
with the python getattr I can't access both attributes directly in outputData and attributes of example unless I use separate calls, the attribute of example needs two calls to getattr.
Edit2: I have found a solution I think works for this, see below
I was able to figure this out - I just wrote a quick function that splits the attribute string (for example outputObj.subObj.propertyIWant) then proceeds down the resultant array, calling getattr on each subobject until it reaches the end of the array and returns the actual attribute.
Code:
def obtainAttribute(sample, attributeString: str):
baseObj = sample
attrArray = attributeString.split(".")
for string in attrArray:
if(attrArray.index(string) == (len(attrArray) - 1)):
return getattr(baseObj,string)
else:
baseObj = getattr(baseObj,string)
return "failed"
sample is the object and attributeString is, for example object.subObject.attributeYouWant

Python Mocking assert_called not working

I am able to successfully mock a function, and I am sure that the original is not called. I added a huge print statement to the original function and when I mock it, this print is not called. When I turn the mock back on, the print statement is not called.
However, my assert_called is failing saying it was never called. Has anyone ever experienced something like this?
class FooTestCase(unittest.TestCase):
#mock.patch('MyObj.helper_function')
def test_simple(self, mock_hf):
my_obj = MyObj()
# internally, this class imports HelperModule
# and the method calls helper_function
my_obj.do_something()
mock_hf.helper_function.assert_called()
return
My error response
AssertionError: Expected 'helper_function' to have been called.
Update
I just added the following lines right before the assertion
print mock_cw.method_calls
print mock_cw.mock_calls
method_calls is an empty list, while mock_calls is a list with 1 item which is
[call(arg1_expected_for_helper_fn, arg2_expected_for_helper_fn)]
Yet the assert still fails
Usually an error like this is a result of not patching the correct location. Try to patch the object itself with this:
#patch.object(MyObj, "helper_function")
def test_simple(mock_hf):
...
Since MyObj is (assumed to be) imported at the top of the test file, this patches the method on that object directly.
The issue is that I was checking to see if mock_hf.helper_function was called, but mock_hf is already mapped to the helper_function. I was more or less checking that helper_function.helper_function was called rather than just helper_function.
The assert line needed to be
mock_hf.assert_called()
I see the original poster has done this, but for anyone else stumbling on this as I did...
Don't forget you need to wrap your expected calls in a call object e.g.
mock_logger.assert_has_calls([call(expected_log_message_1), call(expected_log_message_2)])
If you don't do that, it will complain that the expected call did not happen and you will spend ages comparing the output to try and work out why (as I did!).

Python unable to compare bound method to itself

I am attempting to write a test that checks if a variable holding the bound method of a class is the same as another reference to that method. Normally this is not a problem, but it does not appear to work when done within another method of the same class. Here is a minimal example:
class TestClass:
def sample_method(self):
pass
def test_method(self, method_reference):
print(method_reference is self.sample_method)
I am really using an assert instead of print, but that is neither here nor there since the end result is the same. The test is run as follows:
instance = TestClass()
instance.test_method(instance.sample_method)
The result is False even though I am expecting it to be True. The issue manifests itself in both Python 3.5 and Python 2.7 (running under Anaconda).
I understand that bound methods are closures that are acquired by doing something like TestClass.test_method.__get__(instance, type(instance)). However, I would expect that self.sample_method is already a reference to such a closure, so that self.sample_method and instance.sample_method represent the same reference.
Part of what is confusing me here is the output of the real pytest test that I am running (working on a PR for matplotlib):
assert <bound method TestTransformFormatter.transform1 of <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>> is <bound method TestTransformFormatter.transform1 of <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>>
E + where <bound method TestTransformFormatter.transform1 of <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>> = <matplotlib.ticker.TransformFormatter object at 0x7f0101077e10>.transform
E + and <bound method TestTransformFormatter.transform1 of <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>> = <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>.transform1
If I understand the output correctly, the actual comparison (the first line) is really comparing the same objects, but somehow turning up False. The only thing I can imagine at this point is that __get__ is in fact being called twice, but I know neither why/where/how, nor how to work around it.
They're not the same reference - the objects representing the two methods occupy different locations in memory:
>>> class TestClass:
... def sample_method(self):
... pass
... def test_method(self, method_reference):
... print(hex(id(method_reference)))
... print(hex(id(self.sample_method)))
...
>>> instance = TestClass()
>>> instance.test_method(instance.sample_method)
0x7fed0cc561c8
0x7fed0cc4e688
Changing to method_reference == self.sample_method will make the assert pass, though.
Edit since question was expanded: seems like a flawed test - probably the actual functionality of the code does not require the references to be the same (is), just equal (==). So your change probably didn't break anything except for the test.
While the accepted answer is in no way incorrect, it seems like it should be noted that methods are bound on attribute lookup. Furthermore, the behavior of unbound methods changes between Python 2.X and Python 3.X.
class A:
def method(self):
pass
a = A()
print(a.method is a.method) # False
print(A.method is A.method) # Python 3.X: True, Python 2.X: False

Python - Mocking an object's attribute with multiple values?

I have an object method which changes an attribute of an object. Another method (the one I'm trying to test) calls the first method multiple times and afterward uses the attribute that was modified. How can I test the second method while explicitly saying how the first method changed that attribute?
For example:
def method_to_test(self):
output = []
for _ in range(5):
self.other_method()
output.append(self.attribute_changed_by_other_method)
return output
I want to specify some specific values that attribute_changed_by_other_method will become due to other_method (and the real other_method uses probabilities in deciding on how to change attribute_changed_by_other_method).
I'm guessing the best way to do this would be to "mock" the attribute attribute_changed_by_other_method so that on each time the value is read it gives back a different value of my specification. I can't seem to find how to do this though. The other option I see would be to make sure other_method is mocked to update the attribute in a defined way each time, but I don't know of a particularly clean way of doing this. Can someone suggest a reasonable way of going about this? Thank you much.
What you can actually do is use flexmock for other_method. What you can do with flexmock is set a mock on an instance of your class. Here is an example of how to use it:
class MyTestClass(unittest.TestCase):
def setUp(self):
self.my_obj = MyClass()
self.my_obj_mock = flexmock(self.my_obj)
def my_test_case(self):
self.my_obj_mock.should_receive('other_method').and_return(1).and_return(2).and_return(3)
self.my_obj.method_to_test()
So, what is happening here is that on your instance of MyClass, you are creating a flexmock object out of self.my_obj. Then in your test case, you are stating that when you make your call to method_to_test, you should receive other_method, and each call to it should return 1, 2, 3 respectively.
Furthermore, if you are still interested in knowing how to mock out attribute_changed_by_other_method, you can use Mock's PropertyMock:
Hope this helps. Let me know how it goes!
For anyone still looking for a straightforward answer, this can be done easily with PropertyMock as the accepted answer suggests. Here is one way to do it.
from unittest.mock import patch, PropertyMock
with patch("method_your_class_or_method_calls", new_callable=PropertyMock) as mock_call:
mock_call.side_effect = [111, 222]
class_or_method()
Each subsequent call of that patched method will return that list in sequence.

How do I call a method from a superclass, whos definition is completely deferred to the subclasses?

I want to envoke a method in my code in a supercass, to do some subclass- specific processing before continuing on. I come to python recently from C#... there, I'd probably use an interface. Here's the gist of it (as I picture it, but it's not working):
class superClass:
def do_specific_stuff(self): #To be implemented entirely by the subclass,
#but called from the superclass
pass
def do_general_stuff1(self):
#do misc
def do_general_stuff2(self):
#do more misc
def main_general_stuff(self):
do_general_stuff1()
do_specific_stuff()
do_general_stuff2()
I have a rather complicated implementation of this; this example is exactly what I need and far less painful to understand for a first- time viewer. Calling do_specific_stuff() at the moment gives me the error
'global name 'do_specific_stuff' is not defined.
When I add 'self' as in self.do_specific_stuff I get the error
'TypeError: do_specific_stuff() takes 0 positional arguments but 1 was given.' Any takers? Thanks in advance...
It needs to be
def main_general_stuff(self):
self.do_general_stuff1()
self.do_specific_stuff()
...
The problem is that you are missing the explicit reference to self: Python thinks you mean a global function without it. Note that there is no implicit this like in Java: You need to specify it.

Categories

Resources