Reputation: 113
Program description:
Program creates a
.txt
file with the given name from the first input. After that it accepts text lines for the file from each input, until the input only consists of a string"end"
(this end line should not be included). The program should also handle all possible errors.
My solution:
def writef(f, st):
try:
assert st == "end", "* End of the file (not included)"
assert not(f.endswith(".txt")), "txt only"
except IOError:
print("Unexpected error")
except AssertionError as sterr:
print(sterr)
f.write(st + "\n")
t = input("* Beggining of the file (.txt supported only): ")
f = open(t, "w+")
while True:
exec_st = input("> ")
writef(f, exec_st)
Problems:
.txt
extension (properly display an AssertionError message).AssertionError
message if the string only contains "end"
: * End of the file (not included)
. However, when I try typing the string containing only the word "end"
it outputs the following error instead of the AssertionError:Traceback (most recent call last):
File "C:\Users\1\Desktop\IT\pycharm\em_1.py", line 15, in <module>
writef(f, exec_st)
File "C:\Users\1\Desktop\IT\pycharm\em_1.py", line 4, in writef
assert not(f.endswith(".txt")), "txt only"
AttributeError: '_io.TextIOWrapper' object has no attribute 'endswith'
I will appreciate any help, thanks in advance.
Upvotes: 0
Views: 192
Reputation: 9509
The way assert statements work is that when you say
assert st == "end", "* End of the file (not included)"
You are saying that you assume st
is equal to end
. If for some reason this isn't true, raise an error. Using !=
would make the program work as you explained, however, you shouldn't even be using an assert statement here. Assert statements are only meant for sanity checks, and they get stripped out in production. What I mean by that is most companies will run Python in a special optimized mode that skips over assert statements. See this question for more info. Instead raise an error like so:
if st == "end":
raise RuntimeError("* End of the file (not included)")
That'll take care of making sure your error gets raised when it should, but we still need to take care of the '_io.TextIOWrapper' object has no attribute 'endswith'
error. You're checking if f
does not end with ".txt". f
is whatever open()
returns, and if you lookup the documentation to see what that function returns, you'll find that it does not return a string, but the endswith
function can only operate on strings, hence the error. What you can do instead is pass t
to your writef
function and check if that ends with "txt", or you can do as PIG208 mentioned and check if f.name
ends with ".txt".
Some other things to consider:
You should get in the habit of using more descriptive names. It helps you when you come back to your code later on. I have no idea what t
and st
stand for, and future you won't know what they stand for either.
You should avoid printing out "Unexpected error" whenever you can in favor of a more specific error message. You'll just annoy the user by not telling them what is going on, you'll annoy yourself when your users complain about this very generic error message.
Your try catch block is around some assert statements that aren't doing any IO work, but your catching an IO error anyways. This isn't necessary. If you get an IO error, it's going to come from f.write
or open
or f.close
.
Upvotes: 1
Reputation: 2370
The endswith
function only works with strings. If you want to check whether the input file is legal, you may do it by checking f.name
.
The file extension will not be checked until writef
is called, which doesn't make sense because the file name is already given in t = input("* Beggining of the file (.txt supported only): ")
t = input("* Beggining of the file (.txt supported only): ")
f = open(t, "w+")
assert f.name.endswith(".txt"), "txt only"
The code above raises an AssertionError
if the file name doesn't end with ".txt".
assert st == "end", "* End of the file (not included)"
in the try block raises an exception to output the AssertionError
every time the user types in anything other than "end". Instead of checking it in writef
, you may want to do it in the while loop.
while True:
exec_st = input("> ")
if exec_st == "end":
f.close()
break
writef(f, exec_st)
The code above breaks the loop as soon as a string containing only "end" is entered, and it will not be written into the output file.
Here is the complete solution:
def writef(f, st):
try:
f.write(st + "\n")
except IOError:
print("Unexpected error")
t = input("* Beggining of the file (.txt supported only): ")
f = open(t, "w+")
assert f.name.endswith(".txt"), "txt only"
while True:
exec_st = input("> ")
if exec_st == "end":
f.close()
break
writef(f, exec_st)
Upvotes: 1
Reputation: 114
In order to check the file name, i would recommend you use regex, i'd recommend reading up on it because it makes no sense until you do.
for the "end" case, i believe you want to have f.close()
rather than f.close
if you don't want to use regex, you can check if the filename string contains ".txt", which will fix the majority of cases.
Upvotes: 0