| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 4d07189 commit 36c1d1f
9 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,24 +7,24 @@ Built-in Functions | |||
| 7 | 7 | The Python interpreter has a number of functions and types built into it that | |
| 8 | 8 | are always available. They are listed here in alphabetical order. | |
| 9 | 9 | ||
| 10 | - =================== ================= ================== ================ ==================== | ||
| 11 | - .. .. Built-in Functions .. .. | ||
| 12 | - =================== ================= ================== ================ ==================== | ||
| 13 | - :func:`abs` |func-dict|_ :func:`help` :func:`min` :func:`setattr` | ||
| 14 | - :func:`all` :func:`dir` :func:`hex` :func:`next` :func:`slice` | ||
| 15 | - :func:`any` :func:`divmod` :func:`id` :func:`object` :func:`sorted` | ||
| 16 | - :func:`ascii` :func:`enumerate` :func:`input` :func:`oct` :func:`staticmethod` | ||
| 17 | - :func:`bin` :func:`eval` :func:`int` :func:`open` |func-str|_ | ||
| 18 | - :func:`bool` :func:`exec` :func:`isinstance` :func:`ord` :func:`sum` | ||
| 19 | - |func-bytearray|_ :func:`filter` :func:`issubclass` :func:`pow` :func:`super` | ||
| 20 | - |func-bytes|_ :func:`float` :func:`iter` :func:`print` |func-tuple|_ | ||
| 21 | - :func:`callable` :func:`format` :func:`len` :func:`property` :func:`type` | ||
| 22 | - :func:`chr` |func-frozenset|_ |func-list|_ |func-range|_ :func:`vars` | ||
| 23 | - :func:`classmethod` :func:`getattr` :func:`locals` :func:`repr` :func:`zip` | ||
| 24 | - :func:`compile` :func:`globals` :func:`map` :func:`reversed` :func:`__import__` | ||
| 10 | + =================== ================= ================== ================== ==================== | ||
| 11 | + .. .. Built-in Functions .. .. | ||
| 12 | + =================== ================= ================== ================== ==================== | ||
| 13 | + :func:`abs` :func:`delattr` :func:`hash` |func-memoryview|_ |func-set|_ | ||
| 14 | + :func:`all` |func-dict|_ :func:`help` :func:`min` :func:`setattr` | ||
| 15 | + :func:`any` :func:`dir` :func:`hex` :func:`next` :func:`slice` | ||
| 16 | + :func:`ascii` :func:`divmod` :func:`id` :func:`object` :func:`sorted` | ||
| 17 | + :func:`bin` :func:`enumerate` :func:`input` :func:`oct` :func:`staticmethod` | ||
| 18 | + :func:`bool` :func:`eval` :func:`int` :func:`open` |func-str|_ | ||
| 19 | + :func:`breakpoint` :func:`exec` :func:`isinstance` :func:`ord` :func:`sum` | ||
| 20 | + |func-bytearray|_ :func:`filter` :func:`issubclass` :func:`pow` :func:`super` | ||
| 21 | + |func-bytes|_ :func:`float` :func:`iter` :func:`print` |func-tuple|_ | ||
| 22 | + :func:`callable` :func:`format` :func:`len` :func:`property` :func:`type` | ||
| 23 | + :func:`chr` |func-frozenset|_ |func-list|_ |func-range|_ :func:`vars` | ||
| 24 | + :func:`classmethod` :func:`getattr` :func:`locals` :func:`repr` :func:`zip` | ||
| 25 | + :func:`compile` :func:`globals` :func:`map` :func:`reversed` :func:`__import__` | ||
| 25 | 26 | :func:`complex` :func:`hasattr` :func:`max` :func:`round` | |
| 26 | - :func:`delattr` :func:`hash` |func-memoryview|_ |func-set|_ | ||
| 27 | - =================== ================= ================== ================ ==================== | ||
| 27 | + =================== ================= ================== ================== ==================== | ||
| 28 | 28 | ||
| 29 | 29 | .. using :func:`dict` would create a link to another page, so local targets are | |
| 30 | 30 | used, with replacement texts to make the output in the table consistent | |
@@ -113,6 +113,20 @@ are always available. They are listed here in alphabetical order. | |||
| 113 | 113 | .. index:: pair: Boolean; type | |
| 114 | 114 | ||
| 115 | 115 | ||
| 116 | + .. function:: breakpoint(*args, **kws) | ||
| 117 | + | ||
| 118 | + This function drops you into the debugger at the call site. Specifically, | ||
| 119 | + it calls :func:`sys.breakpointhook`, passing ``args`` and ``kws`` straight | ||
| 120 | + through. By default, ``sys.breakpointhook()`` calls | ||
| 121 | + :func:`pdb.set_trace()` expecting no arguments. In this case, it is | ||
| 122 | + purely a convenience function so you don't have to explicitly import | ||
| 123 | + :mod:`pdb` or type as much code to enter the debugger. However, | ||
| 124 | + :func:`sys.breakpointhook` can be set to some other function and | ||
| 125 | + :func:`breakpoint` will automatically call that, allowing you to drop into | ||
| 126 | + the debugger of choice. | ||
| 127 | + | ||
| 128 | + .. versionadded:: 3.7 | ||
| 129 | + | ||
| 116 | 130 | .. _func-bytearray: | |
| 117 | 131 | .. class:: bytearray([source[, encoding[, errors]]]) | |
| 118 | 132 | :noindex: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -109,6 +109,40 @@ always available. | |||
| 109 | 109 | This function should be used for internal and specialized purposes only. | |
| 110 | 110 | ||
| 111 | 111 | ||
| 112 | + .. function:: breakpointhook() | ||
| 113 | + | ||
| 114 | + This hook function is called by built-in :func:`breakpoint`. By default, | ||
| 115 | + it drops you into the :mod:`pdb` debugger, but it can be set to any other | ||
| 116 | + function so that you can choose which debugger gets used. | ||
| 117 | + | ||
| 118 | + The signature of this function is dependent on what it calls. For example, | ||
| 119 | + the default binding (e.g. ``pdb.set_trace()``) expects no arguments, but | ||
| 120 | + you might bind it to a function that expects additional arguments | ||
| 121 | + (positional and/or keyword). The built-in ``breakpoint()`` function passes | ||
| 122 | + its ``*args`` and ``**kws`` straight through. Whatever | ||
| 123 | + ``breakpointhooks()`` returns is returned from ``breakpoint()``. | ||
| 124 | + | ||
| 125 | + The default implementation first consults the environment variable | ||
| 126 | + :envvar:`PYTHONBREAKPOINT`. If that is set to ``"0"`` then this function | ||
| 127 | + returns immediately; i.e. it is a no-op. If the environment variable is | ||
| 128 | + not set, or is set to the empty string, ``pdb.set_trace()`` is called. | ||
| 129 | + Otherwise this variable should name a function to run, using Python's | ||
| 130 | + dotted-import nomenclature, e.g. ``package.subpackage.module.function``. | ||
| 131 | + In this case, ``package.subpackage.module`` would be imported and the | ||
| 132 | + resulting module must have a callable named ``function()``. This is run, | ||
| 133 | + passing in ``*args`` and ``**kws``, and whatever ``function()`` returns, | ||
| 134 | + ``sys.breakpointhook()`` returns to the built-in :func:`breakpoint` | ||
| 135 | + function. | ||
| 136 | + | ||
| 137 | + Note that if anything goes wrong while importing the callable named by | ||
| 138 | + :envvar:`PYTHONBREAKPOINT`, a :exc:`RuntimeWarning` is reported and the | ||
| 139 | + breakpoint is ignored. | ||
| 140 | + | ||
| 141 | + Also note that if ``sys.breakpointhook()`` is overridden programmatically, | ||
| 142 | + :envvar:`PYTHONBREAKPOINT` is *not* consulted. | ||
| 143 | + | ||
| 144 | + .. versionadded:: 3.7 | ||
| 145 | + | ||
| 112 | 146 | .. function:: _debugmallocstats() | |
| 113 | 147 | ||
| 114 | 148 | Print low-level information to stderr about the state of CPython's memory | |
@@ -187,14 +221,19 @@ always available. | |||
| 187 | 221 | customized by assigning another three-argument function to ``sys.excepthook``. | |
| 188 | 222 | ||
| 189 | 223 | ||
| 190 | - .. data:: __displayhook__ | ||
| 224 | + .. data:: __breakpointhook__ | ||
| 225 | + __displayhook__ | ||
| 191 | 226 | __excepthook__ | |
| 192 | 227 | ||
| 193 | - These objects contain the original values of ``displayhook`` and ``excepthook`` | ||
| 194 | - at the start of the program. They are saved so that ``displayhook`` and | ||
| 195 | - ``excepthook`` can be restored in case they happen to get replaced with broken | ||
| 228 | + These objects contain the original values of ``breakpointhook``, | ||
| 229 | + ``displayhook``, and ``excepthook`` at the start of the program. They are | ||
| 230 | + saved so that ``breakpointhook``, ``displayhook`` and ``excepthook`` can be | ||
| 231 | + restored in case they happen to get replaced with broken or alternative | ||
| 196 | 232 | objects. | |
| 197 | 233 | ||
| 234 | + .. versionadded:: 3.7 | ||
| 235 | + __breakpointhook__ | ||
| 236 | + | ||
| 198 | 237 | ||
| 199 | 238 | .. function:: exc_info() | |
| 200 | 239 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -502,6 +502,18 @@ conflict. | |||
| 502 | 502 | :option:`-O` multiple times. | |
| 503 | 503 | ||
| 504 | 504 | ||
| 505 | + .. envvar:: PYTHONBREAKPOINT | ||
| 506 | + | ||
| 507 | + If this is set, it names a callable using dotted-path notation. The module | ||
| 508 | + containing the callable will be imported and then the callable will be run | ||
| 509 | + by the default implementation of :func:`sys.breakpointhook` which itself is | ||
| 510 | + called by built-in :func:`breakpoint`. If not set, or set to the empty | ||
| 511 | + string, it is equivalent to the value "pdb.set_trace". Setting this to the | ||
| 512 | + string "0" causes the default implementation of :func:`sys.breakpointhook` | ||
| 513 | + to do nothing but return immediately. | ||
| 514 | + | ||
| 515 | + .. versionadded:: 3.7 | ||
| 516 | + | ||
| 505 | 517 | .. envvar:: PYTHONDEBUG | |
| 506 | 518 | ||
| 507 | 519 | If this is set to a non-empty string it is equivalent to specifying the | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -107,6 +107,25 @@ locale remains active when the core interpreter is initialized. | |||
| 107 | 107 | :pep:`538` -- Coercing the legacy C locale to a UTF-8 based locale | |
| 108 | 108 | PEP written and implemented by Nick Coghlan. | |
| 109 | 109 | ||
| 110 | + .. _whatsnew37-pep553: | ||
| 111 | + | ||
| 112 | + PEP 553: Built-in breakpoint() | ||
| 113 | + ------------------------------ | ||
| 114 | + | ||
| 115 | + :pep:`553` describes a new built-in called ``breakpoint()`` which makes it | ||
| 116 | + easy and consistent to enter the Python debugger. Built-in ``breakpoint()`` | ||
| 117 | + calls ``sys.breakpointhook()``. By default, this latter imports ``pdb`` and | ||
| 118 | + then calls ``pdb.set_trace()``, but by binding ``sys.breakpointhook()`` to the | ||
| 119 | + function of your choosing, ``breakpoint()`` can enter any debugger. Or, the | ||
| 120 | + environment variable :envvar:`PYTHONBREAKPOINT` can be set to the callable of | ||
| 121 | + your debugger of choice. Set ``PYTHONBREAKPOINT=0`` to completely disable | ||
| 122 | + built-in ``breakpoint()``. | ||
| 123 | + | ||
| 124 | + .. seealso:: | ||
| 125 | + | ||
| 126 | + :pep:`553` -- Built-in breakpoint() | ||
| 127 | + PEP written and implemented by Barry Warsaw | ||
| 128 | + | ||
| 110 | 129 | ||
| 111 | 130 | Other Language Changes | |
| 112 | 131 | ====================== | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,9 +17,12 @@ | |||
| 17 | 17 | import types | |
| 18 | 18 | import unittest | |
| 19 | 19 | import warnings | |
| 20 | + from contextlib import ExitStack | ||
| 20 | 21 | from operator import neg | |
| 21 | - from test.support import TESTFN, unlink, check_warnings | ||
| 22 | + from test.support import ( | ||
| 23 | + EnvironmentVarGuard, TESTFN, check_warnings, swap_attr, unlink) | ||
| 22 | 24 | from test.support.script_helper import assert_python_ok | |
| 25 | + from unittest.mock import MagicMock, patch | ||
| 23 | 26 | try: | |
| 24 | 27 | import pty, signal | |
| 25 | 28 | except ImportError: | |
@@ -1514,6 +1517,111 @@ def test_construct_singletons(self): | |||
| 1514 | 1517 | self.assertRaises(TypeError, tp, 1, 2) | |
| 1515 | 1518 | self.assertRaises(TypeError, tp, a=1, b=2) | |
| 1516 | 1519 | ||
| 1520 | + | ||
| 1521 | + class TestBreakpoint(unittest.TestCase): | ||
| 1522 | + def setUp(self): | ||
| 1523 | + # These tests require a clean slate environment. For example, if the | ||
| 1524 | + # test suite is run with $PYTHONBREAKPOINT set to something else, it | ||
| 1525 | + # will mess up these tests. Similarly for sys.breakpointhook. | ||
| 1526 | + # Cleaning the slate here means you can't use breakpoint() to debug | ||
| 1527 | + # these tests, but I think that's okay. Just use pdb.set_trace() if | ||
| 1528 | + # you must. | ||
| 1529 | + self.resources = ExitStack() | ||
| 1530 | + self.addCleanup(self.resources.close) | ||
| 1531 | + self.env = self.resources.enter_context(EnvironmentVarGuard()) | ||
| 1532 | + del self.env['PYTHONBREAKPOINT'] | ||
| 1533 | + self.resources.enter_context( | ||
| 1534 | + swap_attr(sys, 'breakpointhook', sys.__breakpointhook__)) | ||
| 1535 | + | ||
| 1536 | + def test_breakpoint(self): | ||
| 1537 | + with patch('pdb.set_trace') as mock: | ||
| 1538 | + breakpoint() | ||
| 1539 | + mock.assert_called_once() | ||
| 1540 | + | ||
| 1541 | + def test_breakpoint_with_breakpointhook_set(self): | ||
| 1542 | + my_breakpointhook = MagicMock() | ||
| 1543 | + sys.breakpointhook = my_breakpointhook | ||
| 1544 | + breakpoint() | ||
| 1545 | + my_breakpointhook.assert_called_once_with() | ||
| 1546 | + | ||
| 1547 | + def test_breakpoint_with_breakpointhook_reset(self): | ||
| 1548 | + my_breakpointhook = MagicMock() | ||
| 1549 | + sys.breakpointhook = my_breakpointhook | ||
| 1550 | + breakpoint() | ||
| 1551 | + my_breakpointhook.assert_called_once_with() | ||
| 1552 | + # Reset the hook and it will not be called again. | ||
| 1553 | + sys.breakpointhook = sys.__breakpointhook__ | ||
| 1554 | + with patch('pdb.set_trace') as mock: | ||
| 1555 | + breakpoint() | ||
| 1556 | + mock.assert_called_once_with() | ||
| 1557 | + my_breakpointhook.assert_called_once_with() | ||
| 1558 | + | ||
| 1559 | + def test_breakpoint_with_args_and_keywords(self): | ||
| 1560 | + my_breakpointhook = MagicMock() | ||
| 1561 | + sys.breakpointhook = my_breakpointhook | ||
| 1562 | + breakpoint(1, 2, 3, four=4, five=5) | ||
| 1563 | + my_breakpointhook.assert_called_once_with(1, 2, 3, four=4, five=5) | ||
| 1564 | + | ||
| 1565 | + def test_breakpoint_with_passthru_error(self): | ||
| 1566 | + def my_breakpointhook(): | ||
| 1567 | + pass | ||
| 1568 | + sys.breakpointhook = my_breakpointhook | ||
| 1569 | + self.assertRaises(TypeError, breakpoint, 1, 2, 3, four=4, five=5) | ||
| 1570 | + | ||
| 1571 | + @unittest.skipIf(sys.flags.ignore_environment, '-E was given') | ||
| 1572 | + def test_envar_good_path_builtin(self): | ||
| 1573 | + self.env['PYTHONBREAKPOINT'] = 'int' | ||
| 1574 | + with patch('builtins.int') as mock: | ||
| 1575 | + breakpoint('7') | ||
| 1576 | + mock.assert_called_once_with('7') | ||
| 1577 | + | ||
| 1578 | + @unittest.skipIf(sys.flags.ignore_environment, '-E was given') | ||
| 1579 | + def test_envar_good_path_other(self): | ||
| 1580 | + self.env['PYTHONBREAKPOINT'] = 'sys.exit' | ||
| 1581 | + with patch('sys.exit') as mock: | ||
| 1582 | + breakpoint() | ||
| 1583 | + mock.assert_called_once_with() | ||
| 1584 | + | ||
| 1585 | + @unittest.skipIf(sys.flags.ignore_environment, '-E was given') | ||
| 1586 | + def test_envar_good_path_noop_0(self): | ||
| 1587 | + self.env['PYTHONBREAKPOINT'] = '0' | ||
| 1588 | + with patch('pdb.set_trace') as mock: | ||
| 1589 | + breakpoint() | ||
| 1590 | + mock.assert_not_called() | ||
| 1591 | + | ||
| 1592 | + def test_envar_good_path_empty_string(self): | ||
| 1593 | + # PYTHONBREAKPOINT='' is the same as it not being set. | ||
| 1594 | + self.env['PYTHONBREAKPOINT'] = '' | ||
| 1595 | + with patch('pdb.set_trace') as mock: | ||
| 1596 | + breakpoint() | ||
| 1597 | + mock.assert_called_once_with() | ||
| 1598 | + | ||
| 1599 | + @unittest.skipIf(sys.flags.ignore_environment, '-E was given') | ||
| 1600 | + def test_envar_unimportable(self): | ||
| 1601 | + for envar in ( | ||
| 1602 | + '.', '..', '.foo', 'foo.', '.int', 'int.' | ||
| 1603 | + 'nosuchbuiltin', | ||
| 1604 | + 'nosuchmodule.nosuchcallable', | ||
| 1605 | + ): | ||
| 1606 | + with self.subTest(envar=envar): | ||
| 1607 | + self.env['PYTHONBREAKPOINT'] = envar | ||
| 1608 | + mock = self.resources.enter_context(patch('pdb.set_trace')) | ||
| 1609 | + w = self.resources.enter_context(check_warnings(quiet=True)) | ||
| 1610 | + breakpoint() | ||
| 1611 | + self.assertEqual( | ||
| 1612 | + str(w.message), | ||
| 1613 | + f'Ignoring unimportable $PYTHONBREAKPOINT: "{envar}"') | ||
| 1614 | + self.assertEqual(w.category, RuntimeWarning) | ||
| 1615 | + mock.assert_not_called() | ||
| 1616 | + | ||
| 1617 | + def test_envar_ignored_when_hook_is_set(self): | ||
| 1618 | + self.env['PYTHONBREAKPOINT'] = 'sys.exit' | ||
| 1619 | + with patch('sys.exit') as mock: | ||
| 1620 | + sys.breakpointhook = int | ||
| 1621 | + breakpoint() | ||
| 1622 | + mock.assert_not_called() | ||
| 1623 | + | ||
| 1624 | + | ||
| 1517 | 1625 | @unittest.skipUnless(pty, "the pty and signal modules must be available") | |
| 1518 | 1626 | class PtyTests(unittest.TestCase): | |
| 1519 | 1627 | """Tests that use a pseudo terminal to guarantee stdin and stdout are | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3523,7 +3523,8 @@ def test_builtins_have_signatures(self): | |||
| 3523 | 3523 | needs_semantic_update = {"round"} | |
| 3524 | 3524 | no_signature |= needs_semantic_update | |
| 3525 | 3525 | # These need *args support in Argument Clinic | |
| 3526 | - needs_varargs = {"min", "max", "print", "__build_class__"} | ||
| 3526 | + needs_varargs = {"breakpoint", "min", "max", "print", | ||
| 3527 | + "__build_class__"} | ||
| 3527 | 3528 | no_signature |= needs_varargs | |
| 3528 | 3529 | # These simply weren't covered in the initial AC conversion | |
| 3529 | 3530 | # for builtin callables | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,5 @@ | |||
| 1 | + :pep:`553` - Add a new built-in called ``breakpoint()`` which calls | ||
| 2 | + ``sys.breakpointhook()``. By default this imports ``pdb`` and calls | ||
| 3 | + ``pdb.set_trace()``, but users may override ``sys.breakpointhook()`` to call | ||
| 4 | + whatever debugger they want. The original value of the hook is saved in | ||
| 5 | + ``sys.__breakpointhook__``. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -422,6 +422,28 @@ builtin_callable(PyObject *module, PyObject *obj) | |||
| 422 | 422 | return PyBool_FromLong((long)PyCallable_Check(obj)); | |
| 423 | 423 | } | |
| 424 | 424 | ||
| 425 | + static PyObject * | ||
| 426 | + builtin_breakpoint(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *keywords) | ||
| 427 | + { | ||
| 428 | + PyObject *hook = PySys_GetObject("breakpointhook"); | ||
| 429 | + | ||
| 430 | + if (hook == NULL) { | ||
| 431 | + PyErr_SetString(PyExc_RuntimeError, "lost sys.breakpointhook"); | ||
| 432 | + return NULL; | ||
| 433 | + } | ||
| 434 | + Py_INCREF(hook); | ||
| 435 | + PyObject *retval = _PyObject_FastCallKeywords(hook, args, nargs, keywords); | ||
| 436 | + Py_DECREF(hook); | ||
| 437 | + return retval; | ||
| 438 | + } | ||
| 439 | + | ||
| 440 | + PyDoc_STRVAR(breakpoint_doc, | ||
| 441 | + "breakpoint(*args, **kws)\n\ | ||
| 442 | + \n\ | ||
| 443 | + Call sys.breakpointhook(*args, **kws). sys.breakpointhook() must accept\n\ | ||
| 444 | + whatever arguments are passed.\n\ | ||
| 445 | + \n\ | ||
| 446 | + By default, this drops you into the pdb debugger."); | ||
| 425 | 447 | ||
| 426 | 448 | typedef struct { | |
| 427 | 449 | PyObject_HEAD | |
@@ -2627,6 +2649,7 @@ static PyMethodDef builtin_methods[] = { | |||
| 2627 | 2649 | BUILTIN_ANY_METHODDEF | |
| 2628 | 2650 | BUILTIN_ASCII_METHODDEF | |
| 2629 | 2651 | BUILTIN_BIN_METHODDEF | |
| 2652 | + {"breakpoint", (PyCFunction)builtin_breakpoint, METH_FASTCALL | METH_KEYWORDS, breakpoint_doc}, | ||
| 2630 | 2653 | BUILTIN_CALLABLE_METHODDEF | |
| 2631 | 2654 | BUILTIN_CHR_METHODDEF | |
| 2632 | 2655 | BUILTIN_COMPILE_METHODDEF | |
| Back | FazBrowse Home | New Git URL |
0 commit comments