Ticket #5222: __init__.py.2.diff

File __init__.py.2.diff, 10.4 KB (added by dnordberg@…, 17 years ago)

Diff file of init.py with last line removed.

  • .py

    old new  
    11import django
    22from optparse import OptionParser
    33import os
    44import sys
    55import textwrap
    66
    77# For backwards compatibility: get_version() used to be in this module.
    88get_version = django.get_version
    99
    10 def load_command_class(name):
     10def find_commands(path):
    1111    """
    12     Given a command name, returns the Command class instance. Raises
    13     ImportError if it doesn't exist.
     12    Given a path to a management directory, return a list of all the command names
     13    that are available. Returns an empty list if no commands are defined.
    1414    """
    15     # Let the ImportError propogate.
    16     return getattr(__import__('django.core.management.commands.%s' % name, {}, {}, ['Command']), 'Command')()
     15    command_dir = os.path.join(path, 'commands')
     16    try:
     17        return [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
     18    except OSError:
     19        return []
     20
     21def load_default_commands():
     22    """
     23    Returns a dictionary of instances of all available Command classes.
     24
     25    This works by looking for and loading all Python modules in the
     26    django.core.management.commands package.
     27
     28    The dictionary is in the format {name: command_instance}.
     29    """
     30    return dict([(name, getattr(__import__('django.core.management.commands.%s' % (name), {}, {}, ['Command']), 'Command')()) for name in find_commands(__path__[0])])
     31
     32def load_project_commands():
     33    """
     34    Returns a dictionary of instances of all available Command classes.
     35
     36    It looks for a management.commands package in each installed application
     37    -- if a commands package exists, it loads all commands in that
     38    application and raises an AttributeError if a command doesn't contain a
     39    Command instance.
     40
     41    The dictionary is in the format {name: command_instance}.
     42    """
     43   
     44    commands = {}
     45
     46    from django.db import models
     47   
     48    # Get commands from all installed apps
     49    for app in models.get_apps():
     50        try:
     51            app_name = '.'.join(app.__name__.split('.')[:-1])
     52            path = os.path.join(os.path.dirname(app.__file__),'management')
     53            commands.update(dict([(name, getattr(__import__('%s.management.commands.%s' % (app_name, name), {}, {}, ['Command']), 'Command')()) for name in find_commands(path)]))
     54        except AttributeError:
     55            sys.stderr.write("Management command '%s' in application '%s' doesn't contain a Command instance.\n" % (name, app_name))
     56            sys.exit(1)
     57           
     58    return commands
    1759
    1860def call_command(name, *args, **options):
    1961    """
    2062    Calls the given command, with the given options and args/kwargs.
    2163   
    2264    This is the primary API you should use for calling specific commands.
    2365   
    2466    Some examples:
    2567        call_command('syncdb')
    2668        call_command('shell', plain=True)
    2769        call_command('sqlall', 'myapp')
    2870    """
    29     klass = load_command_class(name)
     71    klass = getattr(__import__(_DJANGO_COMMANDS[name].__module__, {}, {}, ['Command']), 'Command')()
    3072    return klass.execute(*args, **options)
    3173
    3274class ManagementUtility(object):
    3375    """
    3476    Encapsulates the logic of the django-admin.py and manage.py utilities.
    3577
    3678    A ManagementUtility has a number of commands, which can be manipulated
    3779    by editing the self.commands dictionary.
    3880    """
    3981    def __init__(self):
    40         self.commands = self.default_commands()
    41 
    42     def default_commands(self):
    43         """
    44         Returns a dictionary of instances of all available Command classes.
    45 
    46         This works by looking for and loading all Python modules in the
    47         django.core.management.commands package.
    48 
    49         The dictionary is in the format {name: command_instance}.
    50         """
    51         command_dir = os.path.join(__path__[0], 'commands')
    52         names = [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
    53         return dict([(name, load_command_class(name)) for name in names])
    54 
     82        self.commands = _DJANGO_COMMANDS
     83       
    5584    def usage(self):
    5685        """
    5786        Returns a usage string, for use with optparse.
    5887
    5988        The string doesn't include the options (e.g., "--verbose"), because
    6089        optparse puts those in automatically.
    6190        """
    6291        usage = ["%prog command [options]\nactions:"]
    6392        commands = self.commands.items()
    6493        commands.sort()
    6594        for name, cmd in commands:
    6695            usage.append('  %s %s' % (name, cmd.args))
    6796            usage.extend(textwrap.wrap(cmd.help, initial_indent='    ', subsequent_indent='    '))
    6897            usage.append('')
    6998        return '\n'.join(usage[:-1]) # Cut off the last list element, an empty space.
    7099
    71100    def execute(self, argv=None):
    72101        """
    73102        Parses the given argv from the command line, determines which command
    74103        to run and runs the command.
    75104        """
    76105        if argv is None:
    77106            argv = sys.argv
    78107
    79108        # Create the parser object and parse the command-line args.
    80109        # TODO: Ideally each Command class would register its own options for
    81110        # add_option(), but we'd need to figure out how to allow for multiple
    82111        # Commands using the same options. The optparse library gets in the way
    83112        # by checking for conflicts:
    84113        # http://docs.python.org/lib/optparse-conflicts-between-options.html
    85114        parser = OptionParser(usage=self.usage(), version=get_version())
    86115        parser.add_option('--settings',
    87116            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.')
    88117        parser.add_option('--pythonpath',
    89118            help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".')
    90119        parser.add_option('--plain', action='store_true', dest='plain',
    91120            help='When using "shell": Tells Django to use plain Python, not IPython.')
    92121        parser.add_option('--noinput', action='store_false', dest='interactive', default=True,
    93122            help='Tells Django to NOT prompt the user for input of any kind.')
    94123        parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True,
    95124            help='When using "runserver": Tells Django to NOT use the auto-reloader.')
    96125        parser.add_option('--format', default='json', dest='format',
    97126            help='Specifies the output serialization format for fixtures')
    98127        parser.add_option('--indent', default=None, dest='indent',
    99128            type='int', help='Specifies the indent level to use when pretty-printing output')
    100129        parser.add_option('--verbosity', action='store', dest='verbosity', default='1',
    101130            type='choice', choices=['0', '1', '2'],
    102131            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output')
    103132        parser.add_option('--adminmedia', dest='admin_media_path', default='',
    104133            help='When using "runserver": Specifies the directory from which to serve admin media.')
    105134        options, args = parser.parse_args(argv[1:])
    106135
    107136        # If the 'settings' or 'pythonpath' options were submitted, activate those.
    108137        if options.settings:
    109138            os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
    110139        if options.pythonpath:
    111140            sys.path.insert(0, options.pythonpath)
    112141
    113142        # Run the appropriate command.
    114143        try:
    115144            command_name = args[0]
    116145        except IndexError:
    117146            sys.stderr.write("Type '%s --help' for usage.\n" % os.path.basename(argv[0]))
    118147            sys.exit(1)
    119148        try:
    120149            command = self.commands[command_name]
    121150        except KeyError:
    122151            sys.stderr.write("Unknown command: %r\nType '%s --help' for usage.\n" % (command_name, os.path.basename(argv[0])))
    123152            sys.exit(1)
    124153        command.execute(*args[1:], **options.__dict__)
    125154
    126155class ProjectManagementUtility(ManagementUtility):
    127156    """
    128157    A ManagementUtility that is specific to a particular Django project.
    129158    As such, its commands are slightly different than those of its parent
    130159    class.
    131160
    132161    In practice, this class represents manage.py, whereas ManagementUtility
    133162    represents django-admin.py.
    134163    """
    135164    def __init__(self, project_directory):
    136165        super(ProjectManagementUtility, self).__init__()
    137166
    138167        # Remove the "startproject" command from self.commands, because
    139168        # that's a django-admin.py command, not a manage.py command.
    140169        del self.commands['startproject']
    141170
    142171        # Override the startapp command so that it always uses the
    143172        # project_directory, not the current working directory (which is default).
    144173        from django.core.management.commands.startapp import ProjectCommand
    145174        self.commands['startapp'] = ProjectCommand(project_directory)
    146175
    147176def setup_environ(settings_mod):
    148177    """
    149178    Configure the runtime environment. This can also be used by external
    150179    scripts wanting to set up a similar environment to manage.py.
    151180    """
    152181    # Add this project to sys.path so that it's importable in the conventional
    153182    # way. For example, if this file (manage.py) lives in a directory
    154183    # "myproject", this code would add "/path/to/myproject" to sys.path.
    155184    project_directory, settings_filename = os.path.split(settings_mod.__file__)
    156185    project_name = os.path.basename(project_directory)
    157186    settings_name = os.path.splitext(settings_filename)[0]
    158187    sys.path.append(os.path.join(project_directory, '..'))
    159188    project_module = __import__(project_name, {}, {}, [''])
    160189    sys.path.pop()
    161190
    162191    # Set DJANGO_SETTINGS_MODULE appropriately.
    163192    os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name)
     193   
     194    # Update default commands with project commands for django internal
     195    # webservers and the manage.py utility
     196    _DJANGO_COMMANDS.update(load_project_commands())
     197   
    164198    return project_directory
    165199
    166200def execute_from_command_line(argv=None):
    167201    """
    168202    A simple method that runs a ManagementUtility.
    169203    """
    170204    utility = ManagementUtility()
    171205    utility.execute(argv)
    172206
    173207def execute_manager(settings_mod, argv=None):
    174208    """
    175209    Like execute_from_command_line(), but for use by manage.py, a
    176210    project-specific django-admin.py utility.
    177211    """
    178212    project_directory = setup_environ(settings_mod)
    179213    utility = ProjectManagementUtility(project_directory)
    180214    utility.execute(argv)
     215   
     216# Add default commands to a dict
     217_DJANGO_COMMANDS = load_default_commands()
     218
     219
Back to Top