[Python-Dev] PEP 553 V2 - builtin breakpoint() (was Re: PEP 553: Built-in debug())

Barry Warsaw barry at python.org
Thu Sep 7 14:43:41 EDT 2017

Thanks for all the great feedback folks!  Here then is PEP 553 version
2.  The notable changes are:

* Change the name of the built-in from debug() to breakpoint()
* Modify the signature to be breakpoint(*args, **kws)


Included below for convenience.


PEP: 553
Title: Built-in breakpoint()
Author: Barry Warsaw <barry at python.org>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 2017-09-05
Python-Version: 3.7
Post-History: 2017-09-05, 2017-09-07


This PEP proposes adding a new built-in function called ``breakpoint()``
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.


Python has long had a great debugger in its standard library called ``pdb``.
Setting a break point is commonly written like this::

    import pdb; pdb.set_trace()

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

* 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.


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 ``breakpoint()``
which enters a Python debugger at the call site.  Thus the example
above would be written like so::


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]_.

The signature of the built-in is ``breakpoint(*args, **kws)``.  The
and keyword arguments are passed straight through to
and the signatures must match or a ``TypeError`` will be raised.  The return
from ``sys.breakpointhook()`` is passed back up to, and returned from
``breakpoint()``.  Since ``sys.breakpointhook()`` by default calls
``pdb.set_trace()`` by default it accepts no arguments.

Open issues

Confirmation from other debugger vendors

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.

Breakpoint bytecode

Related, there has been an idea to add a bytecode that calls
``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
this idea into a separate PEP.

Environment variable

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

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()``.


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

* A brand new keyword would require a ``__future__`` to enable it since
  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
  no existing code (since any existing module global would just shadow the
  built-in) and is quite easy to implement.


Why not ``sys.breakpoint()``?  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.breakpoint()

which inherits several of the problems this PEP aims to solve.

Version History

* 2017-09-07

  * ``debug()`` renamed to ``breakpoint()``
  * Signature changed to ``breakpoint(*args, **kws)`` which is passed
    through to ``sys.breakpointhook()``.


.. [1] http://flake8.readthedocs.io/en/latest/

.. [2]

.. [3] https://docs.python.org/3/library/sys.html#sys.displayhook

.. [4] https://github.com/python/cpython/pull/3355


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

More information about the Python-Dev mailing list