I am attempting to convert the following pseudo-code to Python:
If <directory> does not exist:
Create all subdirectories for <directory>
Create a file in <directory>
This sounds simple enough to accomplish with os.makedirs and os.path.isdir:
if not os.path.isdir('/some/path'):
os.makedirs('/some/path')
open('/some/path/test.txt', 'w')
However, upon further inspection there is clearly a race condition present. Consider the following timeline:
the specified directory (/some/path) does not exist
the Python interpreter executes the first line, which evaluates to True
another process creates the directory (/some/path)
makedirs raises an OSError exception since the directory already exists
There are also problems if the directory does initially exist but is removed by another process before the final line is executed.
When it comes to Python, "it's easier to ask for forgiveness than permission." With that in mind, the fragment above could be better written:
try:
os.makedirs('/some/path')
except OSError:
pass
open('/some/path/test.txt', 'w')
This solves the two problems described above but creates a third: os.makedirs raises an OSError exception when one of the following conditions occurs:
the directory already exists
the directory could not be created
This means that there is no way to determine which of the two conditions caused the exception to be raised. In other words, actual failures will be silently ignored, which is not what I want.
How can I work around this problem?
I'll note that all of this is quite a bit more sane in python 3; FileExistsError and PermissionError are separate (subclass of OSError) exceptions that you can catch, and os.makedirs even has a exist_ok kwarg to suppress the former when you're ok with the directory already existing.
If you want to inspect the reason for the OSError, that info is in a tuple in e.args (or optionally e.errno if you just want to look at the error code):
try:
os.makedirs('/etc/python')
except OSError as e:
print e.args
(17, 'File exists')
try:
os.makedirs('/etc/stuff')
except OSError as e:
print e.args
(13, 'Permission denied')
try:
os.makedirs('/etc/stuff')
except OSError as e:
print e.errno
13
So you'll have to do a bit of introspection and handle the two error codes differently in your except block.
Related
I want to explicitly fail the step in behave when I encounter an exception
eg. I am writing the code according to behave documentation -
from behave import *
#when('verify test fails.*?(?P<param_dict>.*)')
def test_logger(context, param_dict):
try:
logger.info("testing the logger. this is info message")
logger.info(1/0)
except Exception as e:
logger.error("arrived at exception: "+str(e))
fail("failed with exception: "+str(e))
but it throws this error:
NameError: name 'fail' is not defined
I tried other ways too, but nothing works
eg. context.failed = True (did not work either)
If I do not try to fail explicitly, final test result becomes PASS even if it goes in exception block ...which is weird.
context.failed is only an attribute set by Behave and doesn't do anything as is. It's an information attribute, and while you can use it to determine a fail-case and throw an assertion error, it will not do anything on it's own. See context.failed
As for the fail method you've mentioned, it is probably from the unittest module, as seen here. This module is used in Behave's development tests (see their Github) as well. I'll agree though, that this should be clarified in their documentation.
To fix your error you'd need to import the unittest module. To explicitly fail the step, you'd just raise the exception after you've logged your message, something like this:
except Exception as e:
logger.error("arrived at exception: "+str(e))
fail("failed with exception: "+str(e))
raise
As #Verv mentioned in their answer, a behave step will be marked as failed whenever an exception is thrown, so you could just re-raise the exception.
However, behave will show the backtrace for normal exceptions, whereas you probably just want to show a specific failure message.
For that, raise an AssertionError. In your code, that would look like this:
except Exception as e:
logger.error("arrived at exception: " + str(e))
raise AssertionError("failed with exception: " + str(e))
If behave encounters an AssertionError, it will fail the step, display the message you instantiate the error with, but not display other exception stuff.
I have code in multi threads to create folder if not exists
if not os.path.exists(folder): os.makedirs(folder)
I got error like this
The folder cannot be created since a file already exists with the same path
I am not sure what can I do for this error, do you have any idea?
Read the docs. If you don't care whether the directory already existed, just that it does when you're done, just call:
os.makedirs(folder, exist_ok=True)
Don't even check for the existence of the directory with exists (subject to race conditions), just call os.makedirs with exist_ok=True and it will create it if it doesn't exist and do nothing if it already exists.
This requires Python 3.2 or higher, but if you're on an earlier Python, you can achieve the same silent ignore with exception handling:
import errno
try:
os.makedirs(folder)
except OSError as e:
if e.errno != errno.EEXIST:
raise # Reraise if failed for reasons other than existing already
I have a script which create a temporary text file and delete after the user close the window.
The problem is that, the temporary text file may or may not be created depending on what the user does.Or sometimes the temporary text file may be deleted before the user exit. There are three possible scenario.
The temporary text file is created with the name of 'tempfilename'.
The temporary text file is created with the name of 'tempfilename' but deleted before the user exit.So, when trying to remove the file it raise OSError
The temporary text file is not created and no variable called 'tempfilename' is created, so it raise NameError
I have tried using this code:
try:
os.remove(str(tempfilename))
except OSError or NameError:
pass
But it seems that it only catch the OSError only. Did i do something wrong?
try:
os.remove(str(tempfilename))
except (OSError, NameError):
pass
tempfilename = None
# ...
if tempfilename is not None and os.path.exists(tempfilename):
os.remove(tempfilename)
It's not good to catch NameError since it will hide other typos in your code (e.g., os.remov(…)).
Also, OSError does not always means that the file did not exist. On Windows, if the file was in use, an exception would be raised (http://docs.python.org/2/library/os.html#os.remove). In that case, you would want to see the exception so you could be aware of the issue and/or handle it another way.
Exception handlers should be kep as narrow as possible to avoid hiding unrelated errors or bugs
I want to move a file, but in the case it is not found I should just ignore it. In all other cases the exception should be propagated. I have the following piece of Python code:
try:
shutil.move(old_path, new_path)
except IOError as e:
if e.errno != 2: raise e
errno == 2 is the one, that has 'No such file or directory' description. I wonder if this is stable across Python versions and platforms, and etc.
It is better to use values from the errno module instead of hardcoding the value 2:
try:
shutil.move(old_path, new_path)
except IOError as e:
if e.errno != errno.ENOENT: raise e
This makes your code less likely to break in case the integer error value changes (although that is unlikely to occur).
if we take a look at a file copy function, we can see there are several exceptions to handle. A good example is here: http://msdn.microsoft.com/en-us/library/9706cfs5.aspx
my question is if i use python shutil copy2, what should I pay attention to cope with various exceptions (source file not found, access not authorized, etc.)?
e.g.
def copy_file (self):
if not os.path.isdir(dest_path):
os.makedirs(dest_path)
shutil.copy2(src_path, dest_path)
what should i do to the above function?
You may just need handle the IOError exception that may be caused due to any permissions or Invalid destination name issue.
try:
shutil.copy(src,dst)
except IOError as e:
print e
The other exceptions mentioned in the MSDN article seems to fall under the same IOError in python. The FileNotFound and DirectoryNotFound are not really applicable as shutil.copy will create the destination if it not already exists. Also, I find that happening of OSError are also remote this in case.