assert asserting when __debug__ == False

assert, debugging, python

Solution

You are not meant to change the value of __debug__ As the note under here states:

Note: The names `None`, `False`, `True` and `__debug__` cannot be reassigned (assignments to them, even as an attribute name, raise `SyntaxError`), so they can be considered “true” constants

The reason this is happening is because `__debug__` is not evaluated at runtime, rather the `-O` command line flag is (At compile time). See also Runtime vs Compile time.

While you can change the value of `__debug__` through the hack `globals()["__debug__"]`, it does nothing, as the `assert expression1, expression2` doesn't really check for the value of `__debug__`. Supplying the `-O` flag assigns `False` to `__debug__` and removes all assert statements. That is to say, `assert` statements are removed by the `-O` flag, not the `__debug__` variable.

You can see this with `dis()` from `dis`. Using the following code:

import dis
dis.dis("assert False")

Without the `-O` flag (`path\to\file>python file.py`):

  1           0 LOAD_CONST               0 (False)
              3 POP_JUMP_IF_TRUE        12
              6 LOAD_GLOBAL              0 (AssertionError)
              9 RAISE_VARARGS            1
        >>   12 LOAD_CONST               1 (None)
             15 RETURN_VALUE

With the `-O` flag (`path\to\file>python -O file.py`):

  1           0 LOAD_CONST               0 (None)
              3 RETURN_VALUE

As you can see, the `assert` statement is essentially removed from the code. Lines 0 to 3 with the `-O` flag are identical to lines 12 to 15 without. No where does it check for the value of `__debug__`.

Problem

I made a simple test program to test the functionality of assigning to `__debug__` using `globals()["__debug__"] = value` (`__debug__ = value` is a `SyntaxError`). It basically tries to raise an `AssertionError` and prints if the error was raised and whether or not it was expected. I did this as I ran in to issues with `__debug__` changing mid-program. ``` print("__debug__ is", __debug__) exp = ["(expected)", "(not expected)"] if __debug__: exp = exp[::-1] try: assert False print("No AssertionError", exp[0]) except AssertionError: print("AssertionError", exp[1]) exp = exp[::-1] globals()["__debug__"] = not __debug__ print("__debug__ is", __debug__) try: assert False print("No AssertionError", exp[0]) except AssertionError: print("AssertionError", exp[1]) ``` It produces unexpected results when run from command prompt, with and without the `-O` flag. ``` C:\Test>python assert.py __debug__ is True AssertionError (expected) __debug__ is False AssertionError (not expected) C:\Test>python -O assert.py __debug__ is False No AssertionError (expected) __debug__ is True No AssertionError (not expected) ``` It seems that `__debug__` is changing, but `assert` is not actually checking if it has.

Original source

Related problems