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'
Related
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
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
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.
I'm writing some code to manipulate the Windows clipboard. The first thing I do is to try and open the clipboard with OpenClipboard() function from the Windows API:
if OpenClipboard(None):
# Access the clipboard here
else:
# Handle failure
This function can fail. So if it does, I would like to raise an exception. My question is, which of the standard Python exceptions should I raise? I'm thinking WindowsError would be the right one, but not sure. Could someone please give me a suggestion?
It is better to avoid raising standard exceptions directly. Create your own exception class, inherit it from the most appropriate one (WindowsError is ok) and raise it. This way you'll avoid confusion between your own errors and system errors.
Raise the windows error and give it some extra infomation, for example
raise WindowsError("Clipboard can't be opened")
Then when its being debugged they can tell what your windows error means rather than just a random windowserror over nothing.
WindowsError seems a reasonable choice, and it will record extra error information for you. From the docs:
exception WindowsError
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. ...
I'm importing a module which raises the following error in some conditions:
RuntimeError: pyparted requires root access
I know that I can just check for root access before the import, but I'd like to know how to catch this spesific kind of error via a try/except statement for future reference. Is there any way to differentiate between this RuntimeError and others that might be raised?
You can check attributes of the exception to differentiate from other possible RuntimeError exceptions. For example, re-raise the error if it does not match a predefined message text.
try:
import pypatred
except RuntimeError,e:
if e.message == 'RuntimeError: pyparted requires root access':
return 'pyparted - no root access'
raise
Of course, direct text comparison is just an example, you could search for included substrings or regular expressions.
It is worth noting that the .message attribute of exceptions is deprecated starting with Python 2.6. You can find the text in .args, usually args[0].
... For 2.6, the message attribute is being deprecated in favor of the args attribute.
I know that I can just check for root access before the import, but I'd like to know how to catch this spesific kind of error via a try/except statement for future reference. Is there any way to differentiate between this RuntimeError and others that might be raised?
If the error is caused by a specific condition, then I think the easiest way to catch the error is to test for the condition, and you can raise a more specific error yourself. After all the 'error' exists before the error is thrown, since in this case its a problem with the environment.
I agree with those above - text matching on an error is kind of a terrifying prospect.
try:
import pyparted
except RuntimeError:
print('RuntimeError is raised')
raise
more on exception handling in tutorial.
This situation should produce ImportError in my opinion. And you can do it yourself:
try:
import pyparted
except RuntimeError as e:
raise ImportError(e)
RuntimeError Raised when an error is detected that doesn’t fall in any of the other categories
def foo():
try:
foo()
except RuntimeError, e:
print e
print " Runtime Error occurred due to exceeded maximum recursion depth "
That is how we will catch the RuntimeError caused by the exceeded recursion limit in python
And if you want to call your function over the recursion limit you can do the following
import sys
def foo():
try:
foo()
except RuntimeError, e:
sys.setrecursionlimit(1200)
foo()
But always it is highly not recommended to change the recursion limit,
but very small changes in the recursion limit are allowed
Yes.
try:
import module
except RuntimeError:
pass
imports are interpreted as any other statement, they are not special. You could do an
if condition:
import module
try:
import ...
except RuntimeError:
# Do something