-
-
Notifications
You must be signed in to change notification settings - Fork 31.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PEP 553 built-in debug() function (bpo-31353) #3355
Changes from all commits
9dc577a
bc4634d
f7e3c40
6696c23
4600bcf
0f46af7
a141f63
79d7ac8
1666925
8437033
6534542
2d75d7a
ed649fa
0bea882
eee151d
05b7cae
6b9a59c
5e0b93a
c57d0dc
eb17d0f
244bff5
c4bed66
6eb3470
af81484
f3200c7
1c60e11
ed41006
b84a018
f6db9e3
cf9e7ac
e46c59d
9bc36b8
b5c2393
2846d3b
50c3e40
6b23d5b
0d2fae5
1cf3e06
6217e90
28bd8e4
8808367
bd68b76
fea5d3d
599108d
a74f23e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -502,6 +502,18 @@ conflict. | |
:option:`-O` multiple times. | ||
|
||
|
||
.. envvar:: PYTHONBREAKPOINT | ||
|
||
If this is set, it names a callable using dotted-path notation. The module | ||
containing the callable will be imported and then the callable will be run | ||
by the default implementation of :func:`sys.breakpointhook` which itself is | ||
called by built-in :func:`breakpoint`. If not set, or set to the empty | ||
string, it is equivalent to the value "pdb.set_trace". Setting this to the | ||
string "0" causes the default implementation of :func:`sys.breakpointhook` | ||
to do nothing but return immediately. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ".. versionadded:: 3.7" is missing here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
|
||
.. versionadded:: 3.7 | ||
|
||
.. envvar:: PYTHONDEBUG | ||
|
||
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 |
---|---|---|
|
@@ -17,9 +17,12 @@ | |
import types | ||
import unittest | ||
import warnings | ||
from contextlib import ExitStack | ||
from operator import neg | ||
from test.support import TESTFN, unlink, check_warnings | ||
from test.support import ( | ||
EnvironmentVarGuard, TESTFN, check_warnings, swap_attr, unlink) | ||
from test.support.script_helper import assert_python_ok | ||
from unittest.mock import MagicMock, patch | ||
try: | ||
import pty, signal | ||
except ImportError: | ||
|
@@ -1514,6 +1517,111 @@ def test_construct_singletons(self): | |
self.assertRaises(TypeError, tp, 1, 2) | ||
self.assertRaises(TypeError, tp, a=1, b=2) | ||
|
||
|
||
class TestBreakpoint(unittest.TestCase): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe you should add a setUp() method using self.addCleanup() to save/restore sys.breakpointhook value, instead of doing that in each test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this is a great suggestion, coupled with the observation below that the test suite could be run with I'm going to use an |
||
def setUp(self): | ||
# These tests require a clean slate environment. For example, if the | ||
# test suite is run with $PYTHONBREAKPOINT set to something else, it | ||
# will mess up these tests. Similarly for sys.breakpointhook. | ||
# Cleaning the slate here means you can't use breakpoint() to debug | ||
# these tests, but I think that's okay. Just use pdb.set_trace() if | ||
# you must. | ||
self.resources = ExitStack() | ||
self.addCleanup(self.resources.close) | ||
self.env = self.resources.enter_context(EnvironmentVarGuard()) | ||
del self.env['PYTHONBREAKPOINT'] | ||
self.resources.enter_context( | ||
swap_attr(sys, 'breakpointhook', sys.__breakpointhook__)) | ||
|
||
def test_breakpoint(self): | ||
with patch('pdb.set_trace') as mock: | ||
breakpoint() | ||
mock.assert_called_once() | ||
|
||
def test_breakpoint_with_breakpointhook_set(self): | ||
my_breakpointhook = MagicMock() | ||
sys.breakpointhook = my_breakpointhook | ||
breakpoint() | ||
my_breakpointhook.assert_called_once_with() | ||
|
||
def test_breakpoint_with_breakpointhook_reset(self): | ||
my_breakpointhook = MagicMock() | ||
sys.breakpointhook = my_breakpointhook | ||
breakpoint() | ||
my_breakpointhook.assert_called_once_with() | ||
# Reset the hook and it will not be called again. | ||
sys.breakpointhook = sys.__breakpointhook__ | ||
with patch('pdb.set_trace') as mock: | ||
breakpoint() | ||
mock.assert_called_once_with() | ||
my_breakpointhook.assert_called_once_with() | ||
|
||
def test_breakpoint_with_args_and_keywords(self): | ||
my_breakpointhook = MagicMock() | ||
sys.breakpointhook = my_breakpointhook | ||
breakpoint(1, 2, 3, four=4, five=5) | ||
my_breakpointhook.assert_called_once_with(1, 2, 3, four=4, five=5) | ||
|
||
def test_breakpoint_with_passthru_error(self): | ||
def my_breakpointhook(): | ||
pass | ||
sys.breakpointhook = my_breakpointhook | ||
self.assertRaises(TypeError, breakpoint, 1, 2, 3, four=4, five=5) | ||
|
||
@unittest.skipIf(sys.flags.ignore_environment, '-E was given') | ||
def test_envar_good_path_builtin(self): | ||
self.env['PYTHONBREAKPOINT'] = 'int' | ||
with patch('builtins.int') as mock: | ||
breakpoint('7') | ||
mock.assert_called_once_with('7') | ||
|
||
@unittest.skipIf(sys.flags.ignore_environment, '-E was given') | ||
def test_envar_good_path_other(self): | ||
self.env['PYTHONBREAKPOINT'] = 'sys.exit' | ||
with patch('sys.exit') as mock: | ||
breakpoint() | ||
mock.assert_called_once_with() | ||
|
||
@unittest.skipIf(sys.flags.ignore_environment, '-E was given') | ||
def test_envar_good_path_noop_0(self): | ||
self.env['PYTHONBREAKPOINT'] = '0' | ||
with patch('pdb.set_trace') as mock: | ||
breakpoint() | ||
mock.assert_not_called() | ||
|
||
def test_envar_good_path_empty_string(self): | ||
# PYTHONBREAKPOINT='' is the same as it not being set. | ||
self.env['PYTHONBREAKPOINT'] = '' | ||
with patch('pdb.set_trace') as mock: | ||
breakpoint() | ||
mock.assert_called_once_with() | ||
|
||
@unittest.skipIf(sys.flags.ignore_environment, '-E was given') | ||
def test_envar_unimportable(self): | ||
for envar in ( | ||
'.', '..', '.foo', 'foo.', '.int', 'int.' | ||
'nosuchbuiltin', | ||
'nosuchmodule.nosuchcallable', | ||
): | ||
with self.subTest(envar=envar): | ||
self.env['PYTHONBREAKPOINT'] = envar | ||
mock = self.resources.enter_context(patch('pdb.set_trace')) | ||
w = self.resources.enter_context(check_warnings(quiet=True)) | ||
breakpoint() | ||
self.assertEqual( | ||
str(w.message), | ||
f'Ignoring unimportable $PYTHONBREAKPOINT: "{envar}"') | ||
self.assertEqual(w.category, RuntimeWarning) | ||
mock.assert_not_called() | ||
|
||
def test_envar_ignored_when_hook_is_set(self): | ||
self.env['PYTHONBREAKPOINT'] = 'sys.exit' | ||
with patch('sys.exit') as mock: | ||
sys.breakpointhook = int | ||
breakpoint() | ||
mock.assert_not_called() | ||
|
||
|
||
@unittest.skipUnless(pty, "the pty and signal modules must be available") | ||
class PtyTests(unittest.TestCase): | ||
"""Tests that use a pseudo terminal to guarantee stdin and stdout are | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
:pep:`553` - Add a new built-in called ``breakpoint()`` which calls | ||
``sys.breakpointhook()``. By default this imports ``pdb`` and calls | ||
``pdb.set_trace()``, but users may override ``sys.breakpointhook()`` to call | ||
whatever debugger they want. The original value of the hook is saved in | ||
``sys.__breakpointhook__``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PYTHONBREAKPOINT should be written:
(as you did in the What's New in Python 3.7) and you should document the variable in Doc/using/cmdline.rst.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, fixed!