Ticket #5369: command.patch

File command.patch, 21.0 KB (added by toddobryan@…, 8 years ago)

patch implementing the refactoring

  • home/tobryan1/workspace/django/django/core/management/__init__.py

    Property changes on: /home/tobryan1/workspace/django
    ___________________________________________________________________
    Name: svn:ignore
       - build
    dist
    *.egg-info
    MANIFEST
    
       + build
    dist
    *.egg-info
    MANIFEST
    .settings
    .project
    .pydevproject
    
    
     
    5252        names = [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
    5353        return dict([(name, load_command_class(name)) for name in names])
    5454
    55     def usage(self):
    56         """
    57         Returns a usage string, for use with optparse.
    58 
    59         The string doesn't include the options (e.g., "--verbose"), because
    60         optparse puts those in automatically.
    61         """
    62         usage = ["%prog command [options]\nactions:"]
     55    def print_help(self, argv):
     56        prog_name = os.path.basename(argv[0])
     57        usage = ['%s <subcommand> [options] [args]' % prog_name]
     58        usage.append('Django command line tool, version %s' % django.get_version())
     59        usage.append("Type '%s help <subcommand>' for help on a specific subcommand." % prog_name)
     60        usage.append('Available subcommands:')
    6361        commands = self.commands.items()
    6462        commands.sort()
    6563        for name, cmd in commands:
    66             usage.append('  %s %s' % (name, cmd.args))
    67             usage.extend(textwrap.wrap(cmd.help, initial_indent='    ', subsequent_indent='    '))
    68             usage.append('')
    69         return '\n'.join(usage[:-1]) # Cut off the last list element, an empty space.
     64            usage.append('  %s' % name)
     65        print '\n'.join(usage)
     66       
     67    def fetch_command(self, subcommand, command_name):
     68        """
     69        Tries to fetch the given subcommand, printing a message with the
     70        appropriate command called from the command line (usually
     71        django-admin.py or manage.py) if it can't be found
     72        """
     73        try:
     74            return self.commands[subcommand]
     75        except KeyError:
     76            sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % (subcommand, command_name))
     77            sys.exit(1)
    7078
    7179    def execute(self, argv=None):
    7280        """
    73         Parses the given argv from the command line, determines which command
    74         to run and runs the command.
     81        Figures out which command is being run (the first arg), creates a parser
     82        appropriate to that command, and runs it
    7583        """
    7684        if argv is None:
    7785            argv = sys.argv
    78 
    79         # Create the parser object and parse the command-line args.
    80         # TODO: Ideally each Command class would register its own options for
    81         # add_option(), but we'd need to figure out how to allow for multiple
    82         # Commands using the same options. The optparse library gets in the way
    83         # by checking for conflicts:
    84         # http://docs.python.org/lib/optparse-conflicts-between-options.html
    85         parser = OptionParser(usage=self.usage(), version=get_version())
    86         parser.add_option('--settings',
    87             help='The Python path to a settings module, e.g. "myproject.settings.main". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.')
    88         parser.add_option('--pythonpath',
    89             help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".')
    90         parser.add_option('--plain', action='store_true', dest='plain',
    91             help='When using "shell": Tells Django to use plain Python, not IPython.')
    92         parser.add_option('--noinput', action='store_false', dest='interactive', default=True,
    93             help='Tells Django to NOT prompt the user for input of any kind.')
    94         parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True,
    95             help='When using "runserver": Tells Django to NOT use the auto-reloader.')
    96         parser.add_option('--format', default='json', dest='format',
    97             help='Specifies the output serialization format for fixtures')
    98         parser.add_option('--indent', default=None, dest='indent',
    99             type='int', help='Specifies the indent level to use when pretty-printing output')
    100         parser.add_option('--verbosity', action='store', dest='verbosity', default='1',
    101             type='choice', choices=['0', '1', '2'],
    102             help='Verbosity level; 0=minimal output, 1=normal output, 2=all output')
    103         parser.add_option('--adminmedia', dest='admin_media_path', default='',
    104             help='When using "runserver": Specifies the directory from which to serve admin media.')
    105         options, args = parser.parse_args(argv[1:])
    106 
    107         # If the 'settings' or 'pythonpath' options were submitted, activate those.
    108         if options.settings:
    109             os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
    110         if options.pythonpath:
    111             sys.path.insert(0, options.pythonpath)
    112 
    113         # Run the appropriate command.
    11486        try:
    115             command_name = args[0]
     87            command_name = argv[1]
    11688        except IndexError:
    117             sys.stderr.write("Type '%s --help' for usage.\n" % os.path.basename(argv[0]))
     89            sys.stderr.write("Type '%s help' for usage.\n" % os.path.basename(argv[0]))
    11890            sys.exit(1)
    119         try:
    120             command = self.commands[command_name]
    121         except KeyError:
    122             sys.stderr.write("Unknown command: %r\nType '%s --help' for usage.\n" % (command_name, os.path.basename(argv[0])))
    123             sys.exit(1)
    124         command.execute(*args[1:], **options.__dict__)
     91        if command_name == 'help':
     92            if len(argv) > 2:
     93                self.fetch_command(argv[2], argv[0]).print_help(argv[2:])
     94            else:
     95                self.print_help(argv)
     96        else:
     97            self.fetch_command(command_name, argv[0]).run(argv[1:])
     98       
    12599
    126100class ProjectManagementUtility(ManagementUtility):
    127101    """
  • home/tobryan1/workspace/django/django/core/management/base.py

     
     1import django
    12from django.core.exceptions import ImproperlyConfigured
    23from django.core.management.color import color_style
     4
     5import itertools
     6from optparse import make_option, OptionParser
    37import sys
    48import os
     9from traceback import print_exc
    510
    611class CommandError(Exception):
    712    pass
     
    813
    914class BaseCommand(object):
    1015    # Metadata about this command.
     16    option_list = (
     17        make_option('--settings',
     18                    help='The Python path to a settings module, e.g. "myproject.settings.main". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.'),
     19        make_option('--pythonpath',
     20                    help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".'),
     21    )
    1122    help = ''
    1223    args = ''
    1324
     
    1829
    1930    def __init__(self):
    2031        self.style = color_style()
     32   
     33    def get_version(self):
     34        """
     35        returns the Django version, which should be correct for all built-in
     36        Django commands. User-supplied commands should override this method.
     37        """
     38        return django.get_version()
     39   
     40    def usage(self):
     41        usage = '%prog [options] ' + self.args
     42        if self.help:
     43            return '%s\n%s' % (self.help, usage)
     44        else:
     45            return usage
     46   
     47    @classmethod
     48    def get_option_list(cls):
     49        """
     50        Builds up a list of parameters to the OptionParser.add_option command
     51        by recursively adding option parameters up the class hierarchy. Requires
     52        BaseCommand subclasses to only extend a single superclass.
     53        """
     54        if cls is BaseCommand:
     55            option_list = BaseCommand.option_list
     56        else:
     57            option_list = cls.__base__.get_option_list()
     58        if cls.option_list is option_list:
     59            return option_list
     60        else:
     61            # this class adds new option_params not in superclasses
     62            # get a list of all options so far
     63            opt_strs = list(itertools.chain(*[op._short_opts + op._long_opts for op in option_list]))
     64            # check for duplicates
     65            for option in cls.option_list:
     66                strs = option._short_opts + option._long_opts
     67                for opt_str in strs:
     68                    if opt_str in opt_strs:
     69                        raise CommandError("%s attempts to redefine the option '%s', which appears in a superclass." %
     70                                       (cls, opt_str))
     71            return option_list + cls.option_list           
     72       
     73    def create_parser(self, prog_name):
     74        return OptionParser(prog=prog_name,
     75                            usage=self.usage(),
     76                            version=self.get_version(),
     77                            option_list=self.__class__.get_option_list())
     78       
     79    def print_help(self, args):
     80        parser = self.create_parser(args[0])
     81        parser.print_help()
     82           
     83    def run(self, args):
     84        parser = self.create_parser(args[0])
     85        (options, args) = parser.parse_args(args[1:])
     86        if options.settings:
     87            os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
     88        if options.pythonpath:
     89            sys.path.insert(0, options.pythonpath)
     90        try:
     91            self.execute(*args, **options.__dict__)
     92        except Exception, e:
     93            print_exc()
     94            parser.print_usage()
    2195
    2296    def execute(self, *args, **options):
    2397        # Switch to English, because django-admin.py creates database content
     
    119193
    120194    def handle_noargs(self, **options):
    121195        raise NotImplementedError()
    122 
     196   
    123197def copy_helper(style, app_or_project, name, directory, other_name=''):
    124198    import django
    125199    import re
  • home/tobryan1/workspace/django/django/core/management/commands/dumpdata.py

     
    11from django.core.management.base import BaseCommand, CommandError
    22
     3from optparse import make_option
     4
    35class Command(BaseCommand):
     6    option_list = (
     7        make_option('--format', default='json', dest='format',
     8            help='Specifies the output serialization format for fixtures'),
     9        make_option('--indent', default=None, dest='indent', type='int',
     10            help='Specifies the indent level to use when pretty-printing output'),
     11    )
    412    help = 'Output the contents of the database as a fixture of the given format.'
    5     args = '[--format] [--indent] [appname ...]'
     13    args = '[appname ...]'
    614
    715    def handle(self, *app_labels, **options):
    816        from django.db.models import get_app, get_apps, get_models
  • home/tobryan1/workspace/django/django/core/management/commands/flush.py

     
    11from django.core.management.base import NoArgsCommand, CommandError
    22from django.core.management.color import no_style
    33
     4from optparse import make_option
     5
    46class Command(NoArgsCommand):
     7    option_list = (
     8        make_option('--verbosity', action='store', dest='verbosity', default='1',
     9            type='choice', choices=['0', '1', '2'],
     10            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
     11        make_option('--noinput', action='store_false', dest='interactive', default=True,
     12            help='Tells Django to NOT prompt the user for input of any kind.'),
     13    )
    514    help = "Executes ``sqlflush`` on the current database."
    6     args = '[--verbosity] [--noinput]'
    715
    816    def handle_noargs(self, **options):
    917        from django.conf import settings
  • home/tobryan1/workspace/django/django/core/management/commands/loaddata.py

     
    11from django.core.management.base import BaseCommand
    22from django.core.management.color import no_style
     3
     4from optparse import make_option
    35import sys
    46import os
    57
     
    911    from sets import Set as set   # Python 2.3 fallback
    1012
    1113class Command(BaseCommand):
     14    option_list = (
     15        make_option('--verbosity', action='store', dest='verbosity', default='1',
     16            type='choice', choices=['0', '1', '2'],
     17            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
     18        )
    1219    help = 'Installs the named fixture(s) in the database.'
    13     args = "[--verbosity] fixture, fixture, ..."
     20    args = "fixture [fixture ...]"
    1421
    1522    def handle(self, *fixture_labels, **options):
    1623        from django.db.models import get_apps
  • home/tobryan1/workspace/django/django/core/management/commands/reset.py

     
    11from django.core.management.base import AppCommand, CommandError
    22from django.core.management.color import no_style
    33
     4from optparse import make_option
     5
    46class Command(AppCommand):
     7    option_list = (
     8        make_option('--noinput', action='store_false', dest='interactive', default=True,
     9            help='Tells Django to NOT prompt the user for input of any kind.'),
     10    )
    511    help = "Executes ``sqlreset`` for the given app(s) in the current database."
    6     args = '[--noinput] [appname ...]'
     12    args = '[appname ...]'
    713
    814    output_transaction = True
    915
  • home/tobryan1/workspace/django/django/core/management/commands/runfcgi.py

     
    1414            pass
    1515        from django.core.servers.fastcgi import runfastcgi
    1616        runfastcgi(args)
     17       
     18    def usage(self):
     19        from django.core.servers.fastcgi import FASTCGI_HELP
     20        return FASTCGI_HELP
  • home/tobryan1/workspace/django/django/core/management/commands/runserver.py

     
    11from django.core.management.base import BaseCommand, CommandError
     2
     3from optparse import make_option
    24import os
    35import sys
    46
     
    35import sys
    46
    57class Command(BaseCommand):
     8    option_list = (
     9        make_option('--noreload', action='store_false', dest='use_reloader', default=True,
     10            help='When using "runserver": Tells Django to NOT use the auto-reloader.'),
     11        make_option('--adminmedia', dest='admin_media_path', default='',
     12            help='When using "runserver": Specifies the directory from which to serve admin media.'),
     13    )
    614    help = "Starts a lightweight Web server for development."
    7     args = '[--noreload] [--adminmedia=ADMIN_MEDIA_PATH] [optional port number, or ipaddr:port]'
     15    args = '[optional port number, or ipaddr:port]'
    816
    917    # Validation is called explicitly each time the server is reloaded.
    1018    requires_model_validation = False
  • home/tobryan1/workspace/django/django/core/management/commands/shell.py

     
    11from django.core.management.base import NoArgsCommand
    22
     3from optparse import make_option
     4
    35class Command(NoArgsCommand):
     6    option_list = (
     7        make_option('--plain', action='store_true', dest='plain',
     8            help='When using "shell": Tells Django to use plain Python, not IPython.'),
     9    )
    410    help = "Runs a Python interactive interpreter. Tries to use IPython, if it's available."
    5     args = '[--plain]'
    611
    712    requires_model_validation = False
    813
  • home/tobryan1/workspace/django/django/core/management/commands/syncdb.py

     
    11from django.core.management.base import NoArgsCommand
    22from django.core.management.color import no_style
     3
     4from optparse import make_option
    35import sys
    46
    57try:
     
    810    from sets import Set as set   # Python 2.3 fallback
    911
    1012class Command(NoArgsCommand):
     13    option_list = (
     14        make_option('--verbosity', action='store', dest='verbosity', default='1',
     15            type='choice', choices=['0', '1', '2'],
     16            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
     17        make_option('--noinput', action='store_false', dest='interactive', default=True,
     18            help='Tells Django to NOT prompt the user for input of any kind.'),
     19    )
    1120    help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
    12     args = '[--verbosity] [--noinput]'
    1321
    1422    def handle_noargs(self, **options):
    1523        from django.db import connection, transaction, models
  • home/tobryan1/workspace/django/django/core/management/commands/test.py

     
    11from django.core.management.base import BaseCommand
     2
     3from optparse import make_option
    24import sys
    35
    46class Command(BaseCommand):
     7    option_list = (
     8        make_option('--verbosity', action='store', dest='verbosity', default='1',
     9            type='choice', choices=['0', '1', '2'],
     10            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
     11        make_option('--noinput', action='store_false', dest='interactive', default=True,
     12            help='Tells Django to NOT prompt the user for input of any kind.'),
     13    )
    514    help = 'Runs the test suite for the specified applications, or the entire site if no apps are specified.'
    6     args = '[--verbosity] [--noinput] [appname ...]'
     15    args = '[appname ...]'
    716
    817    requires_model_validation = False
    918
  • home/tobryan1/workspace/django/django/core/management/commands/testserver.py

     
    11from django.core.management.base import BaseCommand
    22
     3from optparse import make_option
     4
    35class Command(BaseCommand):
     6    option_list = (
     7        make_option('--verbosity', action='store', dest='verbosity', default='1',
     8            type='choice', choices=['0', '1', '2'],
     9            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
     10    )
    411    help = 'Runs a development server with data from the given fixture(s).'
    512    args = '[fixture ...]'
    613
  • home/tobryan1/workspace/django/django/core/servers/fastcgi.py

     
    1717__version__ = "0.1"
    1818__all__ = ["runfastcgi"]
    1919
    20 FASTCGI_HELP = r"""runfcgi:
     20FASTCGI_HELP = r"""
    2121  Run this project as a fastcgi (or some other protocol supported
    2222  by flup) application. To do this, the flup package from
    2323  http://www.saddi.com/software/flup/ is required.
     
    2222  by flup) application. To do this, the flup package from
    2323  http://www.saddi.com/software/flup/ is required.
    2424
    25 Usage:
    26    django-admin.py runfcgi --settings=yourproject.settings [fcgi settings]
    27    manage.py runfcgi [fcgi settings]
     25   runfcgi [options] [fcgi settings]
    2826
    2927Optional Fcgi settings: (setting=value)
    3028  protocol=PROTOCOL    fcgi, scgi, ajp, ... (default fcgi)
Back to Top