2017-09-05 16:42:34 -04:00
|
|
|
|
PEP: 553
|
2017-09-06 12:50:56 -04:00
|
|
|
|
Title: Built-in breakpoint()
|
2017-09-05 16:42:34 -04:00
|
|
|
|
Author: Barry Warsaw <barry@python.org>
|
|
|
|
|
Status: Draft
|
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 2017-09-05
|
|
|
|
|
Python-Version: 3.7
|
2017-09-07 14:27:55 -04:00
|
|
|
|
Post-History: 2017-09-05, 2017-09-07
|
2017-09-05 16:42:34 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
2017-09-06 12:50:56 -04:00
|
|
|
|
This PEP proposes adding a new built-in function called ``breakpoint()`` which
|
2017-09-05 16:42:34 -04:00
|
|
|
|
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.
|
|
|
|
|
|
2017-09-06 12:50:56 -04:00
|
|
|
|
This PEP proposes a new built-in function called ``breakpoint()``
|
|
|
|
|
which enters a Python debugger at the call site. Thus the example
|
|
|
|
|
above would be written like so::
|
2017-09-05 16:42:34 -04:00
|
|
|
|
|
|
|
|
|
foo()
|
2017-09-06 12:50:56 -04:00
|
|
|
|
breakpoint()
|
2017-09-05 16:42:34 -04:00
|
|
|
|
bar()
|
|
|
|
|
|
2017-09-06 12:50:56 -04:00
|
|
|
|
Further, this PEP proposes two new name bindings for the ``sys``
|
|
|
|
|
module, called ``sys.breakpointhook()`` and
|
|
|
|
|
``sys.__breakpointhook__``. By default, ``sys.breakpointhook()``
|
|
|
|
|
implements the actual importing and entry into ``pdb.set_trace()``,
|
|
|
|
|
and it can be set to a different function to change the debugger that
|
|
|
|
|
``breakpoint()`` enters. ``sys.__breakpointhook__`` then stashes the
|
|
|
|
|
default value of ``sys.breakpointhook()`` to make it easy to reset.
|
|
|
|
|
This exactly models the existing ``sys.displayhook()`` /
|
|
|
|
|
``sys.__displayhook__`` and ``sys.excepthook()`` /
|
|
|
|
|
``sys.__excepthook__`` hooks [3]_.
|
2017-09-05 16:42:34 -04:00
|
|
|
|
|
2017-09-07 14:27:55 -04:00
|
|
|
|
The signature of the built-in is ``breakpoint(*args, **kws)``. The positional
|
|
|
|
|
and keyword arguments are passed straight through to ``sys.breakpointhook()``
|
2017-09-07 14:40:12 -04:00
|
|
|
|
and the signatures must match or a ``TypeError`` will be raised. The return
|
2017-09-07 14:27:55 -04:00
|
|
|
|
from ``sys.breakpointhook()`` is passed back up to, and returned from
|
2017-09-07 14:38:37 -04:00
|
|
|
|
``breakpoint()``. Since ``sys.breakpointhook()`` by default calls
|
|
|
|
|
``pdb.set_trace()`` by default it accepts no arguments.
|
2017-09-05 16:42:34 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Open issues
|
|
|
|
|
===========
|
|
|
|
|
|
2017-09-06 20:16:32 -04:00
|
|
|
|
Confirmation from other debugger vendors
|
|
|
|
|
----------------------------------------
|
|
|
|
|
|
2017-09-05 16:42:34 -04:00
|
|
|
|
We want to get confirmation from at least one alternative debugger
|
2017-09-06 12:50:56 -04:00
|
|
|
|
implementation (e.g. PyCharm) that the hooks provided in this PEP will
|
|
|
|
|
be useful to them.
|
2017-09-05 16:42:34 -04:00
|
|
|
|
|
2017-09-07 22:21:03 -04:00
|
|
|
|
|
2017-09-06 20:16:32 -04:00
|
|
|
|
Breakpoint bytecode
|
|
|
|
|
-------------------
|
|
|
|
|
|
2017-09-05 17:12:57 -04:00
|
|
|
|
Related, there has been an idea to add a bytecode that calls
|
2017-09-06 12:50:56 -04:00
|
|
|
|
``sys.breakpointhook()``. Whether built-in ``breakpoint()`` 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
|
|
|
|
|
"breakpoint" bytecode might allow them to avoid bytecode modification
|
|
|
|
|
in order to invoke this trampoline. *NOTE*: It probably makes sense to split
|
|
|
|
|
this idea into a separate PEP.
|
2017-09-05 17:12:57 -04:00
|
|
|
|
|
2017-09-07 22:21:03 -04:00
|
|
|
|
|
2017-09-06 20:16:32 -04:00
|
|
|
|
Environment variable
|
|
|
|
|
--------------------
|
|
|
|
|
|
2017-09-06 18:15:31 -04:00
|
|
|
|
Should we add an environment variable so that ``sys.breakpointhook()`` can be
|
|
|
|
|
set outside of the Python invocation? E.g.::
|
|
|
|
|
|
|
|
|
|
$ export PYTHONBREAKPOINTHOOK=my.debugger:Debugger
|
|
|
|
|
|
|
|
|
|
This would provide execution environments such as IDEs which run Python code
|
|
|
|
|
inside them, to set an internal breakpoint hook before any Python code
|
|
|
|
|
executes.
|
|
|
|
|
|
2017-09-07 22:21:03 -04:00
|
|
|
|
If we did add that hook, what should be the default value and should
|
|
|
|
|
it be easy to disable ``breakpoint()``? The rationale here is calls
|
|
|
|
|
to ``breakpoint()`` that might accidentally sneak into production.
|
|
|
|
|
|
|
|
|
|
The author's opinion is that if we support this environment variable
|
|
|
|
|
it should be enabled --and point to ``pdb.set_trace()``-- by default.
|
|
|
|
|
This way it Just Works for the average developer. The maintainers of
|
|
|
|
|
CI, build, or production systems should be able to easily configure
|
|
|
|
|
their environments to disable ``breakpoint()``. We probably want to
|
|
|
|
|
support a shorthand for "disable built-in breakpoint()", e.g.::
|
|
|
|
|
|
|
|
|
|
$ export PYTHONBREAKPOINTHOOK=0
|
|
|
|
|
|
|
|
|
|
|
2017-09-06 20:16:32 -04:00
|
|
|
|
Call a fancier object by default
|
|
|
|
|
--------------------------------
|
|
|
|
|
|
|
|
|
|
Some folks want to be able to use other ``pdb`` interfaces such as
|
|
|
|
|
``pdb.pm()``. Although this is a less commonly used API, it could be
|
|
|
|
|
supported by binding ``sys.breakpointhook`` to an object that implements
|
|
|
|
|
``__call__()``. Calling this object would call ``pdb.set_trace()``, but the
|
|
|
|
|
object could expose other methods, such as ``pdb.pm()``, making invocation of
|
|
|
|
|
it as handy as ``breakpoint.pm()``.
|
|
|
|
|
|
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
|
|
|
|
|
2017-09-06 12:50:56 -04:00
|
|
|
|
sys.breakpoint()
|
|
|
|
|
----------------
|
|
|
|
|
|
|
|
|
|
Why not ``sys.breakpoint()``? Requiring an import to invoke the debugger is
|
2017-09-05 17:12:57 -04:00
|
|
|
|
explicitly rejected because ``sys`` is not imported in every module. That
|
|
|
|
|
just requires more typing and would lead to::
|
|
|
|
|
|
2017-09-06 12:50:56 -04:00
|
|
|
|
import sys; sys.breakpoint()
|
2017-09-05 17:12:57 -04:00
|
|
|
|
|
|
|
|
|
which inherits several of the problems this PEP aims to solve.
|
|
|
|
|
|
2017-09-05 16:42:34 -04:00
|
|
|
|
|
2017-09-07 14:27:55 -04:00
|
|
|
|
Version History
|
|
|
|
|
===============
|
|
|
|
|
|
|
|
|
|
* 2017-09-07
|
|
|
|
|
|
|
|
|
|
* ``debug()`` renamed to ``breakpoint()``
|
|
|
|
|
* Signature changed to ``breakpoint(*args, **kws)`` which is passed straight
|
|
|
|
|
through to ``sys.breakpointhook()``.
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
2017-09-05 21:09:13 -04:00
|
|
|
|
.. [4] https://github.com/python/cpython/pull/3355
|
2017-09-05 16:42:34 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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:
|