Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
4d770172
Commit
4d770172
authored
Sep 13, 2010
by
Alexander Belopolsky
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #9315: Fix for the trace module to record correct class name
when tracing methods. Unit tests. Patch by Eli Bendersky.
parent
dc69e721
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
291 additions
and
14 deletions
+291
-14
Lib/test/test_trace.py
Lib/test/test_trace.py
+282
-6
Lib/trace.py
Lib/trace.py
+4
-8
Misc/NEWS
Misc/NEWS
+5
-0
No files found.
Lib/test/test_trace.py
View file @
4d770172
# Testing the trace module
from
test.support
import
run_unittest
,
TESTFN
,
rmtree
,
unlink
,
captured_stdout
import
os
import
sys
from
test.support
import
(
run_unittest
,
TESTFN
,
rmtree
,
unlink
,
captured_stdout
)
import
unittest
import
trace
import
os
,
sys
from
trace
import
CoverageResults
,
Trace
from
test.tracedmodules
import
testmod
#------------------------------- Utilities -----------------------------------#
def
fix_ext_py
(
filename
):
"""Given a .pyc/.pyo filename converts it to the appropriate .py"""
if
filename
.
endswith
((
'.pyc'
,
'.pyo'
)):
filename
=
filename
[:
-
1
]
return
filename
def
my_file_and_modname
():
"""The .py file and module name of this file (__file__)"""
modname
=
os
.
path
.
splitext
(
os
.
path
.
basename
(
__file__
))[
0
]
return
fix_ext_py
(
__file__
),
modname
def
get_firstlineno
(
func
):
return
func
.
__code__
.
co_firstlineno
#-------------------- Target functions for tracing ---------------------------#
#
# The relative line numbers of lines in these functions matter for verifying
# tracing. Please modify the appropriate tests if you change one of the
# functions. Absolute line numbers don't matter.
#
def
traced_func_linear
(
x
,
y
):
a
=
x
b
=
y
c
=
a
+
b
return
c
def
traced_func_loop
(
x
,
y
):
c
=
x
for
i
in
range
(
5
):
c
+=
y
return
c
def
traced_func_importing
(
x
,
y
):
return
x
+
y
+
testmod
.
func
(
1
)
def
traced_func_simple_caller
(
x
):
c
=
traced_func_linear
(
x
,
x
)
return
c
+
x
def
traced_func_importing_caller
(
x
):
k
=
traced_func_simple_caller
(
x
)
k
+=
traced_func_importing
(
k
,
x
)
return
k
def
traced_func_generator
(
num
):
c
=
5
# executed once
for
i
in
range
(
num
):
yield
i
+
c
def
traced_func_calling_generator
():
k
=
0
for
i
in
traced_func_generator
(
10
):
k
+=
i
def
traced_doubler
(
num
):
return
num
*
2
def
traced_caller_list_comprehension
():
k
=
10
mylist
=
[
traced_doubler
(
i
)
for
i
in
range
(
k
)]
return
mylist
class
TracedClass
(
object
):
def
__init__
(
self
,
x
):
self
.
a
=
x
def
inst_method_linear
(
self
,
y
):
return
self
.
a
+
y
def
inst_method_calling
(
self
,
x
):
c
=
self
.
inst_method_linear
(
x
)
return
c
+
traced_func_linear
(
x
,
c
)
@
classmethod
def
class_method_linear
(
cls
,
y
):
return
y
*
2
@
staticmethod
def
static_method_linear
(
y
):
return
y
*
2
#------------------------------ Test cases -----------------------------------#
class
TestLineCounts
(
unittest
.
TestCase
):
"""White-box testing of line-counting, via runfunc"""
def
setUp
(
self
):
self
.
tracer
=
Trace
(
count
=
1
,
trace
=
0
,
countfuncs
=
0
,
countcallers
=
0
)
self
.
my_py_filename
=
fix_ext_py
(
__file__
)
self
.
maxDiff
=
None
def
test_traced_func_linear
(
self
):
result
=
self
.
tracer
.
runfunc
(
traced_func_linear
,
2
,
5
)
self
.
assertEqual
(
result
,
7
)
# all lines are executed once
expected
=
{}
firstlineno
=
get_firstlineno
(
traced_func_linear
)
for
i
in
range
(
1
,
5
):
expected
[(
self
.
my_py_filename
,
firstlineno
+
i
)]
=
1
self
.
assertEqual
(
self
.
tracer
.
results
().
counts
,
expected
)
def
test_traced_func_loop
(
self
):
self
.
tracer
.
runfunc
(
traced_func_loop
,
2
,
3
)
firstlineno
=
get_firstlineno
(
traced_func_loop
)
expected
=
{
(
self
.
my_py_filename
,
firstlineno
+
1
):
1
,
(
self
.
my_py_filename
,
firstlineno
+
2
):
6
,
(
self
.
my_py_filename
,
firstlineno
+
3
):
5
,
(
self
.
my_py_filename
,
firstlineno
+
4
):
1
,
}
self
.
assertEqual
(
self
.
tracer
.
results
().
counts
,
expected
)
def
test_traced_func_importing
(
self
):
self
.
tracer
.
runfunc
(
traced_func_importing
,
2
,
5
)
firstlineno
=
get_firstlineno
(
traced_func_importing
)
expected
=
{
(
self
.
my_py_filename
,
firstlineno
+
1
):
1
,
(
fix_ext_py
(
testmod
.
__file__
),
2
):
1
,
(
fix_ext_py
(
testmod
.
__file__
),
3
):
1
,
}
self
.
assertEqual
(
self
.
tracer
.
results
().
counts
,
expected
)
def
test_trace_func_generator
(
self
):
self
.
tracer
.
runfunc
(
traced_func_calling_generator
)
firstlineno_calling
=
get_firstlineno
(
traced_func_calling_generator
)
firstlineno_gen
=
get_firstlineno
(
traced_func_generator
)
expected
=
{
(
self
.
my_py_filename
,
firstlineno_calling
+
1
):
1
,
(
self
.
my_py_filename
,
firstlineno_calling
+
2
):
11
,
(
self
.
my_py_filename
,
firstlineno_calling
+
3
):
10
,
(
self
.
my_py_filename
,
firstlineno_gen
+
1
):
1
,
(
self
.
my_py_filename
,
firstlineno_gen
+
2
):
11
,
(
self
.
my_py_filename
,
firstlineno_gen
+
3
):
10
,
}
self
.
assertEqual
(
self
.
tracer
.
results
().
counts
,
expected
)
def
test_trace_list_comprehension
(
self
):
self
.
tracer
.
runfunc
(
traced_caller_list_comprehension
)
firstlineno_calling
=
get_firstlineno
(
traced_caller_list_comprehension
)
firstlineno_called
=
get_firstlineno
(
traced_doubler
)
expected
=
{
(
self
.
my_py_filename
,
firstlineno_calling
+
1
):
1
,
# List compehentions work differently in 3.x, so the count
# below changed compared to 2.x.
(
self
.
my_py_filename
,
firstlineno_calling
+
2
):
12
,
(
self
.
my_py_filename
,
firstlineno_calling
+
3
):
1
,
(
self
.
my_py_filename
,
firstlineno_called
+
1
):
10
,
}
self
.
assertEqual
(
self
.
tracer
.
results
().
counts
,
expected
)
def
test_linear_methods
(
self
):
# XXX todo: later add 'static_method_linear' and 'class_method_linear'
# here, once issue1764286 is resolved
#
for
methname
in
[
'inst_method_linear'
,]:
tracer
=
Trace
(
count
=
1
,
trace
=
0
,
countfuncs
=
0
,
countcallers
=
0
)
traced_obj
=
TracedClass
(
25
)
method
=
getattr
(
traced_obj
,
methname
)
tracer
.
runfunc
(
method
,
20
)
firstlineno
=
get_firstlineno
(
method
)
expected
=
{
(
self
.
my_py_filename
,
firstlineno
+
1
):
1
,
}
self
.
assertEqual
(
tracer
.
results
().
counts
,
expected
)
class
TestRunExecCounts
(
unittest
.
TestCase
):
"""A simple sanity test of line-counting, via runctx (exec)"""
def
setUp
(
self
):
self
.
my_py_filename
=
fix_ext_py
(
__file__
)
def
test_exec_counts
(
self
):
self
.
tracer
=
Trace
(
count
=
1
,
trace
=
0
,
countfuncs
=
0
,
countcallers
=
0
)
code
=
r'''traced_func_loop(2, 5)'''
code
=
compile
(
code
,
__file__
,
'exec'
)
self
.
tracer
.
runctx
(
code
,
globals
(),
vars
())
firstlineno
=
get_firstlineno
(
traced_func_loop
)
expected
=
{
(
self
.
my_py_filename
,
firstlineno
+
1
):
1
,
(
self
.
my_py_filename
,
firstlineno
+
2
):
6
,
(
self
.
my_py_filename
,
firstlineno
+
3
):
5
,
(
self
.
my_py_filename
,
firstlineno
+
4
):
1
,
}
# When used through 'run', some other spurios counts are produced, like
# the settrace of threading, which we ignore, just making sure that the
# counts fo traced_func_loop were right.
#
for
k
in
expected
.
keys
():
self
.
assertEqual
(
self
.
tracer
.
results
().
counts
[
k
],
expected
[
k
])
class
TestFuncs
(
unittest
.
TestCase
):
"""White-box testing of funcs tracing"""
def
setUp
(
self
):
self
.
tracer
=
Trace
(
count
=
0
,
trace
=
0
,
countfuncs
=
1
)
self
.
filemod
=
my_file_and_modname
()
def
test_simple_caller
(
self
):
self
.
tracer
.
runfunc
(
traced_func_simple_caller
,
1
)
expected
=
{
self
.
filemod
+
(
'traced_func_simple_caller'
,):
1
,
self
.
filemod
+
(
'traced_func_linear'
,):
1
,
}
self
.
assertEqual
(
self
.
tracer
.
results
().
calledfuncs
,
expected
)
def
test_loop_caller_importing
(
self
):
self
.
tracer
.
runfunc
(
traced_func_importing_caller
,
1
)
expected
=
{
self
.
filemod
+
(
'traced_func_simple_caller'
,):
1
,
self
.
filemod
+
(
'traced_func_linear'
,):
1
,
self
.
filemod
+
(
'traced_func_importing_caller'
,):
1
,
self
.
filemod
+
(
'traced_func_importing'
,):
1
,
(
fix_ext_py
(
testmod
.
__file__
),
'testmod'
,
'func'
):
1
,
}
self
.
assertEqual
(
self
.
tracer
.
results
().
calledfuncs
,
expected
)
def
test_inst_method_calling
(
self
):
obj
=
TracedClass
(
20
)
self
.
tracer
.
runfunc
(
obj
.
inst_method_calling
,
1
)
expected
=
{
self
.
filemod
+
(
'TracedClass.inst_method_calling'
,):
1
,
self
.
filemod
+
(
'TracedClass.inst_method_linear'
,):
1
,
self
.
filemod
+
(
'traced_func_linear'
,):
1
,
}
self
.
assertEqual
(
self
.
tracer
.
results
().
calledfuncs
,
expected
)
class
TestCallers
(
unittest
.
TestCase
):
"""White-box testing of callers tracing"""
def
setUp
(
self
):
self
.
tracer
=
Trace
(
count
=
0
,
trace
=
0
,
countcallers
=
1
)
self
.
filemod
=
my_file_and_modname
()
def
test_loop_caller_importing
(
self
):
self
.
tracer
.
runfunc
(
traced_func_importing_caller
,
1
)
expected
=
{
((
os
.
path
.
splitext
(
trace
.
__file__
)[
0
]
+
'.py'
,
'trace'
,
'Trace.runfunc'
),
(
self
.
filemod
+
(
'traced_func_importing_caller'
,))):
1
,
((
self
.
filemod
+
(
'traced_func_simple_caller'
,)),
(
self
.
filemod
+
(
'traced_func_linear'
,))):
1
,
((
self
.
filemod
+
(
'traced_func_importing_caller'
,)),
(
self
.
filemod
+
(
'traced_func_simple_caller'
,))):
1
,
((
self
.
filemod
+
(
'traced_func_importing_caller'
,)),
(
self
.
filemod
+
(
'traced_func_importing'
,))):
1
,
((
self
.
filemod
+
(
'traced_func_importing'
,)),
(
fix_ext_py
(
testmod
.
__file__
),
'testmod'
,
'func'
)):
1
,
}
self
.
assertEqual
(
self
.
tracer
.
results
().
callers
,
expected
)
# Created separately for issue #3821
class
TestCoverage
(
unittest
.
TestCase
):
def
tearDown
(
self
):
rmtree
(
TESTFN
)
...
...
@@ -34,7 +310,6 @@ class TestCoverage(unittest.TestCase):
trace
=
0
,
count
=
1
)
with
captured_stdout
()
as
stdout
:
self
.
_coverage
(
tracer
)
self
.
assertEquals
(
stdout
.
getvalue
(),
""
)
if
os
.
path
.
exists
(
TESTFN
):
files
=
os
.
listdir
(
TESTFN
)
self
.
assertEquals
(
files
,
[])
...
...
@@ -43,5 +318,6 @@ class TestCoverage(unittest.TestCase):
def
test_main
():
run_unittest
(
__name__
)
if
__name__
==
"__main__"
:
if
__name__
==
'__main__'
:
test_main
()
Lib/trace.py
View file @
4d770172
...
...
@@ -57,7 +57,7 @@ import threading
import
time
import
token
import
tokenize
import
types
import
inspect
import
gc
import
pickle
...
...
@@ -395,7 +395,7 @@ def find_lines(code, strs):
# and check the constants for references to other code objects
for
c
in
code
.
co_consts
:
if
i
sinstance
(
c
,
types
.
CodeType
):
if
i
nspect
.
iscode
(
c
):
# find another code object, so recurse into it
linenos
.
update
(
find_lines
(
c
,
strs
))
return
linenos
...
...
@@ -544,7 +544,7 @@ class Trace:
## use of gc.get_referrers() was suggested by Michael Hudson
# all functions which refer to this code object
funcs
=
[
f
for
f
in
gc
.
get_referrers
(
code
)
if
hasattr
(
f
,
"__doc__"
)]
if
inspect
.
isfunction
(
f
)]
# require len(func) == 1 to avoid ambiguity caused by calls to
# new.function(): "In the face of ambiguity, refuse the
# temptation to guess."
...
...
@@ -556,17 +556,13 @@ class Trace:
if
hasattr
(
c
,
"__bases__"
)]
if
len
(
classes
)
==
1
:
# ditto for new.classobj()
clsname
=
str
(
classes
[
0
])
clsname
=
classes
[
0
].
__name__
# cache the result - assumption is that new.* is
# not called later to disturb this relationship
# _caller_cache could be flushed if functions in
# the new module get called.
self
.
_caller_cache
[
code
]
=
clsname
if
clsname
is
not
None
:
# final hack - module name shows up in str(cls), but we've already
# computed module name, so remove it
clsname
=
clsname
.
split
(
"."
)[
1
:]
clsname
=
"."
.
join
(
clsname
)
funcname
=
"%s.%s"
%
(
clsname
,
funcname
)
return
filename
,
modulename
,
funcname
...
...
Misc/NEWS
View file @
4d770172
...
...
@@ -145,6 +145,8 @@ Tools/Demos
Tests
-----
- Issue #9315: Added tests for the trace module. Patch by Eli Bendersky.
- Issue #9323: Make test.regrtest.__file__ absolute, this was not always the
case when running profile or trace, for example.
...
...
@@ -2070,6 +2072,9 @@ Library
- Issue #8235: _socket: Add the constant ``SO_SETFIB``. SO_SETFIB is a socket
option available on FreeBSD 7.1 and newer.
- Issue #9315: Fix for the trace module to record correct class name
for tracing methods.
Extension Modules
-----------------
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment