Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #11745 -- Grouped commands by application in the output of `man…

…age.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
  • Loading branch information...
commit 175e6d77df526dea1ade94661e487072e7c7cd88 1 parent 09ad6d1
Aymeric Augustin authored February 07, 2012
43  django/core/management/__init__.py
... ...
@@ -1,3 +1,4 @@
  1
+import collections
1 2
 import os
2 3
 import sys
3 4
 from optparse import OptionParser, NO_DEFAULT
@@ -5,6 +6,7 @@
5 6
 import warnings
6 7
 
7 8
 from django.core.management.base import BaseCommand, CommandError, handle_default_options
  9
+from django.core.management.color import color_style
8 10
 from django.utils.importlib import import_module
9 11
 
10 12
 # For backwards compatibility: get_version() used to be in this module.
@@ -209,16 +211,32 @@ def __init__(self, argv=None):
209 211
         self.argv = argv or sys.argv[:]
210 212
         self.prog_name = os.path.basename(self.argv[0])
211 213
 
212  
-    def main_help_text(self):
  214
+    def main_help_text(self, commands_only=False):
213 215
         """
214 216
         Returns the script's main help text, as a string.
215 217
         """
216  
-        usage = ['',"Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name,'']
217  
-        usage.append('Available subcommands:')
218  
-        commands = get_commands().keys()
219  
-        commands.sort()
220  
-        for cmd in commands:
221  
-            usage.append('  %s' % cmd)
  218
+        if commands_only:
  219
+            usage = sorted(get_commands().keys())
  220
+        else:
  221
+            usage = [
  222
+                "",
  223
+                "Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name,
  224
+                "",
  225
+                "Available subcommands:",
  226
+            ]
  227
+            commands_dict = collections.defaultdict(lambda: [])
  228
+            for name, app in get_commands().iteritems():
  229
+                if app == 'django.core':
  230
+                    app = 'django'
  231
+                else:
  232
+                    app = app.rpartition('.')[-1]
  233
+                commands_dict[app].append(name)
  234
+            style = color_style()
  235
+            for app in sorted(commands_dict.keys()):
  236
+                usage.append("")
  237
+                usage.append(style.NOTICE("[%s]" % app))
  238
+                for name in sorted(commands_dict[app]):
  239
+                    usage.append("    %s" % name)
222 240
         return '\n'.join(usage)
223 241
 
224 242
     def fetch_command(self, subcommand):
@@ -340,12 +358,15 @@ def execute(self):
340 358
             subcommand = 'help' # Display help if no arguments were given.
341 359
 
342 360
         if subcommand == 'help':
343  
-            if len(args) > 2:
344  
-                self.fetch_command(args[2]).print_help(self.prog_name, args[2])
345  
-            else:
  361
+            if len(args) <= 2:
346 362
                 parser.print_lax_help()
347 363
                 sys.stdout.write(self.main_help_text() + '\n')
348  
-                sys.exit(1)
  364
+            elif args[2] == '--commands':
  365
+                sys.stdout.write(self.main_help_text(commands_only=True) + '\n')
  366
+            else:
  367
+                self.fetch_command(args[2]).print_help(self.prog_name, args[2])
  368
+        elif subcommand == 'version':
  369
+            sys.stdout.write(parser.get_version() + '\n')
349 370
         # Special-cases: We want 'django-admin.py --version' and
350 371
         # 'django-admin.py --help' to work, for backwards compatibility.
351 372
         elif self.argv[1:] == ['--version']:
17  docs/ref/django-admin.txt
@@ -47,11 +47,16 @@ for the given command.
47 47
 Getting runtime help
48 48
 --------------------
49 49
 
50  
-.. django-admin-option:: --help
  50
+.. django-admin:: help
51 51
 
52  
-Run ``django-admin.py help`` to display a list of all available commands.
53  
-Run ``django-admin.py help <command>`` to display a description of the
54  
-given command and a list of its available options.
  52
+Run ``django-admin.py help`` to display usage information and a list of the
  53
+commands provided by each application.
  54
+
  55
+Run ``django-admin.py help --commands`` to display a list of all available
  56
+commands.
  57
+
  58
+Run ``django-admin.py help <command>`` to display a description of the given
  59
+command and a list of its available options.
55 60
 
56 61
 App names
57 62
 ---------
@@ -63,9 +68,9 @@ contains the string ``'mysite.blog'``, the app name is ``blog``.
63 68
 Determining the version
64 69
 -----------------------
65 70
 
66  
-.. django-admin-option:: --version
  71
+.. django-admin:: version
67 72
 
68  
-Run ``django-admin.py --version`` to display the current Django version.
  73
+Run ``django-admin.py version`` to display the current Django version.
69 74
 
70 75
 Examples of output::
71 76
 
8  docs/releases/1.4.txt
@@ -989,6 +989,14 @@ after tests' execution, then you can restore the previous behavior by
989 989
 subclassing ``DjangoTestRunner`` and overriding its ``teardown_databases()``
990 990
 method.
991 991
 
  992
+Output of :djadmin:`manage.py help <help>`
  993
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  994
+
  995
+:djadmin:`manage.py help <help>` now groups available commands by application.
  996
+If you depended on its output, for instance if you parsed it, you must update
  997
+your scripts. To obtain the list of all available management commands in a
  998
+script, you can use :djadmin:`manage.py help --commands <help>` instead.
  999
+
992 1000
 Features deprecated in 1.4
993 1001
 ==========================
994 1002
 
44  tests/regressiontests/admin_scripts/tests.py
@@ -173,6 +173,10 @@ def assertOutput(self, stream, msg):
173 173
         "Utility assertion: assert that the given message exists in the output"
174 174
         self.assertTrue(msg in stream, "'%s' does not match actual output text '%s'" % (msg, stream))
175 175
 
  176
+    def assertNotInOutput(self, stream, msg):
  177
+        "Utility assertion: assert that the given message doesn't exist in the output"
  178
+        self.assertFalse(msg in stream, "'%s' matches actual output text '%s'" % (msg, stream))
  179
+
176 180
 ##########################################################################
177 181
 # DJANGO ADMIN TESTS
178 182
 # This first series of test classes checks the environment processing
@@ -1173,25 +1177,47 @@ def tearDown(self):
1173 1177
         self.remove_settings('settings.py')
1174 1178
 
1175 1179
     def test_version(self):
1176  
-        "--version is handled as a special case"
1177  
-        args = ['--version']
  1180
+        "version is handled as a special case"
  1181
+        args = ['version']
1178 1182
         out, err = self.run_manage(args)
1179 1183
         self.assertNoOutput(err)
1180 1184
         self.assertOutput(out, get_version())
1181 1185
 
  1186
+    def test_version_alternative(self):
  1187
+        "--version is equivalent to version"
  1188
+        args1, args2 = ['version'], ['--version']
  1189
+        self.assertEqual(self.run_manage(args1), self.run_manage(args2))
  1190
+
1182 1191
     def test_help(self):
1183  
-        "--help is handled as a special case"
1184  
-        args = ['--help']
  1192
+        "help is handled as a special case"
  1193
+        args = ['help']
1185 1194
         out, err = self.run_manage(args)
1186 1195
         self.assertOutput(out, "Usage: manage.py subcommand [options] [args]")
1187 1196
         self.assertOutput(out, "Type 'manage.py help <subcommand>' for help on a specific subcommand.")
  1197
+        self.assertOutput(out, '[django]')
  1198
+        self.assertOutput(out, 'startapp')
  1199
+        self.assertOutput(out, 'startproject')
1188 1200
 
1189  
-    def test_short_help(self):
1190  
-        "-h is handled as a short form of --help"
1191  
-        args = ['-h']
  1201
+    def test_help_commands(self):
  1202
+        "help --commands shows the list of all available commands"
  1203
+        args = ['help', '--commands']
1192 1204
         out, err = self.run_manage(args)
1193  
-        self.assertOutput(out, "Usage: manage.py subcommand [options] [args]")
1194  
-        self.assertOutput(out, "Type 'manage.py help <subcommand>' for help on a specific subcommand.")
  1205
+        self.assertNotInOutput(out, 'Usage:')
  1206
+        self.assertNotInOutput(out, 'Options:')
  1207
+        self.assertNotInOutput(out, '[django]')
  1208
+        self.assertOutput(out, 'startapp')
  1209
+        self.assertOutput(out, 'startproject')
  1210
+        self.assertNotInOutput(out, '\n\n')
  1211
+
  1212
+    def test_help_alternative(self):
  1213
+        "--help is equivalent to help"
  1214
+        args1, args2 = ['help'], ['--help']
  1215
+        self.assertEqual(self.run_manage(args1), self.run_manage(args2))
  1216
+
  1217
+    def test_help_short_altert(self):
  1218
+        "-h is handled as a short form of --help"
  1219
+        args1, args2 = ['--help'], ['-h']
  1220
+        self.assertEqual(self.run_manage(args1), self.run_manage(args2))
1195 1221
 
1196 1222
     def test_specific_help(self):
1197 1223
         "--help can be used on a specific command"

0 notes on commit 175e6d7

Please sign in to comment.
Something went wrong with that request. Please try again.