2017-09-05 16:42:34 -04:00
|
|
|
|
PEP: 553
|
|
|
|
|
Title: Built-in debug()
|
|
|
|
|
Author: Barry Warsaw <barry@python.org>
|
|
|
|
|
Status: Draft
|
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 2017-09-05
|
|
|
|
|
Python-Version: 3.7
|
|
|
|
|
Post-History:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
This PEP proposes adding a new built-in function called ``debug()`` which
|
|
|
|
|
enters a Python debugger at the point of the call. Additionally, two new
|
|
|
|
|
names are added to the ``sys`` module to make the debugger pluggable.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rationale
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
Python has long had a great debugger in its standard library called ``pdb``.
|
|
|
|
|
Setting a break point is commonly written like this::
|
|
|
|
|
|
|
|
|
|
foo()
|
|
|
|
|
import pdb; pdb.set_trace()
|
|
|
|
|
bar()
|
|
|
|
|
|
|
|
|
|
Thus after executing ``foo()`` and before executing ``bar()``, Python will
|
|
|
|
|
enter the debugger. However this idiom has several disadvantages.
|
|
|
|
|
|
|
|
|
|
* It's a lot to type (27 characters).
|
|
|
|
|
|
|
|
|
|
* It's easy to typo. The PEP author often mistypes this line, e.g. omitting
|
|
|
|
|
the semicolon, or typing a dot instead of an underscore.
|
|
|
|
|
|
|
|
|
|
* It ties debugging directly to the choice of pdb. There might be other
|
|
|
|
|
debugging options, say if you're using an IDE or some other development
|
|
|
|
|
environment.
|
|
|
|
|
|
|
|
|
|
* Python linters (e.g. flake8 [1]_) complain about this line because it
|
|
|
|
|
contains two statements. Breaking the idiom up into two lines further
|
|
|
|
|
complicates the use of the debugger,
|
|
|
|
|
|
|
|
|
|
These problems can be solved by modeling a solution based on prior art in
|
|
|
|
|
other languages, and utilizing a convention that already exists in Python.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Proposal
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
The JavaScript language provides a ``debugger`` statement [2]_ which enters
|
|
|
|
|
the debugger at the point where the statement appears.
|
|
|
|
|
|
|
|
|
|
This PEP proposes a new built-in function called ``debug()`` which enters a
|
|
|
|
|
Python debugger at the call site. Thus the example above would be written
|
|
|
|
|
like so::
|
|
|
|
|
|
|
|
|
|
foo()
|
|
|
|
|
debug()
|
|
|
|
|
bar()
|
|
|
|
|
|
|
|
|
|
Built-in ``debug()`` takes no arguments.
|
|
|
|
|
|
|
|
|
|
Further, this PEP proposes two new name bindings for the ``sys`` module,
|
|
|
|
|
called ``debughook()`` and ``__debughook__``. By default, ``sys.debughook()``
|
|
|
|
|
implements the actual importing and entry into ``pdb.set_trace()``, and it can
|
|
|
|
|
be set to a different function to change the debugger that ``debug()`` enters.
|
|
|
|
|
``sys.__debughook__`` then stashes the default value of ``sys.debughook()`` to
|
|
|
|
|
make it easy to reset. This exactly models the existing ``sys.displayhook()``
|
|
|
|
|
/ ``sys.__displayhook__`` and ``sys.excepthook()`` / ``sys.__excepthook__``
|
|
|
|
|
hooks [3]_.
|
|
|
|
|
|
|
|
|
|
``sys.displayhook()`` would be called with no arguments. It returns whatever
|
|
|
|
|
is returned from the underlying debugger entry point. ``debug()`` returns
|
|
|
|
|
whatever ``sys.displayhook()`` returns.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Open issues
|
|
|
|
|
===========
|
|
|
|
|
|
|
|
|
|
We want to get confirmation from at least one alternative debugger
|
|
|
|
|
implementation (e.g. PyCharm) that the hooks provided in this PEP will be
|
|
|
|
|
useful to them.
|
|
|
|
|
|
2017-09-05 17:12:57 -04:00
|
|
|
|
Related, there has been an idea to add a bytecode that calls
|
|
|
|
|
``sys.debughook()``. Whether built-in ``debug()`` emits this bytecode (or
|
|
|
|
|
gets peephole optimized to the bytecode) is an open issue. The bytecode is
|
|
|
|
|
useful for debuggers that actively modify bytecode streams to trampoline into
|
|
|
|
|
their own debugger. Having a "debug" bytecode might allow them to avoid
|
|
|
|
|
bytecode modification in order to invoke this trampoline.
|
|
|
|
|
|
2017-09-05 17:16:10 -04:00
|
|
|
|
Does it make sense to define the built-in function's signature as
|
|
|
|
|
``debug(*args, **kws)`` which would just be passed along to the
|
|
|
|
|
``sys.debughook()``? One argument for doing this is that it would allow users
|
|
|
|
|
to pass useful arguments to their actual debugger. This isn't useful for
|
|
|
|
|
``pdb`` but might be useful for alternatives.
|
|
|
|
|
|
2017-09-05 16:42:34 -04:00
|
|
|
|
|
|
|
|
|
Implementation
|
|
|
|
|
==============
|
|
|
|
|
|
|
|
|
|
A pull request exists with the proposed implementation [4]_.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rejected alternatives
|
|
|
|
|
=====================
|
|
|
|
|
|
|
|
|
|
A new keyword
|
|
|
|
|
-------------
|
|
|
|
|
|
|
|
|
|
Originally, the author considered a new keyword, or an extension to an
|
|
|
|
|
existing keyword such as ``break here``. This is rejected on several fronts.
|
|
|
|
|
|
|
|
|
|
* A brand new keyword would require a ``__future__`` to enable it since almost
|
|
|
|
|
any new keyword could conflict with existing code. This negates the ease
|
|
|
|
|
with which you can enter the debugger.
|
|
|
|
|
|
|
|
|
|
* An extended keyword such as ``break here``, while more readable and not
|
|
|
|
|
requiring a ``__future__`` would tie the keyword extension to this new
|
|
|
|
|
feature, preventing more useful extensions such as those proposed in
|
|
|
|
|
PEP 548.
|
|
|
|
|
|
|
|
|
|
* A new keyword would require a modified grammar and likely a new bytecode.
|
|
|
|
|
Each of these makes the implementation more complex. A new built-in breaks
|
|
|
|
|
no existing code (since any existing module global would just shadow the
|
|
|
|
|
built-in) and is quite easy to implement.
|
|
|
|
|
|
2017-09-05 17:12:57 -04:00
|
|
|
|
sys.debug()
|
|
|
|
|
-----------
|
|
|
|
|
|
|
|
|
|
Why not ``sys.debug()``? Requiring an import to invoke the debugger is
|
|
|
|
|
explicitly rejected because ``sys`` is not imported in every module. That
|
|
|
|
|
just requires more typing and would lead to::
|
|
|
|
|
|
|
|
|
|
import sys; sys.debug()
|
|
|
|
|
|
|
|
|
|
which inherits several of the problems this PEP aims to solve.
|
|
|
|
|
|
2017-09-05 16:42:34 -04:00
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
.. [1] http://flake8.readthedocs.io/en/latest/
|
|
|
|
|
|
|
|
|
|
.. [2] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger
|
|
|
|
|
|
|
|
|
|
.. [3] https://docs.python.org/3/library/sys.html#sys.displayhook
|
|
|
|
|
|
|
|
|
|
.. [4] XXX
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
..
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
coding: utf-8
|
|
|
|
|
End:
|