assertionerror returning empty string in python - python

I am doing this:
try: self.failUnless(sel.is_text_present("F!")) #sel.is_text_present("F!") is false
except AssertionError, e:
print("x"+e+"y")
sys.exit()
it is printing nothing except xy. no class name or anything else. what does the error in AssertionError normally contain?
edit: apparently the user provides its own message. selenium generated many of these:
except AssertionError, e: self.verificationErrors.append(str(e))
without sending in a message at all, so it appends a bunch of empty strings to verificationErrors.

Don't catch the errors from assertions. All the assertions in the unittest module take a final parameter, msg, which is the message to be raised if the assertion fails. Put your debugging there if necessary.

Standard assert statement doesn't put anything into the AssertionError, it's the traceback that matters. There is a assert expr, msg variant that sets the error message, if you're using unittest, then the second argument of assertTrue (failUnless is deprecated) will do it.

Sounds like you want to use your assertions as debug statements in the event of a failure. This should help...
import traceback
try:
assert 1 == 2
except AssertionError:
traceback.print_exc()
This prints:
Traceback (most recent call last):
File "./foo.py", line 4, in <module>
assert 1 == 2

Related

Python store and raise last exception with traceback [duplicate]

How do I raise an exception in Python so that it can later be caught via an except block?
How do I manually throw/raise an exception in Python?
Use the most specific Exception constructor that semantically fits your issue.
Be specific in your message, e.g.:
raise ValueError('A very specific bad thing happened.')
Don't raise generic exceptions
Avoid raising a generic Exception. To catch it, you'll have to catch all other more specific exceptions that subclass it.
Problem 1: Hiding bugs
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
For example:
def demo_bad_catch():
try:
raise ValueError('Represents a hidden bug, do not catch this')
raise Exception('This is the exception you expect to handle')
except Exception as error:
print('Caught this error: ' + repr(error))
>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)
Problem 2: Won't catch
And more specific catches won't catch the general exception:
def demo_no_catch():
try:
raise Exception('general exceptions not caught by specific handling')
except ValueError as e:
print('we will not catch exception: Exception')
>>> demo_no_catch()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling
Best Practices: raise statement
Instead, use the most specific Exception constructor that semantically fits your issue.
raise ValueError('A very specific bad thing happened')
which also handily allows an arbitrary number of arguments to be passed to the constructor:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
These arguments are accessed by the args attribute on the Exception object. For example:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
prints
('message', 'foo', 'bar', 'baz')
In Python 2.5, an actual message attribute was added to BaseException in favor of encouraging users to subclass Exceptions and stop using args, but the introduction of message and the original deprecation of args has been retracted.
Best Practices: except clause
When inside an except clause, you might want to, for example, log that a specific type of error happened, and then re-raise. The best way to do this while preserving the stack trace is to use a bare raise statement. For example:
logger = logging.getLogger(__name__)
try:
do_something_in_app_that_breaks_easily()
except AppError as error:
logger.error(error)
raise # just this!
# raise AppError # Don't do this, you'll lose the stack trace!
Don't modify your errors... but if you insist.
You can preserve the stacktrace (and error value) with sys.exc_info(), but this is way more error prone and has compatibility problems between Python 2 and 3, prefer to use a bare raise to re-raise.
To explain - the sys.exc_info() returns the type, value, and traceback.
type, value, traceback = sys.exc_info()
This is the syntax in Python 2 - note this is not compatible with Python 3:
raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]
If you want to, you can modify what happens with your new raise - e.g. setting new args for the instance:
def error():
raise ValueError('oops!')
def catch_error_modify_message():
try:
error()
except ValueError:
error_type, error_instance, traceback = sys.exc_info()
error_instance.args = (error_instance.args[0] + ' <modification>',)
raise error_type, error_instance, traceback
And we have preserved the whole traceback while modifying the args. Note that this is not a best practice and it is invalid syntax in Python 3 (making keeping compatibility much harder to work around).
>>> catch_error_modify_message()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in catch_error_modify_message
File "<stdin>", line 2, in error
ValueError: oops! <modification>
In Python 3:
raise error.with_traceback(sys.exc_info()[2])
Again: avoid manually manipulating tracebacks. It's less efficient and more error prone. And if you're using threading and sys.exc_info you may even get the wrong traceback (especially if you're using exception handling for control flow - which I'd personally tend to avoid.)
Python 3, Exception chaining
In Python 3, you can chain Exceptions, which preserve tracebacks:
raise RuntimeError('specific message') from error
Be aware:
this does allow changing the error type raised, and
this is not compatible with Python 2.
Deprecated Methods:
These can easily hide and even get into production code. You want to raise an exception, and doing them will raise an exception, but not the one intended!
Valid in Python 2, but not in Python 3 is the following:
raise ValueError, 'message' # Don't do this, it's deprecated!
Only valid in much older versions of Python (2.4 and lower), you may still see people raising strings:
raise 'message' # really really wrong. don't do this.
In all modern versions, this will actually raise a TypeError, because you're not raising a BaseException type. If you're not checking for the right exception and don't have a reviewer that's aware of the issue, it could get into production.
Example Usage
I raise Exceptions to warn consumers of my API if they're using it incorrectly:
def api_func(foo):
'''foo should be either 'baz' or 'bar'. returns something very useful.'''
if foo not in _ALLOWED_ARGS:
raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))
Create your own error types when apropos
"I want to make an error on purpose, so that it would go into the except"
You can create your own error types, if you want to indicate something specific is wrong with your application, just subclass the appropriate point in the exception hierarchy:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
and usage:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
Don't do this. Raising a bare Exception is absolutely not the right thing to do; see Aaron Hall's excellent answer instead.
It can't get much more Pythonic than this:
raise Exception("I know Python!")
Replace Exception with the specific type of exception you want to throw.
See the raise statement documentation for Python if you'd like more information.
In Python 3 there are four different syntaxes for raising exceptions:
raise exception
raise exception (args)
raise
raise exception (args) from original_exception
1. Raise exception vs. 2. raise exception (args)
If you use raise exception (args) to raise an exception then the args will be printed when you print the exception object - as shown in the example below.
# Raise exception (args)
try:
raise ValueError("I have raised an Exception")
except ValueError as exp:
print ("Error", exp) # Output -> Error I have raised an Exception
# Raise exception
try:
raise ValueError
except ValueError as exp:
print ("Error", exp) # Output -> Error
3. Statement raise
The raise statement without any arguments re-raises the last exception.
This is useful if you need to perform some actions after catching the exception and then want to re-raise it. But if there wasn't any exception before, the raise statement raises a TypeError Exception.
def somefunction():
print("some cleaning")
a=10
b=0
result=None
try:
result=a/b
print(result)
except Exception: # Output ->
somefunction() # Some cleaning
raise # Traceback (most recent call last):
# File "python", line 8, in <module>
# ZeroDivisionError: division by zero
4. Raise exception (args) from original_exception
This statement is used to create exception chaining in which an exception that is raised in response to another exception can contain the details of the original exception - as shown in the example below.
class MyCustomException(Exception):
pass
a=10
b=0
reuslt=None
try:
try:
result=a/b
except ZeroDivisionError as exp:
print("ZeroDivisionError -- ",exp)
raise MyCustomException("Zero Division ") from exp
except MyCustomException as exp:
print("MyException",exp)
print(exp.__cause__)
Output:
ZeroDivisionError -- division by zero
MyException Zero Division
division by zero
For the common case where you need to throw an exception in response to some unexpected conditions, and that you never intend to catch, but simply to fail fast to enable you to debug from there if it ever happens — the most logical one seems to be AssertionError:
if 0 < distance <= RADIUS:
#Do something.
elif RADIUS < distance:
#Do something.
else:
raise AssertionError("Unexpected value of 'distance'!", distance)
Read the existing answers first, this is just an addendum.
Notice that you can raise exceptions with or without arguments.
Example:
raise SystemExit
exits the program, but you might want to know what happened. So you can use this.
raise SystemExit("program exited")
This will print "program exited" to standard error before closing the program.
Just to note: there are times when you do want to handle generic exceptions. If you're processing a bunch of files and logging your errors, you might want to catch any error that occurs for a file, log it, and continue processing the rest of the files. In that case, a
try:
foo()
except Exception as e:
print(e) # Print out handled error
block is a good way to do it. You'll still want to raise specific exceptions so you know what they mean, though.
Another way to throw an exception is using assert. You can use assert to verify a condition is being fulfilled. If not, then it will raise AssertionError. For more details have a look here.
def avg(marks):
assert len(marks) != 0, "List is empty."
return sum(marks)/len(marks)
mark2 = [55,88,78,90,79]
print("Average of mark2:", avg(mark2))
mark1 = []
print("Average of mark1:", avg(mark1))
You might also want to raise custom exceptions. For example, if you're writing a library, it's a very good practice to make a base exception class for your module, and then have custom sub-exceptions to be more specific.
You can achieve that like this:
class MyModuleBaseClass(Exception):
pass
class MoreSpecificException(MyModuleBaseClass):
pass
# To raise custom exceptions, you can just
# use the raise keyword
raise MoreSpecificException
raise MoreSpecificException('message')
If you're not interested in having a custom base class, you can just inherit your custom exception classes from an ordinary exception class like Exception, TypeError, ValueError, etc.
If you don't care about which error to raise, you could use assert to raise an AssertionError:
>>> assert False, "Manually raised error"
Traceback (most recent call last):
File "<pyshell#24>", line 1, in <module>
assert False, "Manually raised error"
AssertionError: Manually raised error
>>>
The assert keyword raises an AssertionError if the condition is False. In this case, we specified False directly, so it raises the error, but to have it have a text we want it to raise to, we add a comma and specify the error text we want. In this case, I wrote Manually raised error and this raises it with that text.
You should learn the raise statement of Python for that.
It should be kept inside the try block.
Example -
try:
raise TypeError # Replace TypeError by any other error if you want
except TypeError:
print('TypeError raised')

Python: Does finally needs a try-except clause?

Suppose the following code.
try:
some_code_1
except: # will it be called twice, if an error occures in finally?
some_code_2
finally:
some_code_3
Suppose an exception occurs in some_code_3. Do I need an extra try-except clause around some_code_3 (see below) or will the exception with some_code_2 be called again, which in principle could cause an infinite loop?
Is this saver?
try:
some_code_1
except: # will it be called twice, if an error occures in finally?
some_code_2
finally:
try:
some_code_3
except:
pass
Just give it a try:
try:
print(abc) #Will raise NameError
except:
print("In exception")
finally:
print(xyz) #Will raise NameError
Output:
In exception
Traceback (most recent call last):
File "Z:/test/test.py", line 7, in <module>
print(xyz)
NameError: name 'xyz' is not defined
So no, it doesn't end up in an infinite loop
python doesn't go back in the execution flow, but rather statement by statement.
By the time it reaches finally, if an error is thrown there, it needs yet another handle
The finally in your sample code will not catch exception from some_code_3.
whether it's needed to catch exception from some_code_3 depends on your design.

Why doesn't an invalid exception name in an "except" statement cause a NameError immediately?

Consider this example, with a deliberate typo:
try:
print("Hello!")
raise ValueError("?")
except ValueErro:
print("Error!")
finally:
print("World!")
The handling of the explicitly raised ValueError results in a NameError:
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
ValueError: ?
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
NameError: name 'ValueErro' is not defined
However, if a ValueError is not raised:
try:
print("Hello!")
except ValueErro:
print("Error!")
finally:
print("World!")
then no exception occurs; Hello! and World! are simply printed.
Why is there no NameError caused by the typo ValueErro (no such name exists)? Shouldn't this have been detected ahead of time?
Can I use a different syntax to ensure that the problem is caught ahead of time?
After a comment from #DYZ, I found the right search terms to get the answer.
https://docs.python.org/3/tutorial/errors.html#handling-exceptions
The try statement works as follows.
First, the try clause (the statement(s) between the try and except keywords) is executed.
If no exception occurs, the except clause is skipped and execution of the try statement is finished.
Another resource exploring this problem.
https://dbaktiar-on-python.blogspot.com/2009/07/python-lazy-evaluation-on-exception.html
-
My Solution moving forward:
# Explicitly bind the Exception Names in a non-lazy fashion.
errors = (KeyboardInterrupt, ValueErro) # Caught!
try:
print("Hello!")
raise ValueError("?")
except errors:
print("Error!")
finally:
print("World!")
-
tl;dr - The except clauses are entirely skipped if the try clauses executes without exception.
Exceptions can be defined at run time. Example:
myexcept.py contains:
class ValueErro(Exception):
pass
Your program slightly modified:
import_myexcept = False
if import_myexcept:
from myexcept import ValueErro
try:
print("Hello!")
raise ValueError("?")
except ValueErro:
print("Error!")
finally:
print("World!")
This behaves just like your program: NameError: name 'ValueErro' is not defined.
But change: import_myexcept = True, and by the time the except ValueErro: statement is encountered, the ValueErro exception is defined and no NameError occurs.

Exception raising does not reflect in test case even though raised as seen in logs

I'm practicing TDD in Python and came across a problem in testing whether an exception is raised.
Here is my test_phonebook.py with test_add_empty_name_raises_exception which fails.
import unittest
import phonebook
class Test(unittest.TestCase):
def test_add_empty_name_raises_exception(self):
self.assertRaises(ValueError, phonebook.add, "", "1111111111")
if __name__ == "__main__":
# import sys;sys.argv = ['', 'Test.testName']
unittest.main()
Below is my phonebook.py with the method add which adds the data into the dictionary.
import re
_phonebook = {}
file_name = "phonebook.txt"
def is_valid_name(name):
return re.search(r"([A-Z][a-z]*)([\\s\\\'-][A-Z][a-z]*)*", name) is not None
def is_valid_number(number):
return re.search(r"\+?[\d ]+$", number) is not None
def add(name, number):
try:
if is_valid_name(name) and is_valid_number(number):
_phonebook[name] = number
else:
raise ValueError("Invalid arguments.", name, number)
except ValueError as err:
print err.args
if __name__ == '__main__':
pass
My problem is that the test fails even though it is seen in the console log that there was a ValueError raised within the add method.
Finding files... done.
Importing test modules ... done.
('Invalid arguments.', '', '1111111111')
======================================================================
FAIL: test_add_empty_name_raises_exception (path.to.phonebook.test_phonebook.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "path\to\phonebook\test_phonebook.py", line 13, in test_add_empty_name_raises_exception
self.assertRaises(ValueError, phonebook.add, "", "1111111111")
AssertionError: ValueError not raised
----------------------------------------------------------------------
Ran 1 test in 0.002s
How do I solve this? I there something I forgot?
I also tried using the new format for handling exceptions in tests in Python 2.7 but it still hasn't caught the ValueError raising.
def test_add_empty_name_raises_exception(self):
with self.assertRaises(ValueError):
self.phonebook.add("", "1111111111)
I also changed the form of the test case into using lambdas but still no changes.
def test_add_empty_name_raises_exception(self):
self.assertRaises(ValueError, lambda: phonebook.add("", "1111111111"))
I also cleaned my directory and restarted Eclipse Luna and problem still persists.
Possible solution
I was reading the 8.Errors and Exceptions documentation and got to the "Raising Exceptions" part which states that:
If you need to determine whether an exception was raised but don’t intend to handle it,
a simpler form of the raise statement allows you to re-raise the exception:
I added this to the existing add method as such:
def add(name, number):
try:
if is_valid_name(name) and is_valid_number(number):
_phonebook[name] = number
print "Added %s:\t%s" % (name, number)
else:
raise ValueError("Invalid arguments.", name, number)
except ValueError as err:
print err.args
raise
Which caused the test case to pass.
Is this the correct way? To call raise again in the except block?
When you catch an exception (in your except ValueError as err: block), you prevent it from continuing back up the call stack to eventually terminate the program. Essentially, you're saying "I know how to handle this, so no need to panic anyone else."
Re-raising an exception is the proper thing to do if you caught the exception but didn't do so to actually fix anything, for instance, to log that it occurred. Typically, though, one catches an exception in order to correct it.
In your case, you're catching the exception almost immediately after you yourself raised it. Why not put your logging statement in the same else block as the raise? No need for a try: ... except: indent at all.
def add(name, number):
if is_valid_name(name) and is_valid_number(number):
_phonebook[name] = number
print "Added %s:\t%s" % (name, number)
else:
print "Invalid arguments.", name, number
raise ValueError("Invalid arguments.", name, number)
return

Print Python Exception Type (Raised in Fabric)

I'm using Fabric to automate, including the task of creating a directory. Here is my fabfile.py:
#!/usr/bin/env python
from fabric.api import *
def init():
try:
local('mkdir ./www')
except ##what exception?##:
#print exception name to put in above
Run fab fabfile.py and f I already have ./www created an error is raised, but I don't know what kind, so I don't know how to handle the error yet. Fabric only prints out the following:
mkdir: cannot create directory ‘./www’: File exists
Fatal error: local() encountered an error (return code 1) while executing 'mkdir ./www'
Aborting.
What I want to do is be able to find out the error type so that I can except my errors properly without blanket statements. It would be really helpful if an answer does not just tell me how to handle a mkdir exception, but print (or otherwise find the name to) any exception I may run into down the line (mkdir is just an example).
Thank you!
The issue is that fabric uses subprocess for doing these sorts of things. If you look at the source code for local you can see it doesn't actually raise an exception. It calls suprocess.Popen and uses communicate() to read stdout and stderr. If there is a non-zero return code then it returns a call to either warn or abort. The default is abort. So, to do what you want, try this:
def init():
with settings(warn_only=True):
local('mkdir ./www')
If you look at the source for abort, it looks like this:
10 def abort(msg):
21 from fabric.state import output
22 if output.aborts:
23 sys.stderr.write("\nFatal error: %s\n" % str(msg))
24 sys.stderr.write("\nAborting.\n")
25 sys.exit(1)
So, the exception would be a SystemExit exception. While you could catch this, the proper way to do it is outlined above using settings.
It is nothing to handle with exception, it is from the fabric api
try to set the entire script's warn_only setting to be true with
env.warn_only = True
Normally, when you get an uncaught exception, Python will print the exception type along with the error message:
>>> raise IOError("Error message.")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: Error message.
If that's not happening, you're probably not getting an exception at all.
If you really want to catch an arbitrary exception and print it, you want to catch Exception or BaseException. BaseException will include even things like KeyboardInterrupt, though, so be careful with that.
def init():
try:
local('mkdir ./www')
except BaseException as e:
print "local() threw a", type(e).__name__
raise # Reraise the exception
In general:
try:
some_code()
except Exception, e:
print 'Hit An Exception', e
raise
Will tell you what the exception was but if you are not planning on actually handling some of the exceptions then simply getting rid of the try: except: lines will have exactly the same effect.
Also if you run your code under a debugger then you can look at the exception(s) that you hit in more detail.
def init():
try:
local('mkdir ./www')
except Exception as e:
print e.__class__.__name__
That's all there is to it!
edit: Just re-read your question and realized that my code would only print "Fatal" in your case. It looks like fabric is throwing an error and returning their own error code so you would have to look at the documentation. I don't have any experience with fabric so I'd suggest to look here if you haven't already. Sorry if this isn't helpful!

Categories

Resources