Is there a way to run a python script in optimized mode from another Python (Python 3) script?
If I have the following test.py
script (which reads the built-in constant __debug__
):
if __debug__:
print('Debug ON')
else:
print('Debug OFF')
then:
python text.py
prints Debug ON
python -OO text.py
prints Debug OFF
because of how the constant __debug__
works:
This constant is true if Python was not started with an
-O
option. See also theassert
statement.
Also, the value of __debug__
cannot be changed at runtime: __debug__
is a constant, as noted in the documentation here and here. The value of __debug__
is determined when the Python interpreter starts.
The following correctly prints Debug OFF
import subprocess
subprocess.run(["python", "-OO", "test.py"])
But is there a more pythonic way?
The above doesn't seem very portable if the interpreter is not called python
.
I've already searched here and the web without luck.
compile
I've come up with a solution using the built-in function compile
, as follows.
Contents of the file main.py
:
with open('test.py') as f:
source_code = f.read()
compiled = compile(
source_code,
filename='test.py', mode='exec', optimize=2)
exec(compiled)
Contents of the file test.py
:
if __debug__:
print('Debug ON')
else:
print('Debug OFF')
The output from running python main.py
is:
Debug OFF
Possible values for the parameter optimize
:
-1
: use same optimization level as the Python interpreter that is running the function compile
0
: no optimization, and __debug__ == true
1
: like -O
, i.e., removes assert
statements, and __debug__ == false
2
: like -OO
, i.e., removes also docstrings.Don't know if it's the best option, just sharing if can be useful fo others.
subprocess.run
The subprocess
-based approach is still more concise, and can be made portable by using sys.executable
:
import subprocess
import sys
if not sys.executable:
raise RuntimeError(sys.executable)
proc = subprocess.run(
[sys.executable, '-OO', 'test.py'],
capture_output=True, text=True)
if proc.returncode != 0:
raise RuntimeError(proc.returncode)
The above code calls the function subprocess.run
.
The check for the value of the variable sys.executable
is motivated by the documentation of CPython:
If Python is unable to retrieve the real path to its executable,
sys.executable
will be an empty string orNone
.
The check is implemented with a raise
statement, instead of an assert
statement, in order to check also in cases that the above Python code is itself run with optimization requested from Python, e.g., by using python -O
or python -OO
or the environment variable PYTHONOPTIMIZE
.
When optimization is requested, assert
statements are removed.
Using raise
statements also enables raising an exception other than AssertionError
, in this case RuntimeError
.
For running Python code that is within a function inside the same source file (i.e., inside main.py
, not inside test.py
), the function inspect.getsource
can be used, together with the option -c
of python
.
By the way better answers are welcome!