How to test Python function which writes to file [duplicate] - python

This question already has answers here:
How to do unit testing of functions writing files using Python's 'unittest'
(7 answers)
Closed 8 years ago.
I have a Python function that takes a list as an argument and writes it to a file:
def write_file(a):
try:
f = open('testfile', 'w')
for i in a:
f.write(str(i))
finally:
f.close()
How do I test this function ?
def test_write_file(self):
a = [1,2,3]
#what next ?

Call the write_file function and check whether testfile is created with expected content.
def test_write_file(self):
a = [1,2,3]
write_file(a)
with open('testfile') as f:
assert f.read() == '123' # Replace this line with the method
# provided by your testing framework.
If you don't want test case write to actual filesystem, use something like mock.mock_open.

First solution: rewrite you function to accept a writable file-like object. You can then pass a StringIO instead and test the StringIO's value after the call.
Second solution: use some mock library that let you patch builtins.

Related

How can I call a function with a string? [duplicate]

This question already has answers here:
Calling a function of a module by using its name (a string)
(18 answers)
Closed 2 years ago.
I have used the following code:
from time import time
import datetime
now = datetime.datetime.now()
Report = now.strftime("%Y%m%d_%H%M%S") + "Prueba llamada de funciones" + ".txt"
modo=0
def llamar_funciones():
if (modo==1):
Alimentaciones_1(Report)
Alimentaciones_2(Report)
else:
print("¿Que ensayos de alimentaciones quieres hacer?")
Ensayo=input()
Nombre_Ensayo= "Alimentaciones_" + Ensayo
print(Nombre_Ensayo)
Nombre_Ensayo(Report)
def Alimentaciones_1(Report):
f = open(Report,"a")
f.write("1.funtzioa")
f.close()
def Alimentaciones_2(Report):
f = open(Report,"a")
f.write("\n2.funtzioa")
f.close()
llamar_funciones()
I get the following error:
TypeError: 'str' object is not callable
How can I call the function 1 or 2 depending on the value of the variable "modo"??
You simply need another if statement. You can't call strings, but you can branch based on them.
if Ensayo == "1":
Alimentaciones_1(Report)
elif Ensayo == "2":
Alimentaciones_2(Report)
else:
# ... Handle invalid user input here ...
For what it's worth, you can call a function whose name is a string, but it's poor coding style and extremely bug-prone. To be clear, the following is for educational purposes; do not do it. The above snippet is the accepted way to do this sort of thing.
eval("Alimentaciones_{}".format(Ensayo))(Report) # <-- Bad idea
Python has two functions that might help you, exec() and eval().
They both take a string and treat it like python code (you could use the string from the input and run it), and behave slightly differently.
However, and this is important, don't use them. At all. Those functions are extremely dangerous, as they let the user call every function from your code if they wish, and it's bad practice.
I recommend to use if cases to check for the values you want like:
if my_str == "my_func":
my_func(...)
elif my_str == "my_other_func":
my_other_func(...)
...
This might be tedious but it will let your users call whatever they need to and not more.

Reading a File Line by Line in Python [duplicate]

This question already has answers here:
How to read a file line-by-line into a list?
(28 answers)
Closed 7 months ago.
I am pretty new to Python. So I was trying out my first basic piece of code. So i was trying to read a file and print it line by line in Python. Here is my code:
class ReadFile(object):
def main (self):
readFile = ReadFile()
readFile.printData()
def printData(self):
filename = "H:\\Desktop\\TheFile.txt"
try:
with open(filename, 'r') as f:
value = f.readline()
print(value)
f.close()
except Exception as ex:
print(ex)
Now When I run it, I get no output. So I tried debugging it. I see the control jumps from one method to another (main --> printData) and then exists. Its doesn't execute anything within the method. Can you tell me what am I doing wrong here? I am new, so a little insight as to why the code is behaving this way would be nice as well.
If the idea here is to understand how to read a file line by line then all you need to do is:
with open(filename, 'r') as f:
for line in f:
print(line)
It's not typical to put this in a try-except block.
Coming back to your original code there are several mistakes there which I'm assuming stem from a lack of understanding of how classes are defined/work in python.
The way you've written that code suggests you perhaps come from a Java background. I highly recommend doing one of the myriad free and really good online python courses offered on Coursera, or EdX.
Anyways, here's how I would do it using a class:
class ReadFile:
def __init__(self, path):
self.path = path
def print_data(self):
with open(self.path, 'r') as f:
for line in f:
print(line)
if __name__ == "__main__":
reader = ReadFile("H:\\Desktop\\TheFile.txt")
reader.print_data()
You don't really need a class for this and neither do you need a try block or a file.close when using a context manager (With open ....).
Please read up on how classes are used in python. A function will do for this
def read():
filename = "C:\\Users\\file.txt"
with open(filename, 'r') as f:
for line in f:
print(line)
you don't usually put main method in a class. Python is not like Java or C#. all the code outside of class will execute when you load the file.
you only create classes when you want to encapsulate some data with methods together in an object. In your case it looks like you don't need a class at all, but if you want one you have to explicitly create and call it, for example:
class A:
def __init__(self):
print('constructor')
def bang(self):
print('bang')
# code outside of the class gets executed (like a 'main' method in Java/C#)
a = A()
a.bang()
There are a few problems here.
The first is that you are declaring a class but then not using it (except from within itself). You would need to create an instance of the class outside of the class (or call a class method on it) in order for it to be instantiated.
class ReadFile:
def print_data(self):
...
# Create a new object which is an instance of the class ReadFile
an_object = ReadFile()
# Call the print_data() method on an_object
an_object.print_data()
Now, you don't actually need to use classes to solve this problem, so you could ignore all this, and just use the code you have inside your printData method:
filename = "H:\\Desktop\\TheFile.txt"
try:
with open(filename, 'r') as f:
value = f.readline()
print(value)
# don't need to do this, as f is only valid within the
# scope of the 'with' block
# f.close()
except Exception as ex:
print(ex)
You will find this almost does what you want. You just need to modify it to print the entire file, not just the first line. Here, instead of just reading a single line with f.readline() we can iterate over the result of f.readlines():
filename = "H:\\Desktop\\TheFile.txt"
try:
with open(filename, 'r') as f:
for value in f.readlines(): # read all lines
print(value)
except Exception as ex:
print(ex)

function_exists in PHP for python3 [duplicate]

This question already has answers here:
How do I check if a variable exists?
(14 answers)
Closed 6 years ago.
Is there something like function_exists in PHP for Python3? I am implementing something that allows users (through some web UI) to define simple rules in JSON as follows (in some weird lisp-like structure):
["_and", ["_tautology"], ["tautology"]]
and would like to turn that into a python statement, for instance these functions
import operator
from functools import reduce
def _and(*args):
return lambda context: reduce(operator.and, [arg(context) for arg in args], True)
def _tautology(*_):
return lambda *__: True
by turning that original JSON rule into
_and(_tautology(), _tautology())
Just out of curiousity, is ast made for this kind of task? I did this once before but I am looking for something that is scalable. Because what I did before this was practically maintaining a dictionary like follows
mapping = {'_and': _and}
and the list would keep growing, and that results in more code typed to describe what the string value means, instead of implementing them. Or I should have used another rule engine? Because one of the rule would look like
["_and", ["_equals", "fieldA", "some_value"],
["_equals", "fieldB", "some_other_value"]]
Assuming _equals is
def _equals(field_name, value):
return lambda context: context[field_name] == value
so that the rule is expanded to
_and(_equals('fieldA', 'some_value'),
_equals('fieldB', 'some_other_value'))
TL;DR
Main Question: is there something like function_exists for Python3, is ast suitable for this?
Secondary Question: should I use some sort of rule engine instead?
Regarding the duplicate question report No, I am not checking if a variable exists. I want to know if there is a function that has the same name, as a string value. For example, if I have a string '_and' I want to know if there is a function named _and, not trying to figure out whether this identifier _and is actually a function.
As Morton pointed out, you could use globals() and locals() to fetch a variable using a string containing the name.
In [32]: a = 1
In [33]: def b():
c = 2
print(globals()['a'])
print(globals()['b'])
print(locals()['c'])
....:
In [34]: b()
1
<function b at 0x7f425cae3ae8>
2
But! For your task I would recommend using a decorator that registers your functions to a mapping automatically.
_mapping = {}
def register(f):
_mapping[f.__name__] = f
return f
#register
def _and(*args):
return lambda context: reduce(operator.and_,
[arg(context) for arg in args], True)
#register
def _tautology(*_):
return lambda *_: True
and so your function_exists would be just
_mapping[key]
AST is suitable for inspecting syntax trees generated from parsed python source, modifying existing syntax trees and generating new ones and transpiling to python from a different language by generating syntax trees from it (to name a few uses). So in a way yes, you could generate AST from your JSON and compile that. I believe that is actually what Hy does, though not from JSON, but full blown lisp syntax.

Correct way to write to files?

I was wondering if there was any difference between doing:
var1 = open(filename, 'w').write("Hello world!")
and doing:
var1 = open(filename, 'w')
var1.write("Hello world!")
var1.close()
I find that there is no need (AttributeError) if I try to run close() after using the first method (all in one line).
I was wondering if one way was actually any different/'better' than the other, and secondly, what is Python actually doing here? I understand that open() returns a file object, but how come running all of the code in one line automatically closes the file too?
Using with statement is preferred way:
with open(filename, 'w') as f:
f.write("Hello world!")
It will ensure the file object is closed outside the with block.
Let me example to you why your first instance wont work if you initial a close() method. This will be useful for your future venture into learning object orientated programming in Python
Example 1
When you run open(filename, 'w') , it will initialise and return an file handle object.
When you call for open(filename, 'w').write('helloworld'), you are calling the write method on the file object that you initiated. Since the write method do not return any value/object, var1 in your code above will be of NoneType
Example 2
Now in your second example, you are storing the file object as var1.
var1 will have the write method as well as the close method and hence it will work.
This is in contrast to what you have done in your first example.
falsetru have provided a good example of how you can read and write file using the with statement
Reading and Writing file using the with statement
to write
with open(filename, 'w') as f:
f.write("helloworld")
to read
with open(filename) as f:
for line in f:
## do your stuff here
Using nested with statements to read/write multiple files at once
Hi here's an update to your question on the comments. Not too sure if this is the most pythonic way. But if you will like to use the with statement to read/write mulitple files at the same time using the with statement. What you can do is the nest the with statement within one another
For instance :
with open('a.txt', 'r') as a:
with open('b.txt', 'w') as b:
for line in a:
b.write(line)
How and Why
The file object itself is a iterator. Therefore, you could iterator thru the file with a for loop. The file object contains the next() method, which, with each iteration will be called until the end of file is reached.
The with statement was introduced in python 2.5. Prior to python 2.5 to achieve the same effect, one have to
f = open("hello.txt")
try:
for line in f:
print line,
finally:
f.close()
Now the with statement does that automatically for you. The try and finally statement are in place to ensure if there is any expection/error raised in the for loop, the file will be closed.
source : Python Built-in Documentation
Official documentations
Using the with statement, f.close() will be called automatically when it finishes. https://docs.python.org/2/tutorial/inputoutput.html
Happy venture into python
cheers,
biobirdman
#falsetru's answer is correct, in terms of telling you how you're "supposed" to open files. But you also asked what the difference was between the two approaches you tried, and why they do what they do.
The answer to those parts of your question is that the first approach doesn't do what you probably think it does. The following code
var1 = open(filename, 'w').write("Hello world!")
is roughly equivalent to
tmp = open(filename, 'w')
var1 = tmp.write("Hello world!")
del tmp
Notice that the open() function returns a file object, and that file object has a write() method. But write() doesn't have any return value, so var1 winds up being None. From the official documentation for file.write(str):
Write a string to the file. There is no return value. Due to buffering, the string may not actually show up in the file until the flush() or close() method is called.
Now, the reason you don't need to close() is that the main implementation of Python (the one found at python.org, also called CPython) happens to garbage-collect objects that no longer have references to them, and in your one-line version, you don't have any reference to the file object once the statement completes. You'll find that your multiline version also doesn't strictly need the close(), since all references will be cleaned up when the interpreter exits. But see answers to this question for a more detailed explanation about close() and why it's still a good idea to use it, unless you're using with instead.

Using a variable at once or passing it around

This question isn't really about Python but about Python in particular. Say, I've read a file:
f = open(file_name, "rb")
body = f.read()
f.close()
Since the file is already read in the variable and closed, does it matter in terms of performance whether I use the variable body within the same method or pass around to another method? Is there enough information to answer my question?
Python doesn't create copies of objects passed to functions (including strings)
def getidof(s):
return id(s)
s = 'blabla'
id(s) == getidof(s) # True
So even passing a huge string doesn't affect performances, of course you will have a slight overhead because you called a function, but the type of the argument and its length doesn't matter.

Categories