-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Support for the new builtin breakpoint function in Python 3.7 #3331
Support for the new builtin breakpoint function in Python 3.7 #3331
Conversation
Discovered that the debugging module has no test coverage, so I want to develop tests for it before I start fiddling with it's behaviours. |
@tonybaloney for historic reasons its in |
@RonnyPfannschmidt where would you recommend I put these tests? is |
@tonybaloney for now please put them into test-pdb, as a follow-up it seems sensible to rename that file |
…esetting back when system default (pdb) is used""
…ystem default is set
…akpoint() not supported
…alled when breakpoint() is used
This PR is ready for review, I still need to add some documentation to explain the behaviours, but would like feedback on the work so far (most of it was just tests tbh!) |
Tested with the example IPython class, which breaks but seems to be caused by #2064
|
@nicoddemus @RonnyPfannschmidt done (except docs) |
Build failed on 1 test https://travis-ci.org/pytest-dev/pytest/jobs/357232290#L585 I asserted the output was "1 passed" but it is "2 passed" on Travis. Might have something to do with Hypothesis, trying to repro locally, but I can make the assertion a bit more vauge |
Yep. once I install hypothesis, it changes to 2 passed locally as well (which I guess makes sense as the hypothesis plugin is designed to do that) |
…veloping in pytest)
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.
Awesome work @tonybaloney, many thanks. Please take a look at my comments.
_pytest/debugging.py
Outdated
@@ -27,12 +34,20 @@ def pytest_configure(config): | |||
if config.getvalue("usepdb"): | |||
config.pluginmanager.register(PdbInvoke(), 'pdbinvoke') | |||
|
|||
# Use custom Pdb class set_trace instead of default Pdb on breakpoint() call | |||
if SUPPORTS_BREAKPOINT_BUILTIN: | |||
_environ_pythonbreakpoint = getattr(os.environ, 'PYTHONBREAKPOINT', '') |
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.
This seems like it should be _environ_pythonbreakpoint = os.environ.get('PYTHONBREAKPOINT', '')
right?
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.
Fixed in f1f4c8c
changelog/3180.feature.rst
Outdated
@@ -0,0 +1,12 @@ | |||
Support for Python 3.7s builtin breakpoint() method. |
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 for the detailed changelog entry, but unfortunately towncrier can't format multi-paragraph entries correctly in the CHANGELOG.
I suggest adding this to a new section after pdb section in the docs
, and reducing the changelog entry to:
Support for Python 3.7s builtin ``breakpoint()`` method, see `the debugging documentation <link here>`_ for details.
The new section could be named something like Support for breakpoint() support
and provide a link to the relevant PEP as well which would act as an introduction to the topic as well.
testing/test_pdb.py
Outdated
called.append("set_trace") | ||
|
||
_pytest._CustomDebugger = _CustomDebugger | ||
return called |
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.
It probably doesn't matter, but I think it is better to get rid of the reference to the class after the test:
_pytest._CustomDebugger = _CustomDebugger
yield called
del _pytest._CustomDebugger
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.
Done in f1f4c8c
testing/test_pdb.py
Outdated
""" | ||
config = testdir.parseconfig() | ||
|
||
pytest_configure(config) |
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.
This is clever, but it might be dangerous to call pytest_configure
by hand like this. How about:
testdir.makeconftest("""
from pytest import hookimpl
from _pytest.debugging import pytestPDB
@hookimpl(hookwrapper=True)
def pytest_configure(config):
yield
assert sys.breakpointhook is pytestPDB.set_trace
@hookimpl(hookwrapper=True)
def pytest_unconfigure(config):
yield
assert sys.breakpointhook is sys.__breakpoint__
""")
testdir.makepyfile("""
def test_nothing(): pass
""")
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.
I couldn't locate the right test pattern looking at the others. This makes sense
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.
Fixed in f1f4c8c
testing/test_pdb.py
Outdated
assert sys.breakpointhook != pytestPDB.set_trace | ||
|
||
@pytest.mark.skipif(not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin") | ||
def test_sys_breakpointhook_configure_and_unconfigure_with_pdb_flag(self, testdir): |
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.
You can probably parametrize this test with the above.
@pytest.mark.skipif(not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin")
@pytest.mark.parametrize('args', [('--pdb',), ()])
def test_sys_breakpointhook_configure_and_unconfigure(self, testdir, args):
...
result = testdir.runpytest_inprocess(*args)
(It's not necessary to pass p1
to runpytest_inprocess
).
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.
Fixed in f1f4c8c
testing/test_pdb.py
Outdated
def test_pdb_not_altered(self, testdir): | ||
""" | ||
Test that calling PDB set_trace() is not affected | ||
when PYTHONBREAKPOINT=0 |
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.
Is this comment correct? I don't see PYTHONBREAKPOINT
being set in the test..
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.
Removed in f1f4c8c
testing/test_pdb.py
Outdated
import pytest | ||
|
||
|
||
_ENVIRON_PYTHONBREAKPOINT = getattr(os.environ, 'PYTHONBREAKPOINT', '') |
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.
Again this seems like it should be `_ENVIRON_PYTHONBREAKPOINT = os.environ.get('PYTHONBREAKPOINT', '')
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.
Fixed in f1f4c8c
@nicoddemus made the code changes. Docs still need improving, but explain the behaviour for now. I can add more examples later when I've got some more time |
Hi @tonybaloney thanks for the quick response! I made some doc formatting changes (all minor), hope you don't mind. I worry though that the |
Our rst-linter unfortunately doesn't accept `ref` directives in the CHANGELOG files
@nicoddemus not sure I really understood this properly. It doesn't seem to execute. If I change the assertions it doesnt fail the tests |
@tonybaloney Oh my bad, my example was incomplete: ...
testdir.makepyfile("""
def test_nothing(): pass
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines([
'*1 passed in *',
]) IOW, |
@nicoddemus that makes sense, but all 3 fail now
I looked at the documentation and https://docs.pytest.org/en/latest/reference.html#_pytest.hookspec.pytest_configure that hook doesn't support hookwrapper=True. I tried taking that out and just get another error
|
* Execute pytest in a subprocess in cases of tests which change global state * Parametrize with --pdb and without the flag
testing/test_pdb.py
Outdated
""" | ||
assert sys.breakpointhook != pytestPDB.set_trace | ||
assert sys.breakpointhook == pytestPDB.set_trace |
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.
This test seemed incorrect to me and it was failing on my system: wasn't sys.breakpoint
supposed to be set in the normal circumstance? I changed the logic and docstring to reflect that and it passes. @tonybaloney please double check here.
@tonybaloney sorry my bad, I forgot
|
@nicoddemus I figured out why that last test was failing, because the test is being run inside a pytest session, the new behaviour would mean that sys.breakpointhook is going to be unpredictable depending on the version of pytest being used and it doesn't test anything other than runtime assumptions. I'm all done now :) |
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 a lot @tonybaloney!
I would like a second set of eyes to take a look before merging though, do you have some time to review this @RonnyPfannschmidt?
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.
looks great 👍
Test that supports breakpoint global marks on Python 3.7+ and not on | ||
CPython 3.5, 2.7 | ||
""" | ||
if sys.version_info.major == 3 and sys.version_info.minor >= 7: |
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.
could use sys.version_info >= (3, 7)
as a slightly more readable alternative.
@@ -17,6 +17,7 @@ Andreas Zeidler | |||
Andrzej Ostrowski | |||
Andy Freeland | |||
Anthon van der Neut | |||
Anthony Shaw | |||
Anthony Sottile |
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.
well hello fellow anthony :D
well done, im happy to merge 👍 |
Working on conditions stated in #3180
Support for Python 3.7s builtin breakpoint() method.
These are the behaviours:
Thanks for submitting a PR, your contribution is really appreciated!
Here's a quick checklist that should be present in PRs (you can delete this text from the final description, this is
just a guideline):
changelog
folder, with a name like<ISSUE NUMBER>.<TYPE>.rst
. See changelog/README.rst for details.master
branch for bug fixes, documentation updates and trivial changes.features
branch for new features and removals/deprecations.Unless your change is trivial or a small documentation fix (e.g., a typo or reword of a small section) please:
AUTHORS
in alphabetical order;