Fixed #11745 -- Grouped commands by application in the output of `manage.py help`. Made 'version' consistent with 'help' while I was in the area, and added tests. Thanks Jannis for the feedback and review.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17462 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Aymeric Augustin 2012-02-07 18:46:29 +00:00
parent 09ad6d1b88
commit 175e6d77df
4 changed files with 88 additions and 28 deletions

View File

@ -1,3 +1,4 @@
import collections
import os
import sys
from optparse import OptionParser, NO_DEFAULT
@ -5,6 +6,7 @@ import imp
import warnings
from django.core.management.base import BaseCommand, CommandError, handle_default_options
from django.core.management.color import color_style
from django.utils.importlib import import_module
# For backwards compatibility: get_version() used to be in this module.
@ -209,16 +211,32 @@ class ManagementUtility(object):
self.argv = argv or sys.argv[:]
self.prog_name = os.path.basename(self.argv[0])
def main_help_text(self):
def main_help_text(self, commands_only=False):
"""
Returns the script's main help text, as a string.
"""
usage = ['',"Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name,'']
usage.append('Available subcommands:')
commands = get_commands().keys()
commands.sort()
for cmd in commands:
usage.append(' %s' % cmd)
if commands_only:
usage = sorted(get_commands().keys())
else:
usage = [
"",
"Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name,
"",
"Available subcommands:",
]
commands_dict = collections.defaultdict(lambda: [])
for name, app in get_commands().iteritems():
if app == 'django.core':
app = 'django'
else:
app = app.rpartition('.')[-1]
commands_dict[app].append(name)
style = color_style()
for app in sorted(commands_dict.keys()):
usage.append("")
usage.append(style.NOTICE("[%s]" % app))
for name in sorted(commands_dict[app]):
usage.append(" %s" % name)
return '\n'.join(usage)
def fetch_command(self, subcommand):
@ -340,12 +358,15 @@ class ManagementUtility(object):
subcommand = 'help' # Display help if no arguments were given.
if subcommand == 'help':
if len(args) > 2:
self.fetch_command(args[2]).print_help(self.prog_name, args[2])
else:
if len(args) <= 2:
parser.print_lax_help()
sys.stdout.write(self.main_help_text() + '\n')
sys.exit(1)
elif args[2] == '--commands':
sys.stdout.write(self.main_help_text(commands_only=True) + '\n')
else:
self.fetch_command(args[2]).print_help(self.prog_name, args[2])
elif subcommand == 'version':
sys.stdout.write(parser.get_version() + '\n')
# Special-cases: We want 'django-admin.py --version' and
# 'django-admin.py --help' to work, for backwards compatibility.
elif self.argv[1:] == ['--version']:

View File

@ -47,11 +47,16 @@ for the given command.
Getting runtime help
--------------------
.. django-admin-option:: --help
.. django-admin:: help
Run ``django-admin.py help`` to display a list of all available commands.
Run ``django-admin.py help <command>`` to display a description of the
given command and a list of its available options.
Run ``django-admin.py help`` to display usage information and a list of the
commands provided by each application.
Run ``django-admin.py help --commands`` to display a list of all available
commands.
Run ``django-admin.py help <command>`` to display a description of the given
command and a list of its available options.
App names
---------
@ -63,9 +68,9 @@ contains the string ``'mysite.blog'``, the app name is ``blog``.
Determining the version
-----------------------
.. django-admin-option:: --version
.. django-admin:: version
Run ``django-admin.py --version`` to display the current Django version.
Run ``django-admin.py version`` to display the current Django version.
Examples of output::

View File

@ -989,6 +989,14 @@ after tests' execution, then you can restore the previous behavior by
subclassing ``DjangoTestRunner`` and overriding its ``teardown_databases()``
method.
Output of :djadmin:`manage.py help <help>`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:djadmin:`manage.py help <help>` now groups available commands by application.
If you depended on its output, for instance if you parsed it, you must update
your scripts. To obtain the list of all available management commands in a
script, you can use :djadmin:`manage.py help --commands <help>` instead.
Features deprecated in 1.4
==========================

View File

@ -173,6 +173,10 @@ class AdminScriptTestCase(unittest.TestCase):
"Utility assertion: assert that the given message exists in the output"
self.assertTrue(msg in stream, "'%s' does not match actual output text '%s'" % (msg, stream))
def assertNotInOutput(self, stream, msg):
"Utility assertion: assert that the given message doesn't exist in the output"
self.assertFalse(msg in stream, "'%s' matches actual output text '%s'" % (msg, stream))
##########################################################################
# DJANGO ADMIN TESTS
# This first series of test classes checks the environment processing
@ -1173,25 +1177,47 @@ class CommandTypes(AdminScriptTestCase):
self.remove_settings('settings.py')
def test_version(self):
"--version is handled as a special case"
args = ['--version']
"version is handled as a special case"
args = ['version']
out, err = self.run_manage(args)
self.assertNoOutput(err)
self.assertOutput(out, get_version())
def test_help(self):
"--help is handled as a special case"
args = ['--help']
out, err = self.run_manage(args)
self.assertOutput(out, "Usage: manage.py subcommand [options] [args]")
self.assertOutput(out, "Type 'manage.py help <subcommand>' for help on a specific subcommand.")
def test_version_alternative(self):
"--version is equivalent to version"
args1, args2 = ['version'], ['--version']
self.assertEqual(self.run_manage(args1), self.run_manage(args2))
def test_short_help(self):
"-h is handled as a short form of --help"
args = ['-h']
def test_help(self):
"help is handled as a special case"
args = ['help']
out, err = self.run_manage(args)
self.assertOutput(out, "Usage: manage.py subcommand [options] [args]")
self.assertOutput(out, "Type 'manage.py help <subcommand>' for help on a specific subcommand.")
self.assertOutput(out, '[django]')
self.assertOutput(out, 'startapp')
self.assertOutput(out, 'startproject')
def test_help_commands(self):
"help --commands shows the list of all available commands"
args = ['help', '--commands']
out, err = self.run_manage(args)
self.assertNotInOutput(out, 'Usage:')
self.assertNotInOutput(out, 'Options:')
self.assertNotInOutput(out, '[django]')
self.assertOutput(out, 'startapp')
self.assertOutput(out, 'startproject')
self.assertNotInOutput(out, '\n\n')
def test_help_alternative(self):
"--help is equivalent to help"
args1, args2 = ['help'], ['--help']
self.assertEqual(self.run_manage(args1), self.run_manage(args2))
def test_help_short_altert(self):
"-h is handled as a short form of --help"
args1, args2 = ['--help'], ['-h']
self.assertEqual(self.run_manage(args1), self.run_manage(args2))
def test_specific_help(self):
"--help can be used on a specific command"