summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_cprofile.py1
-rwxr-xr-xLib/test/test_profile.py22
-rw-r--r--Misc/NEWS3
-rw-r--r--Python/ceval.c18
4 files changed, 42 insertions, 2 deletions
diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py
index 349d342..4586b36 100644
--- a/Lib/test/test_cprofile.py
+++ b/Lib/test/test_cprofile.py
@@ -9,6 +9,7 @@ from test.test_profile import ProfileTest, regenerate_expected_output
class CProfileTest(ProfileTest):
profilerclass = cProfile.Profile
+ expected_max_output = "{built-in method max}"
def get_expected_output(self):
return _ProfileOutput
diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py
index c972fc6..243a322 100755
--- a/Lib/test/test_profile.py
+++ b/Lib/test/test_profile.py
@@ -16,6 +16,7 @@ class ProfileTest(unittest.TestCase):
profilerclass = profile.Profile
methodnames = ['print_stats', 'print_callers', 'print_callees']
+ expected_max_output = ':0(max)'
def get_expected_output(self):
return _ProfileOutput
@@ -53,6 +54,27 @@ class ProfileTest(unittest.TestCase):
results[i+1].split('\n'),
expected[method].split('\n'))))
+ def test_calling_conventions(self):
+ # Issue #5330: profile and cProfile wouldn't report C functions called
+ # with keyword arguments. We test all calling conventions.
+ stmts = [
+ "max([0])",
+ "max([0], key=int)",
+ "max([0], **dict(key=int))",
+ "max(*([0],))",
+ "max(*([0],), key=int)",
+ "max(*([0],), **dict(key=int))",
+ ]
+ for stmt in stmts:
+ s = StringIO()
+ prof = self.profilerclass(timer, 0.001)
+ prof.runctx(stmt, globals(), locals())
+ stats = pstats.Stats(prof, stream=s)
+ stats.print_stats()
+ res = s.getvalue()
+ self.assertTrue(self.expected_max_output in res,
+ "Profiling {0!r} didn't report max:\n{1}".format(stmt, res))
+
def regenerate_expected_output(filename, cls):
filename = filename.rstrip('co')
diff --git a/Misc/NEWS b/Misc/NEWS
index 6fa6d99..b06767d 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 3.1 Release Candidate 2?
Core and Builtins
-----------------
+- Issue #5330: C functions called with keyword arguments were not reported by
+ the various profiling modules (profile, cProfile). Patch by Hagen Fürstenau.
+
Library
-------
diff --git a/Python/ceval.c b/Python/ceval.c
index e693147..b5b5c27 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3951,10 +3951,17 @@ do_call(PyObject *func, PyObject ***pp_stack, int na, int nk)
PCALL(PCALL_METHOD);
else if (PyType_Check(func))
PCALL(PCALL_TYPE);
+ else if (PyCFunction_Check(func))
+ PCALL(PCALL_CFUNCTION);
else
PCALL(PCALL_OTHER);
#endif
- result = PyObject_Call(func, callargs, kwdict);
+ if (PyCFunction_Check(func)) {
+ PyThreadState *tstate = PyThreadState_GET();
+ C_TRACE(result, PyCFunction_Call(func, callargs, kwdict));
+ }
+ else
+ result = PyObject_Call(func, callargs, kwdict);
call_fail:
Py_XDECREF(callargs);
Py_XDECREF(kwdict);
@@ -4039,10 +4046,17 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
PCALL(PCALL_METHOD);
else if (PyType_Check(func))
PCALL(PCALL_TYPE);
+ else if (PyCFunction_Check(func))
+ PCALL(PCALL_CFUNCTION);
else
PCALL(PCALL_OTHER);
#endif
- result = PyObject_Call(func, callargs, kwdict);
+ if (PyCFunction_Check(func)) {
+ PyThreadState *tstate = PyThreadState_GET();
+ C_TRACE(result, PyCFunction_Call(func, callargs, kwdict));
+ }
+ else
+ result = PyObject_Call(func, callargs, kwdict);
ext_call_fail:
Py_XDECREF(callargs);
Py_XDECREF(kwdict);