Python unittest a module instead of a function - python

I'm trying to write a test.py file to test a module I wrote. The specifications of the program are that I take serial user input and then print, not return a single answer. The first line of user input indicates how many inputs will follow. With an example program, "4\n1\n2\n3\n4\n" would mean there are 4 inputs and the inputs are [1,2,3,4]. Here is an example of the program that would take the input (sumEx.py):
import sys
def sum():
n = int(sys.stdin.readline().strip())
nums = []
for _ in range(n):
nums.append(int(sys.stdin.readline().strip()))
result = 0
for num in nums:
result += num
print(result)
if __name__ == "__main__":
sum()
I realize that in this example the for loop is redundant, but this is just an example for the actual program I am working on to abstract the problem. Currently, this is the test file I have:
from io import StringIO
import sys
from _pytest.monkeypatch import MonkeyPatch
import unittest
from sumEx import sum as program
class Testing(unittest.TestCase):
def test_string(self):
monkeypatch = MonkeyPatch()
monkeypatch.setattr('sys.stdin', StringIO("8\n1\n2\n3\n4\n5\n6\n7\n8\n"))
self.assertEqual(program(), 36)
def test_boolean(self):
monkeypatch = MonkeyPatch()
monkeypatch.setattr('sys.stdin', StringIO("4\0\n1\n2\n3\n"))
self.assertEqual(program(), 6)
if __name__ == '__main__':
unittest.main()
The problem is that my tests will only work if I returned them instead of printing them. Ideally, my test file would call the file sumEx.py and then
if __name__ == "__main__":
sum()
would call the sum function, the test would supply the input (like an actual person typing each line), and then whatever sum prints would be considered the output for the test. Any help is greatly appreciated. Please ask any questions if something is too vague. Thank you!

If anyone is curious, this is what I'm gonna go with for now. This takes input from a file and mimics user input through sys.stdin. It then reads the correct output from a file and compares it to the output of the program. It also runs the same test case with different inputs with the help of parameterization. Thank you #MrBeanBremen for the suggestion!
class Testing(unittest.TestCase):
def load_file(self, fileName, inOut):
try:
inputFile = open(fileName, 'r')
fileInput = r'{}'.format(inputFile.readline())
for line in inputFile.readlines():
fileInput = r'{}'.format(fileInput + line)
if inOut == 'in':
fileInput = r'{}'.format(fileInput+'\n')
inputFile.close()
return fileInput
except:
print("ERROR LOADING FILE")
#parameterized.expand([
["./tests/test0in.txt", "./tests/test0out.txt"],
["./tests/test1in.txt", "./tests/test1out.txt"],
["./tests/test2in.txt", "./tests/test2out.txt"]])
#patch('sys.stdout', new_callable=StringIO)
def test(self, inputFile, outputFile, mock_stdout):
monkeypatch = MonkeyPatch()
monkeypatch.setattr('sys.stdin', StringIO(self.load_file(inputFile, "in")))
program.main()
self.assertEqual(mock_stdout.getvalue(), self.load_file(outputFile, "out"))
if __name__ == '__main__':
unittest.main(verbosity=2)

Related

problem about Parameter transfer of jsonpath

I am running a code like below, but it's not what I want. real_path is defined at def check, so it's static.
#code before change
def check(path):
with open(path,'r', encoding="utf-8") as f:
file=json.load(f)
real_path='C:\\Documents and Settings\\Administrator\\Local Settings\\Temp\\5.exe'
call = jsonpath(file,"$.behavior.processes[?(#.process_path==real_path)].calls[?(#.category=='network')]")
print(call)
if __name__ == "__main__":
path="C:/users/hdl/Desktop/2min/2-5.json"
#real_path = 'C:\\Documents and Settings\\Administrator\\Local Settings\\Temp\\5.exe'
check(path)
Then I have changed like below, I have defined the real_path at main, thus it has worked.
def check(path):
with open(path,'r',encoding="utf-8") as f:
file=json.load(f)
#real_path='C:\\Documents and Settings\\Administrator\\Local Settings\\Temp\\5.exe'
call = jsonpath(file,"$.behavior.processes[?(#.process_path==real_path)].calls[?(#.category=='network')]")
print(call)
if __name__ == "__main__":
path="C:/users/hdl/Desktop/2min/2-5.json"
real_path = 'C:\\Documents and Settings\\Administrator\\Local Settings\\Temp\\5.exe'
check(path)
Does somebody know why?
What if I want to define at def check, what should I do?

Accessing a variable after being appended in file a.py from a function in file b.py

I have a problem trying to access a variable from file a.py from a function in file b.py. I tried looking around the internet and could not find anything, or I don't know exactly how to look for what I need. I also tried to make another file and update the variable in file c.py, but file b.py still see's the first initialization of the variable. I tried to update the variable in file a.py and afterwards import a.py in the function in b.py.
File a.py
var = []
def run():
a.welcome()
while True:
menu = a.menu()
if menu == 1:
def retrieve_path(source_path):
"""The function takes 1 parameter and checks if the file name exist as well as the file path
Adds the csv data to a variable
source_path (str): Path against whom to check for validity
"""
if not source_path:
print("Invalid file name, Please try again\n")
return
else:
import os
isFile = os.path.isfile(source_path)
if not isFile:
print("Invalid file path\n")
return
else:
with open(source_path, "r") as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
for line in csv_reader:
line = list(line)
var.append(line)
if __name__ == "__main__":
run()
file b.py
I tried like this but I get the first initialization of the variable var = []
I first updated var from file a.py and afterwards, I tried to use the function below inside file b.py but still the same result.
from a import var
from a import *
import a
def a_function():
from a import var
from a import *
import a
print(var)
print(a.var)
This prints the first initialization of var which = [] not after it was appended.
If I print var from a, from inside the function it prints it updated.
If I print var from a, from outside the function it prints it updated.
What I don’t understand is, why after updating it, and importing it into b, I still get the first initialization. Debugger didn’t help as well.
I can work around it by adding the function retrieve_path inside b.py and then appending the data in another variable inside file b.py but I would like to know why its not importing var updated with the data.
File b.py
var2 = []
def retrieve_path(source_path):
"""The function takes 1 parameter and checks if the file name exist as well as the file path
Adds the csv data to a variable
source_path (str): Path against whom to check for validity
"""
if not source_path:
print("Invalid file name, Please try again\n")
return
else:
import os
isFile = os.path.isfile(source_path)
if not isFile:
print("Invalid file path\n")
return
else:
with open(source_path, "r") as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
for line in csv_reader:
line = list(line)
var.append(line)
var2.append(line)
The reason I didn't use Class if that was one of the solutions, is because I haven't learned that much about Classes and don't know how to use them properly for the time being.
I hope I was quite explicit and you understand my dilemma. Also, have in mind I just started learning Python, so a newbi explanation and solution are more than welcomed.
The correct way is to call the run function before accessing var. Either
import a
a.run
print(a.var)
or:
from a import var, run
run
print(var)
The import statement only runs the content of the module, not the functions declared in it.
The idiomatic way of running a script is indeed what you have in a.py:
if __name__ == "__main__":
run()
And the run function will be called if you use the file like a script with python a.py, because a file that is started directly by the interpretor will be named __main__. But when it is imported, it is named according to the file name. So here it would be a and not main. Said differently, run is never called when a.py is imported.
One possibility would be to end a.py with an unconditional call of run:
...
line = list(line)
var.append(line)
run()
It should be harmless because Python keeps track of the already imported module, and run should be called only once even if the module was imported from multiple places. Yet it would be an anti-pattern, because by convention import should have as few side effects as possible, while run seems to do plenty of actions.
Ok, this is just a part of the project which was for the school, which I finished, but I wanted to make this part with records a little bit different than I've done for the grade. If some function dont make sense, its because the project it is not finished. My only concerned is towards records variable.
main.py
import tui, csv
records = []
def run():
tui.welcome()
while True:
menu = tui.menu()
if menu == 1:
def retrieve_path(source_path):
"""The function takes 1 parameter and checks if the file name exist as well as the file path
Adds the csv data to a variable
source_path (str): Path against whom to check for validity
"""
if not source_path:
print("Invalid file name, Please try again\n")
return
else:
import os
isFile = os.path.isfile(source_path)
if not isFile:
print("Invalid file path\n")
return
else:
with open(source_path, "r") as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
for line in csv_reader:
line = list(line)
records.append(line)
tui.started("Data Loading")
retrieve_path(tui.source_data_path())
tui.completed("Data Loading")
if menu == 2:
tui.started("Retrieving data")
process_menu = tui.process_type()
tui.completed("Retrieving data")
if process_menu == 1:
tui.started("Retrieving entity name")
tui.entity_name()
tui.completed("Retrieving entity name")
if process_menu == 2:
tui.started("Retrieving entity details")
entity, cols = tui.entity_details()
tui.list_entity(entity, cols)
tui.completed("Retrieving entity details")
if menu == 3:
print(tui.main_records)
if menu == 4:
break
if __name__ == "__main__":
run()
Second file is:
tui.py
def welcome():
message = "System Management"
print("*" * len(message))
print(message)
print("*" * len(message))
def menu():
main_menu = "-"
while main_menu != "0":
if main_menu == "-":
print('Main Menu:'
'\n1. Load Data'
'\n2. Process Data'
'\n3. Visualise Data'
'\n4. Save Data'
'\n0. Exit')
elif main_menu in "1234":
return int(main_menu)
elif main_menu not in "1234":
error(main_menu)
return None
else:
print('Main Menu:'
'\n1. Load Data'
'\n2. Process Data'
'\n3. Visualise Data'
'\n4. Save Data'
'\n0. Exit')
main_menu = input()
def started(operation):
print("{} has started.\n".format(operation))
def completed(operation):
print("{} has completed.\n".format(operation))
def error(error_msg):
print("Error! {} is not a valid option.".format(error_msg))
def source_data_path():
print("Please enter the path to the source data file:")
source_path = input()
if ".csv" not in source_path:
return None
else:
return source_path
def process_type():
process_menu = "-"
while process_menu != "0":
if process_menu == "-":
print('Process Menu:'
'\n1. Retrieve entity'
'\n2. Retrieve entity details'
'\n3. Categorise entities by type'
'\n4. Categorise entities by gravity'
'\n5. Summarise entities by orbit'
'\n6. Return to Main Menu')
elif process_menu == "6":
menu()
return None
elif process_menu in "12345":
return int(process_menu)
elif process_menu not in "12345":
error(process_menu)
return None
else:
print('Process Menu:'
'\n1. Retrieve entity'
'\n2. Retrieve entity details'
'\n3. Categorise entities by type'
'\n4. Categorise entities by gravity'
'\n5. Summarise entities by orbit'
'\n6. Return to Main Menu')
process_menu = input()
def entity_name():
entity = input("Please enter the name of an entity: ")
return entity
def entity_details():
entity = input("Please enter the name of an entity: ")
indexes = input("Please enter the indexes number (e.g. 0,1,5,7):\n")
return entity, list(indexes)
Please have
First time I did the project I added def retrieve_path(source_path): to tui.py and it worked fine.
What I don't really understand is why is the variable records being appended to, I can print it from within run and outside of run function, but in tui.py i get only records = [] and how to solve this without creating the function retrieve_path in tui.py
This is what it was asked of us at the time being and it was not my personal choice to do it like this.
I am sorry for not pasting everything here and mistyping some parts like == _ main _ .

Calling Functions in Main Function

I've written a program and want to call the functions in the main. However, I've been receiving a SyntaxError. I'm not sure what I'm doing wrong. Here is my code, I've tried a few things but the main function won't call the rest of the functions.
class Matrix(object):
def open_file():
'''Opens the file if it exists, otherwise prints out error message'''
Done = False
while not Done:
try:
File = input("Enter a filename: ").lower() #Asks user for a file to input
Open_File = open(File, "r") #Open the file if it exists and reads it
Info = Open_File.readlines()[1:]
Open_File.close() #Close the file
Done = True #Exits the while loop
except FileNotFoundError:
print("Sorry that file doesn't exist!") #prints out error message if file doesn't exist
return Info #Info is the file_pointer(fp)
def __init__(self): # This completed method is given
'''Create and initialize your class attributes.'''
self._matrix = {} #Intialize the matrix
self._rooms = 0 #Set the rooms equal to zero
def read_file(self, Info): #Info is equvalient to the file pointer or fp
'''Build an adjacency matrix that you read from a file fp.'''
self._rooms = Info.readline()
self._rooms = int(self._rooms)
for line in Info:
a, b = map(int, line.split())
self._matrix.setdefault(a, set()).add(b)
self._matrix.setdefault(b, set()).add(a)
return self._rooms and self._matrix
def __str__(self):
'''Return the adjacency matrix as a string.'''
s = str(self._matrix)
return s #__str__ always returns a string
def main(self):
matrix = Matrix()
info = matrix.open_file()
matrix.read_file(info)
s = str(matrix)
print(s)
if __name__ == '__main__':
m = Matrix()
m.main()
A few things:
it's self.read_file, not just read_file. It's an instance method so you need to use self.
Same for __init__(self), you need to call self.__init__. Although typically you don't do this manually. You would "instantiate" the class via Matrix().
You can't assign to a function call, so open_file() = Info simply doesn't make sense. Perhaps you mean info = open_file().
It looks like you're a little confused about how to lay out your class. Try leaving main outside of the class, like this (untested):
def main:
matrix = Matrix()
info = matrix.open_file()
matrix.read_file(info)
s = str(matrix)
print(s)
You will also need to dedent if __name__ == '__main__' to the global scope.
Ideally you may want to write something like below. Also, your open_file() has to be rewritten.
class Matrix(object):
def open_file(self):
File = input("Enter a filename: ").lower() #Asks user for a file to input
fp = open(File, "r")
return fp
#### Your matrix class code goes here
def main():
myMatrix = Matrix()
fp = myMatrix.open_file()
ret = myMatrix.read_file(fp)
print(myMatrix)
if __name__ == "__main__":
main()
There is an error in your program's entry. ' if name == 'main':'shouldn't be included in a Class. It should be global. And another, you want to call a member function of Matrix, but where is the object of Matrix. The code below is correct:
Class Matrix(object):
#################
your codes
#################
if __name__ == '__main__':
m = Matrix()
m.main()
the way this is posted
if __name__ == "__main__":
main()
is going to be executed when the class is defined -- not when the program is run. As written, the class won't have been instantiated so there's no Matrix object on which you can call main().
You'll need to move the call out one indent, so it is aligned with the class definition, and then create an object before calling its main():
if __name__ == "__main__":
instance = Matrix()
instance.main()
You've also got the assignments backwards in main(). It should read more like this:
info = open_file()
self.read_file(Info)
s = __str__(self)
print(s)
the open_file() method also has some issues. You want to create Info outside the scope of your loop so you know you've got it to return. Your comment indicates the Info is supposed to be the file pointer -- but it's not, as you wrote it. Open_File is the file pointer, and Info is the content of the file (at least, everything but the first line). Unless you're expecting a huge amount of data, it's probably easier to pass the contents -- or to combine open_file and read_file into the same function.
You also want to use the usual python pattern for opening and closing the files the with context manager - that will close your file for you.
Heres a quick and dirty version of Open_file and Read_file in one package.
def read_file(self):
#get the filename first
filename = None
while not filename:
user_fn = input("Enter a filename: ").lower()
if os.path.exists(user_fn):
filename = user_fn
else:
print ("Sorry that file doesn't exist!")
# 'with' will automatically close the file for you
with open(filename, 'rt') as filepointer:
# file objects are iterable:
for line in filepointer:
a, b = map(int, line.split())
self._matrix.setdefault(a, set()).add(b)
self._matrix.setdefault(b, set()).add(a)
I'm not clear what self._matrix.setdefault(a, set()).add(b) is supposed to be doing for you here, but in syntactic terms you can simply the structure to "get the filename, open with with, iterate over it"

Write to file from different functions(python)

is it possible to write to a single file from different function python.
from __future__ import print_function
f = open("txt.txt", "wb")
def f1():
...write to txt.txt
def f2():
...write to txt.txt
is it possible?
Just taking the previous suggestions and putting it into code. Thanks all.
functions.py:
def f1(file):
file.write("Function one.")
def f2(file):
file.write("Function two.")
main.py:
from functions import f1, f2
with open('text.txt','w') as f:
f1(f)
f2(f)

Simple word scrabble code using python that takes command line parameters

I am trying to create a simple word scrabble script that finds words score values. The script should reads two parameters from the command line and display the best word value, which returns the word with highest point value. I have created a constructor that reads the file and populate a dictionary of letter/value for use with the remaining methods of the class. For example the command line parameters should look like the following:
scrabble.py c:\tiles.txt apple,squash
Output: The best value is squash with 18.
Here is what I have so far. I know that import argv is helful, but not sure how to get started.
from sys import argv
class Scrabble:
def __init__(self, tilesFile):
with open(tilesFile, "r") as f:
lines = [ line.strip().split(":") for line in f ]
self.tiles = { k:int(v) for k,v in lines }
def getWordValue(self, word):
sum = 0
for letter in word.upper():
sum += self.tiles[letter]
return sum
def getBestWord(self):
pass
def main():
s1 = Scrabble("tile_values.txt")
value = s1.getWordValue("hello")
print(value)
if __name__ == '__main__':
main()
pass
What you need is to use the argparse module
https://docs.python.org/3/library/argparse.html
I took your example and added argparse. There are some issues with your Scrabble constructor. But you will get the idea of using args on the command line
python scrabble.py tiles.txt apple squash orange
import argparse
import sys
class Scrabble:
def __init__(self, tilesFile):
with open(tilesFile, "r") as f:
lines = [ line.strip().split(":") for line in f ]
self.tiles = { k:int(v) for k,v in lines }
def getWordValue(self, word):
sum = 0
for letter in word.upper():
sum += self.tiles[letter]
return sum
def getBestWord(self):
pass
def main(argv):
s1 = Scrabble(argv[1])
if len(argv) < 3:
print 'no words given'
sys.exit(1)
# argv[2:] means the items in argv starting from the 3rd item.
# the first item will be the name of the script you are running
# the second item should be the tiles file.
for word in argv[2:]:
value = s1.getWordValue(word)
print(value)
if __name__ == '__main__':
main(argv)
You can get the arguments you script was passed on the command line with sys.argv.
from sys import argv
print("This is a list of all of the command line arguments: ", argv)

Categories

Resources