How to properly handle errors while working with files? - python

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:
My program accepts all sorts of files. I can't figure out how to handle an error which will display that the file should be of .txt extension (properly display an AssertionError message).
After each input line it also outputs the 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.

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)

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.

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.

Related

Syntax error code worked earlier but now it doesnt

I'm having an error and it worked earlier but it now just doesn't, any tips?
SyntaxError: cannot assign to function call this is the error and I know where it is located, I really no longer have any idea why its like.from io import open_code
import time
def count1():
for xa in range(1,900000000000000000000000000000000000000000): # loop
time.sleep(1)
with open('door4.txt','w') as f1: # file (think of it as number 1)
f1.write(str(xa)) # writes the number into the file door 4
with open('door5.txt','r') as f2: # another file,
#this one gets saved to the file, the other part (above)is only there for throughout the session
cant = f2.read() # becomes the saved string value '1'
varpir = int(cant) = int(cant) + 1 #here is the issue it says the error
#if you delete a few lines then it works but not how I want it to work
with open('door5.txt', "w") as f3: #same file above but with write priveleges
f3.write(str(varpir)) # writes the code
print(xa) # prints the code of door4
print(varpir) # prints the code of door5
def all():
count1()
all() # the line that runs it all
Sorry for not making it clear what I want! What I want is that the code works without any errors, the current error is at the varpir variable line, I tried doing this but this just gives another error, the error: ValueError: invalid literal for int() with base 10:
edit: the file data got flushed so it was empty causing it to crash, this is actually the solution, thanks though
varpir = int(cant)
varpir = varpir + int(1)``` ''

(Python) How to handle and work with each distinct lines in a string? [duplicate]

This question already has answers here:
How should I read a file line-by-line in Python?
(3 answers)
Closed 2 years ago.
I am trying to do exercise about "Filtering the file contents" and here is the full questions:
Create a program which reads all of the lines from the file and tests the lines. If the line has only letters and/or numbers, the program prints "[line] was ok.". If the line has special characters, the program should print "[line] was invalid.". When the program works, it prints out something like this:
>>>
5345m345ö34l was ok.
no2no123non4 was ok.
noq234n5ioqw#% was invalid.
%#""SGMSGSER was invalid.
doghdp5234 was ok.
sg,dermoepm was invalid.
43453-frgsd was invalid.
hsth())) was invalid.
bmepm35wae was ok.
vmopaem2234+0+ was invalid.
gsdm12313 was ok.
bbrbwb55be3"?"#? was invalid.
"?"#%#"!%#"&"?%%"?#?#"?" was invalid.
retrte#%#?% was invalid.
abcdefghijklmnopqrstuvxy was ok.
>>>
It is advisable to read the lines one at a time, test them with the isalmun() string test and go on from there. Also remember that the strings may also end in a line break (\n), which is allowed, but fails the .isalnum() test if not sliced away.
Here is my implementation:
n=open("strings.txt","r")
x=n.read()
if x.isalnum()==True:
print(x," was ok")
else:
print(x," was invalid")
n.close()
And the system's response:
5345m34534l
no2no123non4
noq234n5ioqw#%
%#""SGMSGSER
doghdp5234
sg,dermoepm
43453-frgsd
hsth()))
bmepm35wae
vmopaem2234+0+
gsdm12313
gswrgsrdgrsgsig45
)/(/)(#=%#)%/
++-+-+--+--+-+>-<+-<<_<-+>>++.
was invalid
I really don't know how to solve this. Please help me with what I have missed
Thank you in advance!!!
something like this - the code needs to loop over the file line by line
with open('strings.txt') as f:
lines = [l.strip() for l in f.readlines()]
for line in lines:
if line.isalnum():
print(f'{line} was ok')
else:
print(f'{line} was invalid')
You may need to loop over your lines with a for loop. The way you're doing it now is, that all of your lines are stored under x.
Something like this:
file = open("strings.txt","r")
for line in file:
if line.isalnum()==True:
print(line," was ok")
else:
print(line," was invalid")
file.close()
n = open("strings.txt", "r", encoding="utf8")
for line in n:
if line.strip().isalnum():
print(line.strip(), " was ok")
else:
print(line.strip(), " was invalid")
n.close()
x = n.read() is a string consisting of all lines of the file . you need to read the file line by line with for.
strip() - Remove spaces at the beginning and at the end of the string,

Format of if statement to check if a file exists

I understand that this question may exist, however I am just trying to figure out my formatting. I am not the best when it comes to formatting things like this and am just doing a bit of guess work that just leads to issues.
I have a custom file type that it must save to, a .gcom and a file name that is declared with the function. Currently the function looks like this:
def cComFile(): # This will NOT write command code (Yet) I want to see if file creation works!
filetype='.gcom'
commands_Directory = 'C:\\Genisis_AI\\Commands\\' # Unused at the moment
file_name = command
if os.path.isfile(("C:\\Genisis_AI\\Commands\\{}").format(file_name).join("{}").format(filetype)):
a = raw_input(('{} already exists! Would you like to overwrite this? [Y/N]: ').format(cComFile.file_name))
string.lower(a)
if a == 'y':
print(("Command: {} , has been rewritten!").format(file_name))
elif a == 'n':
pass
else:
f = open((cComFile.commands_Directory.join(cComFile.file_name.join(cComFile.filetype)),'w+'))
f.write('command was made')
print(('Command made" {}').format(cComFile.command))
I am getting an issue with line 135 which is the following line:
if os.path.isfile(("C:\\Genisis_AI\\Commands\\{}").format(file_name).join("{}").format(filetype)):
The error I am receiving is the following:
Traceback (most recent call last):
File "testing/aaa.py", line 149, in <module>
cComFile('test')
File "testing/aaa.py", line 135, in cComFile
if os.path.isfile(("C:\\Genisis_AI\\Commands\\{}").format(file_name).join("{}").format(filetype)):
KeyError: 'C'
I understand that I am most likely doing this all the wrong way but its a learning experience I suppose. And the chances are that me getting that wrong means that the formatting for the rest of this function are also incorrect as well. Thank you for reading and any help would be nice.
(I understand this is messy and I don't mind it at the moment, I tend to clean up after things work)
You can pass several arguments to format:
if os.path.isfile("C:\\Genisis_AI\\Commands\\{}.{}".format(file_name, filetype)):
Or if you're using Python 3.6 (note the f before the string):
if os.path.isfile(f"C:\\Genisis_AI\\Commands\\{file_name}.{filetype}"):
Or if you prefer the % syntax:
if os.path.isfile("C:\\Genisis_AI\\Commands\\%s.%s" % (file_name, filetype)):
you can pass multiuple values to format function like this, with multiple '{}'.
"C:\\Genisis_AI\\Commands\\{}.{}".format(file_name, filetype)
So basically you jut want to check if a file exists? Why not use a try statement instead of the if?
import errno
try:
with open(filename,'w') as file:
# do stuff with the file
except IOError as e:
# if returned error is [Errno 2] "No such file or directory"
if e.errno == errno.ENOENT:
#do something else
This uses the errno module which makes available error codes from your system. This works for me on windows, may be slightly different on Linux not sure.

How Can I Remove Skipped Lines from Pastebin Output?

I am trying to use Pastebin to host two text files for me to allow any copy of my script to update itself through the internet. My code is working, but the resultant .py file has a blank line added between each line. Here is my script...
import os, inspect, urllib2
runningVersion = "1.00.0v"
versionUrl = "http://pastebin.com/raw.php?i=3JqJtUiX"
codeUrl = "http://pastebin.com/raw.php?i=GWqAQ0Xj"
scriptFilePath = (os.path.abspath(inspect.getfile(inspect.currentframe()))).replace("\\", "/")
def checkUpdate(silent=1):
# silently attempt to update the script file by default, post messages if silent==0
# never update if "No_Update.txt" exists in the same folder
if os.path.exists(os.path.dirname(scriptFilePath)+"/No_Update.txt"):
return
try:
versionData = urllib2.urlopen(versionUrl)
except urllib2.URLError:
if silent==0:
print "Connection failed"
return
currentVersion = versionData.read()
if runningVersion!=currentVersion:
if silent==0:
print "There has been an update.\nWould you like to download it?"
try:
codeData = urllib2.urlopen(codeUrl)
except urllib2.URLError:
if silent==0:
print "Connection failed"
return
currentCode = codeData.read()
with open(scriptFilePath.replace(".py","_UPDATED.py"), mode="w") as scriptFile:
scriptFile.write(currentCode)
if silent==0:
print "Your program has been updated.\nChanges will take effect after you restart"
elif silent==0:
print "Your program is up to date"
checkUpdate()
I stripped the GUI (wxpython) and set the script to update another file instead of the actual running one. The "No_Update" bit is for convenience while working.
I noticed that opening the resultant file with Notepad does not show the skipped lines, opening with Wordpad gives a jumbled mess, and opening with Idle shows the skipped lines. Based on that, this seems to be a formatting problem even though the "raw" Pastebin file does not appear to have any formatting.
EDIT: I could just strip all blank lines or leave it as is without any problems, (that I've noticed) but that would greatly reduce readability.
Try adding the binary qualifier in your open():
with open(scriptFilePath.replace(".py","_UPDATED.py"), mode="wb") as scriptFile:
I notice that your file on pastebin is in DOS format, so it has \r\n in it. When you call scriptFile.write(), it translates \r\n to \r\r\n, which is terribly confusing.
Specifying "b" in the open() will cause scriptfile to skip that translate and write the file is DOS format.
In the alternative, you could ensure that the pastebin file has only \n in it, and use mode="w" in your script.

Python not splitting CRLF correctly

I'm writing a script to convert very simple function documentation to XML in python. The format I'm using would convert:
date_time_of(date) Returns the time part of the indicated date-time value, setting the date part to 0.
to:
<item name="date_time_of">
<arg>(date)</arg>
<help> Returns the time part of the indicated date-time value, setting the date part to 0.</help>
</item>
So far it works great (the XML I posted above was generated from the program) but the problem is that it should be working with several lines of documentation pasted, but it only works for the first line pasted into the application. I checked the pasted documentation in Notepad++ and the lines did indeed have CRLF at the end, so what is my problem?
Here is my code:
mainText = input("Enter your text to convert:\r\n")
try:
for line in mainText.split('\r\n'):
name = line.split("(")[0]
arg = line.split("(")[1]
arg = arg.split(")")[0]
hlp = line.split(")",1)[1]
print('<item name="%s">\r\n<arg>(%s)</arg>\r\n<help>%s</help>\r\n</item>\r\n' % (name,arg,hlp))
except:
print("Error!")
Any idea of what the issue is here?
Thanks.
input() only reads one line.
Try this. Enter a blank line to stop collecting lines.
lines = []
while True:
line = input('line: ')
if line:
lines.append(line)
else:
break
print(lines)
The best way to handle reading lines from standard input (the console) is to iterate over the sys.stdin object. Rewritten to do this, your code would look something like this:
from sys import stdin
try:
for line in stdin:
name = line.split("(")[0]
arg = line.split("(")[1]
arg = arg.split(")")[0]
hlp = line.split(")",1)[1]
print('<item name="%s">\r\n<arg>(%s)</arg>\r\n<help>%s</help>\r\n</item>\r\n' % (name,arg,hlp))
except:
print("Error!")
That said, It's worth noting that your parsing code could be significantly simplified with a little help from regular expressions. Here's an example:
import re, sys
for line in sys.stdin:
result = re.match(r"(.*?)\((.*?)\)(.*)", line)
if result:
name = result.group(1)
arg = result.group(2).split(",")
hlp = result.group(3)
print('<item name="%s">\r\n<arg>(%s)</arg>\r\n<help>%s</help>\r\n</item>\r\n' % (name,arg,hlp))
else:
print "There was an error parsing this line: '%s'" % line
I hope this helps you simplify your code.
Patrick Moriarty,
It seems to me that you didn't particularly mention the console and that your main concern is to pass several lines together at one time to be treated. There's only one manner in which I could reproduce your problem: it is, executing the program in IDLE, to copy manually several lines from a file and pasting them to raw_input()
Trying to understand your problem led me to the following facts:
when data is copied from a file and pasted to raw_input() , the newlines \r\n are transformed into \n , so the string returned by raw_input() has no more \r\n . Hence no split('\r\n') is possible on this string
pasting in a Notepad++ window a data containing isolated \r and \n characters, and activating display of the special characters, it appears CR LF symbols at all the extremities of the lines, even at the places where there are \r and \n alone. Hence, using Notepad++ to verify the nature of the newlines leads to erroneous conclusion
.
The first fact is the cause of your problem. I ignore the prior reason of this transformation affecting data copied from a file and passed to raw_input() , that's why I posted a question on stackoverflow:
Strange vanishing of CR in strings coming from a copy of a file's content passed to raw_input()
The second fact is responsible of your confusion and despair. Not a chance....
.
So, what to do to solve your problem ?
Here's a code that reproduce this problem. Note the modified algorithm in it, replacing your repeated splits applied to each line.
ch = "date_time_of(date) Returns the time part.\r\n"+\
"divmod(a, b) Returns quotient and remainder.\r\n"+\
"enumerate(sequence[, start=0]) Returns an enumerate object.\r\n"+\
"A\rB\nC"
with open('funcdoc.txt','wb') as f:
f.write(ch)
print "Having just recorded the following string in a file named 'funcdoc.txt' :\n"+repr(ch)
print "open 'funcdoc.txt' to manually copy its content, and paste it on the following line"
mainText = raw_input("Enter your text to convert:\n")
print "OK, copy-paste of file 'funcdoc.txt' ' s content has been performed"
print "\nrepr(mainText)==",repr(mainText)
try:
for line in mainText.split('\r\n'):
name,_,arghelp = line.partition("(")
arg,_,hlp = arghelp.partition(") ")
print('<item name="%s">\n<arg>(%s)</arg>\n<help>%s</help>\n</item>\n' % (name,arg,hlp))
except:
print("Error!")
.
Here's the solution mentioned by delnan : « read from the source instead of having a human copy and paste it. »
It works with your split('\r\n') :
ch = "date_time_of(date) Returns the time part.\r\n"+\
"divmod(a, b) Returns quotient and remainder.\r\n"+\
"enumerate(sequence[, start=0]) Returns an enumerate object.\r\n"+\
"A\rB\nC"
with open('funcdoc.txt','wb') as f:
f.write(ch)
print "Having just recorded the following string in a file named 'funcdoc.txt' :\n"+repr(ch)
#####################################
with open('funcdoc.txt','rb') as f:
mainText = f.read()
print "\nfile 'funcdoc.txt' has just been opened and its content copied and put to mainText"
print "\nrepr(mainText)==",repr(mainText)
print
try:
for line in mainText.split('\r\n'):
name,_,arghelp = line.partition("(")
arg,_,hlp = arghelp.partition(") ")
print('<item name="%s">\n<arg>(%s)</arg>\n<help>%s</help>\n</item>\n' % (name,arg,hlp))
except:
print("Error!")
.
And finally, here's the solution of Python to process the altered human copy: providing the splitlines() function that treat all kind of newlines (\r or \n or \r\n) as splitters. So replace
for line in mainText.split('\r\n'):
by
for line in mainText.splitlines():

Categories