Author: Carl Friedrich Bolz-Tereick <[email protected]>
Branch: py3.7
Changeset: r97793:690fff498e45
Date: 2019-10-16 12:45 +0000
http://bitbucket.org/pypy/pypy/changeset/690fff498e45/
Log: Merged in Yannick_Jadoul/pypy/py3.7-pep553 (pull request #671)
PEP 533 implementation
diff --git a/pypy/module/__builtin__/app_breakpoint.py
b/pypy/module/__builtin__/app_breakpoint.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/__builtin__/app_breakpoint.py
@@ -0,0 +1,16 @@
+# NOT_RPYTHON
+"""
+Plain Python definition of the builtin breakpoint function.
+"""
+
+import sys
+
+def breakpoint(*args, **kwargs):
+ """Call sys.breakpointhook(*args, **kws). sys.breakpointhook() must accept
+whatever arguments are passed.
+
+By default, this drops you into the pdb debugger."""
+
+ if not hasattr(sys, 'breakpointhook'):
+ raise RuntimeError('lost sys.breakpointhook')
+ return sys.breakpointhook(*args, **kwargs)
diff --git a/pypy/module/__builtin__/moduledef.py
b/pypy/module/__builtin__/moduledef.py
--- a/pypy/module/__builtin__/moduledef.py
+++ b/pypy/module/__builtin__/moduledef.py
@@ -23,6 +23,8 @@
'bin' : 'app_operation.bin',
'oct' : 'app_operation.oct',
'hex' : 'app_operation.hex',
+
+ 'breakpoint' : 'app_breakpoint.breakpoint',
}
interpleveldefs = {
diff --git a/pypy/module/__builtin__/test/test_breakpoint.py
b/pypy/module/__builtin__/test/test_breakpoint.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/__builtin__/test/test_breakpoint.py
@@ -0,0 +1,158 @@
+class AppTestBreakpoint:
+ def setup_class(cls):
+ cls.w_import_mock_pdb = cls.space.appexec([], """():
+ import sys
+ from contextlib import contextmanager
+ from types import ModuleType
+
+ @contextmanager
+ def w_import_mock_pdb():
+ try:
+ mock_pdb = ModuleType('pdb')
+ mock_pdb.set_trace = None
+ sys.modules['pdb'] = mock_pdb
+ yield mock_pdb
+ finally:
+ del sys.modules['pdb']
+
+ return w_import_mock_pdb
+ """)
+
+ cls.w_mock_function = cls.space.appexec([], """():
+ from contextlib import contextmanager
+
+ class MockedCallable:
+ def __init__(self):
+ self.called = 0
+
+ def __call__(self, *args, **kwargs):
+ self.called += 1
+ self.last_call = (args, kwargs)
+
+ @contextmanager
+ def mock_function(scope, attr, delete=False):
+ old = getattr(scope, attr)
+ try:
+ if not delete:
+ new = MockedCallable()
+ setattr(scope, attr, new)
+ yield new
+ else:
+ delattr(scope, attr)
+ yield
+ finally:
+ setattr(scope, attr, old)
+
+ return mock_function
+ """)
+
+
+ def test_default(self):
+ import sys
+ assert sys.breakpointhook is sys.__breakpointhook__
+
+ import os
+ assert 'PYTHONBREAKPOINT' not in os.environ
+
+ with self.import_mock_pdb() as pdb:
+ with self.mock_function(pdb, 'set_trace') as mocked:
+ breakpoint()
+ assert mocked.called == 1
+
+
+ def test_args_kwargs(self):
+ import sys
+ with self.import_mock_pdb() as pdb:
+ with self.mock_function(pdb, 'set_trace') as mocked:
+ breakpoint(1, 2, 3, x=4, y=5)
+ assert mocked.called == 1
+ assert mocked.last_call == ((1, 2, 3), {'x': 4, 'y': 5})
+
+
+ def test_breakpointhook(self):
+ import sys
+ with self.import_mock_pdb() as pdb:
+ with self.mock_function(sys, 'breakpointhook') as mocked, \
+ self.mock_function(pdb, 'set_trace') as mocked_pdb:
+ breakpoint()
+ assert mocked.called == 1
+ assert mocked_pdb.called == 0
+
+ with self.mock_function(pdb, 'set_trace') as mocked_pdb:
+ breakpoint()
+ assert mocked_pdb.called == 1
+
+
+ def test_breakpointhook_lost(self):
+ import sys
+ with self.import_mock_pdb() as pdb:
+ with self.mock_function(sys, 'breakpointhook', delete=True):
+ with raises(RuntimeError) as excinfo:
+ breakpoint()
+ assert str(excinfo.value) == "lost sys.breakpointhook"
+
+
+ def test_env_default(self):
+ import os
+ try:
+ os.environ['PYTHONBREAKPOINT'] = ""
+
+ import sys
+ with self.import_mock_pdb() as pdb:
+ with self.mock_function(pdb, 'set_trace') as mocked:
+ breakpoint()
+ assert mocked.called == 1
+ finally:
+ del os.environ['PYTHONBREAKPOINT']
+
+
+ def test_env_disable(self):
+ import os
+ try:
+ os.environ['PYTHONBREAKPOINT'] = "0"
+
+ import sys
+ with self.import_mock_pdb() as pdb:
+ with self.mock_function(pdb, 'set_trace') as mocked:
+ breakpoint()
+ assert mocked.called == 0
+
+ with self.mock_function(sys, 'breakpointhook') as mocked:
+ breakpoint()
+ assert mocked.called == 1
+ finally:
+ del os.environ['PYTHONBREAKPOINT']
+
+
+ def test_env_other(self):
+ import os
+ try:
+ os.environ['PYTHONBREAKPOINT'] = 'sys.exit'
+
+ import sys
+ with self.import_mock_pdb() as pdb:
+ with self.mock_function(sys, 'exit') as mocked, \
+ self.mock_function(pdb, 'set_trace') as mocked_pdb:
+ breakpoint()
+ assert mocked.called == 1
+ assert mocked_pdb.called == 0
+ finally:
+ del os.environ['PYTHONBREAKPOINT']
+
+
+ def test_env_nonexistent(self):
+ import os
+ import warnings
+ try:
+ os.environ['PYTHONBREAKPOINT'] = 'blah.bleh'
+
+ import sys
+ with self.import_mock_pdb() as pdb:
+ with self.mock_function(pdb, 'set_trace') as mocked_pdb, \
+ warnings.catch_warnings(record=True) as w:
+ breakpoint()
+ assert mocked_pdb.called == 0
+ assert len(w) == 1
+ assert str(w[-1].message) == 'Ignoring unimportable
$PYTHONBREAKPOINT: "blah.bleh"'
+ finally:
+ del os.environ['PYTHONBREAKPOINT']
diff --git a/pypy/module/sys/app.py b/pypy/module/sys/app.py
--- a/pypy/module/sys/app.py
+++ b/pypy/module/sys/app.py
@@ -68,6 +68,31 @@
except:
return False # got an exception again... ignore, report the original
+def breakpointhook(*args, **kwargs):
+ """This hook function is called by built-in breakpoint()."""
+
+ import importlib, os, warnings
+
+ hookname = os.getenv('PYTHONBREAKPOINT')
+ if hookname is None or len(hookname) == 0:
+ hookname = 'pdb.set_trace'
+ elif hookname == '0':
+ return None
+ modname, dot, funcname = hookname.rpartition('.')
+ if dot == '':
+ modname = 'builtins'
+
+ try:
+ module = importlib.import_module(modname)
+ hook = getattr(module, funcname)
+ except:
+ warnings.warn(
+ 'Ignoring unimportable $PYTHONBREAKPOINT: "{}"'.format(hookname),
+ RuntimeWarning)
+ return None
+
+ return hook(*args, **kwargs)
+
def exit(exitcode=None):
"""Exit the interpreter by raising SystemExit(exitcode).
If the exitcode is omitted or None, it defaults to zero (i.e., success).
diff --git a/pypy/module/sys/moduledef.py b/pypy/module/sys/moduledef.py
--- a/pypy/module/sys/moduledef.py
+++ b/pypy/module/sys/moduledef.py
@@ -109,6 +109,8 @@
appleveldefs = {
'excepthook' : 'app.excepthook',
'__excepthook__' : 'app.excepthook',
+ 'breakpointhook' : 'app.breakpointhook',
+ '__breakpointhook__' : 'app.breakpointhook',
'exit' : 'app.exit',
'callstats' : 'app.callstats',
'copyright' : 'app.copyright_str',
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit