summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coverage/cmdline.py26
-rw-r--r--tests/coveragetest.py72
2 files changed, 74 insertions, 24 deletions
diff --git a/coverage/cmdline.py b/coverage/cmdline.py
index 46a87ca6..97ea596c 100644
--- a/coverage/cmdline.py
+++ b/coverage/cmdline.py
@@ -228,7 +228,6 @@ class CmdOptionParser(CoverageOptionParser):
if usage:
usage = "%prog " + usage
super(CmdOptionParser, self).__init__(
- prog="coverage %s" % action,
usage=usage,
description=description,
)
@@ -242,6 +241,15 @@ class CmdOptionParser(CoverageOptionParser):
# results, and they will compare equal to objects.
return (other == "<CmdOptionParser:%s>" % self.cmd)
+ def get_prog_name(self):
+ program_name = super(CmdOptionParser, self).get_prog_name()
+
+ # Include the sub-command for this parser as part of the command.
+ result = "%(command)s %(subcommand)s" % {
+ 'command': program_name, 'subcommand': self.cmd}
+ return result
+
+
GLOBAL_ARGS = [
Opts.debug,
Opts.help,
@@ -372,6 +380,8 @@ OK, ERR, FAIL_UNDER = 0, 1, 2
class CoverageScript(object):
"""The command-line interface to coverage.py."""
+ program_name = os.path.basename(sys.argv[0])
+
def __init__(self, _covpkg=None, _run_python_file=None,
_run_python_module=None, _help_fn=None, _path_exists=None):
# _covpkg is for dependency injection, so we can test this code.
@@ -523,13 +533,17 @@ class CoverageScript(object):
assert error or topic or parser
if error:
print(error)
- print("Use 'coverage help' for help.")
+ print("Use '%(program_name)s help' for help." % {
+ 'program_name': self.program_name})
elif parser:
print(parser.format_help().strip())
else:
+ help_params = self.covpkg.__dict__
+ help_params.update({
+ 'program_name': self.program_name})
help_msg = textwrap.dedent(HELP_TOPICS.get(topic, '')).strip()
if help_msg:
- print(help_msg % self.covpkg.__dict__)
+ print(help_msg % help_params)
else:
print("Don't know topic %r" % topic)
@@ -682,7 +696,7 @@ HELP_TOPICS = {
Coverage.py, version %(__version__)s
Measure, collect, and report on code coverage in Python programs.
- usage: coverage <command> [options] [args]
+ usage: %(program_name)s <command> [options] [args]
Commands:
annotate Annotate source files with execution information.
@@ -694,12 +708,12 @@ HELP_TOPICS = {
run Run a Python program and measure code execution.
xml Create an XML report of coverage results.
- Use "coverage help <command>" for detailed help on any command.
+ Use "%(program_name)s help <command>" for detailed help on any command.
For full documentation, see %(__url__)s
""",
'minimum_help': """\
- Code coverage for Python. Use 'coverage help' for help.
+ Code coverage for Python. Use '%(program_name)s help' for help.
""",
'version': """\
diff --git a/tests/coveragetest.py b/tests/coveragetest.py
index 5042c98d..8b54c819 100644
--- a/tests/coveragetest.py
+++ b/tests/coveragetest.py
@@ -10,6 +10,14 @@ import os
import random
import re
import shlex
+try:
+ shlex.quote
+except AttributeError:
+ # Useful function, available under a different (undocumented) name
+ # in Python versions earlier than 3.3.
+ import pipes
+ shlex.quote = pipes.quote
+ del pipes
import shutil
import sys
@@ -332,25 +340,53 @@ class CoverageTest(
ret_actual = script.command_line(shlex.split(args))
self.assertEqual(ret_actual, ret)
- def run_command(self, cmd):
- """Run the command-line `cmd` in a sub-process, and print its output.
+ coverage_command = "coverage"
- Use this when you need to test the process behavior of coverage.
-
- Compare with `command_line`.
-
- Returns the process' stdout text.
-
- """
- # Running Python sub-processes can be tricky. Use the real name of our
- # own executable. So "python foo.py" might get executed as
- # "python3.3 foo.py". This is important because Python 3.x doesn't
- # install as "python", so you might get a Python 2 executable instead
- # if you don't use the executable's basename.
- if cmd.startswith("python "):
- cmd = os.path.basename(sys.executable) + cmd[6:]
-
- _, output = self.run_command_status(cmd)
+ def run_command(self, cmd):
+ """ Run the command-line `cmd` in a sub-process.
+
+ :param cmd: The command line to invoke in a sub-process.
+ :return: Combined content of `stdout` and `stderr` output
+ streams from the sub-process.
+
+ Use this when you need to test the process behavior of
+ coverage.
+
+ Compare with `command_line`.
+
+ Handles the following command name specially:
+
+ * "python" is replaced with the command name of the current
+ Python interpreter.
+
+ * "coverage" is replaced with the command name for the main
+ Coverage.py program.
+
+ """
+ split_commandline = cmd.split(" ", 1)
+ command_name = split_commandline[0]
+ command_args = split_commandline[1:]
+
+ if command_name == "python":
+ # Running a Python interpreter in a sub-processes can be
+ # tricky. Use the real name of our own executable. So
+ # "python foo.py" might get executed as "python3.3
+ # foo.py". This is important because Python 3.x doesn't
+ # install as "python", so you might get a Python 2
+ # executable instead if you don't use the executable's
+ # basename.
+ command_name = os.path.basename(sys.executable)
+
+ if command_name == "coverage":
+ # The invocation requests the Coverage.py program. Test
+ # whether that's actually the command name to use.
+ if command_name != self.coverage_command:
+ # Substitute the actual Coverage.py main command name.
+ command_name = self.coverage_command
+
+ full_commandline = " ".join([shlex.quote(command_name)] + command_args)
+
+ _, output = self.run_command_status(full_commandline)
return output
def run_command_status(self, cmd):