diff options
-rw-r--r-- | coverage/cmdline.py | 26 | ||||
-rw-r--r-- | tests/coveragetest.py | 72 |
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): |