What is the use of "assert" in Python? - python

What does assert mean? How is it used?

The assert statement exists in almost every programming language. It has two main uses:
It helps detect problems early in your program, where the cause is clear, rather than later when some other operation fails. A type error in Python, for example, can go through several layers of code before actually raising an Exception if not caught early on.
It works as documentation for other developers reading the code, who see the assert and can confidently say that its condition holds from now on.
When you do...
assert condition
... you're telling the program to test that condition, and immediately trigger an error if the condition is false.
In Python, it's roughly equivalent to this:
if not condition:
raise AssertionError()
Try it in the Python shell:
>>> assert True # nothing happens
>>> assert False
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
Assertions can include an optional message, and you can disable them when running the interpreter.
To print a message if the assertion fails:
assert False, "Oh no! This assertion failed!"
Do not use parenthesis to call assert like a function. It is a statement. If you do assert(condition, message) you'll be running the assert with a (condition, message) tuple as first parameter.
As for disabling them, when running python in optimized mode, where __debug__ is False, assert statements will be ignored. Just pass the -O flag:
python -O script.py
See here for the relevant documentation.

Watch out for the parentheses. As has been pointed out in other answers, in Python 3, assert is still a statement, so by analogy with print(..), one may extrapolate the same to assert(..) or raise(..) but you shouldn't.
This is wrong:
assert(2 + 2 == 5, "Houston we've got a problem")
This is correct:
assert 2 + 2 == 5, "Houston we've got a problem"
The reason the first one will not work is that bool( (False, "Houston we've got a problem") ) evaluates to True.
In the statement assert(False), these are just redundant parentheses around False, which evaluate to their contents. But with assert(False,) the parentheses are now a tuple, and a non-empty tuple evaluates to True in a boolean context.

As other answers have noted, assert is similar to throwing an exception if a given condition isn't true. An important difference is that assert statements get ignored if you compile your code with the optimization option -O. The documentation says that assert expression can better be described as being equivalent to
if __debug__:
if not expression: raise AssertionError
This can be useful if you want to thoroughly test your code, then release an optimized version when you're happy that none of your assertion cases fail - when optimization is on, the __debug__ variable becomes False and the conditions will stop getting evaluated. This feature can also catch you out if you're relying on the asserts and don't realize they've disappeared.

The goal of an assertion in Python is to inform developers about unrecoverable errors in a program.
Assertions are not intended to signal expected error conditions, like “file not found”, where a user can take corrective action (or just try again).
Another way to look at it is to say that assertions are internal self-checks in your code. They work by declaring some conditions as impossible in your code. If these conditions don’t hold that means there’s a bug in the program.
If your program is bug-free, these conditions will never occur. But if one of them does occur the program will crash with an assertion error telling you exactly which “impossible” condition was triggered. This makes it much easier to track down and fix bugs in your programs.
Here’s a summary from a tutorial on Python’s assertions I wrote:
Python’s assert statement is a debugging aid, not a mechanism for handling run-time errors. The goal of using assertions is to let developers find the likely root cause of a bug more quickly. An assertion error should never be raised unless there’s a bug in your program.

Others have already given you links to documentation.
You can try the following in a interactive shell:
>>> assert 5 > 2
>>> assert 2 > 5
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
builtins.AssertionError:
The first statement does nothing, while the second raises an exception. This is the first hint: asserts are useful to check conditions that should be true in a given position of your code (usually, the beginning (preconditions) and the end of a function (postconditions)).
Asserts are actually highly tied to programming by contract, which is a very useful engineering practice:
http://en.wikipedia.org/wiki/Design_by_contract.

From docs:
Assert statements are a convenient way to insert debugging assertions into a program
You can read more here: http://docs.python.org/release/2.5.2/ref/assert.html

The assert statement has two forms.
The simple form, assert <expression>, is equivalent to
if __​debug__:
if not <expression>: raise AssertionError
The extended form, assert <expression1>, <expression2>, is equivalent to
if __​debug__:
if not <expression1>: raise AssertionError(<expression2>)

Assertions are a systematic way to check that the internal state of a program is as the programmer expected, with the goal of catching bugs. See the example below.
>>> number = input('Enter a positive number:')
Enter a positive number:-1
>>> assert (number > 0), 'Only positive numbers are allowed!'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: Only positive numbers are allowed!
>>>

Here is a simple example, save this in file (let's say b.py)
def chkassert(num):
assert type(num) == int
chkassert('a')
and the result when $python b.py
Traceback (most recent call last):
File "b.py", line 5, in <module>
chkassert('a')
File "b.py", line 2, in chkassert
assert type(num) == int
AssertionError

As summarized concisely on the C2 Wiki:
An assertion is a boolean expression at a specific point in a program which will be true unless there is a bug in the program.
You can use an assert statement to document your understanding of the code at a particular program point. For example, you can document assumptions or guarantees about inputs (preconditions), program state (invariants), or outputs (postconditions).
Should your assertion ever fail, this is an alert for you (or your successor) that your understanding of the program was wrong when you wrote it, and that it likely contains a bug.
For more information, John Regehr has a wonderful blog post on the Use of Assertions, which applies to the Python assert statement as well.

The assert statement exists in almost every programming language. It helps detect problems early in your program, where the cause is clear, rather than later as a side-effect of some other operation. They always expect a True condition.
When you do something like:
assert condition
You're telling the program to test that condition and immediately trigger an error if it is false.
In Python, assert expression, is equivalent to:
if __debug__:
if not <expression>: raise AssertionError
You can use the extended expression to pass an optional message:
if __debug__:
if not (expression_1): raise AssertionError(expression_2)
Try it in the Python interpreter:
>>> assert True # Nothing happens because the condition returns a True value.
>>> assert False # A traceback is triggered because this evaluation did not yield an expected value.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
There are some caveats to seen before using them mainly for those who deem to toggles between the assert and if statements. The aim to use assert is on occasions when the program verifies a condition and return a value that should stop the program immediately instead of taking some alternative way to bypass the error:
1. Parentheses
As you may have noticed, the assert statement uses two conditions. Hence, do not use parentheses to englobe them as one for obvious advice. If you do such as:
assert (condition, message)
Example:
>>> assert (1==2, 1==1)
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
You will be running the assert with a (condition, message) which represents a tuple as the first parameter, and this happens cause non-empty tuple in Python is always True. However, you can do separately without problem:
assert (condition), "message"
Example:
>>> assert (1==2), ("This condition returns a %s value.") % "False"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: This condition returns a False value.
2. Debug purpose
If you are wondering regarding when use assert statement. Take an example used in real life:
* When your program tends to control each parameter entered by the user or whatever else:
def loremipsum(**kwargs):
kwargs.pop('bar') # return 0 if "bar" isn't in parameter
kwargs.setdefault('foo', type(self)) # returns `type(self)` value by default
assert (len(kwargs) == 0), "unrecognized parameter passed in %s" % ', '.join(kwargs.keys())
* Another case is on math when 0 or non-positive as a coefficient or constant on a certain equation:
def discount(item, percent):
price = int(item['price'] * (1.0 - percent))
print(price)
assert (0 <= price <= item['price']),\
"Discounted prices cannot be lower than 0 "\
"and they cannot be higher than the original price."
return price
* or even a simple example of a boolean implementation:
def true(a, b):
assert (a == b), "False"
return 1
def false(a, b):
assert (a != b), "True"
return 0
3. Data processing or data validation
The utmost importance is to not rely on the assert statement to execute data processing or data validation because this statement can be turned off on the Python initialization with -O or -OO flag – meaning value 1, 2, and 0 (as default), respectively – or PYTHONOPTIMIZE environment variable.
Value 1:
* asserts are disabled;
* bytecode files are generated using .pyo extension instead of .pyc;
* sys.flags.optimize is set to 1 (True);
* and, __debug__ is set to False;
Value 2: disables one more stuff
* docstrings are disabled;
Therefore, using the assert statement to validate a sort of expected data is extremely dangerous, implying even to some security issues. Then, if you need to validate some permission I recommend you raise AuthError instead. As a preconditional effective, an assert is commonly used by programmers on libraries or modules that do not have a user interact directly.

if the statement after assert is true then the program continues , but if the statement after assert is false then the program gives an error. Simple as that.
e.g.:
assert 1>0 #normal execution
assert 0>1 #Traceback (most recent call last):
#File "<pyshell#11>", line 1, in <module>
#assert 0>1
#AssertionError

What does assert mean? How is it used?
There are great answers here, but not to the second part of the question. Despite many years of practical experience, I only understood the purpose of asserts recently.
Others have already explained how assert is used, so I am super brief. This is how you use it:
assert condition, "error message"
And do not use parentheses, assert is a keyword, not a function.
assert (condition, "error message") # wrong: this never fails!
A good explanation of how to use assert is given here: http://wiki.c2.com/?WhatAreAssertions
The point of assert is to declare invariants in your code. An invariant is a condition that should never be violated unless there is a bug in the code. Think of them as executable documentation. This is deeply connected to how object-oriented programming encapsulates code from the outside world.
In plain English: You should use an assert like a comment in your code for other developers. But it is better than a comment, the "comment" is actually checked in debug mode! If your program cannot be expected to work correctly if the assert is removed, you are using it wrong. In fact, Python will ignore all asserts if you turn on optimizations (python -O). So don't rely on them to be there. In particular, do not use asserts to validate user input. Raise exceptions instead.
Here is a nice example to tie it all together. Let's assume you want to have a special number class in your code which represents positive integers called PositiveInt. Why would you want that? You have many functions that use positive integers as parameters. By using PositiveInt in your code, you don't have to check again and again in every function whether the input is valid. It is guaranteed by PositiveInt. A crude implementation looks like this
class PositiveInt(int):
# int is immutable, so we have to override new and not init
def __new__(cls, value):
if value <= 0:
raise ValueError(f"{value} is not positive")
assert value > 0, "value must be positive"
return super(PositiveInt, cls).__new__(cls, value)
As you can see, I use both an if ...: raise ... for input validation and an assert at the end of the function. This seems superfluous, but only in this trivial example! Imagine that the function is a bit longer and more complex, so it is not obvious that you have validated the input correctly. The assert at the end makes sure that a bug in your validation code is detected. It also makes the intend of the validation code clear to another programmer, more so than a simple comment.
In summary: use assert like a comment. Use it everywhere! It is cheap and if it ever becomes a performance problem for your users, you can turn it off in releases with python -O.

In Pycharm, if you use assert along with isinstance to declare an object's type, it will let you access the methods and attributes of the parent object while you are coding, it will auto-complete automatically.
For example, let's say self.object1.object2 is a MyClass object.
import MyClasss
def code_it(self):
testObject = self.object1.object2 # at this point, program doesn't know that testObject is a MyClass object yet
assert isinstance(testObject , MyClasss) # now the program knows testObject is a MyClass object
testObject.do_it() # from this point on, PyCharm will be able to auto-complete when you are working on testObject

If you ever want to know exactly what a reserved function does in python, type in help(enter_keyword)
Make sure if you are entering a reserved keyword that you enter it as a string.

Python assert is basically a debugging aid which test condition for internal self-check of your code.
Assert makes debugging really easy when your code gets into impossible edge cases. Assert check those impossible cases.
Let's say there is a function to calculate price of item after discount :
def calculate_discount(price, discount):
discounted_price = price - [discount*price]
assert 0 <= discounted_price <= price
return discounted_price
here, discounted_price can never be less than 0 and greater than actual price. So, in case the above condition is violated assert raises an Assertion Error, which helps the developer to identify that something impossible had happened.
Hope it helps :)

My short explanation is:
assert raises AssertionError if expression is false, otherwise just continues the code, and if there's a comma whatever it is it will be AssertionError: whatever after comma, and to code is like: raise AssertionError(whatever after comma)
A related tutorial about this:
https://www.tutorialspoint.com/python/assertions_in_python.htm

As written in other answers, assert statements are used to check the state of
the program at a given point.
I won't repeat what was said about associated
message, parentheses, or -O option and __debug__ constant. Check also the
doc for first
hand information. I will focus on your question: what is the use of assert?
More precisely, when (and when not) should one use assert?
The assert statements are useful to debug a program, but discouraged to check user
input. I use the following rule of thumb: keep assertions to detect a this
should not happen situation. A user
input may be incorrect, e.g. a password too short, but this is not a this
should not happen case. If the diameter of a circle is not twice as large as its
radius, you are in a this should not happen case.
The most interesting, in my mind, use of assert is inspired by the
programming by contract as
described by B. Meyer in [Object-Oriented Software Construction](
https://www.eiffel.org/doc/eiffel/Object-Oriented_Software_Construction%2C_2nd_Edition
) and implemented in the [Eiffel programming language](
https://en.wikipedia.org/wiki/Eiffel_(programming_language)). You can't fully
emulate programming by contract using the assert statement, but it's
interesting to keep the intent.
Here's an example. Imagine you have to write a head function (like the
[head function in Haskell](
http://www.zvon.org/other/haskell/Outputprelude/head_f.html)). The
specification you are given is: "if the list is not empty, return the
first item of a list". Look at the following implementations:
>>> def head1(xs): return xs[0]
And
>>> def head2(xs):
... if len(xs) > 0:
... return xs[0]
... else:
... return None
(Yes, this can be written as return xs[0] if xs else None, but that's not the point).
If the list is not empty, both functions have the same result and this result
is correct:
>>> head1([1, 2, 3]) == head2([1, 2, 3]) == 1
True
Hence, both implementations are (I hope) correct. They differ when you try to
take the head item of an empty list:
>>> head1([])
Traceback (most recent call last):
...
IndexError: list index out of range
But:
>>> head2([]) is None
True
Again, both implementations are correct, because no one should pass an empty
list to these functions (we are out of the specification). That's an
incorrect call, but if you do such a call, anything can happen.
One function raises an exception, the other returns a special value.
The most important is: we can't rely on this behavior. If xs is empty,
this will work:
print(head2(xs))
But this will crash the program:
print(head1(xs))
To avoid some surprises, I would like to know when I'm passing some unexpected
argument to a function. In other words: I would like to know when the observable
behavior is not reliable, because it depends on the implementation, not on the specification.
Of course, I can read the specification, but programmers do not always read carefully
the docs.
Imagine if I had a way to insert the specification into the code to get the
following effect: when I violate the specification, e.g by passing an empty
list to head, I get a warning. That would be a great help to write a correct
(i.e. compliant with the specification) program. And that's where assert
enters on the scene:
>>> def head1(xs):
... assert len(xs) > 0, "The list must not be empty"
... return xs[0]
And
>>> def head2(xs):
... assert len(xs) > 0, "The list must not be empty"
... if len(xs) > 0:
... return xs[0]
... else:
... return None
Now, we have:
>>> head1([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty
And:
>>> head2([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty
Note that head1 throws an AssertionError, not an IndexError. That's
important because an AssertionError is not any runtime error: it signals a
violation of the specification. I wanted a warning, but I get an error.
Fortunately, I can disable the check (using the -O option),
but at my own risks. I will do it a crash is really expensive, and hope for the
best. Imagine my program is embedded in a spaceship that travels through a
black hole. I will disable assertions and hope the program is robust enough
to not crash as long as possible.
This example was only about preconditions, be you can use assert to check
postconditions (the return value and/or the state) and invariants (state of a
class). Note that checking postconditions and invariants with assert can be
cumbersome:
for postconditions, you need to assign the return value to a variable, and
maybe to store the iniial state of the object if you are dealing with a method;
for invariants, you have to check the state before and after a method call.
You won't have something as sophisticated as Eiffel, but you can however
improve the overall quality of a program.
To summarize, the assert statement is a convenient way to detect a this
should not happen situation. Violations of the specification (e.g. passing
an empty list to head) are first class this should not happen situations.
Hence, while the assert statement may be used to detect any unexpected situation,
it is a privilegied way to ensure that the specification is fulfilled.
Once you have inserted assert statements into the code to represent the
specification, we can hope you have improved the quality of the program because
incorrect arguments, incorrect return values, incorrect states of a class...,
will be reported.

Assertions are statements that state a fact confidently in our program.
Syntax : assert <condition> or assert <condition>,<error message>
It has a condition/expression which is supposed to be always true. If the condition is false, the assert statement will halt the program and throw an error message saying AssertionError. So your assertion expression will be something that you don't want in your program.
e.g.
assert <condition> -- using assert without <error message>
var = int(input("Enter value 1-9 inclusive:"))
assert var!=0
print(var)
Output :
If input is 0 :
AssertionError
If input is 1 :
1
assert <condition>,<error message> -- using assert with an <error message>
var = int(input("Enter value 1-9 inclusive:"))
assert var!=0,"Input cannot be zero"
print(var)
Output :
If input is 0 :
AssertionError: Input cannot be zero
If input is 1 :
1
Key Points :
It is used as a debugging tool.
It takes an expression and an optional message.
It exists in almost every programming language

The assert keyword in Python raises an AssertionError if the code following the assert keyword is False. If not, it continues as nothing happened.
Example 1:
a = 5
b = 6
assert a == b
OUTPUT:
AssertionError
This is because, obviously, a does not equal b.
This is particularly useful if you want to raise an Exception in your code.
def get_dict_key(d, k):
try:
assert k in d
return d[k]
except Exception:
print("Key must be in dict.")
The above example is practically useless, but remember, it is mostly used for debugging purposes, so you can track down your bugs.

format :
assert Expression[,arguments]
When assert encounters a statement,Python evaluates the expression.If the statement is not true,an exception is raised(assertionError).
If the assertion fails, Python uses ArgumentExpression as the argument for the AssertionError. AssertionError exceptions can be caught and handled like any other exception using the try-except statement, but if not handled, they will terminate the program and produce a traceback.
Example:
def KelvinToFahrenheit(Temperature):
assert (Temperature >= 0),"Colder than absolute zero!"
return ((Temperature-273)*1.8)+32
print KelvinToFahrenheit(273)
print int(KelvinToFahrenheit(505.78))
print KelvinToFahrenheit(-5)
When the above code is executed, it produces the following result:
32.0
451
Traceback (most recent call last):
File "test.py", line 9, in <module>
print KelvinToFahrenheit(-5)
File "test.py", line 4, in KelvinToFahrenheit
assert (Temperature >= 0),"Colder than absolute zero!"
AssertionError: Colder than absolute zero!

def getUser(self, id, Email):
user_key = id and id or Email
assert user_key
Can be used to ensure parameters are passed in the function call.

>>>this_is_very_complex_function_result = 9
>>>c = this_is_very_complex_function_result
>>>test_us = (c < 4)
>>> #first we try without assert
>>>if test_us == True:
print("YES! I am right!")
else:
print("I am Wrong, but the program still RUNS!")
I am Wrong, but the program still RUNS!
>>> #now we try with assert
>>> assert test_us
Traceback (most recent call last):
File "<pyshell#52>", line 1, in <module>
assert test_us
AssertionError
>>>

Related

Analyze 'return' statement inside function

Sometimes inside one function we need to use the return statement several times.
When developer changes a function with multiple returns inside, it's easy to oversee some parts of code where yet another return was "hidden".
If unit tests do not cover all possible paths, disaster is guaranteed - it's only a question of time.
def my_function():
'''Multiple "return" inside'''
if condition 1:
return 1, 2, 3
if condition 2:
return 2, 3, 4
return 5 # this is wrong: only 1 value returned, while 3-tuple expected
Let's assume here: last return is wrong, because other callers expect tuple of 3 items.
I wonder if you know an easy way how to catch such parts of code automatically? I thought I could use AST, but I could not find any useful example of this.
This question is about automatic code analysis and listing such cases found - could be with running a separate script.
Of course I could write a try-to-guess parser (with e.g. regex) and then 'manually' check all unclear cases, but maybe there is a simpler way...
Depending on what version of Python you're using and what you really want to achieve, there are several ways to refactor the code.
One way, as has been already suggested, is to use Type Hints in Python 3.
Another way is refactor your code such that instead of using multiple return statements, you call other more atomic methods that handle those conditions and return the appropriate values. You use exception handling in those atomic methods to make sure the output is as desired, or raise an exception if final return type is unexpected.
def my_function():
'''Multiple "return" inside'''
if condition 1:
output = func_handle_condition_one()
if condition 2:
output = func_handle_condition_two()
output = some_other_value
if type(output) is not tuple:
raise TypeError("Invalid type for output")
return output
Additionally, ensure that you're using the right constructs for your conditions (such as whether you want to use multiple if or the if-elif-else construct). You could even re-factor your calling code to call the right function instead of calling one that has so many conditional statements.
Why not set a variable that gets returned at the end and check for its length
def my_function():
'''Multiple "return" inside'''
return_value=(0,0,0)
if condition 1:
return_value=(1, 2, 3)
elif condition 2:
return_value=(2, 3, 4)
else:
return_value=5 # this is wrong: only 1 value returned, while 3-tuple expected
try:
if len(return_value)==3:
return return_value
else:
print("Error: must return tuple of length 3")
except:
print("Error: must return tuple")
My proposal for the final type check of the result would be:
assert isinstance(return_value, tuple) and len(return_value) == 3
Advantage: as assert is easily switched off after debugging phase; still succinct statement for formulating the expectation.

Assert using Python- How do I check if the input is Integer or not?

I wrote a function, which gets a number as an input.
For example:
def return_it_back(n):
return n
I simply need to check if the input is integer or not with assert.
So, I wrote a test function:
def test():
assert return_it_back("k"), "incorrect input"
test()
Python doesn't show "incorrect input". Doesn't the assert return_it_back("k"), "incorrect input" need to print the "incorrect input"?
assert condition, message is just syntactic sugar for:
if not condition:
raise AssertionError(message)
In your code, return_it_back() just returns it's argument, so
assert return_it_back(n), message
is equivalent to
assert n, message
which is equivalent to
if not n:
raise AssertionError(message)
so what's get tested is the truth value of n, whatever it is.
In Python, all objects have a boolean value - empty collections (builtin ones at least), the empty string, numerical zeros and None having a false value and most other objects having by default a true value.
IOW, unless n is an empty collection, empty string, numerical zero or None it will eval to True and the assertion will succeed.
If you want to test whether an object is of a given class (or list of classes), you can use isinstance(obj, cls) (or isinstance(obj, cls, othercls, etc)). Typechecking arguments is usually considered unpythonic (as long as the object acts as expected, who cares what type it is, AKA duck typing), but there are a couple places where it makes sense - when sanitizing user inputs, at subsystems boundary, and eventually when it's garanteed that any other type will break the function one way or another.
Also, assert is a coder tool, not something to use for arguments validation - if your code is compiled with the --optimize flag for example assert statements will be ignored. IOW it's fine for unittesting (but there are more advanced tools in the unittest package) or debugging but not for production code. If you really want to prevent your function from accepting anything but ints you should raise a TypeError (or a ValueError if for example you expect a positive integer and get a negative one) instead.
There are several ways, one might be
def return_it_back(n):
assert type(n) == int, "Incorrect input"
return n
return_it_back(123)
return_it_back('123')
This will obviously break on the second attempt.
You can also check the return value as in your attempt with
def return_it_back(n):
return n
assert type(return_it_back(123)) == int, "Incorrect input"
assert type(return_it_back('123')) == int, "Incorrect input"
but this is redundant and therefore not considered "pythonic". Take the first alternative.

How do I handle multiple asserts within a single Python unittest?

This is a problem that came up when performing a single test that had multiple independent failure modes, due to having multiple output streams. I also wanted to show the results of asserting the data on all those modes, regardless of which failed first. Python's unittest has no such feature outside of using a Suite to represent the single test, which was unacceptable since my single test always needed to be run as a single unit; it just doesn't capture the nature of the thing.
A practical example is testing an object that also generates a log. You want to assert the output of it's methods, but you also want to assert the log output. The two outputs require different tests, which can be neatly expressed as two of the stock asserts expressions, but you also don't want the failure of one to hide the possible failure of the other within the test. So you really need to test both at the same time.
I cobbled together this useful little widget to solve my problem.
def logFailures(fnList):
failurelog = []
for fn in fnList:
try:
fn()
except AssertionError as e:
failurelog.append("\nFailure %d: %s" % (len(failurelog)+1,str(e)))
if len(failurelog) != 0:
raise AssertionError(
"%d failures within test.\n %s" % (len(failurelog),"\n".join(failurelog))
)
Which is used like so:
def test__myTest():
# do some work here
logFailures([
lambda: assert_(False,"This test failed."),
lambda: assert_(False,"This test also failed."),
])
The result is that logFailures() will raise an exception that contains a log of all the assertions that were raised in methods within the list.
The question: While this does the job, I'm left wondering if there's a better way to handle this, other than having to go to the length of creating nested suites of tests and so forth?
With using a subtest, execution would not stop after the first failure
https://docs.python.org/3/library/unittest.html#subtests
Here is example with two fail asserts:
class TestMultipleAsserts(unittest.TestCase):
def test_multipleasserts(self):
with self.subTest():
self.assertEqual(1, 0)
with self.subTest():
self.assertEqual(2, 0)
Output will be:
======================================================================
FAIL: test_multipleasserts (__main__.TestMultipleAsserts) (<subtest>)
----------------------------------------------------------------------
Traceback (most recent call last):
File "./test.py", line 9, in test_multipleasserts
self.assertEqual(1, 0)
AssertionError: 1 != 0
======================================================================
FAIL: test_multipleasserts (__main__.TestMultipleAsserts) (<subtest>)
----------------------------------------------------------------------
Traceback (most recent call last):
File "./test.py", line 11, in test_multipleasserts
self.assertEqual(2, 0)
AssertionError: 2 != 0
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=2)
You can easy wrap subtest as following
class MyTestCase(unittest.TestCase):
def expectEqual(self, first, second, msg=None):
with self.subTest():
self.assertEqual(first, second, msg)
class TestMA(MyTestCase):
def test_ma(self):
self.expectEqual(3, 0)
self.expectEqual(4, 0)
I disagree with the dominant opinion that one should write a test method for each assertion. There are situations where you want to check multiple things in one test method. Here is my answer for how to do it:
# Works with unittest in Python 2.7
class ExpectingTestCase(unittest.TestCase):
def run(self, result=None):
self._result = result
self._num_expectations = 0
super(ExpectingTestCase, self).run(result)
def _fail(self, failure):
try:
raise failure
except failure.__class__:
self._result.addFailure(self, sys.exc_info())
def expect_true(self, a, msg):
if not a:
self._fail(self.failureException(msg))
self._num_expectations += 1
def expect_equal(self, a, b, msg=''):
if a != b:
msg = '({}) Expected {} to equal {}. '.format(self._num_expectations, a, b) + msg
self._fail(self.failureException(msg))
self._num_expectations += 1
And here are some situations where I think it's useful and not risky:
1) When you want to test code for different sets of data. Here we have an add() function and I want to test it with a few example inputs. To write 3 test methods for the 3 data sets means repeating yourself which is bad. Especially if the call was more elaborate.:
class MyTest(ExpectingTestCase):
def test_multiple_inputs(self):
for a, b, expect in ([1,1,2], [0,0,0], [2,2,4]):
self.expect_equal(expect, add(a,b), 'inputs: {} {}'.format(a,b))
2) When you want to check multiple outputs of a function. I want to check each output but I don't want a first failure to mask out the other two.
class MyTest(ExpectingTestCase):
def test_things_with_no_side_effects(self):
a, b, c = myfunc()
self.expect_equal('first value', a)
self.expect_equal('second value', b)
self.expect_equal('third value', c)
3) Testing things with heavy setup costs. Tests must run quickly or people stop using them. Some tests require a db or network connection that takes a second which would really slow down your test. If you are testing the db connection itself, then you probably need to take the speed hit. But if you are testing something unrelated, we want to do the slow setup once for a whole set of checks.
This feels like over-engineering to me. Either:
Use two asserts in one test case. If the first assert fails, it's true, you won't know whether the second assert passed or not. But you're going to fix the code anyway, so fix it, and then you'll find out if the second assert passed.
Write two tests, one to check each condition. If you fear duplicated code in the tests, put the bulk of the code in a helper method that you call from the tests.

Using assert within methods - Python

is it bad practice to use asserts within methods?
e.g.
def add(x, y):
assert isinstance(x, int) and isinstance(y, int)
return x + y
Any ideas?
Not at all.
In your sample, provided you have documented that add expects integers, asserting this constraint at the beginning of the method is actually great practice.
Just imagine the other choices you have and how bad they are:
don't verify your arguments. This means, the method will fail later with a strange backtrace that will presumably confuse the caller and force him to have a look at the implementation of add to get a hint what's going on.
be nice and try to convert the input to int - very bad idea, users will keep wondering why add(2.4,3.1) keeps returning 5.
It's ok because you may run your application with -O command line option and no code would be generated for your assert statement see here
Update:
But also you should handle all errors anyway. Otherwise after stripping assertions unhandled exceptions may occur. (as McConnell recomended. See his citations here)
It's not but if your code contains more assert statements than your actual code then I would be angry.
Instead of using assertions and raising Assertion exception...better perform proper checks using instance() and raise a proper TypeError.

Best practice for using assert?

Is there a performance or code maintenance issue with using assert as part of the standard code instead of using it just for debugging purposes?
Is
assert x >= 0, 'x is less than zero'
better or worse than
if x < 0:
raise Exception('x is less than zero')
Also, is there any way to set a business rule like if x < 0 raise error that is always checked without the try/except/finally so, if at anytime throughout the code x is less than 0 an error is raised, like if you set assert x < 0 at the start of a function, anywhere within the function where x becomes less then 0 an exception is raised?
Asserts should be used to test conditions that should never happen. The purpose is to crash early in the case of a corrupt program state.
Exceptions should be used for errors that can conceivably happen, and you should almost always create your own Exception classes.
For example, if you're writing a function to read from a configuration file into a dict, improper formatting in the file should raise a ConfigurationSyntaxError, while you can assert that you're not about to return None.
In your example, if x is a value set via a user interface or from an external source, an exception is best.
If x is only set by your own code in the same program, go with an assertion.
"assert" statements are removed when the compilation is optimized. So, yes, there are both performance and functional differences.
The current code generator emits no code for an assert statement when optimization is requested at compile time. - Python 2 Docs Python 3 Docs
If you use assert to implement application functionality, then optimize the deployment to production, you will be plagued by "but-it-works-in-dev" defects.
See PYTHONOPTIMIZE and -O -OO
To be able to automatically throw an error when x become less than zero throughout the function. You can use class descriptors. Here is an example:
class LessThanZeroException(Exception):
pass
class variable(object):
def __init__(self, value=0):
self.__x = value
def __set__(self, obj, value):
if value < 0:
raise LessThanZeroException('x is less than zero')
self.__x = value
def __get__(self, obj, objType):
return self.__x
class MyClass(object):
x = variable()
>>> m = MyClass()
>>> m.x = 10
>>> m.x -= 20
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "my.py", line 7, in __set__
raise LessThanZeroException('x is less than zero')
LessThanZeroException: x is less than zero
The four purposes of assert
Assume you work on 200,000 lines of code with four colleagues Alice, Bernd, Carl, and Daphne.
They call your code, you call their code.
Then assert has four roles:
Inform Alice, Bernd, Carl, and Daphne what your code expects.
Assume you have a method that processes a list of tuples and the program logic can break if those tuples are not immutable:
def mymethod(listOfTuples):
assert(all(type(tp)==tuple for tp in listOfTuples))
This is more trustworthy than equivalent information in the documentation
and much easier to maintain.
Inform the computer what your code expects.
assert enforces proper behavior from the callers of your code.
If your code calls Alices's and Bernd's code calls yours,
then without the assert, if the program crashes in Alices code,
Bernd might assume it was Alice's fault,
Alice investigates and might assume it was your fault,
you investigate and tell Bernd it was in fact his.
Lots of work lost.
With asserts, whoever gets a call wrong, they will quickly be able to see it was
their fault, not yours. Alice, Bernd, and you all benefit.
Saves immense amounts of time.
Inform the readers of your code (including yourself) what your code has achieved at some point.
Assume you have a list of entries and each of them can be clean (which is good)
or it can be smorsh, trale, gullup, or twinkled (which are all not acceptable).
If it's smorsh it must be unsmorshed; if it's trale it must be baludoed;
if it's gullup it must be trotted (and then possibly paced, too);
if it's twinkled it must be twinkled again except on Thursdays.
You get the idea: It's complicated stuff.
But the end result is (or ought to be) that all entries are clean.
The Right Thing(TM) to do is to summarize the effect of your
cleaning loop as
assert(all(entry.isClean() for entry in mylist))
This statements saves a headache for everybody trying to understand
what exactly it is that the wonderful loop is achieving.
And the most frequent of these people will likely be yourself.
Inform the computer what your code has achieved at some point.
Should you ever forget to pace an entry needing it after trotting,
the assert will save your day and avoid that your code
breaks dear Daphne's much later.
In my mind, assert's two purposes of documentation (1 and 3) and
safeguard (2 and 4) are equally valuable.
Informing the people may even be more valuable than informing the computer
because it can prevent the very mistakes the assert aims to catch (in case 1)
and plenty of subsequent mistakes in any case.
In addition to the other answers, asserts themselves throw exceptions, but only AssertionErrors. From a utilitarian standpoint, assertions aren't suitable for when you need fine grain control over which exceptions you catch.
The only thing that's really wrong with this approach is that it's hard to make a very descriptive exception using assert statements. If you're looking for the simpler syntax, remember you can also do something like this:
class XLessThanZeroException(Exception):
pass
def CheckX(x):
if x < 0:
raise XLessThanZeroException()
def foo(x):
CheckX(x)
#do stuff here
Another problem is that using assert for normal condition-checking is that it makes it difficult to disable the debugging asserts using the -O flag.
The English language word assert here is used in the sense of swear, affirm, avow. It doesn't mean "check" or "should be". It means that you as a coder are making a sworn statement here:
# I solemnly swear that here I will tell the truth, the whole truth,
# and nothing but the truth, under pains and penalties of perjury, so help me FSM
assert answer == 42
If the code is correct, barring Single-event upsets, hardware failures and such, no assert will ever fail. That is why the behaviour of the program to an end user must not be affected. Especially, an assert cannot fail even under exceptional programmatic conditions. It just doesn't ever happen. If it happens, the programmer should be zapped for it.
As has been said previously, assertions should be used when your code SHOULD NOT ever reach a point, meaning there is a bug there. Probably the most useful reason I can see to use an assertion is an invariant/pre/postcondition. These are something that must be true at the start or end of each iteration of a loop or a function.
For example, a recursive function (2 seperate functions so 1 handles bad input and the other handles bad code, cause it's hard to distinguish with recursion). This would make it obvious if I forgot to write the if statement, what had gone wrong.
def SumToN(n):
if n <= 0:
raise ValueError, "N must be greater than or equal to 0"
else:
return RecursiveSum(n)
def RecursiveSum(n):
#precondition: n >= 0
assert(n >= 0)
if n == 0:
return 0
return RecursiveSum(n - 1) + n
#postcondition: returned sum of 1 to n
These loop invariants often can be represented with an assertion.
Well, this is an open question, and I have two aspects that I want to touch on: when to add assertions and how to write the error messages.
Purpose
To explain it to a beginner - assertions are statements which can raise errors, but you won't be catching them. And they normally should not be raised, but in real life they sometimes do get raised anyway. And this is a serious situation, which the code cannot recover from, what we call a 'fatal error'.
Next, it's for 'debugging purposes', which, while correct, sounds very dismissive. I like the 'declaring invariants, which should never be violated' formulation better, although it works differently on different beginners... Some 'just get it', and others either don't find any use for it, or replace normal exceptions, or even control flow with it.
Style
In Python, assert is a statement, not a function! (remember assert(False, 'is true') will not raise. But, having that out of the way:
When, and how, to write the optional 'error message'?
This acually applies to unit testing frameworks, which often have many dedicated methods to do assertions (assertTrue(condition), assertFalse(condition), assertEqual(actual, expected) etc.). They often also provide a way to comment on the assertion.
In throw-away code you could do without the error messages.
In some cases, there is nothing to add to the assertion:
def dump(something):
assert isinstance(something, Dumpable)
# ...
But apart from that, a message is useful for communication with other programmers (which are sometimes interactive users of your code, e.g. in Ipython/Jupyter etc.).
Give them information, not just leak internal implementation details.
instead of:
assert meaningless_identifier <= MAGIC_NUMBER_XXX, 'meaningless_identifier is greater than MAGIC_NUMBER_XXX!!!'
write:
assert meaningless_identifier > MAGIC_NUMBER_XXX, 'reactor temperature above critical threshold'
or maybe even:
assert meaningless_identifier > MAGIC_NUMBER_XXX, f'reactor temperature({meaningless_identifier }) above critical threshold ({MAGIC_NUMBER_XXX})'
I know, I know - this is not a case for a static assertion, but I want to point to the informational value of the message.
Negative or positive message?
This may be conroversial, but it hurts me to read things like:
assert a == b, 'a is not equal to b'
these are two contradictory things written next to eachother. So whenever I have an influence on the codebase, I push for specifying what we want, by using extra verbs like 'must' and 'should', and not to say what we don't want.
assert a == b, 'a must be equal to b'
Then, getting AssertionError: a must be equal to b is also readable, and the statement looks logical in code. Also, you can get something out of it without reading the traceback (which can sometimes not even be available).
For what it's worth, if you're dealing with code which relies on assert to function properly, then adding the following code will ensure that asserts are enabled:
try:
assert False
raise Exception('Python assertions are not working. This tool relies on Python assertions to do its job. Possible causes are running with the "-O" flag or running a precompiled (".pyo" or ".pyc") module.')
except AssertionError:
pass
Is there a performance issue?
Please remember to "make it work first before you make it work fast".
Very few percent of any program are usually relevant for its speed.
You can always kick out or simplify an assert if it ever proves to
be a performance problem -- and most of them never will.
Be pragmatic:
Assume you have a method that processes a non-empty list of tuples and the program logic will break if those tuples are not immutable. You should write:
def mymethod(listOfTuples):
assert(all(type(tp)==tuple for tp in listOfTuples))
This is probably fine if your lists tend to be ten entries long, but
it can become a problem if they have a million entries.
But rather than discarding this valuable check entirely you could
simply downgrade it to
def mymethod(listOfTuples):
assert(type(listOfTuples[0])==tuple) # in fact _all_ must be tuples!
which is cheap but will likely catch most of the actual program errors anyway.
An Assert is to check -
1. the valid condition,
2. the valid statement,
3. true logic;
of source code. Instead of failing the whole project it gives an alarm that something is not appropriate in your source file.
In example 1, since variable 'str' is not null. So no any assert or exception get raised.
Example 1:
#!/usr/bin/python
str = 'hello Python!'
strNull = 'string is Null'
if __debug__:
if not str: raise AssertionError(strNull)
print str
if __debug__:
print 'FileName '.ljust(30,'.'),(__name__)
print 'FilePath '.ljust(30,'.'),(__file__)
------------------------------------------------------
Output:
hello Python!
FileName ..................... hello
FilePath ..................... C:/Python\hello.py
In example 2, var 'str' is null. So we are saving the user from going ahead of faulty program by assert statement.
Example 2:
#!/usr/bin/python
str = ''
strNull = 'NULL String'
if __debug__:
if not str: raise AssertionError(strNull)
print str
if __debug__:
print 'FileName '.ljust(30,'.'),(__name__)
print 'FilePath '.ljust(30,'.'),(__file__)
------------------------------------------------------
Output:
AssertionError: NULL String
The moment we don't want debug and realized the assertion issue in the source code. Disable the optimization flag
python -O assertStatement.py
nothing will get print
Both the use of assert and the raising of exceptions are about communication.
Assertions are statements about the correctness of code addressed at developers: An assertion in the code informs readers of the code about conditions that have to be fulfilled for the code being correct. An assertion that fails at run-time informs developers that there is a defect in the code that needs fixing.
Exceptions are indications about non-typical situations that can occur at run-time but can not be resolved by the code at hand, addressed at the calling code to be handled there. The occurence of an exception does not indicate that there is a bug in the code.
Best practice
Therefore, if you consider the occurence of a specific situation at run-time as a bug that you would like to inform the developers about ("Hi developer, this condition indicates that there is a bug somewhere, please fix the code.") then go for an assertion. If the assertion checks input arguments of your code, you should typically add to the documentation that your code has "undefined behaviour" when the input arguments violate that conditions.
If instead the occurrence of that very situation is not an indication of a bug in your eyes, but instead a (maybe rare but) possible situation that you think should rather be handled by the client code, raise an exception. The situations when which exception is raised should be part of the documentation of the respective code.
Is there a performance [...] issue with using assert
The evaluation of assertions takes some time. They can be eliminated at compile time, though. This has some consequences, however, see below.
Is there a [...] code maintenance issue with using assert
Normally assertions improve the maintainability of the code, since they improve readability by making assumptions explicit and during run-time regularly verifying these assumptions. This will also help catching regressions. There is one issue, however, that needs to be kept in mind: Expressions used in assertions should have no side-effects. As mentioned above, assertions can be eliminated at compile time - which means that also the potential side-effects would disappear. This can - unintendedly - change the behaviour of the code.
In IDE's such as PTVS, PyCharm, Wing assert isinstance() statements can be used to enable code completion for some unclear objects.
I'd add I often use assert to specify properties such as loop invariants or logical properties my code should have, much like I'd specify them in formally-verified software.
They serve both the purpose of informing readers, helping me reason, and checking I am not making a mistake in my reasoning. For example :
k = 0
for i in range(n):
assert k == i * (i + 1) // 2
k += i
#do some things
or in more complicated situations:
def sorted(l):
return all(l1 <= l2 for l1, l2 in zip(l, l[1:]))
def mergesort(l):
if len(l) < 2: #python 3.10 will have match - case for this instead of checking length
return l
k = len(l // 2)
l1 = mergesort(l[:k])
l2 = mergesort(l[k:])
assert sorted(l1) # here the asserts allow me to explicit what properties my code should have
assert sorted(l2) # I expect them to be disabled in a production build
return merge(l1, l2)
Since asserts are disabled when python is run in optimized mode, do not hesitate to write costly conditions in them, especially if it makes your code clearer and less bug-prone

Categories