116

How do I disable assertions in Python?

That is, if an assertion fails, I don't want it to throw an AssertionError, but to keep going.

How do I do that?

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
Claudiu
  • 224,032
  • 165
  • 485
  • 680

6 Answers6

118

#How do I disable assertions in Python?

There are multiple approaches that affect a single process, the environment, or a single line of code.

I demonstrate each.

For the whole process

Using the -O flag (capital O) disables all assert statements in a process.

For example:

$ python -Oc "assert False"

$ python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

Note that by disable I mean it also does not execute the expression that follows it:

$ python -Oc "assert 1/0"

$ python -c "assert 1/0"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

For the environment

You can use an environment variable to set this flag as well.

This will affect every process that uses or inherits the environment.

E.g., in Windows, setting and then clearing the environment variable:

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError
C:\>SET PYTHONOPTIMIZE=TRUE

C:\>python -c "assert False"

C:\>SET PYTHONOPTIMIZE=

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

Same in Unix (using set and unset for respective functionality)

Single point in code

You continue your question:

if an assertion fails, I don't want it to throw an AssertionError, but to keep going.

You can either ensure control flow does not reach the assertion, for example:

if False:
    assert False, "we know this fails, but we don't get here"

or if you want the assert expression to be exercised then you can catch the assertion error:

try:
    assert False, "this code runs, fails, and the exception is caught"
except AssertionError as e:
    print(repr(e))

which prints:

AssertionError('this code runs, fails, and the exception is caught')

and you'll keep going from the point you handled the AssertionError.

References

From the assert documentation:

An assert statement like this:

assert expression #, optional_message

Is equivalent to

if __debug__:
    if not expression: raise AssertionError #(optional_message)

And,

the built-in variable __debug__ is True under normal circumstances, False when optimization is requested (command line option -O).

and further

Assignments to __debug__ are illegal. The value for the built-in variable is determined when the interpreter starts.

From the usage docs:

-O

Turn on basic optimizations. This changes the filename extension for compiled (bytecode) files from .pyc to .pyo. See also PYTHONOPTIMIZE.

and

PYTHONOPTIMIZE

If this is set to a non-empty string it is equivalent to specifying the -O option. If set to an integer, it is equivalent to specifying -O multiple times.

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
  • would it be possible to skip the code that fails in case of 'Single point in code'? I tried setting `__debug__` to False but that is not allowed. – Matthijs Sep 04 '19 at 19:32
  • 2
    @Matthijs you can either ensure control flow doesn't reach it (e.g. `if False: assert False`) or you can catch the Assertion error. Those are your choices. Updated the answer to address your question. – Russia Must Remove Putin Sep 04 '19 at 20:36
  • Thanks for the answer, but not yet completely what i was thinking about. I would like to disable asserts inside a function during runtime, ideally with some sort of context manager: assertion is evaluated: `foo()` and switching assertions off: `with skip_assertion(): foo()`. The benefit of this being that i dont have to add another flag on the function – Matthijs Sep 04 '19 at 21:42
  • 2
    You could rewrite the bytecode of the function, rewrite the AST, or rewrite the function itself. (manually or programmatically, for either). Rewriting the AST would probably be the most reliable approach ("simply" replace `Assert` objects with `Pass` objects). A context manager wouldn't directly work for that, but you could have some kind of mechanism that used decorated functions in that way. Regardless, I don't recommend it. I suspect your reason for wanting to do so is you are calling code you don't control and getting AssertionErrors. If so, you likely need to find a different fix. – Russia Must Remove Putin Sep 05 '19 at 15:07
63

Call Python with the -O flag:

test.py:

assert False
print('Done')

Output:

C:\temp\py>C:\Python26\python.exe test.py
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    assert(False)
AssertionError

C:\temp\py>C:\Python26\python.exe -O test.py
Done
Francisco
  • 10,918
  • 6
  • 34
  • 45
Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
18

Both of the two answers already given are valid (call Python with either -O or -OO on the command line).

From the Python documentation, here is the difference between them:

  • -O Turn on basic optimizations. This changes the filename extension for compiled (bytecode) files from .pyc to .pyo.

  • -OO Discard docstrings in addition to the -O optimizations.

To check if assertions are enabled or disabled, see the value of __debug__.

Asclepius
  • 57,944
  • 17
  • 167
  • 143
Michael Currie
  • 13,721
  • 9
  • 42
  • 58
  • What does "discard docstrings" mean? Do those add to runtime costs in any way? – Eike P. Jan 29 '23 at 15:14
  • 1
    @EikeP. `-OO` instructs the interpreter to omit docstrings when generating the bytecode, so that means the bytecode will be somewhat smaller and therefore the Python virtual machine running the bytecode will be slightly faster. I agree with you that it probably has only a very tiny effect on performance. – Michael Currie Jan 29 '23 at 15:51
8

Use python -O:

$ python -O
>>> assert False
>>> 
John Millikin
  • 197,344
  • 39
  • 212
  • 226
3

You should NOT disable assertions. They catch unanticipated errors when attention is elsewhere. See Rule 5 in "The power of ten" (DOI, Wikipedia).

Write raise statements, instead of assert statements:

if x_is_broken():
    raise RuntimeError('`x` is broken.')

The raise statements remain present, whatever the optimization options with which Python is run. Also, using raise statements enables specifying a type of exception different than AssertionError. This is very useful for users. Moreover, just writing a raise statement prompts to ask oneself whether AssertionError is the right choice there.

In addition, when writing a raise statement, we are lead to write an informative message, for example raise AssertionError('An error occurred with `x`.'). Writing an error message is possible in an assert statement (e.g., assert x, 'An error occurred with `x`.', and parentheses can be used for messages written over multiple lines), however, it can be forgotten. In contrast, raise AssertionError(....) requires that .... be filled (and the form raise AssertionError is unusual and not recommended).

When writing error messages, it is remarkable how many further coding errors will be revealed.

Sidenote: computationally expensive assertion checks can be run only when requested. One way is:

import logging


log = logging.getLogger(__name__)


if log.getEffectiveLevel() < logging.DEBUG:
    if not check_expensive_property(x):
        raise RuntimeError('`x` is broken.')
0 _
  • 10,524
  • 11
  • 77
  • 109
  • 1
    // , The problem is, though, that the statement still adds to cyclomatic complexity, and error handling should handle the rest? – Nathan Basanese Jan 18 '17 at 02:13
  • 2
    The assertions that would be guarded as above are expensive calls that significantly slow down execution. For some algorithms, checks of this sort can take orders of magnitude longer than the entire program. Think of running a naive but simpler implementation (so less likely to contain errors) of the same algorithm to check correctness. Or a check by exhaustive enumeration of something that is out of the question for normal operation. – 0 _ Jan 18 '17 at 02:20
  • I don't see much of a problem with readability, because such a statement doesn't add nesting to the code. Extracting it as a function call can move it out of the way, if that's an issue (and I expect that such a refactoring should reduce cyclomatic complexity). In any event, cyclomatic complexity should not govern safety checks. – 0 _ Jan 18 '17 at 02:22
  • The power of ten assert is not the same as Python assert – Antti Haapala -- Слава Україні Jan 24 '21 at 18:38
2

Running in optimized mode should do it:

python -OO module.py
Michael Currie
  • 13,721
  • 9
  • 42
  • 58
FogleBird
  • 74,300
  • 25
  • 125
  • 131