from django.core.management import setup_environ from optparse import OptionParser import os import sys import textwrap import logging _PATH_TO_DJANGO_MANAGEMENT="../django/core/management" try: import settings # Assumed to be in the same directory. except ImportError: sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) sys.exit(1) _DJANGO_COMMANDS = {} def find_commands(path): """ Given a path to a management directory, return a list of all the command names that are available. Returns an empty list if no commands are defined. """ command_dir = os.path.join(path, 'commands') try: return [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')] except OSError: return [] def load_command_class(name, module=None): """ Given a command name, returns the Command class instance. Raises Raises ImportError if a command module doesn't exist, or AttributeError if a command module doesn't include . """ # Let any errors propogate. if module: return getattr(__import__('%s.management.commands.%s' % (module, name), {}, {}, ['Command']), 'Command')() else: return getattr(__import__('django.core.management.commands.%s' % (name ), {}, {}, ['Command']), 'Command')() def call_command(name, *args, **options): """ Calls the given command, with the given options and args/kwargs. This is the primary API you should use for calling specific commands. Some examples: call_command('syncdb') call_command('shell', plain=True) call_command('sqlall', 'myapp') """ klass = getattr(__import__(_DJANGO_COMMANDS[name].__module__, {}, {}, ['Command']), 'Command')() return klass.execute(*args, **options) class ManagementUtility(object): """ Encapsulates the logic of the django-admin.py and manage.py utilities. A ManagementUtility has a number of commands, which can be manipulated by editing the self.commands dictionary. """ def __init__(self): self.commands = self.default_commands() def default_commands(self): """ Returns a dictionary of instances of all available Command classes. This works by looking for and loading all Python modules in the django.core.management.commands package. The dictionary is in the format {name: command_instance}. """ command_dir = os.path.join(_PATH_TO_DJANGO_MANAGEMENT, 'commands') names = [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')] commands = dict([(name, load_command_class(name)) for name in names]) _DJANGO_COMMANDS = commands return commands class ProjectManagementUtility(ManagementUtility): """ Encapsulates the logic of the django-admin.py and manage.py utilities. A ManagementUtility has a number of commands, which can be manipulated by editing the self.commands dictionary. """ def __init__(self): self.commands = {} self.commands = self.default_commands() def default_commands(self): """ Returns a dictionary of instances of all available Command classes. This works by looking for and loading all Python modules in the django.core.management.commands package. It also looks for a management.commands package in each installed application -- if a commands package exists, it loads all commands in that application. The dictionary is in the format {name: command_instance}. """ from django.db import models # Base command set #commands = super(ProjectManagementUtility, self).default_commands() commands = {} # Get commands from all installed apps for app in models.get_apps(): try: app_name = '.'.join(app.__name__.split('.')[:-1]) path = os.path.join(os.path.dirname(app.__file__),'management') commands.update(dict([(name, load_command_class(name, app_name)) for name in find_commands(path)])) except AttributeError: sys.stderr.write("Management command '%s' in application '%s' doesn't contain a Command instance.\n" % (name, app_name)) sys.exit(1) _DJANGO_COMMANDS = commands return commands def usage(self): """ Returns a usage string, for use with optparse. The string doesn't include the options (e.g., "--verbose"), because optparse puts those in automatically. """ usage = ["%prog command [options]\nactions:"] commands = self.commands.items() commands.sort() for name, cmd in commands: usage.append(' %s %s' % (name, cmd.args)) usage.extend(textwrap.wrap(cmd.help, initial_indent=' ', subsequent_indent=' ')) usage.append('') return '\n'.join(usage[:-1]) # Cut off the last list element, an empty space. def execute(self, argv=None): """ Parses the given argv from the command line, determines which command to run and runs the command. """ if argv is None: argv = sys.argv parser = OptionParser(usage=self.usage()) parser.add_option("--log", action="store", type="string", dest="logfile", default=None, help="Log messages to a file."), parser.add_option('--settings', 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.') parser.add_option('--pythonpath', help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".') parser.add_option('--format', default='json', dest='format', help='Specifies the output serialization format for fixtures') parser.add_option('--indent', default=None, dest='indent', type='int', help='Specifies the indent level to use when pretty-printing output') parser.add_option('--verbosity', action='store', dest='verbosity', default='1', type='choice', choices=['0', '1', '2'], help='Verbosity level; 0=minimal output, 1=normal output, 2=all output') options, args = parser.parse_args(argv[1:]) # If the 'settings' or 'pythonpath' options were submitted, activate those. if options.settings: os.environ['DJANGO_SETTINGS_MODULE'] = options.settings if options.pythonpath: sys.path.insert(0, options.pythonpath) # Set logging level = logging.INFO i = 0 while i < int(options.verbosity): level -= 10 i += 1 logging.basicConfig(level=level, format='%(asctime)s | %(levelname)s | %(message)s', datefmt='%d-%m %H:%M', filename=options.logfile, filemode='w+') try: command_name = args[0] except IndexError: sys.stderr.write("Type '%s --help' for usage.\n" % os.path.basename(argv[0])) sys.exit(1) try: command = self.commands[command_name] except KeyError: sys.stderr.write("Unknown command: %r\nType '%s --help' for usage.\n" % (command_name, os.path.basename(argv[0]))) sys.exit(1) command.execute(*args[1:], **options.__dict__) def execute_from_custom_command_line(settings_mod, argv=None): """ A simple method that runs a ManagementUtility. """ setup_environ(settings_mod) utility = ProjectManagementUtility() utility.execute(argv) if __name__ == "__main__": execute_from_custom_command_line(settings)