Detecting for invalid file inputs, Python - python

I have an assignment to write a Python script which "detects whether the file is readable or not".
I am stuck as to which exceptions I should run. Let's say the input file is intended to be a text file, with extension *.txt
What is the exception I should raise? I suspect there should be multiple. At the moment, I have:
with open('example_file.txt") as textfile:
if not textfile.lower().endswith('.txt'):
raise argparse.ArgumentTypeError(
'Not a text file! Argument filename must be of type *.txt')
return textfile
However, that only checks the file extension. What else could I possibly check? What is the standard for file I/O in Python?

To check whether the file exists:
import os.path
if os.path.exists('example_file.txt'):
print('it exists!')
Beyond this, successfully opening the file will demonstrate readability. The built-in open raises an IOError exception if it fails. Failure can occur for more than one reason, so we must check whether it failed due to readability:
import errno
try:
textfile = open('example_file.txt', 'r')
textfile.close()
print("file is readable")
except IOError as e:
if e.errno == errno.EACCES:
print("file exists, but isn't readable")
elif e.errno == errno.ENOENT:
print("files isn't readable because it isn't there")
The relevant section of the docs on file permissions. Note that the use of os.access to check readability before calling open is discouraged.

Related

Should I close a file with file.close() when there is a FileNotFoundError exception?

I'm trying to open a file in python and print a message when the file doesn't exist. But I'm confused whether to close the file or not when the exception happens.
try:
file = open(sys.argv[1], "r")
file.close() # should I do this?
except OSError:
print(f"{sys.argv[1]} file not found.")
A simpler method of checking if a file exists:
import os
if not os.path.exists(sys.argv[1]):
print(f"{sys.argv[1]} file not found.")
But to answer your question, the ```file.close()`` happens only when the file exists and you successfully open the file. Not when the exception occurs.
Edit:
As pointed out by #ekhumoro, the above has a race condition (when other processes access that file). If no other process accesses that file, then the above code works.
Solution is as #ekhumoro pointed out is to use your original try/except method.

fake `.gz` raise IOError, 'Not a gzipped file'

Let's say I have a fake gz file test.bson.gz generated by echo "hello world" > test.bson.gz, and I have tried:
try:
bson_file = gzip.open('test.bson.gz', mode='rb')
except:
print("cannot open")
No exception will be caught here. (Really strange, since this is not a valid gz...)
Then I do:
data = bson_file.read(4)
I will get:
File "/usr/lib/python2.7/gzip.py", line 190, in _read_gzip_header
raise IOError, 'Not a gzipped file'
IOError: Not a gzipped file
Is there any way that I can determine (even catch error) whether this .gz is valid when I try to open it, not wait until I wanna read it?
Thanks!
You can use gzip.peek(n):
Read n uncompressed bytes without advancing the file position.
try:
bson_file = gzip.open('test.bson.gz', mode='rb')
bson_file.peek(1)
except OSError:
print("cannot open")
That way you will catch the error without consuming the file contents.
Hint: You should avoid catching all errors unconditionally. I added except OSError, because IOError was merged to OSError in Python 3.3 - see PEP3151.

exception stop read files python

I'm trying to control exceptions when reading files, but I have a problem. I'm new to Python, and I am not yet able to control how I can catch an exception and still continue reading text from the files I am accessing. This is my code:
import errno
import sys
class Read:
#FIXME do immutables this 2 const
ROUTE = "d:\Profiles\user\Desktop\\"
EXT = ".txt"
def setFileReaded(self, fileToRead):
content = ""
try:
infile = open(self.ROUTE+fileToRead+self.EXT)
except FileNotFoundError as error:
if error.errno == errno.ENOENT:
print ("File not found, please check the name and try again")
else:
raise
sys.exit()
with infile:
content = infile.read()
infile.close()
return content
And from another class I tell it:
read = Read()
print(read.setFileReaded("verbs"))
print(read.setFileReaded("object"))
print(read.setFileReaded("sites"))
print(read.setFileReaded("texts"))
Buy only print this one:
turn on
connect
plug
File not found, please check the name and try again
And no continue with the next files. How can the program still reading all files?
It's a little difficult to understand exactly what you're asking here, but I'll try and provide some pointers.
sys.exit() will terminate the Python script gracefully. In your code, this is called when the FileNotFoundError exception is caught. Nothing further will be ran after this, because your script will terminate. So none of the other files will be read.
Another thing to point out is that you close the file after reading it, which is not needed when you open it like this:
with open('myfile.txt') as f:
content = f.read()
The file will be closed automatically after the with block.

Under which circumstances will the python f.readlines method fail?

I use the code below to read in a text file (always a few thousand lines long). Is the except Exception as e block unnecessary?
try:
in_file=open(in_file,'rU')
try:
in_content=in_file.readlines()
except Exception as e:
sys.stderr.write('Error: %s\n' % e.message)
sys.exit(1)
finally:
in_file.close()
except IOError:
sys.stderr.write('I/O Error: Input file not found.')
sys.exit(1)
Also please tell me of the circumstances under which the file.readlines() method in Python will fail?
I believe that IOError is the only possible thing that can happen. This covers both the file not existing and inadequate permissions. Any python reference I have seen only has IOError with files :). I'm not sure by what you mean with the stack trace, since it seems to just print the error itself?
import sys
try:
with open("in_file",'rU') as in_file:
in_content=in_file.readlines()
except Exception as e: #Should be replaceable with IOError, doesn't hurt to not
sys.stderr.write('%s\n' % e)
sys.exit(1)
The pythonic way to read file looks like this:
with open(in_file_name,'rU') as in_file:
in_content = in_file.readlines()
This should give you all the benefits of your code. So you don't need to worry about what kind of errors can occur. Python will take care of it. A file opened using the with statement will be closed in case of an exception.

Python : Check file is locked

My goal is to know if a file is locked by another process or not, even if I don't have access to that file!
So to be more clear, let's say I'm opening the file using python's built-in open() with 'wb' switch (for writing). open() will throw IOError with errno 13 (EACCES) if:
the user does not have permission to the file or
the file is locked by another process
How can I detect case (2) here?
(My target platform is Windows)
You can use os.access for checking your access permission. If access permissions are good, then it has to be the second case.
As suggested in earlier comments, os.access does not return the correct result.
But I found another code online that does work. The trick is that it attempts to rename the file.
From: https://blogs.blumetech.com/blumetechs-tech-blog/2011/05/python-file-locking-in-windows.html
def isFileLocked(filePath):
'''
Checks to see if a file is locked. Performs three checks
1. Checks if the file even exists
2. Attempts to open the file for reading. This will determine if the file has a write lock.
Write locks occur when the file is being edited or copied to, e.g. a file copy destination
3. Attempts to rename the file. If this fails the file is open by some other process for reading. The
file can be read, but not written to or deleted.
#param filePath:
'''
if not (os.path.exists(filePath)):
return False
try:
f = open(filePath, 'r')
f.close()
except IOError:
return True
lockFile = filePath + ".lckchk"
if (os.path.exists(lockFile)):
os.remove(lockFile)
try:
os.rename(filePath, lockFile)
sleep(1)
os.rename(lockFile, filePath)
return False
except WindowsError:
return True
According to the docs:
errno.EACCES
Permission denied
errno.EBUSY
Device or resource busy
So just do this:
try:
fp = open("file")
except IOError as e:
print e.errno
print e
Figure out the errno code from there, and you're set.

Categories