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
436831db
Commit
436831db
authored
Jan 13, 2016
by
Senthil Kumaran
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue22642 - Convert trace module's option handling mechanism from getopt to argparse.
Patch contributed by SilentGhost.
parent
121edbf7
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
156 additions
and
205 deletions
+156
-205
Lib/test/test_trace.py
Lib/test/test_trace.py
+22
-0
Lib/trace.py
Lib/trace.py
+134
-205
No files found.
Lib/test/test_trace.py
View file @
436831db
import
os
import
sys
from
test.support
import
TESTFN
,
rmtree
,
unlink
,
captured_stdout
from
test.support.script_helper
import
assert_python_ok
,
assert_python_failure
import
unittest
import
trace
...
...
@@ -364,6 +365,27 @@ class Test_Ignore(unittest.TestCase):
# Matched before.
self
.
assertTrue
(
ignore
.
names
(
jn
(
'bar'
,
'baz.py'
),
'baz'
))
class
TestCommandLine
(
unittest
.
TestCase
):
def
test_failures
(
self
):
_errors
=
(
(
b'filename is missing: required with the main options'
,
'-l'
,
'-T'
),
(
b'cannot specify both --listfuncs and (--trace or --count)'
,
'-lc'
),
(
b'argument -R/--no-report: not allowed with argument -r/--report'
,
'-rR'
),
(
b'must specify one of --trace, --count, --report, --listfuncs, or --trackcalls'
,
'-g'
),
(
b'-r/--report requires -f/--file'
,
'-r'
),
(
b'--summary can only be used with --count or --report'
,
'-sT'
),
(
b'unrecognized arguments: -y'
,
'-y'
))
for
message
,
*
args
in
_errors
:
*
_
,
stderr
=
assert_python_failure
(
'-m'
,
'trace'
,
*
args
)
self
.
assertIn
(
message
,
stderr
)
def
test_listfuncs_flag_success
(
self
):
with
open
(
TESTFN
,
'w'
)
as
fd
:
self
.
addCleanup
(
unlink
,
TESTFN
)
fd
.
write
(
"a = 1
\
n
"
)
status
,
stdout
,
stderr
=
assert_python_ok
(
'-m'
,
'trace'
,
'-l'
,
TESTFN
)
self
.
assertIn
(
b'functions called:'
,
stdout
)
if
__name__
==
'__main__'
:
unittest
.
main
()
Lib/trace.py
View file @
436831db
...
...
@@ -48,6 +48,7 @@ Sample use, programmatically
r.write_results(show_missing=True, coverdir="/tmp")
"""
__all__
=
[
'Trace'
,
'CoverageResults'
]
import
argparse
import
linecache
import
os
import
re
...
...
@@ -76,51 +77,6 @@ else:
sys
.
settrace
(
None
)
threading
.
settrace
(
None
)
def
_usage
(
outfile
):
outfile
.
write
(
"""Usage: %s [OPTIONS] <file> [ARGS]
Meta-options:
--help Display this help then exit.
--version Output version information then exit.
Otherwise, exactly one of the following three options must be given:
-t, --trace Print each line to sys.stdout before it is executed.
-c, --count Count the number of times each line is executed
and write the counts to <module>.cover for each
module executed, in the module's directory.
See also `--coverdir', `--file', `--no-report' below.
-l, --listfuncs Keep track of which functions are executed at least
once and write the results to sys.stdout after the
program exits.
-T, --trackcalls Keep track of caller/called pairs and write the
results to sys.stdout after the program exits.
-r, --report Generate a report from a counts file; do not execute
any code. `--file' must specify the results file to
read, which must have been created in a previous run
with `--count --file=FILE'.
Modifiers:
-f, --file=<file> File to accumulate counts over several runs.
-R, --no-report Do not generate the coverage report files.
Useful if you want to accumulate over several runs.
-C, --coverdir=<dir> Directory where the report files. The coverage
report for <package>.<module> is written to file
<dir>/<package>/<module>.cover.
-m, --missing Annotate executable lines that were not executed
with '>>>>>> '.
-s, --summary Write a brief summary on stdout for each file.
(Can only be used with --count or --report.)
-g, --timing Prefix each line with the time since the program started.
Only used while tracing.
Filters, may be repeated multiple times:
--ignore-module=<mod> Ignore the given module(s) and its submodules
(if it is a package). Accepts comma separated
list of module names
--ignore-dir=<dir> Ignore files in the given directory (multiple
directories can be joined by os.pathsep).
"""
%
sys
.
argv
[
0
])
PRAGMA_NOCOVER
=
"#pragma NO COVER"
# Simple rx to find lines with no code.
...
...
@@ -264,7 +220,13 @@ class CoverageResults:
def
write_results
(
self
,
show_missing
=
True
,
summary
=
False
,
coverdir
=
None
):
"""
@param coverdir
Write the coverage results.
:param show_missing: Show lines that had no hits.
:param summary: Include coverage summary per module.
:param coverdir: If None, the results of each module are placed in it's
directory, otherwise it is included in the directory
specified.
"""
if
self
.
calledfuncs
:
print
()
...
...
@@ -646,168 +608,135 @@ class Trace:
calledfuncs
=
self
.
_calledfuncs
,
callers
=
self
.
_callers
)
def
_err_exit
(
msg
):
sys
.
stderr
.
write
(
"%s: %s
\
n
"
%
(
sys
.
argv
[
0
],
msg
))
sys
.
exit
(
1
)
def
main
(
argv
=
None
):
import
getopt
if
argv
is
None
:
argv
=
sys
.
argv
try
:
opts
,
prog_argv
=
getopt
.
getopt
(
argv
[
1
:],
"tcrRf:d:msC:lTg"
,
[
"help"
,
"version"
,
"trace"
,
"count"
,
"report"
,
"no-report"
,
"summary"
,
"file="
,
"missing"
,
"ignore-module="
,
"ignore-dir="
,
"coverdir="
,
"listfuncs"
,
"trackcalls"
,
"timing"
])
except
getopt
.
error
as
msg
:
sys
.
stderr
.
write
(
"%s: %s
\
n
"
%
(
sys
.
argv
[
0
],
msg
))
sys
.
stderr
.
write
(
"Try `%s --help' for more information
\
n
"
%
sys
.
argv
[
0
])
sys
.
exit
(
1
)
trace
=
0
count
=
0
report
=
0
no_report
=
0
counts_file
=
None
missing
=
0
ignore_modules
=
[]
ignore_dirs
=
[]
coverdir
=
None
summary
=
0
listfuncs
=
False
countcallers
=
False
timing
=
False
for
opt
,
val
in
opts
:
if
opt
==
"--help"
:
_usage
(
sys
.
stdout
)
sys
.
exit
(
0
)
if
opt
==
"--version"
:
sys
.
stdout
.
write
(
"trace 2.0
\
n
"
)
sys
.
exit
(
0
)
if
opt
==
"-T"
or
opt
==
"--trackcalls"
:
countcallers
=
True
continue
if
opt
==
"-l"
or
opt
==
"--listfuncs"
:
listfuncs
=
True
continue
if
opt
==
"-g"
or
opt
==
"--timing"
:
timing
=
True
continue
if
opt
==
"-t"
or
opt
==
"--trace"
:
trace
=
1
continue
if
opt
==
"-c"
or
opt
==
"--count"
:
count
=
1
continue
if
opt
==
"-r"
or
opt
==
"--report"
:
report
=
1
continue
if
opt
==
"-R"
or
opt
==
"--no-report"
:
no_report
=
1
continue
if
opt
==
"-f"
or
opt
==
"--file"
:
counts_file
=
val
continue
if
opt
==
"-m"
or
opt
==
"--missing"
:
missing
=
1
continue
if
opt
==
"-C"
or
opt
==
"--coverdir"
:
coverdir
=
val
continue
if
opt
==
"-s"
or
opt
==
"--summary"
:
summary
=
1
continue
if
opt
==
"--ignore-module"
:
for
mod
in
val
.
split
(
","
):
ignore_modules
.
append
(
mod
.
strip
())
continue
if
opt
==
"--ignore-dir"
:
for
s
in
val
.
split
(
os
.
pathsep
):
s
=
os
.
path
.
expandvars
(
s
)
# should I also call expanduser? (after all, could use $HOME)
s
=
s
.
replace
(
"$prefix"
,
os
.
path
.
join
(
sys
.
base_prefix
,
"lib"
,
"python"
+
sys
.
version
[:
3
]))
s
=
s
.
replace
(
"$exec_prefix"
,
os
.
path
.
join
(
sys
.
base_exec_prefix
,
"lib"
,
"python"
+
sys
.
version
[:
3
]))
s
=
os
.
path
.
normpath
(
s
)
ignore_dirs
.
append
(
s
)
continue
assert
0
,
"Should never get here"
if
listfuncs
and
(
count
or
trace
):
_err_exit
(
"cannot specify both --listfuncs and (--trace or --count)"
)
if
not
(
count
or
trace
or
report
or
listfuncs
or
countcallers
):
_err_exit
(
"must specify one of --trace, --count, --report, "
"--listfuncs, or --trackcalls"
)
if
report
and
no_report
:
_err_exit
(
"cannot specify both --report and --no-report"
)
if
report
and
not
counts_file
:
_err_exit
(
"--report requires a --file"
)
if
no_report
and
len
(
prog_argv
)
==
0
:
_err_exit
(
"missing name of file to run"
)
# everything is ready
if
report
:
results
=
CoverageResults
(
infile
=
counts_file
,
outfile
=
counts_file
)
results
.
write_results
(
missing
,
summary
=
summary
,
coverdir
=
coverdir
)
else
:
sys
.
argv
=
prog_argv
progname
=
prog_argv
[
0
]
sys
.
path
[
0
]
=
os
.
path
.
split
(
progname
)[
0
]
t
=
Trace
(
count
,
trace
,
countfuncs
=
listfuncs
,
countcallers
=
countcallers
,
ignoremods
=
ignore_modules
,
ignoredirs
=
ignore_dirs
,
infile
=
counts_file
,
outfile
=
counts_file
,
timing
=
timing
)
def
main
():
parser
=
argparse
.
ArgumentParser
()
parser
.
add_argument
(
'--version'
,
action
=
'version'
,
version
=
'trace 2.0'
)
grp
=
parser
.
add_argument_group
(
'Main options'
,
'One of these (or --report) must be given'
)
grp
.
add_argument
(
'-c'
,
'--count'
,
action
=
'store_true'
,
help
=
'Count the number of times each line is executed and write '
'the counts to <module>.cover for each module executed, in '
'the module
\
'
s directory. See also --coverdir, --file, '
'--no-report below.'
)
grp
.
add_argument
(
'-t'
,
'--trace'
,
action
=
'store_true'
,
help
=
'Print each line to sys.stdout before it is executed'
)
grp
.
add_argument
(
'-l'
,
'--listfuncs'
,
action
=
'store_true'
,
help
=
'Keep track of which functions are executed at least once '
'and write the results to sys.stdout after the program exits. '
'Cannot be specified alongside --trace or --count.'
)
grp
.
add_argument
(
'-T'
,
'--trackcalls'
,
action
=
'store_true'
,
help
=
'Keep track of caller/called pairs and write the results to '
'sys.stdout after the program exits.'
)
grp
=
parser
.
add_argument_group
(
'Modifiers'
)
_grp
=
grp
.
add_mutually_exclusive_group
()
_grp
.
add_argument
(
'-r'
,
'--report'
,
action
=
'store_true'
,
help
=
'Generate a report from a counts file; does not execute any '
'code. --file must specify the results file to read, which '
'must have been created in a previous run with --count '
'--file=FILE'
)
_grp
.
add_argument
(
'-R'
,
'--no-report'
,
action
=
'store_true'
,
help
=
'Do not generate the coverage report files. '
'Useful if you want to accumulate over several runs.'
)
grp
.
add_argument
(
'-f'
,
'--file'
,
help
=
'File to accumulate counts over several runs'
)
grp
.
add_argument
(
'-C'
,
'--coverdir'
,
help
=
'Directory where the report files go. The coverage report '
'for <package>.<module> will be written to file '
'<dir>/<package>/<module>.cover'
)
grp
.
add_argument
(
'-m'
,
'--missing'
,
action
=
'store_true'
,
help
=
'Annotate executable lines that were not executed with '
'">>>>>> "'
)
grp
.
add_argument
(
'-s'
,
'--summary'
,
action
=
'store_true'
,
help
=
'Write a brief summary for each file to sys.stdout. '
'Can only be used with --count or --report'
)
grp
.
add_argument
(
'-g'
,
'--timing'
,
action
=
'store_true'
,
help
=
'Prefix each line with the time since the program started. '
'Only used while tracing'
)
grp
=
parser
.
add_argument_group
(
'Filters'
,
'Can be specified multiple times'
)
grp
.
add_argument
(
'--ignore-module'
,
action
=
'append'
,
default
=
[],
help
=
'Ignore the given module(s) and its submodules'
'(if it is a package). Accepts comma separated list of '
'module names.'
)
grp
.
add_argument
(
'--ignore-dir'
,
action
=
'append'
,
default
=
[],
help
=
'Ignore files in the given directory '
'(multiple directories can be joined by os.pathsep).'
)
parser
.
add_argument
(
'filename'
,
nargs
=
'?'
,
help
=
'file to run as main program'
)
parser
.
add_argument
(
'arguments'
,
nargs
=
argparse
.
REMAINDER
,
help
=
'arguments to the program'
)
opts
=
parser
.
parse_args
()
if
opts
.
ignore_dir
:
rel_path
=
'lib'
,
'python{0.major}.{0.minor}'
.
format
(
sys
.
version_info
)
_prefix
=
os
.
path
.
join
(
sys
.
base_prefix
,
*
rel_path
)
_exec_prefix
=
os
.
path
.
join
(
sys
.
base_exec_prefix
,
*
rel_path
)
def
parse_ignore_dir
(
s
):
s
=
os
.
path
.
expanduser
(
os
.
path
.
expandvars
(
s
))
s
=
s
.
replace
(
'$prefix'
,
_prefix
).
replace
(
'$exec_prefix'
,
_exec_prefix
)
return
os
.
path
.
normpath
(
s
)
opts
.
ignore_module
=
[
mod
.
strip
()
for
i
in
opts
.
ignore_module
for
mod
in
i
.
split
(
','
)]
opts
.
ignore_dir
=
[
parse_ignore_dir
(
s
)
for
i
in
opts
.
ignore_dir
for
s
in
i
.
split
(
os
.
pathsep
)]
if
opts
.
report
:
if
not
opts
.
file
:
parser
.
error
(
'-r/--report requires -f/--file'
)
results
=
CoverageResults
(
infile
=
opts
.
file
,
outfile
=
opts
.
file
)
return
results
.
write_results
(
opts
.
missing
,
opts
.
summary
,
opts
.
coverdir
)
if
not
any
([
opts
.
trace
,
opts
.
count
,
opts
.
listfuncs
,
opts
.
trackcalls
]):
parser
.
error
(
'must specify one of --trace, --count, --report, '
'--listfuncs, or --trackcalls'
)
if
opts
.
listfuncs
and
(
opts
.
count
or
opts
.
trace
):
parser
.
error
(
'cannot specify both --listfuncs and (--trace or --count)'
)
if
opts
.
summary
and
not
opts
.
count
:
parser
.
error
(
'--summary can only be used with --count or --report'
)
if
opts
.
filename
is
None
:
parser
.
error
(
'filename is missing: required with the main options'
)
sys
.
argv
=
opts
.
filename
,
*
opts
.
arguments
sys
.
path
[
0
]
=
os
.
path
.
dirname
(
opts
.
filename
)
t
=
Trace
(
opts
.
count
,
opts
.
trace
,
countfuncs
=
opts
.
listfuncs
,
countcallers
=
opts
.
trackcalls
,
ignoremods
=
opts
.
ignore_module
,
ignoredirs
=
opts
.
ignore_dir
,
infile
=
opts
.
file
,
outfile
=
opts
.
file
,
timing
=
opts
.
timing
)
try
:
with
open
(
prog
name
)
as
fp
:
code
=
compile
(
fp
.
read
(),
prog
name
,
'exec'
)
with
open
(
opts
.
file
name
)
as
fp
:
code
=
compile
(
fp
.
read
(),
opts
.
file
name
,
'exec'
)
# try to emulate __main__ namespace as much as possible
globs
=
{
'__file__'
:
prog
name
,
'__file__'
:
opts
.
file
name
,
'__name__'
:
'__main__'
,
'__package__'
:
None
,
'__cached__'
:
None
,
}
t
.
runctx
(
code
,
globs
,
globs
)
except
OSError
as
err
:
_err_
exit
(
"Cannot run file %r because: %s"
%
(
sys
.
argv
[
0
],
err
))
sys
.
exit
(
"Cannot run file %r because: %s"
%
(
sys
.
argv
[
0
],
err
))
except
SystemExit
:
pass
results
=
t
.
results
()
if
not
no_report
:
results
.
write_results
(
missing
,
summary
=
summary
,
coverdir
=
coverdir
)
if
not
opts
.
no_report
:
results
.
write_results
(
opts
.
missing
,
opts
.
summary
,
opts
.
coverdir
)
if
__name__
==
'__main__'
:
main
()
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