2010-10-16 22:29:11 -03:00
|
|
|
import gc
|
2001-09-22 01:28:19 -03:00
|
|
|
import pprint
|
|
|
|
import sys
|
|
|
|
import unittest
|
|
|
|
|
|
|
|
|
Merged revisions 60124-60142 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r60131 | georg.brandl | 2008-01-20 12:13:29 +0100 (Sun, 20 Jan 2008) | 3 lines
#1351692: in pprint, always call format() for dict and list items to enable
custom formatting of contents via subclassing PrettyPrinter.
........
r60133 | georg.brandl | 2008-01-20 12:43:03 +0100 (Sun, 20 Jan 2008) | 2 lines
#1178141: add addinfourl.code to get http status code from urllib.
........
r60134 | georg.brandl | 2008-01-20 13:05:43 +0100 (Sun, 20 Jan 2008) | 4 lines
#856047: respect the ``no_proxy`` env var when checking for proxies
in urllib and using the other ``_proxy`` env vars.
Original patch by Donovan Baarda.
........
r60135 | georg.brandl | 2008-01-20 13:18:17 +0100 (Sun, 20 Jan 2008) | 4 lines
#1664522: in urllib, don't read non-existing directories in ftp mode,
returning a 0-byte file -- raise an IOError instead.
Original patch from Phil Knirsch.
........
r60136 | georg.brandl | 2008-01-20 13:57:47 +0100 (Sun, 20 Jan 2008) | 2 lines
#799369: document possible sys.platform values.
........
r60137 | georg.brandl | 2008-01-20 14:08:37 +0100 (Sun, 20 Jan 2008) | 2 lines
#652749: document the constants added to the builtins by site.py.
........
r60138 | georg.brandl | 2008-01-20 14:59:46 +0100 (Sun, 20 Jan 2008) | 2 lines
#1648: add sys.gettrace() and sys.getprofile().
........
r60139 | georg.brandl | 2008-01-20 15:17:42 +0100 (Sun, 20 Jan 2008) | 2 lines
#1669: don't allow shutil.rmtree() to be called on a symlink.
........
r60140 | georg.brandl | 2008-01-20 15:20:02 +0100 (Sun, 20 Jan 2008) | 2 lines
Fix test_pyclbr after urllib change.
........
r60141 | christian.heimes | 2008-01-20 15:28:28 +0100 (Sun, 20 Jan 2008) | 1 line
Fixed a wrong assumption in configure.in and Include/pyport.h. The is finite function is not called isfinite() but finite(). Sorry, my fault. :)
........
r60142 | georg.brandl | 2008-01-20 15:31:27 +0100 (Sun, 20 Jan 2008) | 2 lines
#1876: fix typos in test_operator.
........
2008-01-20 11:14:11 -04:00
|
|
|
class TestGetProfile(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
sys.setprofile(None)
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
sys.setprofile(None)
|
|
|
|
|
|
|
|
def test_empty(self):
|
2010-10-16 22:30:26 -03:00
|
|
|
self.assertIsNone(sys.getprofile())
|
Merged revisions 60124-60142 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r60131 | georg.brandl | 2008-01-20 12:13:29 +0100 (Sun, 20 Jan 2008) | 3 lines
#1351692: in pprint, always call format() for dict and list items to enable
custom formatting of contents via subclassing PrettyPrinter.
........
r60133 | georg.brandl | 2008-01-20 12:43:03 +0100 (Sun, 20 Jan 2008) | 2 lines
#1178141: add addinfourl.code to get http status code from urllib.
........
r60134 | georg.brandl | 2008-01-20 13:05:43 +0100 (Sun, 20 Jan 2008) | 4 lines
#856047: respect the ``no_proxy`` env var when checking for proxies
in urllib and using the other ``_proxy`` env vars.
Original patch by Donovan Baarda.
........
r60135 | georg.brandl | 2008-01-20 13:18:17 +0100 (Sun, 20 Jan 2008) | 4 lines
#1664522: in urllib, don't read non-existing directories in ftp mode,
returning a 0-byte file -- raise an IOError instead.
Original patch from Phil Knirsch.
........
r60136 | georg.brandl | 2008-01-20 13:57:47 +0100 (Sun, 20 Jan 2008) | 2 lines
#799369: document possible sys.platform values.
........
r60137 | georg.brandl | 2008-01-20 14:08:37 +0100 (Sun, 20 Jan 2008) | 2 lines
#652749: document the constants added to the builtins by site.py.
........
r60138 | georg.brandl | 2008-01-20 14:59:46 +0100 (Sun, 20 Jan 2008) | 2 lines
#1648: add sys.gettrace() and sys.getprofile().
........
r60139 | georg.brandl | 2008-01-20 15:17:42 +0100 (Sun, 20 Jan 2008) | 2 lines
#1669: don't allow shutil.rmtree() to be called on a symlink.
........
r60140 | georg.brandl | 2008-01-20 15:20:02 +0100 (Sun, 20 Jan 2008) | 2 lines
Fix test_pyclbr after urllib change.
........
r60141 | christian.heimes | 2008-01-20 15:28:28 +0100 (Sun, 20 Jan 2008) | 1 line
Fixed a wrong assumption in configure.in and Include/pyport.h. The is finite function is not called isfinite() but finite(). Sorry, my fault. :)
........
r60142 | georg.brandl | 2008-01-20 15:31:27 +0100 (Sun, 20 Jan 2008) | 2 lines
#1876: fix typos in test_operator.
........
2008-01-20 11:14:11 -04:00
|
|
|
|
|
|
|
def test_setget(self):
|
|
|
|
def fn(*args):
|
|
|
|
pass
|
|
|
|
|
|
|
|
sys.setprofile(fn)
|
2010-10-16 22:30:26 -03:00
|
|
|
self.assertIs(sys.getprofile(), fn)
|
2001-09-22 01:28:19 -03:00
|
|
|
|
|
|
|
class HookWatcher:
|
|
|
|
def __init__(self):
|
|
|
|
self.frames = []
|
|
|
|
self.events = []
|
|
|
|
|
|
|
|
def callback(self, frame, event, arg):
|
2004-03-24 17:57:10 -04:00
|
|
|
if (event == "call"
|
|
|
|
or event == "return"
|
|
|
|
or event == "exception"):
|
2023-11-02 13:38:08 -03:00
|
|
|
self.add_event(event, frame, arg)
|
2001-09-22 01:28:19 -03:00
|
|
|
|
2023-11-02 13:38:08 -03:00
|
|
|
def add_event(self, event, frame=None, arg=None):
|
2001-09-22 01:28:19 -03:00
|
|
|
"""Add an event to the log."""
|
|
|
|
if frame is None:
|
|
|
|
frame = sys._getframe(1)
|
|
|
|
|
|
|
|
try:
|
|
|
|
frameno = self.frames.index(frame)
|
|
|
|
except ValueError:
|
|
|
|
frameno = len(self.frames)
|
|
|
|
self.frames.append(frame)
|
|
|
|
|
2023-11-02 13:38:08 -03:00
|
|
|
self.events.append((frameno, event, ident(frame), arg))
|
2001-09-22 01:28:19 -03:00
|
|
|
|
|
|
|
def get_events(self):
|
|
|
|
"""Remove calls to add_event()."""
|
2007-11-27 06:40:20 -04:00
|
|
|
disallowed = [ident(self.add_event.__func__), ident(ident)]
|
2001-09-24 15:44:11 -03:00
|
|
|
self.frames = None
|
2001-09-22 01:28:19 -03:00
|
|
|
|
2001-09-24 15:44:11 -03:00
|
|
|
return [item for item in self.events if item[2] not in disallowed]
|
2001-09-22 01:28:19 -03:00
|
|
|
|
|
|
|
|
2001-09-26 18:00:33 -03:00
|
|
|
class ProfileSimulator(HookWatcher):
|
2001-10-04 11:49:46 -03:00
|
|
|
def __init__(self, testcase):
|
|
|
|
self.testcase = testcase
|
2001-09-26 18:00:33 -03:00
|
|
|
self.stack = []
|
|
|
|
HookWatcher.__init__(self)
|
|
|
|
|
|
|
|
def callback(self, frame, event, arg):
|
2001-10-03 18:15:32 -03:00
|
|
|
# Callback registered with sys.setprofile()/sys.settrace()
|
2001-09-26 18:00:33 -03:00
|
|
|
self.dispatch[event](self, frame)
|
|
|
|
|
|
|
|
def trace_call(self, frame):
|
|
|
|
self.add_event('call', frame)
|
|
|
|
self.stack.append(frame)
|
|
|
|
|
|
|
|
def trace_return(self, frame):
|
|
|
|
self.add_event('return', frame)
|
|
|
|
self.stack.pop()
|
|
|
|
|
|
|
|
def trace_exception(self, frame):
|
2001-10-04 11:49:46 -03:00
|
|
|
self.testcase.fail(
|
|
|
|
"the profiler should never receive exception events")
|
2001-09-26 18:00:33 -03:00
|
|
|
|
2004-03-24 17:57:10 -04:00
|
|
|
def trace_pass(self, frame):
|
|
|
|
pass
|
|
|
|
|
2001-09-26 18:00:33 -03:00
|
|
|
dispatch = {
|
|
|
|
'call': trace_call,
|
|
|
|
'exception': trace_exception,
|
|
|
|
'return': trace_return,
|
2004-03-24 17:57:10 -04:00
|
|
|
'c_call': trace_pass,
|
|
|
|
'c_return': trace_pass,
|
|
|
|
'c_exception': trace_pass,
|
2001-09-26 18:00:33 -03:00
|
|
|
}
|
2001-09-22 01:28:19 -03:00
|
|
|
|
2001-09-26 18:00:33 -03:00
|
|
|
|
|
|
|
class TestCaseBase(unittest.TestCase):
|
2023-11-02 13:38:08 -03:00
|
|
|
def check_events(self, callable, expected, check_args=False):
|
2001-09-26 18:00:33 -03:00
|
|
|
events = capture_events(callable, self.new_watcher())
|
2023-11-02 13:38:08 -03:00
|
|
|
if check_args:
|
|
|
|
if events != expected:
|
|
|
|
self.fail("Expected events:\n%s\nReceived events:\n%s"
|
|
|
|
% (pprint.pformat(expected), pprint.pformat(events)))
|
|
|
|
else:
|
|
|
|
if [(frameno, event, ident) for frameno, event, ident, arg in events] != expected:
|
|
|
|
self.fail("Expected events:\n%s\nReceived events:\n%s"
|
|
|
|
% (pprint.pformat(expected), pprint.pformat(events)))
|
2001-09-22 01:28:19 -03:00
|
|
|
|
2001-09-26 18:00:33 -03:00
|
|
|
|
|
|
|
class ProfileHookTestCase(TestCaseBase):
|
|
|
|
def new_watcher(self):
|
|
|
|
return HookWatcher()
|
|
|
|
|
2001-09-22 01:28:19 -03:00
|
|
|
def test_simple(self):
|
|
|
|
def f(p):
|
|
|
|
pass
|
|
|
|
f_ident = ident(f)
|
2001-09-25 17:48:14 -03:00
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
|
|
|
(1, 'return', f_ident),
|
2001-09-22 01:28:19 -03:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_exception(self):
|
2001-09-25 17:48:14 -03:00
|
|
|
def f(p):
|
|
|
|
1/0
|
|
|
|
f_ident = ident(f)
|
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
2001-10-04 11:49:46 -03:00
|
|
|
(1, 'return', f_ident),
|
2001-09-25 17:48:14 -03:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_caught_exception(self):
|
2001-09-22 01:28:19 -03:00
|
|
|
def f(p):
|
2001-09-24 15:44:11 -03:00
|
|
|
try: 1/0
|
2024-10-15 13:00:04 -03:00
|
|
|
except ZeroDivisionError: pass
|
2001-09-22 01:28:19 -03:00
|
|
|
f_ident = ident(f)
|
2001-09-25 17:48:14 -03:00
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
|
|
|
(1, 'return', f_ident),
|
2001-09-22 01:28:19 -03:00
|
|
|
])
|
|
|
|
|
2001-09-24 15:44:11 -03:00
|
|
|
def test_caught_nested_exception(self):
|
|
|
|
def f(p):
|
|
|
|
try: 1/0
|
2024-10-15 13:00:04 -03:00
|
|
|
except ZeroDivisionError: pass
|
2001-09-24 15:44:11 -03:00
|
|
|
f_ident = ident(f)
|
2001-09-25 17:48:14 -03:00
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
2001-09-24 15:44:11 -03:00
|
|
|
(1, 'return', f_ident),
|
|
|
|
])
|
|
|
|
|
2001-09-22 01:28:19 -03:00
|
|
|
def test_nested_exception(self):
|
2001-09-24 15:44:11 -03:00
|
|
|
def f(p):
|
|
|
|
1/0
|
|
|
|
f_ident = ident(f)
|
2001-09-25 17:48:14 -03:00
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
2001-09-24 15:44:11 -03:00
|
|
|
# This isn't what I expected:
|
2001-10-04 11:49:46 -03:00
|
|
|
# (0, 'exception', protect_ident),
|
2001-09-24 15:44:11 -03:00
|
|
|
# I expected this again:
|
2001-10-04 11:49:46 -03:00
|
|
|
(1, 'return', f_ident),
|
2001-09-24 15:44:11 -03:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_exception_in_except_clause(self):
|
2001-09-22 01:28:19 -03:00
|
|
|
def f(p):
|
|
|
|
1/0
|
|
|
|
def g(p):
|
|
|
|
try:
|
|
|
|
f(p)
|
2024-10-15 13:00:04 -03:00
|
|
|
except ZeroDivisionError:
|
2001-09-24 15:44:11 -03:00
|
|
|
try: f(p)
|
2024-10-15 13:00:04 -03:00
|
|
|
except ZeroDivisionError: pass
|
2001-09-22 01:28:19 -03:00
|
|
|
f_ident = ident(f)
|
|
|
|
g_ident = ident(g)
|
2001-09-25 17:48:14 -03:00
|
|
|
self.check_events(g, [(1, 'call', g_ident),
|
2001-09-24 15:44:11 -03:00
|
|
|
(2, 'call', f_ident),
|
2001-10-04 11:49:46 -03:00
|
|
|
(2, 'return', f_ident),
|
2001-09-25 17:48:14 -03:00
|
|
|
(3, 'call', f_ident),
|
2001-10-04 11:49:46 -03:00
|
|
|
(3, 'return', f_ident),
|
2001-09-25 17:48:14 -03:00
|
|
|
(1, 'return', g_ident),
|
2001-09-22 01:28:19 -03:00
|
|
|
])
|
|
|
|
|
2016-06-02 07:07:09 -03:00
|
|
|
def test_exception_propagation(self):
|
2001-09-24 15:44:11 -03:00
|
|
|
def f(p):
|
|
|
|
1/0
|
|
|
|
def g(p):
|
|
|
|
try: f(p)
|
|
|
|
finally: p.add_event("falling through")
|
|
|
|
f_ident = ident(f)
|
|
|
|
g_ident = ident(g)
|
2001-09-25 17:48:14 -03:00
|
|
|
self.check_events(g, [(1, 'call', g_ident),
|
2001-09-24 15:44:11 -03:00
|
|
|
(2, 'call', f_ident),
|
2001-10-04 11:49:46 -03:00
|
|
|
(2, 'return', f_ident),
|
2001-09-24 15:44:11 -03:00
|
|
|
(1, 'falling through', g_ident),
|
2001-10-04 11:49:46 -03:00
|
|
|
(1, 'return', g_ident),
|
2001-09-24 15:44:11 -03:00
|
|
|
])
|
2001-09-22 01:28:19 -03:00
|
|
|
|
2001-09-25 17:48:14 -03:00
|
|
|
def test_raise_twice(self):
|
|
|
|
def f(p):
|
|
|
|
try: 1/0
|
2024-10-15 13:00:04 -03:00
|
|
|
except ZeroDivisionError: 1/0
|
2001-09-25 17:48:14 -03:00
|
|
|
f_ident = ident(f)
|
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
2001-10-04 11:49:46 -03:00
|
|
|
(1, 'return', f_ident),
|
2001-09-25 17:48:14 -03:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_raise_reraise(self):
|
|
|
|
def f(p):
|
|
|
|
try: 1/0
|
2024-10-15 13:00:04 -03:00
|
|
|
except ZeroDivisionError: raise
|
2001-09-25 17:48:14 -03:00
|
|
|
f_ident = ident(f)
|
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
2001-10-04 11:49:46 -03:00
|
|
|
(1, 'return', f_ident),
|
2001-09-25 17:48:14 -03:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_raise(self):
|
|
|
|
def f(p):
|
|
|
|
raise Exception()
|
|
|
|
f_ident = ident(f)
|
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
2001-10-04 11:49:46 -03:00
|
|
|
(1, 'return', f_ident),
|
2001-09-25 17:48:14 -03:00
|
|
|
])
|
|
|
|
|
2001-10-03 18:15:32 -03:00
|
|
|
def test_distant_exception(self):
|
|
|
|
def f():
|
|
|
|
1/0
|
|
|
|
def g():
|
|
|
|
f()
|
|
|
|
def h():
|
|
|
|
g()
|
|
|
|
def i():
|
|
|
|
h()
|
|
|
|
def j(p):
|
|
|
|
i()
|
|
|
|
f_ident = ident(f)
|
|
|
|
g_ident = ident(g)
|
|
|
|
h_ident = ident(h)
|
|
|
|
i_ident = ident(i)
|
|
|
|
j_ident = ident(j)
|
|
|
|
self.check_events(j, [(1, 'call', j_ident),
|
|
|
|
(2, 'call', i_ident),
|
|
|
|
(3, 'call', h_ident),
|
|
|
|
(4, 'call', g_ident),
|
|
|
|
(5, 'call', f_ident),
|
2001-10-04 11:49:46 -03:00
|
|
|
(5, 'return', f_ident),
|
|
|
|
(4, 'return', g_ident),
|
|
|
|
(3, 'return', h_ident),
|
|
|
|
(2, 'return', i_ident),
|
|
|
|
(1, 'return', j_ident),
|
2001-10-03 18:15:32 -03:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_generator(self):
|
|
|
|
def f():
|
|
|
|
for i in range(2):
|
|
|
|
yield i
|
|
|
|
def g(p):
|
|
|
|
for i in f():
|
|
|
|
pass
|
|
|
|
f_ident = ident(f)
|
|
|
|
g_ident = ident(g)
|
|
|
|
self.check_events(g, [(1, 'call', g_ident),
|
|
|
|
# call the iterator twice to generate values
|
|
|
|
(2, 'call', f_ident),
|
|
|
|
(2, 'return', f_ident),
|
|
|
|
(2, 'call', f_ident),
|
|
|
|
(2, 'return', f_ident),
|
|
|
|
# once more; returns end-of-iteration with
|
|
|
|
# actually raising an exception
|
|
|
|
(2, 'call', f_ident),
|
|
|
|
(2, 'return', f_ident),
|
|
|
|
(1, 'return', g_ident),
|
|
|
|
])
|
|
|
|
|
2023-10-09 05:38:45 -03:00
|
|
|
def test_unfinished_generator(self):
|
|
|
|
def f():
|
|
|
|
for i in range(2):
|
|
|
|
yield i
|
|
|
|
def g(p):
|
|
|
|
next(f())
|
|
|
|
|
|
|
|
f_ident = ident(f)
|
|
|
|
g_ident = ident(g)
|
2023-11-02 13:38:08 -03:00
|
|
|
self.check_events(g, [(1, 'call', g_ident, None),
|
|
|
|
(2, 'call', f_ident, None),
|
|
|
|
(2, 'return', f_ident, 0),
|
|
|
|
(1, 'return', g_ident, None),
|
|
|
|
], check_args=True)
|
2023-10-09 05:38:45 -03:00
|
|
|
|
2001-10-03 18:15:32 -03:00
|
|
|
def test_stop_iteration(self):
|
|
|
|
def f():
|
|
|
|
for i in range(2):
|
|
|
|
yield i
|
|
|
|
def g(p):
|
|
|
|
for i in f():
|
|
|
|
pass
|
|
|
|
f_ident = ident(f)
|
|
|
|
g_ident = ident(g)
|
|
|
|
self.check_events(g, [(1, 'call', g_ident),
|
|
|
|
# call the iterator twice to generate values
|
|
|
|
(2, 'call', f_ident),
|
|
|
|
(2, 'return', f_ident),
|
|
|
|
(2, 'call', f_ident),
|
|
|
|
(2, 'return', f_ident),
|
|
|
|
# once more to hit the raise:
|
|
|
|
(2, 'call', f_ident),
|
2001-10-04 11:49:46 -03:00
|
|
|
(2, 'return', f_ident),
|
2001-10-03 18:15:32 -03:00
|
|
|
(1, 'return', g_ident),
|
|
|
|
])
|
|
|
|
|
2001-09-25 17:48:14 -03:00
|
|
|
|
2001-09-26 18:00:33 -03:00
|
|
|
class ProfileSimulatorTestCase(TestCaseBase):
|
|
|
|
def new_watcher(self):
|
2001-10-04 11:49:46 -03:00
|
|
|
return ProfileSimulator(self)
|
2001-09-26 18:00:33 -03:00
|
|
|
|
|
|
|
def test_simple(self):
|
|
|
|
def f(p):
|
|
|
|
pass
|
|
|
|
f_ident = ident(f)
|
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
|
|
|
(1, 'return', f_ident),
|
|
|
|
])
|
|
|
|
|
|
|
|
def test_basic_exception(self):
|
|
|
|
def f(p):
|
|
|
|
1/0
|
|
|
|
f_ident = ident(f)
|
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
2001-10-04 11:49:46 -03:00
|
|
|
(1, 'return', f_ident),
|
2001-09-26 18:00:33 -03:00
|
|
|
])
|
|
|
|
|
2001-10-03 18:15:32 -03:00
|
|
|
def test_caught_exception(self):
|
|
|
|
def f(p):
|
|
|
|
try: 1/0
|
2024-10-15 13:00:04 -03:00
|
|
|
except ZeroDivisionError: pass
|
2001-10-03 18:15:32 -03:00
|
|
|
f_ident = ident(f)
|
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
|
|
|
(1, 'return', f_ident),
|
|
|
|
])
|
|
|
|
|
|
|
|
def test_distant_exception(self):
|
|
|
|
def f():
|
|
|
|
1/0
|
|
|
|
def g():
|
|
|
|
f()
|
|
|
|
def h():
|
|
|
|
g()
|
|
|
|
def i():
|
|
|
|
h()
|
|
|
|
def j(p):
|
|
|
|
i()
|
|
|
|
f_ident = ident(f)
|
|
|
|
g_ident = ident(g)
|
|
|
|
h_ident = ident(h)
|
|
|
|
i_ident = ident(i)
|
|
|
|
j_ident = ident(j)
|
|
|
|
self.check_events(j, [(1, 'call', j_ident),
|
|
|
|
(2, 'call', i_ident),
|
|
|
|
(3, 'call', h_ident),
|
|
|
|
(4, 'call', g_ident),
|
|
|
|
(5, 'call', f_ident),
|
2001-10-04 11:49:46 -03:00
|
|
|
(5, 'return', f_ident),
|
|
|
|
(4, 'return', g_ident),
|
|
|
|
(3, 'return', h_ident),
|
|
|
|
(2, 'return', i_ident),
|
|
|
|
(1, 'return', j_ident),
|
2001-10-03 18:15:32 -03:00
|
|
|
])
|
|
|
|
|
2019-05-22 07:05:02 -03:00
|
|
|
# bpo-34125: profiling method_descriptor with **kwargs
|
|
|
|
def test_unbound_method(self):
|
|
|
|
kwargs = {}
|
|
|
|
def f(p):
|
|
|
|
dict.get({}, 42, **kwargs)
|
|
|
|
f_ident = ident(f)
|
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
|
|
|
(1, 'return', f_ident)])
|
|
|
|
|
2018-07-21 05:30:59 -03:00
|
|
|
# Test an invalid call (bpo-34126)
|
|
|
|
def test_unbound_method_no_args(self):
|
|
|
|
def f(p):
|
|
|
|
dict.get()
|
|
|
|
f_ident = ident(f)
|
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
|
|
|
(1, 'return', f_ident)])
|
|
|
|
|
|
|
|
# Test an invalid call (bpo-34126)
|
|
|
|
def test_unbound_method_invalid_args(self):
|
|
|
|
def f(p):
|
|
|
|
dict.get(print, 42)
|
|
|
|
f_ident = ident(f)
|
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
|
|
|
(1, 'return', f_ident)])
|
|
|
|
|
2018-09-19 07:06:20 -03:00
|
|
|
# Test an invalid call (bpo-34125)
|
2019-04-22 15:48:12 -03:00
|
|
|
def test_unbound_method_no_keyword_args(self):
|
2018-09-19 07:06:20 -03:00
|
|
|
kwargs = {}
|
|
|
|
def f(p):
|
|
|
|
dict.get(**kwargs)
|
|
|
|
f_ident = ident(f)
|
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
|
|
|
(1, 'return', f_ident)])
|
|
|
|
|
|
|
|
# Test an invalid call (bpo-34125)
|
2019-04-22 15:48:12 -03:00
|
|
|
def test_unbound_method_invalid_keyword_args(self):
|
2018-09-19 07:06:20 -03:00
|
|
|
kwargs = {}
|
|
|
|
def f(p):
|
|
|
|
dict.get(print, 42, **kwargs)
|
|
|
|
f_ident = ident(f)
|
|
|
|
self.check_events(f, [(1, 'call', f_ident),
|
|
|
|
(1, 'return', f_ident)])
|
|
|
|
|
2001-09-26 18:00:33 -03:00
|
|
|
|
2001-09-22 01:28:19 -03:00
|
|
|
def ident(function):
|
|
|
|
if hasattr(function, "f_code"):
|
|
|
|
code = function.f_code
|
|
|
|
else:
|
2007-02-25 16:55:47 -04:00
|
|
|
code = function.__code__
|
2001-09-22 01:28:19 -03:00
|
|
|
return code.co_firstlineno, code.co_name
|
|
|
|
|
|
|
|
|
2001-09-25 17:48:14 -03:00
|
|
|
def protect(f, p):
|
|
|
|
try: f(p)
|
|
|
|
except: pass
|
|
|
|
|
|
|
|
protect_ident = ident(protect)
|
|
|
|
|
|
|
|
|
2001-09-26 18:00:33 -03:00
|
|
|
def capture_events(callable, p=None):
|
|
|
|
if p is None:
|
|
|
|
p = HookWatcher()
|
2010-10-16 22:29:11 -03:00
|
|
|
# Disable the garbage collector. This prevents __del__s from showing up in
|
|
|
|
# traces.
|
|
|
|
old_gc = gc.isenabled()
|
|
|
|
gc.disable()
|
|
|
|
try:
|
|
|
|
sys.setprofile(p.callback)
|
|
|
|
protect(callable, p)
|
|
|
|
sys.setprofile(None)
|
|
|
|
finally:
|
|
|
|
if old_gc:
|
|
|
|
gc.enable()
|
2001-09-25 17:48:14 -03:00
|
|
|
return p.get_events()[1:-1]
|
2001-09-22 01:28:19 -03:00
|
|
|
|
|
|
|
|
|
|
|
def show_events(callable):
|
|
|
|
import pprint
|
|
|
|
pprint.pprint(capture_events(callable))
|
|
|
|
|
|
|
|
|
2022-07-05 15:18:47 -03:00
|
|
|
class TestEdgeCases(unittest.TestCase):
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
self.addCleanup(sys.setprofile, sys.getprofile())
|
|
|
|
sys.setprofile(None)
|
|
|
|
|
|
|
|
def test_reentrancy(self):
|
|
|
|
def foo(*args):
|
|
|
|
...
|
|
|
|
|
|
|
|
def bar(*args):
|
|
|
|
...
|
|
|
|
|
|
|
|
class A:
|
|
|
|
def __call__(self, *args):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def __del__(self):
|
|
|
|
sys.setprofile(bar)
|
|
|
|
|
|
|
|
sys.setprofile(A())
|
2022-10-19 19:31:47 -03:00
|
|
|
sys.setprofile(foo)
|
|
|
|
self.assertEqual(sys.getprofile(), bar)
|
2022-07-05 15:18:47 -03:00
|
|
|
|
|
|
|
def test_same_object(self):
|
|
|
|
def foo(*args):
|
|
|
|
...
|
|
|
|
|
|
|
|
sys.setprofile(foo)
|
|
|
|
del foo
|
|
|
|
sys.setprofile(sys.getprofile())
|
|
|
|
|
2023-09-18 11:30:08 -03:00
|
|
|
def test_profile_after_trace_opcodes(self):
|
|
|
|
def f():
|
|
|
|
...
|
|
|
|
|
|
|
|
sys._getframe().f_trace_opcodes = True
|
|
|
|
prev_trace = sys.gettrace()
|
|
|
|
sys.settrace(lambda *args: None)
|
|
|
|
f()
|
|
|
|
sys.settrace(prev_trace)
|
|
|
|
sys.setprofile(lambda *args: None)
|
|
|
|
f()
|
|
|
|
|
2024-07-23 19:25:26 -03:00
|
|
|
def test_method_with_c_function(self):
|
|
|
|
# gh-122029
|
|
|
|
# When we have a PyMethodObject whose im_func is a C function, we
|
|
|
|
# should record both the call and the return. f = classmethod(repr)
|
|
|
|
# is just a way to create a PyMethodObject with a C function.
|
|
|
|
class A:
|
|
|
|
f = classmethod(repr)
|
|
|
|
events = []
|
|
|
|
sys.setprofile(lambda frame, event, args: events.append(event))
|
|
|
|
A().f()
|
|
|
|
sys.setprofile(None)
|
|
|
|
# The last c_call is the call to sys.setprofile
|
|
|
|
self.assertEqual(events, ['c_call', 'c_return', 'c_call'])
|
|
|
|
|
2022-07-05 15:18:47 -03:00
|
|
|
|
2001-09-22 01:28:19 -03:00
|
|
|
if __name__ == "__main__":
|
2015-04-13 17:00:43 -03:00
|
|
|
unittest.main()
|