Mocking inherited methods - python

Please forgive my noob status, but I have come across a construct I don't really understand and hope someone can explain it for me.
class Base(object):
def mogrify(self, column):
return self.mogrifiers.get(column.lower().strip()) or (lambda x: x)
...
class MyClass(some.package.Base):
def mogrifiers(self):
return {
'column1': (lambda x: datetime.datetime.fromtimestamp(int(x)))
}
...
class MyOtherClass(object):
def convert_columns:
...
new_row[colkey] = self.myclass.mogrify(colkey)(value)
This all works, but I'm trying to write a unit test and mock out MyClass.
As far as I can tell, mogrifiers returns a dictionary of all the columns and any transformations that are required.
The code I am testing calls mogrify (inherited from the Base class) with a specific column name in a string.
This tries to extract the column from the dictionary and returns the lambda function ? or if it doesn't exist in the dictionary, it returns a lambda that just gives the string back ?
So that just leaves me with the (value) bit in the code I'm trying to test. It's no clear what it does.
If I don't want to test the underlying conversion/transformation my mock could just return the simple lambda.
So I've done that, but it throws an exception on the call to mogrify saying:
E TypeError: 'str' object is not callable
Can anyone provide some clues what I'm missing here?

As far as I can tell, mogrifiers returns a dictionary of all the
columns and any transformations that are required.
That is correct, though as you've shown it it will create a fresh dictionary each time which seems unnecessary.
The code I am testing calls mogrify (inherited from the Base class)
with a specific column name in a string.
This tries to extract the column from the dictionary and returns the
lambda function ? or if it doesn't exist in the dictionary, it returns
a lambada that just gives the string back ?
Yes, that is also correct (except that a lambada is a dance, but I think you meant lambda again).
So that just leaves me with the (value) bit in the code I'm trying to
test. It's no clear what it does.
The call self.myclass.mogrify(colkey) returns a callable, the (value) simply calls it. It may be clearer if I rewrite like this:
fn = self.myclass.mogrify(colkey)
new_row[colkey] = fn(value)
splitting it into two lines will also make it clearer whether the problem is with the call self.myclass.mogrify(colkey) or fn(value). If as seems likely it is the fn(value) call it means your mocked mogrify is returning a str instead of returning a callable; it could however be that you got the mock wrong and the mocked mogrify method is actually a string.
I would suggest you rewrite as shown and also insert a print between the two lines and see what is actually being returned.

Related

Simplified string alignment with a function?

I have a python program with lots of text I want to align and .format seemed messy, so I planned on using .center(shutil.get_terminal_size().columns) on the end of a print like so:
import shutil
print("Hello world!".center(shutil.get_terminal_size().columns))
and should be returned centered in my console, and it is.
However, If I want to simplify this into a single function:
def align_center():
center(shutil.get_terminal_size().columns)
and add that to the end of a print fuction:
print("Hello World!".align_center())
(I've also tried it without the parentheses at the end of .align_center)
it returns:
AttributeError: 'str' object has no attribute 'align_center'
I'm pretty sure I had it working correctly earlier but I changed something and it stopped, Am I crazy and this simplification via a function isn't possible? Am I applying it wrong?
I don't think you ever had it working if you simply appended it to the string. That would make it an atrribute and the str object is unlikely to have an attribute that matches the name of an arbitrary method you created.
This might help: pass the string to the method and return it formatted. Something like this:
def align_center(s):
return s.center(shutil.get_terminal_size().columns)
then:
print(align_center(s))

returning functions from a method in python

I have tried looking into the documentation and google search , but I am unable to find out the significance of the [clazz] at the end of method. Could someone help me understand the meaning of the [clazz] at the end of the method? Thanks.
def get_context_setter(context, clazz):
return {
int: context.setFieldToInt,
datetime: context.setFieldToDatetime
}[clazz]
setFieldToInt and setFieldToDatetime are methods inside context class.
This function returns one of two things. It returns either context.setFieldToInt or context.setFieldToDatetime. It does so by using a dictionary as what would be a switch statement in other programming languages.
It checks whether clazz is a reference to the class int or a reference to the class datetime, and then returns the appropriate method.
It's identical to this code:
def get_context_setter(context, clazz):
lookup_table = {int: context.setFieldToInt,
datetime: context.setFieldToDatetime
}
context_function = lookup_table[clazz] # figure out which to return
return context_function
Using a dict instead of a switch statement is pretty popular, see Replacements for switch statement in Python? .
More briefly.
The code presented is expecting the class of some object as a parameter poorly named as clazz.
It's then using that class as a dictionary key.
They're essentially trying to accept two different types and call a method on the object type.
class is a keyword in Python.
The author of the code you show chose to use a strange spelling instead of a longer snake_case parameter name like obj_class.
The parameters really should have been named obj, obj_class
Or
instance, instance_class
Even better, the class really need not be a separate parameter.

How to pass parameters in a Python Dispatch Table

I am trying to construct a dispatch the following way:
def run_nn(type=None):
print type, 'nn'
return
def run_svm(type=None):
print type, 'svm'
return
action = {'nn' : run_nn( type=None),
'svm' : run_svm(type=None),}
I want the function to be executed only when called with something like:
action.get('nn',type='foo')
With expectation it to print:
foo nn
But it breaks giving:
TypeError: get() takes no keyword arguments
What's the right way to do it?
Furthermore, two functions run_nn() and run_svm() were executed without even being called. I don't want that. How can I avoid it?
You're calling the functions while building the dictionary. You should instead put the function objects in the dict without calling them. And afterwards, get the appropriate function from the dict and call it with the keyword argument.
What you want is:
action = {'nn' : run_nn,
'svm' : run_svm,}
...
action.get('nn')(type='foo') # get function object from dict and then call it.
I'll suggest you use action['nn'] over action.get('nn') since you're not specifying any default callable in the get method; the get method returns None when you don't specify one. A KeyError is much more intuitive than a TypeError NoneType object is not callable in this scenario.
On another note, you can drop those return statements as you aren't actually returning anything. Your function will still return without them.
BTW, I have the feeling your function(s) want to change behavior depending on type (although your type is counter-intuitive as it is always a string). In any case, you may have a look at functools.singledispatch. That'll transform your function(s) into a single-dispatch generic function with the possibility to create several overloaded implementations.
Finally, although type does make for a good argument name, you will run into problems when you need to use the builtin type in your function.

Why am I getting this TypeError?

RESOLVED: Okay, you guys probably won't believe this. I did a lot of digging and it turns out that all the files we are loading and using were created incorrectly. The files fail to conform with the code we are writing — the things we want to do in our program are simply not possible based on the current state of the files we load. I am currently working on fixing this. Sorry about the non-question, guys!
In Python I have code that essentially reads as follows:
partsList = getPartsList() # this function returns a list
for part in partsList:
...
bar(partsList)
def bar(partsList):
for part in partsList:
...
But when I run the code I get the following TypeError:
TypeError: iteration over non-sequence
This TypeError is in reference to the noted line:
def bar(partsList):
for part in partsList: # this is the line with the TypeError
...
How can this be? I know that partsList is not a non-sequence because just before my program calls bar(partsList), I explicitly iterate over partsList.
My function does not modify partsList before interacting with it, and I do not modify partsList when iterating through it prior to calling the function, yet somehow it changes from a list to a non-sequence when the function is called.
I am working entirely within a class so these are all methods actually; I just thought it would be easier to read if I present the code this way.
The following is in response to the comments:
I wish I could provide you all with the full code, but at the moment the program requires exactly 275 files to run and has 20+ .py files. I will mention that the method in question does employ recursion after iteration through its given list. I thought this may be linked to the error, but when when attempting to print the list itself and its contents, the program gave the same TypeError before making it through the method even once, so I know that this is not due to the recursion; it never even recursed.
Ok I have inserted print statements as follows (keep in mind these are within methods in a class):
def someMethod(self):
...
partsList = self.getPartsList() # this function returns a list
for part in partsList:
...
print partsList # prints [object(1), object(2)]
self.bar(partsList)
def bar(self, partsList):
print partsList # prints <filename.class instance at 0x04886148>
for part in partsList: # still gives me the TypeError
...
When I say filename.class I don't literally mean filename and class. You guys know what I mean.
Is the second print statement printing <filename.class instance at 0x04886148> because it is pointing to the actual partsList? I'm not entirely sure how pointers and references work in Python.
You don't define bar correctly; its first argument is a reference to the object that calls it, and the second argument is the list you pass as the explicit argument.
def bar(self, partsList):
for part in partsList:
...
Your answer is there in the print lines.
def bar(self, partsList):
print partsList # prints <filename.class instance at 0x04886148>
for part in partsList: # still gives me the TypeError
...
partsList isn't a list going into this method. Here is some tweaked, functioning, example code from your code:
class myClass():
def someMethod(self):
partsList=self.getPartsList()
for part in partsList:
print part
self.bar(partsList)
def bar(self, pList):
print pList
for part in pList:
print part
def getPartsList(self):
return ['a', 'b', 'c']
Running this interactively gets me this:
from fake_try import myClass
x = myClass()
x.someMethod()
a
b
c
['a', 'b', 'c']
a
b
c
You'll notice that when I called "print pList" I received a pretty print output of the list. You are receiving an object of your class type.
I understand and empathize with your situation. Having a large, complex program throwing errors can be quite painful to debug. Unfortunately without seeing your entire code I don't think anyone here will be able to debug your issue because my guess is that you are calling 'someMethod' in a way that is unexpected in the actual code(or in an unexpected place) which is causing you to have issues.
There are a couple of ways you can debug this.
I am assuming that everything ran UNTIL you added the someMethod functionality? Revert your code to a state prior to the error and add lines on at a time(with dummy functions if neccesary) to find exactly where the unexpected value is coming from. If you cannot revert my first step would be to simplify all logic surrounding this issue. You have a function 'getPartsList()' that's supposed to return a list. It looks like it is here, but make it even easier to check. Make a dummy function that simply returns a fake list and see what the behavior is. Change things one step at a time until you iron out where the issue is.
You may not be familiar with the inspect module. Try importing inspect in your module and using inspect.getmember(x) with x being the object you want more information about. I would probably use this in place of you print partsList in the bar method( something like inspect.getmember(partsList) ) I would guess that you're somehow passing a class there instead of the list, this should tell you what that class has been instantiated as.

How can I add a required argument to existing python function using a decorator?

So, I would like to modify the json.loads() function to accept a new keyword parameter, but not have it just be a part of kwargs. In other words, I want it be an explicit part of the function's signature.
Here's my guess on how to do this. Are there better ways of doing this?
def json_to_python_syntax(json_method):
"""
Translate JSON-conforming key names to Pythonic standards on dict.
The goal of this decorator is to add a standard keyword parameter
'convert_syntax' onto the method. But, I'm not sure how to do this.
"""
#wraps(json_method)
def wrapper(json_string, convert_syntax=False, **kwargs):
pythonic_dict = dict()
json_syntax_dict = json_method(json_string, **kwargs)
if not convert_syntax:
return json_syntax_dict
for key, value in json_syntax_dict.iteritems():
for json_syntax in re.finditer(r'[A-Z]', key):
key = key.replace(
json_syntax.group(), '_' + json_syntax.group()[0].lower())
pythonic_dict[key] = value
return pythonic_dict
return wrapper
My concern with this method is that it this monkeys with the expected order of keyword parameters in json.loads (It makes convert_syntax the first expected parameter after the json string) and could mess up other calls to json.loads within the larger program that assume the standard order.
Seeing as your change breaks the expected signature of json.loads and you're concerned with it breaking other code that depends on the original signature, I'd agree with Simeon Visser, seems like you shouldn't do this at all.
Only code you write will be able to properly call your new method, so why not give your method a different name, rather than decorating an existing method? If you want to prevent other code from calling this method without the convert_syntax flag, just avoid importing the json module at all, and instead import your json library that wraps the json module.

Categories