Python: Getting a WindowsError instead of an IOError - python

I am trying to understand exceptions with Python 2.7.6, on Windows 8.
Here's the code I am testing, which aims to create a new directory at My_New_Dir. If the directory already exists, I want to delete the entire directory and its contents, and then create a fresh directory.
import os
dir = 'My_New_Dir'
try:
os.mkdir(dir)
except IOError as e:
print 'exception thrown'
shutil.rmtree(dir)
os.mkdir(dir)
The thing is, the exception is never thrown. The code works fine if the directory does not already exist, but if the directory does exist, then I get the error:
WindowsError: [Error 183] Cannot create a file when that file already exists: 'My_New_Dir'
But according to the Python documentation for os.mkdir(),
If the directory already exists, OSError is raised.
So why is the Windows error being thrown, rather than the Python exception?

WindowsError is a subclass of OSError. From the exceptions documentation:
Raised when a Windows-specific error occurs or when the error number does not correspond to an errno value. The winerror and strerror values are created from the return values of the GetLastError() and FormatMessage() functions from the Windows Platform API. The errno value maps the winerror value to corresponding errno.h values. This is a subclass of OSError.
You are trying to catch IOError however, which is not such a parent class of WindowsError; as a result it won't suffice to catch either OSError nor WindowsError.
Alter your code to use the correct exception here:
try:
os.mkdir(dir)
except OSError as e:
or use WindowsError; this would tie your code to the Windows platform.

You mis-read it. It is "OSError" not "IOError", and WindowsError is a subclasss of "OSError" for your specific working OS.
>>> issubclass(WindowsError, OSError)
True
Besides, for your propose, this API is better:
os.path.isdir(path): Return True if path is an existing directory. This follows symbolic links, so both islink() and isdir() can be true for the same path.
if os.path.isdir(dir):
shutil.rmtree(dir)
os.mkdir(dir)

If you search for "WindowsError" on the exceptions page, you will see that WindowsError is in fact a Python exception. It is a subclass of OSError, so the documentation is still correct. If you change to
try:
os.mkdir(dir)
except OSError as e:
print 'exception thrown'
shutil.rmtree(dir)
os.mkdir(dir)
then you will catch the exception.

Related

How would you catch python Exception inside an except clause

How would you catch exception within exception in python ?
Consider the following case
bak_filename = filename + ".bak"
#This try is needed because if bak_filename existed, rename will fail
try:
os.rename(filename, bak_filename)
except WindowsError:
#However, os.remove may still fail e.g. file in use. How would you handle this exception within except clause ?
#try and except around this os.remove?
os.remove(bak_filename)
os.rename(filename, bak_filename)
Any thought of :
Rewriting to avoid double try?
Not necessarily this example, but in some case we cannot rewrite, how would you handle double try ?
A solution to avoid all this exception wrapping would be to use shutil.move
shutil.move(filename, bak_filename)
If the destination already exists but is not a directory, it may be overwritten depending on os.rename() semantics.
If the destination is on the current filesystem, then os.rename() is used. Otherwise, src is copied to dst using copy_function and then removed. In case of symlinks, a new symlink pointing to the target of src will be created in or as dst and src will be removed.
So it basically does what you're trying to do, but in a library which is available on all python distros.
Note that the performance may be bad if the file is big and the target file exists and os.rename refuses to overwrite it (completely depends on the operating system but for instance Windows will refuse to rename over an existing file), because the fallback when os.rename throws OSError is copying the source then deleting. The implementation doesn't try to remove the file then rename again, because if rename fails, Python assumes that we're trying to rename across filesystems, and a copy+delete is in order in that case (this is exactly how Unix mv works).
try:
os.rename(src, real_dst)
except OSError:
if os.path.islink(src):
...
else:
copy_function(src, real_dst)
os.unlink(src)
To workaround that possible file existence, a prior os.remove call wrapped in a try/except OSError statement could be done.
try:
os.remove(bak_filename)
except OSError:
pass
shutil.move(filename, bak_filename) # or os.rename(filename, bak_filename)
Of course if bak_filename is locked/not deletable, an exception can still be raised by shutil.mode. Also note that if we tried to delete the target file, os.rename will be as good as shutil.move. If the target file could not be deleted, the operation can't succeed anyway.
You can read more on Exception Chaining. But, that's for Python 3
In Python 2, you can store your exception in a variable, then raise it again explicitly like this:
try:
do something
except Exception as e:
try:
do something again
except:
pass
raise e

How to catch Permission Error with Popen process

This is the error:
Permission Error: Copying of text from this document is not allowed.
I am opening a .exe file on windows. So regular try except block does not seem to catch it. Neither does OSError.
I solved it with the following:
try:
"""code here"""
except subprocess.CalledProcessError:
"""unlock files and try again"""
Try
exception PermissionError
Raised when trying to run an operation without the adequate access rights - for example filesystem permissions. Corresponds to errno EACCES and EPERM.
If you specified irrelevant Exception while trying to catch permission error, I wouldn't be surprised they it is caught

Python create directory failing

I am using some pretty standard code:
1 if not os.path.exists(args.outputDirectory):
2 if not os.makedirs(args.outputDirectory, 0o666):
3 sys.exit('Fatal: output directory "' + args.outputDirectory + '" does not exist and cannot be created')
I remove the directory and the check at 1 drops through to 2. I one-step beyond that and hit the error message at 3.
However, when I check, the directory was created successfully.
drwxrwsr-x 2 userId userGroup 4096 Jun 25 16:07 output/
What am I missing??
os.makedirs does not indicate whether it succeeded through its return value: it always returns None.
None is False-y, therefore, not os.makedirs(args.outputDirectory, 0o666) is always True, which triggers your sys.exit code path.
Fortunately, you don't need any of that. If os.makedirs fails, it'll throw an OSError.
You should catch the exception, not check the return value:
try:
if not os.path.exists(args.outputDirectory):
os.makedirs(args.outputDirectory, 0o666):
except OSError:
sys.exit('Fatal: output directory "' + args.outputDirectory + '" does not exist and cannot be created')
If no OSError is thrown, that means the directory was successfully created.
You don't need to call os.path.exists() (or os.path.isdir()); os.makedirs() has exist_ok parameter.
And as #Thomas Orozco mentioned, you shouldn't check os.makedirs()' return value because os.makedirs() indicates errors by raising an exception instead:
try:
os.makedirs(args.output_dir, mode=0o666, exist_ok=True)
except OSError as e:
sys.exit("Can't create {dir}: {err}".format(dir=output_dir, err=e))
Note: Unlike os.path.exist()-based solution; it raises an error if the path exists but it is not a directory (or a symlink to a directory).
There could be issues with the mode parameter, see the note for versions of Python before 3.4.1

How do I import FileNotFoundError from Python 3?

I am currently using Python 2 on a project that needs a Python 3 built-in exception: FileNotFoundError. How do I do it?
You can of course define any exceptions you want.
But they're not going to do you any good. The whole point of FileNotFoundError is that any Python operation that runs into a file-not-found error will raise that exception. Just defining your own exception won't make that true. All you're going to get is an OSError (or IOError, depending on 2.x version) with an appropriate errno value. If you try to handle a custom FileNotFoundError, your handler will never get called.
So, what you really want is (for example):
try:
f = open(path)
except OSError as e:
if e.errno == errno.ENOENT:
# do your FileNotFoundError code here
else:
raise
You could use IOError instead:
Raised when an I/O operation (such as a print statement, the built-in open() function or a method of a file object) fails for an I/O-related reason, e.g., “file not found” or “disk full”.
This class is derived from EnvironmentError. See the discussion above for more information on exception instance attributes.
Changed in version 2.6: Changed socket.error to use this as a base class.
You can simply create the FileNotFoundError exception yourself:
class FileNotFoundError(OSError):
pass
This new exception class inherits from OSError just like the one in Python 3.x.
Here is a reference on User-defined Exceptions in Python.
Short answer: Just use EnvironmentError and check err.errno == errno.ENOENT for either Python 2 or Python 3.
Long answer:
As other answers have mentioned, FileNotFoundError is new to Python 3.
Python 2 used OSError (or IOError, depending on 2.x version). OSError and IOError both inherit from EnvironmentError.
In Python 3, EnvironmentError is aliased to OSError. FileNotFoundError inherits from OSError, which means that FileNotFoundError can be caught with EnvironmentError, and it shares the same interface as OSError and IOError.
So, good news! This means that there is a relatively easy way to make your project compatible with both Python 2 and Python 3 at the same time: leave FileNotFoundError out of it, and just catch EnvironmentError.
# Works for Python 2. Also works for Python 3.
import errno
try:
open("fake.file", 'r')
except EnvironmentError as err:
if err.errno == errno.ENOENT: # ENOENT -> "no entity" -> "file not found"
print("Caught 'file not found' exception")
else:
raise

os.rename on windows raise WindowsError instead of OSError

Python documentation says that
os.rename(src, dst)
... On Windows, if dst already exists, OSError will be raised even if it is a file ...
However, for me it raises WindowsError. Is there a mistake in the documentation?
The second part of the question (more general, but inspired by the problem formulated above):
UPD I am sorry, the second part of the question was incorrect. WindowsError is indeed catched by except OSError as it should.
Since OSError is a superclass of WindowsError, just catch the OSError.
FWIW, the core devs are free to raise an exception more specific than the minimum promised by the docs.
Also, the following code works fine for me (Python2.7.2 running on WindowsXP):
try:
raise os.rename('nonexisting_file', 'def')
except OSError:
print 'caught'

Categories