Allow `__debug__` to be set at runtime

The builtins.__debug__ attribute controls whether assertions are checked at runtime.
Running Python with -O or -OO sets builtins.__debug__ to False, otherwise it is set to True.
Currently it cannot be changed at runtime.

builtins.__debug__ = False
  File "<python-input-3>", line 1
    builtins.__debug__ = False
    ^^^^^^^^^^^^^^^^^^
SyntaxError: cannot assign to __debug__

Should we allow it to be set at runtime, so that assertions can be turned on and off at runtime?
The performance impact would be negligible.

Is this a good idea? What do you think?

1 Like

IMO there is no valid use case for it. We are either debugging or we are not. I can’t think of any case where we would toggle between debugging and not while the code is running.

3 Likes

When not debugging, are assertions stripped out of bytecode when the module is loaded, or are they still there and just get ignored?

If they are stripped out, I think toggling on __debug__ would require reloading the world–or it would only affect code that was interpreted in the future, and imported modules wouldn’t be affected. The latter option doesn’t sound so useful for debugging, and the former option seems like you might as well just restart in debug mode.

Currently they are stripped out, but I think @markshannon is suggesting to change that. The performance impact of that can be mitigated through runtime optimisations.

The real question is whether people might consider their assertions to be secrets, and therefore consider it a feature that they are not in the bytecode.

5 Likes

We can generate two versions of bytecode and switch between them on fly after changing __debug__, but I do not think this is worth a hassle.

2 Likes

We could allow it to be set to False at runtime, but setting it to True wouldn’t work because the bytecode might not include debugging information (the source code could be missing), and the necessary debugging libraries might not be available on the system (in a production environment).

That said, this change would introduce backward incompatibility.

I personally use -O and -OO in production.

My gut take is that even allowing builtins.__debug__ to be set to False at runtime is dangerous as we need to assume that there is code with logically load bearing calls in assert statements. Disabling at the global scope across all modules would hurt that.

Setting __debug__ no further than the current file’s globals() for use within the file seems more reasonable to support - though I don’t have a compelling reason why we’d want to.

We do not today (assignment to __debug__ even if specified as a global or nonlocal is always a SyntaxError - raised during parsing, not at runtime). The name __debug__ is treated as… very special.

5 Likes

I even thought about proposing to make __debug__ a true keyword, like True, False and None. This would make it less special and the compiler code slightly simpler.

2 Likes

Concur. It would just muddy the distinction between the modes. asserts should only be used for things the developer knows are true. Because we’re imperfect and will shoot ourselves in the foot if given the opportunity.

1 Like