I have a python module file (func.py) and a unit test file (f_test.py):
# func.py
def f(x):
return x + 1
x = input("Enter x: "))
print("f(x): " + str(f(x)))
and
# f_test.py
import unittest
from func import f
class MyTest(unittest.TestCase):
def test(self):
self.assertEqual(f(1), 2)
When I run f_test.py I expect the test suite to be executed (successfully).
Instead however I see the following input:
Finding files... done.
Importing test modules ... Enter x:
If I comment out the input/output lines from func.py then I get the expected behaviour.
How do I achieve it without modifying func.py?
When you import func, all the code inside is run. Running the definition def f(x)... is what creates the function f.
You can distinguish between importing and running a file by using if __name__=='__main__'.
For instance:
# func.py
def f(x):
return x + 1
if __name__ == '__main__':
x = input("Enter x: "))
print("f(x): " + str(f(x)))
When you run func.py, __name__=='__main__' will be true. When you import it, it will be false (__name__ will be 'func' instead).
Of course, the correct answer is to modify func.py. If you absolutely, positively, won't modify func.py, then you could redirect standard input:
# f_test.py
import os
import sys
import unittest
oldstdin, sys.stdin = sys.stdin, StringIO.StringIO('7')
try:
from func import f
finally:
sys.stdin = oldstdin
class MyTest(unittest.TestCase):
def test(self):
self.assertEqual(f(1), 2)
You need to add to the bottom of f_test.py:
if __name__ == '__main__':
unittest.main()
This way the tests will be executed when the file is run (I forget this more times than I would like to admit).
Related
import sys
import PyPDF2
from tqdm import tqdm
import time
from gtts import gTTS
import os
# our pdf file
book = "think.pdf"
def main():
check_file()
readText()
generate_audio()
# checking file type
def check_file():
if not book.endswith(".pdf"):
sys.exit("File isn't a pdf!")
# looping through our book's text
def readText():
with open(book, "rb") as f:
pdf = PyPDF2.PdfFileReader(f)
myText = ""
for pageNum in tqdm((range(pdf.numPages))):
time.sleep(0.3)
pageObj = pdf.getPage(pageNum)
myText += pageObj.extractText()
# converting text to audio
def generate_audio():
fileOutput = gTTS(text=myText, lang="en")
print("Generating Speech...")
value = fileOutput.save("audio.mp3").time()
os.system("start audio.mp3")
print("Successfully Generated!!")
if __name__ == "__main__":
main()
my functions don't take parameters and don't have inputs, didn't know writing tests would take longer than writing the entire app's code, I didn't write tests before I'm a noob, tried assert and nothing worked fore example this:
from project import check_file, readText, generate_audio
import pytest
def test_check_file():
assert check_file(".pdf") == True
def test_readText():
pass
def test_generate_audio():
assert generate_audio() == "audio.mp3"
If your tests are hard to write, this suggests your code is inflexible, using bad practices, and needs to be refactored.
Global variables. Globals are generally a bad idea. Using globals means you can't test your functions with a variety of inputs.
Side-effects. A side-effect is anything that a function does rather than accepting and returning values. Using globals and calling functions like sys.exit are examples.
Logic vs side-effects. Sometimes side-effects are necessary, but if you combine them together with logic you can't get one without the other. The rule of thumb is a function should perform logic or have a side effect.
Something like this.
import sys
import PyPDF2
from tqdm import tqdm
import time
from gtts import gTTS
import os
import logging
def main():
book = "think.pdf"
if not check_book_filename(book):
sys.exit("File isn't a pdf!")
text_to_speech(
get_book_text(book), "audio.mp3"
)
# Describe what the function does in the name.
# Take all inputs as arguments.
# Return the result of the check.
# No side effects.
def check_book_filename(book):
return book.endswith(".pdf")
# Describe what the function does in the name.
# Take all inputs as arguments.
# Return the result.
# No side effects.
def get_book_text(book):
with open(book, "rb") as f:
pdf = PyPDF2.PdfFileReader(f)
myText = ""
for pageNum in tqdm((range(pdf.numPages))):
# What is the sleep for?
time.sleep(0.3)
pageObj = pdf.getPage(pageNum)
myText += pageObj.extractText()
return myText
# Describe what the function does in the name.
# Take all inputs as arguments.
# Use a logger rather than printing. The logger can be mocked and tested.
# No logic, only side effects.
def text_to_speech(myText, filename="audio.mp3"):
fileOutput = gTTS(text=myText, lang="en")
logging.info("Generating Speech...")
fileOutput.save(filename)
os.system("start " + filename)
logging.info("Successfully Generated!!")
import pytest
def test_check_book_filename():
assert check_book_filename("test.pdf")
assert not check_book_filename("test.jpg")
def test_get_book_text():
# You need to provide a sample PDF and its expected text.
assert get_book_text(some_pdf) == expected_text
# There isn't much you can usefully test here except that there is
# a file. Maybe you could check that it's a valid MP3, but
# for now just check it contains something.
def test_text_to_speech():
audio_file = "tmp/test.mp3"
text_to_speech("this is a test", audio_file)
assert os.path.getsize(audio_file) > 0
if __name__ == "__main__":
main()
I have two python scripts one of whic has to write a json (file1.py) and another one(file2.py) is to import file1.
My python script file1.py has executed successfully, but when I try to import in file2.py it doesn't work as it contain if __name__ == '__main__':
file1.py
def demo(opt,streamPixel):
#some functions
if __name__ == '__main__':
streamPixel = "{\"type\":\"FeatureCollection\",\"features\":["
#parser = argparse.ArgumentParser()
Transformation= 'TPS'
FeatureExtraction = 'ResNet'
SequenceModeling = 'BiLSTM'
Prediction = 'Attn'
num_fiducial = 20
input_channel = 1
output_channel = 512
imgH = 72
imgW =320
hidden_size = 256
rgb = False
batch_max_length = 25
character = '01'
sensitive =True
#PAD = True
image_folder ='D:/work/source_code/VIC_OCR/cropped'
workers = 4
batch_size= 192
num_class = 4
saved_model = 'D:\\SARIGHA\\source_code\\saved_models\\TPS-ResNet-BiLSTM-Attn-Seed323\\best_accuracy.pth'
opt = None
""" vocab / character number configuration """
if sensitive:
character = string.printable[:-6] # same with ASTER setting (use 94 char).
cudnn.benchmark = True
cudnn.deterministic = True
num_gpu = torch.cuda.device_count()
demo(opt,streamPixel)
file2.py:
import file1
from file1 import demo
if I run my file2.py is simply produce like this
(victoria) D:\work\source_code\textReg\imageOrientation>python file2.py
(victoria) D:\work\source_code\textReg\imageOrientation>
is there is any possible to import file1.py in file2.py
You could instead create a class, put it in file1.py and import it like this
from file1.py import pixelModel
pixelModel = pixelModel()
class pixelModel():
# all your variables you have mentioned in main
def __init__(sensitive):
self.sensitive = sensitive
if sensitive:
character = string.printable[:-6]
cudnn.benchmark = True
cudnn.deterministic = True
self.num_gpu = torch.cuda.device_count()
demo(opt,streamPixel)
What do you mean by it doesn't work? What exactly happens? If file2.py is purely just that, of course it won't run, because you're not running anything. if __name__ == '__main__': means that that stuff will only run if it's being run directly, rather than imported.
When you write stuff under if __name__ == '__main__', they get executed when our script is run from the command line. If you import your script in an other python script, this part won't get executed (see this well detailed explanation to understand why).
One way to be able to import the code in another script would be to put it in a function like this:
file1.py:
def myfunction():
# Do what you want here
print('This is my function in file1')
if __name__ == '__main__':
myfunction()
file2.py:
from file1 import myfunction
if __name__ == '__main__':
myfunction()
I tried to word the question right, but what I'm trying to do is check the stdout of a list after the while statement. I mock the user input for two iterations and break during the thirs iteration.
here is my run code.
def main():
pirateList = []
maxLengthList = 6
while len(pirateList) < maxLengthList:
item = input("Argh! Enter the item: ")
if item == "exit":
break;
else:
pirateList.append(item)
print(pirateList)
print(pirateList)
main()
here is my test code, i should be expecting [bow, arrow]
import unittest
from unittest.mock import patch
import io
import sys
from RunFile import main
class GetInputTest(unittest.TestCase):
#patch('builtins.input', side_effect=["bow", "arrow","exit"])
def test_output(self,m):
saved_stdout = sys.stdout
try:
out = io.StringIO()
sys.stdout = out
main()
output = out.getvalue().strip()
assert output.endswith('[bow, arrow]')
finally:
sys.stdout = saved_stdout
if __name__ == "__main__":
unittest.main()
when I run this code the program just gets hung up.No errors or tracks
The import statement you are having
from RunFile import main
Actually runs the main function, as it should, and asks for the input. You should have the standard if-clause there:
if __name__ == "__main__":
main()
You might also want to change the stdout handling, here is an example:
class GetInputTest(unittest.TestCase):
#patch('builtins.input', side_effect=["bow", "arrow","exit"])
#patch('sys.stdout', new_callable=StringIO)
def run_test_with_stdout_capture(self , mock_output, mock_input ):
main()
return mock_output.getvalue()
def test( self ):
print ("GOT: + " + self.run_test_with_stdout_capture())
if __name__ == "__main__":
unittest.main()
Do note that you cannot print inside the #patch sys.stdout -- it will get captured!
Just learning Python and spent quite some time on this. Why isn't it outputting anything when I pass arguments like this:
python new2.py Alice
Source code:
#!/usr/bin/python
import sys
def Hello(name):
if name == 'Alice' or name == 'Nick':
name = name + '!!!'
else:
name = name + '???'
print 'Hello', name
def main():
Hello(sys.argv[1])
Python doesn't implicitly call your main function. You either call it directly:
def main():
Hello(sys.argv[1])
main()
or you wrap it in an idiomatic clause to do a similar thing:
if __name__ == "__main__":
main()
I have a script (script1.py) of the following form:
#!/bin/python
import sys
def main():
print("number of command line options: {numberOfOptions}".format(numberOfOptions = len(sys.argv)))
print("list object of all command line options: {listOfOptions}".format(listOfOptions = sys.argv))
for i in range(0, len(sys.argv)):
print("option {i}: {option}".format(i = i, option = sys.argv[i]))
if __name__ == '__main__':
main()
I want to import this script in another script (script2.py) and pass to it some arguments. The script script2.py could look something like this:
import script1
listOfOptions = ['option1', 'option2']
#script1.main(listOfOptions) insert magic here
How could I pass the arguments defined in script2.py to the main function of script1.py as though they were command line options?
So, for example, would it be Pythonic to do something such as the following?:
import script1
import sys
sys.argv = ['option1', 'option2']
script1.main()
Separate command line parsing and called function
For reusability of your code, it is practical to keep the acting function separated from command line parsing
scrmodule.py
def fun(a, b):
# possibly do something here
return a + b
def main():
#process command line argumens
a = 1 #will be read from command line
b = 2 #will be read from command line
# call fun()
res = fun(a, b)
print "a", a
print "b", b
print "result is", res
if __name__ == "__main__":
main()
Reusing it from another place
from scrmodule import fun
print "1 + 2 = ", fun(1, 2)
# script1.py
#!/bin/python
import sys
#main function is expecting argument from test_passing_arg_to_module.py code.
def main(my_passing_arg):
print("number of command line options: {numberOfOptions}".format(numberOfOptions = len(sys.argv)))
print("list object of all command line options: {listOfOptions}".format(listOfOptions = my_passing_arg))
print(my_passing_arg)
if __name__ == '__main__':
main()
#test_passing_arg_to_module.py
import script1
my_passing_arg="Hello world"
#calling main() function from script1.py code.
#pass my_passinga_arg variable to main(my_passing_arg) function in scritp1.py.
script1.main(my_passing_arg)
##################
# Execute script
# $python3.7 test_passing_arg_to_module.py
# Results.
# number of command line options: 1
# list object of all command line options: Hello world
# Hello world