Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Add some docstrings to the base classes for management commands. Refs…

… #9170.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@9082 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 5563362c4c86d1c519bfa4732fed050c232e366a 1 parent 922aba3
James Bennett authored September 22, 2008

Showing 1 changed file with 186 additions and 7 deletions. Show diff stats Hide diff stats

  1. 193  django/core/management/base.py
193  django/core/management/base.py
... ...
@@ -1,3 +1,9 @@
  1
+"""
  2
+Base classes for writing management commands (named commands which can
  3
+be executed through ``django-admin.py`` or ``manage.py``).
  4
+
  5
+"""
  6
+
1 7
 import os
2 8
 import sys
3 9
 from optparse import make_option, OptionParser
@@ -12,13 +18,26 @@
12 18
     from sets import Set as set     # For Python 2.3
13 19
 
14 20
 class CommandError(Exception):
  21
+    """
  22
+    Exception class indicating a problem while executing a management
  23
+    command.
  24
+
  25
+    If this exception is raised during the execution of a management
  26
+    command, it will be caught and turned into a nicely-printed error
  27
+    message to the appropriate output stream (i.e., stderr); as a
  28
+    result, raising this exception (with a sensible description of the
  29
+    error) is the preferred way to indicate that something has gone
  30
+    wrong in the execution of a command.
  31
+    
  32
+    """
15 33
     pass
16 34
 
17 35
 def handle_default_options(options):
18 36
     """
19  
-    Include any default options that all commands should accept
20  
-    here so that ManagementUtility can handle them before searching
21  
-    for user commands.
  37
+    Include any default options that all commands should accept here
  38
+    so that ManagementUtility can handle them before searching for
  39
+    user commands.
  40
+    
22 41
     """
23 42
     if options.settings:
24 43
         os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
@@ -26,6 +45,80 @@ def handle_default_options(options):
26 45
         sys.path.insert(0, options.pythonpath)
27 46
 
28 47
 class BaseCommand(object):
  48
+    """
  49
+    The base class from which all management commands ultimately
  50
+    derive.
  51
+
  52
+    Use this class if you want access to all of the mechanisms which
  53
+    parse the command-line arguments and work out what code to call in
  54
+    response; if you don't need to change any of that behavior,
  55
+    consider using one of the subclasses defined in this file.
  56
+
  57
+    If you are interested in overriding/customizing various aspects of
  58
+    the command-parsing and -execution behavior, the normal flow works
  59
+    as follows:
  60
+
  61
+    1. ``django-admin.py`` or ``manage.py`` loads the command class
  62
+       and calls its ``run_from_argv()`` method.
  63
+
  64
+    2. The ``run_from_argv()`` method calls ``create_parser()`` to get
  65
+       an ``OptionParser`` for the arguments, parses them, performs
  66
+       any environment changes requested by options like
  67
+       ``pythonpath``, and then calls the ``execute()`` method,
  68
+       passing the parsed arguments.
  69
+
  70
+    3. The ``execute()`` method attempts to carry out the command by
  71
+       calling the ``handle()`` method with the parsed arguments; any
  72
+       output produced by ``handle()`` will be printed to standard
  73
+       output and, if the command is intended to produce a block of
  74
+       SQL statements, will be wrapped in ``BEGIN`` and ``COMMIT``.
  75
+
  76
+    4. If ``handle()`` raised a ``ComandError``, ``execute()`` will
  77
+       instead print an error message to ``stderr``.
  78
+
  79
+    Thus, the ``handle()`` method is typically the starting point for
  80
+    subclasses; many built-in commands and command types either place
  81
+    all of their logic in ``handle()``, or perform some additional
  82
+    parsing work in ``handle()`` and then delegate from it to more
  83
+    specialized methods as needed.
  84
+
  85
+    Several attributes affect behavior at various steps along the way:
  86
+    
  87
+    ``args``
  88
+        A string listing the arguments accepted by the command,
  89
+        suitable for use in help messages; e.g., a command which takes
  90
+        a list of application names might set this to '<appname
  91
+        appname ...>'.
  92
+
  93
+    ``can_import_settings``
  94
+        A boolean indicating whether the command needs to be able to
  95
+        import Django settings; if ``True``, ``execute()`` will verify
  96
+        that this is possible before proceeding. Default value is
  97
+        ``True``.
  98
+
  99
+    ``help``
  100
+        A short description of the command, which will be printed in
  101
+        help messages.
  102
+
  103
+    ``option_list``
  104
+        This is the list of ``optparse`` options which will be fed
  105
+        into the command's ``OptionParser`` for parsing arguments.
  106
+
  107
+    ``output_transaction``
  108
+        A boolean indicating whether the command outputs SQL
  109
+        statements; if ``True``, the output will automatically be
  110
+        wrapped with ``BEGIN;`` and ``COMMIT;``. Default value is
  111
+        ``False``.
  112
+
  113
+    ``requires_model_validation``
  114
+        A boolean; if ``True``, validation of installed models will be
  115
+        performed prior to executing the command. Default value is
  116
+        ``True``. To validate an individual application's models
  117
+        rather than all applications' models, call
  118
+        ``self.validate(app)`` from ``handle()``, where ``app`` is the
  119
+        application's Python module.
  120
+    
  121
+    """
29 122
     # Metadata about this command.
30 123
     option_list = (
31 124
         make_option('--settings',
@@ -48,12 +141,19 @@ def __init__(self):
48 141
 
49 142
     def get_version(self):
50 143
         """
51  
-        Returns the Django version, which should be correct for all built-in
52  
-        Django commands. User-supplied commands should override this method.
  144
+        Return the Django version, which should be correct for all
  145
+        built-in Django commands. User-supplied commands should
  146
+        override this method.
  147
+        
53 148
         """
54 149
         return django.get_version()
55 150
 
56 151
     def usage(self, subcommand):
  152
+        """
  153
+        Return a brief description of how to use this command, by
  154
+        default from the attribute ``self.help``.
  155
+        
  156
+        """
57 157
         usage = '%%prog %s [options] %s' % (subcommand, self.args)
58 158
         if self.help:
59 159
             return '%s\n\n%s' % (usage, self.help)
@@ -61,22 +161,45 @@ def usage(self, subcommand):
61 161
             return usage
62 162
 
63 163
     def create_parser(self, prog_name, subcommand):
  164
+        """
  165
+        Create and return the ``OptionParser`` which will be used to
  166
+        parse the arguments to this command.
  167
+        
  168
+        """
64 169
         return OptionParser(prog=prog_name,
65 170
                             usage=self.usage(subcommand),
66 171
                             version=self.get_version(),
67 172
                             option_list=self.option_list)
68 173
 
69 174
     def print_help(self, prog_name, subcommand):
  175
+        """
  176
+        Print the help message for this command, derived from
  177
+        ``self.usage()``.
  178
+        
  179
+        """
70 180
         parser = self.create_parser(prog_name, subcommand)
71 181
         parser.print_help()
72 182
 
73 183
     def run_from_argv(self, argv):
  184
+        """
  185
+        Set up any environment changes requested (e.g., Python path
  186
+        and Django settings), then run this command.
  187
+        
  188
+        """
74 189
         parser = self.create_parser(argv[0], argv[1])
75 190
         options, args = parser.parse_args(argv[2:])
76 191
         handle_default_options(options)
77 192
         self.execute(*args, **options.__dict__)
78 193
 
79 194
     def execute(self, *args, **options):
  195
+        """
  196
+        Try to execute this command, performing model validation if
  197
+        needed (as controlled by the attribute
  198
+        ``self.requires_model_validation``). If the command raises a
  199
+        ``CommandError``, intercept it and print it sensibly to
  200
+        stderr.
  201
+        
  202
+        """
80 203
         # Switch to English, because django-admin.py creates database content
81 204
         # like permissions, and those shouldn't contain any translations.
82 205
         # But only do this if we can assume we have a working settings file,
@@ -110,8 +233,9 @@ def execute(self, *args, **options):
110 233
     def validate(self, app=None, display_num_errors=False):
111 234
         """
112 235
         Validates the given app, raising CommandError for any errors.
113  
-
  236
+        
114 237
         If app is None, then this will validate all installed apps.
  238
+        
115 239
         """
116 240
         from django.core.management.validation import get_validation_errors
117 241
         try:
@@ -128,9 +252,22 @@ def validate(self, app=None, display_num_errors=False):
128 252
             print "%s error%s found" % (num_errors, num_errors != 1 and 's' or '')
129 253
 
130 254
     def handle(self, *args, **options):
  255
+        """
  256
+        The actual logic of the command. Subclasses must implement
  257
+        this method.
  258
+        
  259
+        """
131 260
         raise NotImplementedError()
132 261
 
133 262
 class AppCommand(BaseCommand):
  263
+    """
  264
+    A management command which takes one or more installed application
  265
+    names as arguments, and does something with each of them.
  266
+
  267
+    Rather than implementing ``handle()``, subclasses must implement
  268
+    ``handle_app()``, which will be called once for each application.
  269
+    
  270
+    """
134 271
     args = '<appname appname ...>'
135 272
 
136 273
     def handle(self, *app_labels, **options):
@@ -149,9 +286,27 @@ def handle(self, *app_labels, **options):
149 286
         return '\n'.join(output)
150 287
 
151 288
     def handle_app(self, app, **options):
  289
+        """
  290
+        Perform the command's actions for ``app``, which will be the
  291
+        Python module corresponding to an application name given on
  292
+        the command line.
  293
+        
  294
+        """
152 295
         raise NotImplementedError()
153 296
 
154 297
 class LabelCommand(BaseCommand):
  298
+    """
  299
+    A management command which takes one or more arbitrary arguments
  300
+    (labels) on the command line, and does something with each of
  301
+    them.
  302
+
  303
+    Rather than implementing ``handle()``, subclasses must implement
  304
+    ``handle_label()``, which will be called once for each label.
  305
+
  306
+    If the arguments should be names of installed applications, use
  307
+    ``AppCommand`` instead.
  308
+    
  309
+    """
155 310
     args = '<label label ...>'
156 311
     label = 'label'
157 312
 
@@ -167,9 +322,24 @@ def handle(self, *labels, **options):
167 322
         return '\n'.join(output)
168 323
 
169 324
     def handle_label(self, label, **options):
  325
+        """
  326
+        Perform the command's actions for ``label``, which will be the
  327
+        string as given on the command line.
  328
+        
  329
+        """
170 330
         raise NotImplementedError()
171 331
 
172 332
 class NoArgsCommand(BaseCommand):
  333
+    """
  334
+    A command which takes no arguments on the command line.
  335
+
  336
+    Rather than implementing ``handle()``, subclasses must implement
  337
+    ``handle_noargs()``; ``handle()`` itself is overridden to ensure
  338
+    no arguments are passed to the command.
  339
+
  340
+    Attempting to pass arguments will raise ``CommandError``.
  341
+    
  342
+    """
173 343
     args = ''
174 344
 
175 345
     def handle(self, *args, **options):
@@ -178,12 +348,17 @@ def handle(self, *args, **options):
178 348
         return self.handle_noargs(**options)
179 349
 
180 350
     def handle_noargs(self, **options):
  351
+        """
  352
+        Perform this command's actions.
  353
+        
  354
+        """
181 355
         raise NotImplementedError()
182 356
 
183 357
 def copy_helper(style, app_or_project, name, directory, other_name=''):
184 358
     """
185 359
     Copies either a Django application layout template or a Django project
186 360
     layout template into the specified directory.
  361
+
187 362
     """
188 363
     # style -- A color style object (see django.core.management.color).
189 364
     # app_or_project -- The string 'app' or 'project'.
@@ -236,7 +411,11 @@ def copy_helper(style, app_or_project, name, directory, other_name=''):
236 411
                 sys.stderr.write(style.NOTICE("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new))
237 412
 
238 413
 def _make_writeable(filename):
239  
-    "Makes sure that the file is writeable. Useful if our source is read-only."
  414
+    """
  415
+    Make sure that the file is writeable. Useful if our source is
  416
+    read-only.
  417
+    
  418
+    """
240 419
     import stat
241 420
     if sys.platform.startswith('java'):
242 421
         # On Jython there is no os.access()

0 notes on commit 5563362

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