Python Development Mode

Added in version 3.7.

The Python Development Mode introduces additional runtime checks that are tooexpensive to be enabled by default. It should not be more verbose than thedefault if the code is correct; new warnings are only emitted when an issue isdetected.

It can be enabled using the-Xdev command line option or bysetting thePYTHONDEVMODE environment variable to1.

See alsoPython debug build.

Effects of the Python Development Mode

Enabling the Python Development Mode is similar to the following command, butwith additional effects described below:

PYTHONMALLOC=debugPYTHONASYNCIODEBUG=1python-Wdefault-Xfaulthandler

Effects of the Python Development Mode:

The Python Development Mode does not enable thetracemalloc module bydefault, because the overhead cost (to performance and memory) would be toolarge. Enabling thetracemalloc module provides additional informationon the origin of some errors. For example,ResourceWarning logs thetraceback where the resource was allocated, and a buffer overflow error logsthe traceback where the memory block was allocated.

The Python Development Mode does not prevent the-O command lineoption from removingassert statements nor from setting__debug__ toFalse.

The Python Development Mode can only be enabled at the Python startup. Itsvalue can be read fromsys.flags.dev_mode.

Changed in version 3.8:Theio.IOBase destructor now logsclose() exceptions.

Changed in version 3.9:Theencoding anderrors arguments are now checked for string encodingand decoding operations.

ResourceWarning Example

Example of a script counting the number of lines of the text file specified inthe command line:

importsysdefmain():fp=open(sys.argv[1])nlines=len(fp.readlines())print(nlines)# The file is closed implicitlyif__name__=="__main__":main()

The script does not close the file explicitly. By default, Python does not emitany warning. Example using README.txt, which has 269 lines:

$pythonscript.pyREADME.txt269

Enabling the Python Development Mode displays aResourceWarning warning:

$python-Xdevscript.pyREADME.txt269script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='README.rst' mode='r' encoding='UTF-8'>  main()ResourceWarning: Enable tracemalloc to get the object allocation traceback

In addition, enablingtracemalloc shows the line where the file wasopened:

$python-Xdev-Xtracemalloc=5script.pyREADME.rst269script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='README.rst' mode='r' encoding='UTF-8'>  main()Object allocated at (most recent call last):  File "script.py", lineno 10    main()  File "script.py", lineno 4    fp = open(sys.argv[1])

The fix is to close explicitly the file. Example using a context manager:

defmain():# Close the file explicitly when exiting the with blockwithopen(sys.argv[1])asfp:nlines=len(fp.readlines())print(nlines)

Not closing a resource explicitly can leave a resource open for way longer thanexpected; it can cause severe issues upon exiting Python. It is bad inCPython, but it is even worse in PyPy. Closing resources explicitly makes anapplication more deterministic and more reliable.

Bad file descriptor error example

Script displaying the first line of itself:

importosdefmain():fp=open(__file__)firstline=fp.readline()print(firstline.rstrip())os.close(fp.fileno())# The file is closed implicitlymain()

By default, Python does not emit any warning:

$pythonscript.pyimport os

The Python Development Mode shows aResourceWarning and logs a “Bad filedescriptor” error when finalizing the file object:

$python-Xdevscript.pyimport osscript.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='script.py' mode='r' encoding='UTF-8'>  main()ResourceWarning: Enable tracemalloc to get the object allocation tracebackException ignored in: <_io.TextIOWrapper name='script.py' mode='r' encoding='UTF-8'>Traceback (most recent call last):  File "script.py", line 10, in <module>    main()OSError: [Errno 9] Bad file descriptor

os.close(fp.fileno()) closes the file descriptor. When the file objectfinalizer tries to close the file descriptor again, it fails with theBadfiledescriptor error. A file descriptor must be closed only once. In theworst case scenario, closing it twice can lead to a crash (seebpo-18748for an example).

The fix is to remove theos.close(fp.fileno()) line, or open the file withclosefd=False.