diff --git a/coverage/cmdline.py b/coverage/cmdline.py index 059d42a21..f7c828640 100644 --- a/coverage/cmdline.py +++ b/coverage/cmdline.py @@ -85,6 +85,11 @@ class Opts(object): "which isn't done by default." ), ) + sort = optparse.make_option( + '--sort', action='store', metavar='COLUMN', + help="Sort the report by the named column: name, stmts, miss, branch, brpart, or cover. " + "Default is name." + ) show_missing = optparse.make_option( '-m', '--show-missing', action='store_true', help="Show line numbers of statements in each module that weren't executed.", @@ -221,6 +226,7 @@ def __init__(self, *args, **kwargs): skip_covered=None, skip_empty=None, show_contexts=None, + sort=None, source=None, timid=None, title=None, @@ -410,6 +416,7 @@ def get_prog_name(self): Opts.include, Opts.omit, Opts.precision, + Opts.sort, Opts.show_missing, Opts.skip_covered, Opts.no_skip_covered, @@ -601,6 +608,7 @@ def command_line(self, argv): skip_covered=options.skip_covered, skip_empty=options.skip_empty, precision=options.precision, + sort=options.sort, **report_args ) elif options.action == "annotate": diff --git a/coverage/config.py b/coverage/config.py index 6d336d1f9..84d9758bf 100644 --- a/coverage/config.py +++ b/coverage/config.py @@ -211,6 +211,7 @@ def __init__(self): self.show_missing = False self.skip_covered = False self.skip_empty = False + self.sort = None # Defaults for [html] self.extra_css = None diff --git a/coverage/control.py b/coverage/control.py index bd7ba2e6e..cc0c271ac 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -831,7 +831,7 @@ def _get_file_reporters(self, morfs=None): def report( self, morfs=None, show_missing=None, ignore_errors=None, file=None, omit=None, include=None, skip_covered=None, - contexts=None, skip_empty=None, precision=None, + contexts=None, skip_empty=None, precision=None, sort=None ): """Write a textual summary report to `file`. @@ -882,6 +882,7 @@ def report( ignore_errors=ignore_errors, report_omit=omit, report_include=include, show_missing=show_missing, skip_covered=skip_covered, report_contexts=contexts, skip_empty=skip_empty, precision=precision, + sort=sort ): reporter = SummaryReporter(self) return reporter.report(morfs, outfile=file) diff --git a/coverage/summary.py b/coverage/summary.py index 97d9fff07..986cd2f2d 100644 --- a/coverage/summary.py +++ b/coverage/summary.py @@ -104,10 +104,18 @@ def report(self, morfs, outfile=None): # Sort the lines and write them out. if getattr(self.config, 'sort', None): - position = column_order.get(self.config.sort.lower()) + sort_option = self.config.sort.lower() + reverse = False + if sort_option[0] == '-': + reverse = True + sort_option = sort_option[1:] + elif sort_option[0] == '+': + sort_option = sort_option[1:] + + position = column_order.get(sort_option) if position is None: raise CoverageException("Invalid sorting option: {!r}".format(self.config.sort)) - lines.sort(key=lambda l: (l[1][position], l[0])) + lines.sort(key=lambda l: (l[1][position], l[0]), reverse=reverse) for line in lines: self.writeout(line[0]) diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py index db70a9949..560a3d175 100644 --- a/tests/test_cmdline.py +++ b/tests/test_cmdline.py @@ -42,6 +42,7 @@ class BaseCmdLineTest(CoverageTest): _defaults.Coverage().report( ignore_errors=None, include=None, omit=None, morfs=[], show_missing=None, skip_covered=None, contexts=None, skip_empty=None, precision=None, + sort=None, ) _defaults.Coverage().xml_report( ignore_errors=None, include=None, omit=None, morfs=[], outfile=None, @@ -402,6 +403,11 @@ def test_report(self): cov.load() cov.report(contexts=["foo", "bar"]) """) + self.cmd_executes("report --sort=-foo", """\ + cov = Coverage() + cov.load() + cov.report(sort='-foo') + """) def test_run(self): # coverage run [-p] [-L] [--timid] MODULE.py [ARG1 ARG2 ...]