Python using mock for a multiple user inputs - python

A follow on for this question.
I am accepting user input in a for loop and have written a test case, test_apple_record. In this for loop, it queries a method self.dispatch_requested() ( not shown) which can randomly return True or False. Based on this answer, the code asks user for another input -- where the tray should be dispatched.
I am using the side_effect argument for mock.patch. How to automatically pass the hotel number as the user input using mock? I still want to continue passing the numbers [5, 6, 7] to the for loop, but now also want to pass in the hotel number based on response by self.dispatch_requested()
thank you
class SomeClass(unittest.TestCase):
def apple_counter(self):
apple_record = {}
for i in range(3):
apple_tray = input("enter tray number:")
apple_record[apple_tray] = (i+1)*10
print("i=%d, apple_record=%s"%(i, apple_record))
if self.dispath_requested():
number = input("Enter Hotel number to dispatch this tray:")
update_hotel_record(number, apple_tray)
def update_hotel_record(self, number, tray):
self.hotel_record[number] = tray
def test_apple_record(self):
with mock.patch('builtins.input', side_effect=[5, 6, 7]):
self.apple_counter()

You actually want your side_effect to look like this:
m_input.side_effect = [1, 100, 2, 200, 3, 300]
Each time the input method is called, it will return the next item. So each time in your loop, you call input twice.
Also, I don't know the final structure of your unit test, however, seeing that you have a conditional statement around the second input that is called in your loop, you should probably set a mock around that method to always return True.
When you get to the scenario where you want to test your code for when self.dispath_requested() returns false, you have to keep in mind the second input will not be called, so your side_effect has to be re-written accordingly to match the expected behaviour for your code.
Also, finally, again, I'm not sure what your code actually looks like, however, based on how you seem to have your actual implementation and test code under the same class, I strongly advise not doing that. Try a structure similar to this:
Create a separate test class:
class Tests(unittest.TestCase):
def setUp(self):
self.s = SomeClass()
#patch('__builtin__.input')
def test_apple_record(self, m_input):
m_input.side_effect = [1, 100, 2, 200, 3, 300]
self.s.apple_counter()
if __name__ == '__main__':
unittest.main()
So, you create an instance of SomeClass, and then this in effect will let you mock out the properties of the object much easier, which will make your unit tests much easier to write.
You will also notice that I used a decorator (#patch) instead of the "with" context. It's a personal preference, and I find it much easier to read the code using decorators.
Hope this helps.

Turns out my last answer was not useless after all! As there is no way of knowing which input you require but to read the prompt, you could simply replace the input() function with one that gives different answers depending on the prompt.
# first we need a generator for each type of response to `input()`
def tray_number_generator():
trays = ["1", "5", "7"]
for i in trays:
yield i
trays = tray_number_generator()
def room_number_generator():
rooms = ["112", "543", "724"]
for i in rooms:
yield i
rooms = room_number_generator()
# this can be written simpler as a generator expression like this:
trays = (tray for tray in ["1", "5", "7"])
rooms = (room for room in ["112", "543", "724"])
# now you can write a function that selects the next output depending on the prompt:
def mock_input(prompt):
if "room" in prompt.lower():
return next(rooms)
if "tray" in prompt.lower():
return next(trays)
# this can now be used to replace the `input()` function
with mock.patch('builtins.input', mock_input):
do_stuff()

I don't want go deeply in how mock both input and dispatch_requested and couple the answers to have a complete control and write a good unit test for this method. I think it is more interesting how to change your design to make the test (and so the code) simpler and more clear:
class SomeClass(object):
def apple_counter(self):
apple_record = {}
for i in range(3):
apple_tray = input("enter tray number:")
apple_record[apple_tray] = (i+1)*10
print("i=%d, apple_record=%s"%(i, apple_record))
self._dispatch_and_ask_number()
def _dispatch_and_ask_number(self):
if self.dispatch_requested():
number = self._ask_hotel_number()
update_hotel_record(number, apple_tray)
def _ask_try_number(self):
return input("enter tray number:")
def _ask_hotel_number(self):
return input("Enter Hotel number to dispatch this tray:")
def update_hotel_record(self, number, tray):
self.hotel_record[number] = tray
Now you are in a better position to create a new class with just one responsibility of ask user input and then mock it to have a complete control in your test:
class AskUserInput(class):
try_number_message = "Enter tray number:"
hotel_number_message = "Enter Hotel number to dispatch this tray:"
def try_number(self):
return input(self.try_number_message)
def hotel_number(self):
return input(self.hotel_number_message)
And SomeClass can be changed like:
class SomeClass(object):
_ask = AskUserInput()
def apple_counter(self):
apple_record = {}
for i in range(3):
apple_tray = self._ask.try_number()
apple_record[apple_tray] = (i+1)*10
print("i=%d, apple_record=%s"%(i, apple_record))
self._dispatch_and_ask_number()
def _dispatch_and_ask_number(self):
if self.dispatch_requested():
number = self._ask.hotel_number()
update_hotel_record(number, apple_tray)
def update_hotel_record(self, number, tray):
self.hotel_record[number] = tray
And finally the test
class TestSomeClass(unittest.TestCase):
#patch("AskUserInput.try_number")
#patch("AskUserInput.hotel_number")
def test_apple_record(self, mock_try_number, mock_hotel_number):
# Now you can use both side_effects and return_value
# to make your test clear and simple on what you test.
If you are playing with legacy code this approch is not really useful, but if you are testing something that you are developing now is better to turn it in a more testable code: make your code more testable improve design almost every times.

Related

How do I access the parameters of the function one by one?

So, I'm still learning how to code and I'm making this higher or lower game, and I made a function that pulls out info from a huge list with dictionaries inside it called "data":
Here is my code so far:
def choice_of_oponents(opponent1, opponent2):
"""
Gets the info on 2 people randomly and assigns them to the variables 'opponent1' and 'opponent2'
"""
opponent1 = random.choice(data)
opponent2 = random.choice(data)
def winner(opponent1, opponent2):
#This function is supposed to pull out the info stored in the parameters in the first function and determine the winner based on the data
I'm not sure how to write the second function or if it is even possible to pull out info from the parameters of the 1st function without making extra variables. Can someone help solve this?
Maybe what you're missing is the concept of return-ing the output of a function. Also, you don't need any inputs to your first function (note that you didn't use them anyway).
Try something like this:
def choice_of_opponents():
"""
Gets the info on 2 people randomly and assigns them to the variables
'opponent1' and 'opponent2'
"""
opponent1_result = random.choice(data)
opponent2_result = random.choice(data)
return opponent1_result, opponent2_result
def winner(opponent1, opponent2):
if opponent1 > opponent2:
return 1
elif opponent2 > opponent1:
return 2
else:
return 0 # A tie
op1, op2 = choice_of_opponents()
print(winner(op1, op2))

Controlling dynamic properties in Shady according to video frames not time

I am trying to use Shady to present a sequence of image frames. I'm controlling the flow from another machine, so that I first instruct the machine running Shady to present the first frame, and later on to run the rest of the frames.
I create a World instance, and attach to it an animation callback function. Within this callback I listen for communications from the other machine (using UDP).
First I receive a command to load a given sequence (stored as a numpy array), and I do
def loadSequence(self, fname):
yy = np.load(fname)
pages = []
sz = yy.shape[0]
for j in range(yy.shape[1]/yy.shape[0]):
pages.append(yy[:, j*sz:(j+1)*sz])
deltax, deltay = (self.screen_px[0] - sz) / 2, (self.screen_px[1] - sz) / 2
if (self.sequence is None):
self.sequence = self.wind.Stimulus(pages, 'sequence', multipage=True, anchor=Shady.LOCATION.UPPER_LEFT, position=[deltax, deltay], visible=False)
else:
self.sequence.LoadPages(pages, visible=False)
When I receive the command to show the first frame, I then do:
def showFirstFrame(self, pars):
self.sequence.page = 0 if (pars[0] == 0) else (len(self.sequence.pages) - 1)
self.sequence.visible = True
But what do I do now to get the other frames to be be displayed? In the examples I see, s.page is set as a function of time, but I need to show all frames, regardless of time. So I was thinking of doing something along these lines:
def showOtherFrames(self, pars, ackClient):
direction, ack = pars[0], pars[2]
self.sequence.page = range(1, len(self.sequence.pages)) if (direction == 0) else range(len(self.sequence.pages)-2, -1, -1)
But this won't work. Alternatively I thought of defining a function that takes t as argument, but ignores it and uses instead a counter kept in a global variable, but I'd like to understand what is the proper way of doing this.
When you make s.page a dynamic property, the function assigned to it must take one argument (t), but you can still just use any variables in the space when defining that function, and not even use the time argument at all.
So, for example, you could do something as simple as:
w = Shady.World(...)
s = w.Stimulus(...)
s.page = lambda t: w.framesCompleted
which will set the page property to the current frame count. That sounds like it could be useful for your problem.
Your global-variable idea is one perfectly valid way to do this. Or, since it looks like you're defining things as methods of an instance of your own custom class, you could use instance methods as your animation callbacks and/or dynamic property values—then, instead of truly global variables, it makes sense to use attributes of self:
import Shady
class Foo(object):
def __init__(self, stimSources):
self.wind = Shady.World()
self.stim = self.wind.Stimulus(stimSources, multipage=True)
self.stim.page = self.determinePage # dynamic property assignment
def determinePage(self, t):
# Your logic here.
# Ignore `t` if you think that's appropriate.
# Use `self.wind.framesCompleted` if it's helpful.
# And/or use custom attributes of `self` if that's
# helpful (or, similarly, global variables if you must).
# But since this is called once per frame (whenever the
# frame happens to be) it could be as simple as:
return self.stim.page + 1
# ...which is indefinitely sustainable since page lookup
# will wrap around to the number of available pages.
# Let's demo this idea:
foo = Foo(Shady.PackagePath('examples/media/alien1/*.png'))
Shady.AutoFinish(foo.wind)
Equivalent to that simple example, you could have the statement self.stim.page += 1 (and whatever other logic) inside a more-general animation callback.
Another useful tool for frame-by-frame animation is support for python's generator functions, i.e. functions that include a yield statement. Worked examples are included in python -m Shady demo precision and python -m Shady demo dithering.
It can also be done in a StateMachine which is always my preferred answer to such things:
import Shady
class Foo(object):
def __init__(self, stimSources):
self.wind = Shady.World()
self.stim = self.wind.Stimulus(stimSources, multipage=True)
foo = Foo(Shady.PackagePath('examples/media/alien1/*.png'))
sm = Shady.StateMachine()
#sm.AddState
class PresentTenFrames(sm.State):
def ongoing(self): # called on every frame while the state is active
foo.stim.page += 1
if foo.stim.page > 9:
self.ChangeState()
#sm.AddState
class SelfDestruct(sm.State):
onset = foo.wind.Close
foo.wind.SetAnimationCallback(sm)
Shady.AutoFinish(foo.wind)

Python (Alternate two messages)

I have some code, and my goal is to make it so that when left button is clicked it will post text saying "Programming is fun!" and when it is pressed again, it will change that text to "It is fun to program", my idea was to make x = 0 if I wanted the first statement, and x = 1 if I wanted the second statement, but it keeps saying x is not defined, I've tried returning x but it simply won't... I've tried a variety of different methods but I can't figure it out. Thoughts? I'd like an alternative method to this, because I'm not sure that mine will work.
def text():
pf = Label(window2,text="Programming is fun")
pf.pack()
x = 0
def text2():
fp = Label(window2,text="It is fun to program")
fp.pack()
x = 1
def bt(event):
if x == 0:
text()
elif x == 1:
text2()
window2 = Tk()
window2.geometry("500x500")
The problem is that, in the scope of your functions, the variable x is indeed undefined.
An example:
height = 5
def some_function():
# code here can not access height just like that
When you want to access variables in functions, you generally have three options:
1) Put your code in a class instead. This requires some understanding of object oriented programming, and if you're a beginner this might not be the best choice for you
2) Pass the variable as an argument to the function and add it to the function's parameter list, for example like this:
def my_function(height):
# here height can be used
And when calling the function:
height_of_bob = 2
my_function(height_of_bob)
3) Use a global variable. This is usually not necessary, and is considered bad practice in general, but it will solve your problem just fine.
I found a way to do this below, the down low is that it's creating the text through that function, and then it's rebinding the key to do other function and then that function deletes previous text, creates the new text and then rebinds to the previous function, and the cycle continues. Here's the code.
def text(event):
global pf
fp.pack_forget()
pf = Label(window2,text="Programming is fun")
pf.pack()
window2.bind("<Button-1>", text2)
def text2(event):
global fp
pf.pack_forget()
fp = Label(window2,text="It is fun to program")
fp.pack()
window2.bind("<Button-1>", text)
window2 = Tk()
window2.geometry("500x500")
pf = Label(window2,text="Programming is fun")
fp = Label(window2,text="It is fun to program")
window2.bind("<Button-1>", text)

Function runs by itself but not when in a class

class Fibonacci:
def fn(num):
if num <= 0:
return 0
if num <= 1:
return 1
else:
Result = fn(num - 1) +fn(num - 2)
return Result
amount = int(input("How many numbers do you want? : "))
i = 1
while i < amount:
FibValue = fn(i)
print(FibValue)
i += 1
Fibonacci()
Here are my errors:
File "C:/Users/Carsten/PycharmProjects/untitled/Lesson13.py", line 30, in <module>
class Fibonacci:
File "C:/Users/Carsten/PycharmProjects/untitled/Lesson13.py", line 45, in Fibonacci
FibValue = fn(i)
File "C:/Users/Carsten/PycharmProjects/untitled/Lesson13.py", line 38, in fn
Result = fn(num - 1) +fn(num - 2)
NameError: name 'fn' is not defined
I'm not quite sure as to why I can run the def Fibonacci: function on its own but as soon as I put it under a class it gives me these errors. I'm still a beginner and have little idea of what these errors mean but even looking them up isn't of much assistance. Any help is appreciated. I realize I can use this as just a standalone function but I'm in the middle of a problem in the youtube series I'm watching to teach myself and I don't want to simply skip ahead in the video and just see the answer to the rest of the problem. Thanks
When you change the function to a class method (i.e. put it inside the class), then only an object of that class can invoke the function. The syntax is as stanleyli mentioned. Perhaps a little more clear:
fib_obj = Fibonacci()
fib_value = fib_obj.fn(i)
As Ignazio already pointed out, this is a very poor example of Class usage. The class has no attributes (data associated with the object), and making the class only makes it harder to use the function.
A Class is better used when you have a collection of data and functions that act on that data, where the combination embodies a higher-level concept. For instance, a game board with piece locations and movement functions would be a good use of a class.
I understand now. Also see the tutorial references here. Essentially, an iterable is a Class that includes a next (explicit) and/or __next__ (implicit) method. That's why you start with the class structure.
Once you've done that, your main program reduces to
for i in Fibonacci(amount):
print i

Where to put this class in django?

I have a class for data entry that requires a lot of input from the user. I use it to semi-automate the process of putting stuff in the db where it is possible.
My instinct is to put it in my model classes, and write tests on it, but it would be an insane amount of work, and I have a lot of raw_input() functions and logic loops that I don't know how to test or what to do with.
Should I keep this module separate or try to include it in the model classes?
def define(self, word=False, word_pk=False):
'''Defining a word, there may be language specific elements to edit in here'''
try:
if word_pk:
word = Word.objects.get(id=word_pk)
else:
word = Word.objects.get(language__name=self.language_ISO, name=word)
except:
return "Word lookup failed for word=%s word_pk=%s\n" % (word, word_pk)
print "\n\tThe Word is: '%s'...\n" % (word)
wiktionary_list = word.wiktionary_lookup(self.wiktionary_prefix, self.driver)
wn_tuple = word.wn_lookup()
while choice("Would you like to add a/another definition for '%s'?: " % word):
#Ask the user if they want to use the wn output for definitions, make them select which ones
if choice("Would you like to choose a wordnet definition?: "):
chosen_defs = ask_input("Which ones? (choose all that apply with a space between numbers): ")
chosen_defs = [int(i) for i in (chosen_defs.split())]
#Wornet only gives part of speech and definition information so I need to split that here.
for i in chosen_defs:
#Print_n_save function will return False if it exits successfully, so there is an option to repeat this loop if the user makes a mistake somewhere
repeat = True
while repeat:
tup = wn_tuple[i]
print "\n(%s) - %s\n" % (tup[0], tup[1])
audio_tup = self.add_audio(word)
picture_tup = self.add_picture(word)
new_definition = Definition()
new_definition.word=word
new_definition.part_speech= tup[0]
new_definition.definition=tup[1]
new_definition.def_source="Wordnet"
new_definition.add_pronunciation()
new_definition.word_audio=audio_tup[0]
new_definition.audio_source=audio_tup[1]
new_definition.picture=picture_tup[0]
new_definition.pic_source=picture_tup[1]
repeat = self.print_n_save(new_definition)
elif choice("Would you like to choose a wiktionary definition?: "):
choose_defs = ask_input("Which ones would you like to choose? (Numbers separated by spaces): ")
chosen_defs = [int(i) for i in choose_defs.split()]
for i in chosen_defs:
#Print_n_save function will return False if it exits successfully, so there is an option to repeat this loop if the user makes a mistake somewhere
repeat = True
while repeat:
print "\n%s\n" % (wiktionary_list[i])
audio_tup = self.add_audio(word)
picture_tup = self.add_picture(word)
new_definition = Definition()
new_definition.word=word
new_definition.get_pos()
new_definition.definition=wiktionary_list[i]
new_definition.def_source="Wiktionary"
new_definition.add_pronunciation()
new_definition.word_audio=audio_tup[0]
new_definition.audio_source=audio_tup[1]
new_definition.picture=picture_tup[0]
new_definition.pic_source=picture_tup[1]
repeat = self.print_n_save(new_definition)
else:
#Print_n_save function will return False if it exits successfully, so there is an option to repeat this loop if the user makes a mistake somewhere
repeat = True
while repeat:
#Asking for definition, inputting raw from some internet source
definition = ask_input("What is the definition?: ")
definition_source = ask_input("What is the source of the definition?: ")
audio_tup = self.add_audio(word)
picture_tup = self.add_picture(word)
new_definition = Definition()
new_definition.word=word
new_definition.get_pos()
new_definition.definition=definition
new_definition.def_source=definition_source
new_definition.add_pronunciation()
new_definition.word_audio=audio_tup[0]
new_definition.audio_source=audio_tup[1]
new_definition.picture=picture_tup[0]
new_definition.pic_source=picture_tup[1]
repeat = self.print_n_save(new_definition)
Don't try to force a raw python function into a single box.
What you should have done (a long long time ago), is separate it out into separate functions so it would be easier to test and figure things out.
Since you're asking for user input, websites do that through forms, so you're going to need a form - or a form wizard/set/whatever.
That form is going to need at least one view to handle it, so you might need to write that too, or use a generic view.
Who knows, the model might even need to do something post processing (I didn't really read the code)
I would put this into management/commands. Just wrap your functions into a BaseCommand class and you are good to go. And here is how to make testing.

Categories