1
0
mirror of https://github.com/django/django.git synced 2025-10-25 14:46:09 +00:00

Fixed #5369 -- Refactored the django-admin.py help system, allowing each subcommand to register its own options. Thanks for the patch, Todd O'Bryan

git-svn-id: http://code.djangoproject.com/svn/django/trunk@6075 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty
2007-09-09 21:57:59 +00:00
parent 6f0bc3d02b
commit 71504127fd
15 changed files with 389 additions and 211 deletions

View File

@@ -18,9 +18,9 @@ def load_command_class(name):
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)
@@ -52,76 +52,59 @@ class ManagementUtility(object):
names = [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
return dict([(name, load_command_class(name)) for name in names])
def usage(self):
def print_help(self, argv):
"""
Returns a usage string, for use with optparse.
The string doesn't include the options (e.g., "--verbose"), because
optparse puts those in automatically.
Returns the help message, as a string.
"""
usage = ["%prog command [options]\nactions:"]
commands = self.commands.items()
prog_name = os.path.basename(argv[0])
usage = ['%s <subcommand> [options] [args]' % prog_name]
usage.append('Django command line tool, version %s' % django.get_version())
usage.append("Type '%s help <subcommand>' for help on a specific subcommand." % prog_name)
usage.append('Available subcommands:')
commands = self.commands.keys()
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.
for cmd in commands:
usage.append(' %s' % cmd)
print '\n'.join(usage)
def fetch_command(self, subcommand, command_name):
"""
Tries to fetch the given subcommand, printing a message with the
appropriate command called from the command line (usually
django-admin.py or manage.py) if it can't be found.
"""
try:
return self.commands[subcommand]
except KeyError:
sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % (subcommand, command_name))
sys.exit(1)
def execute(self, argv=None):
"""
Parses the given argv from the command line, determines which command
to run and runs the command.
Figures out which command is being run (the first arg), creates a parser
appropriate to that command, and runs it.
"""
if argv is None:
argv = sys.argv
# Create the parser object and parse the command-line args.
# TODO: Ideally each Command class would register its own options for
# add_option(), but we'd need to figure out how to allow for multiple
# Commands using the same options. The optparse library gets in the way
# by checking for conflicts:
# http://docs.python.org/lib/optparse-conflicts-between-options.html
parser = OptionParser(usage=self.usage(), version=get_version())
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('--plain', action='store_true', dest='plain',
help='When using "shell": Tells Django to use plain Python, not IPython.')
parser.add_option('--noinput', action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.')
parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True,
help='When using "runserver": Tells Django to NOT use the auto-reloader.')
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')
parser.add_option('--adminmedia', dest='admin_media_path', default='',
help='When using "runserver": Specifies the directory from which to serve admin media.')
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)
# Run the appropriate command.
try:
command_name = args[0]
command_name = argv[1]
except IndexError:
sys.stderr.write("Type '%s --help' for usage.\n" % os.path.basename(argv[0]))
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__)
if command_name == 'help':
if len(argv) > 2:
self.fetch_command(argv[2], argv[0]).print_help(argv[2:])
else:
self.print_help(argv)
# Special-cases: We want 'django-admin.py --version' and
# 'django-admin.py --help' to work, for backwards compatibility.
elif argv[1:] == ['--version']:
print django.get_version()
elif argv[1:] == ['--help']:
self.print_help(argv)
else:
self.fetch_command(command_name, argv[0]).run(argv[1:])
class ProjectManagementUtility(ManagementUtility):
"""

View File

@@ -1,13 +1,23 @@
import django
from django.core.exceptions import ImproperlyConfigured
from django.core.management.color import color_style
import itertools
from optparse import make_option, OptionParser
import sys
import os
from traceback import print_exc
class CommandError(Exception):
pass
class BaseCommand(object):
# Metadata about this command.
option_list = (
make_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.'),
make_option('--pythonpath',
help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".'),
)
help = ''
args = ''
@@ -19,6 +29,43 @@ class BaseCommand(object):
def __init__(self):
self.style = color_style()
def get_version(self):
"""
Returns the Django version, which should be correct for all built-in
Django commands. User-supplied commands should override this method.
"""
return django.get_version()
def usage(self):
usage = '%prog [options] ' + self.args
if self.help:
return '%s\n\n%s' % (usage, self.help)
else:
return usage
def create_parser(self, prog_name):
return OptionParser(prog=prog_name,
usage=self.usage(),
version=self.get_version(),
option_list=self.option_list)
def print_help(self, args):
parser = self.create_parser(args[0])
parser.print_help()
def run(self, args):
parser = self.create_parser(args[0])
(options, args) = parser.parse_args(args[1:])
if options.settings:
os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
if options.pythonpath:
sys.path.insert(0, options.pythonpath)
try:
self.execute(*args, **options.__dict__)
except Exception, e:
print_exc()
parser.print_usage()
def execute(self, *args, **options):
# Switch to English, because django-admin.py creates database content
# like permissions, and those shouldn't contain any translations.
@@ -69,7 +116,7 @@ class BaseCommand(object):
raise NotImplementedError()
class AppCommand(BaseCommand):
args = '[appname ...]'
args = '<appname appname ...>'
def handle(self, *app_labels, **options):
from django.db import models
@@ -90,7 +137,7 @@ class AppCommand(BaseCommand):
raise NotImplementedError()
class LabelCommand(BaseCommand):
args = '[label ...]'
args = '<label label ...>'
label = 'label'
def handle(self, *labels, **options):
@@ -168,4 +215,3 @@ def _make_writeable(filename):
st = os.stat(filename)
new_permissions = stat.S_IMODE(st.st_mode) | stat.S_IWUSR
os.chmod(filename, new_permissions)

View File

@@ -2,7 +2,7 @@ from django.core.management.base import LabelCommand
class Command(LabelCommand):
help = "Creates the table needed to use the SQL cache backend."
args = "[tablename]"
args = "<tablename>"
label = 'tablename'
requires_model_validation = False

View File

@@ -1,8 +1,16 @@
from django.core.management.base import BaseCommand, CommandError
from optparse import make_option
class Command(BaseCommand):
option_list = (
make_option('--format', default='json', dest='format',
help='Specifies the output serialization format for fixtures'),
make_option('--indent', default=None, dest='indent', type='int',
help='Specifies the indent level to use when pretty-printing output'),
)
help = 'Output the contents of the database as a fixture of the given format.'
args = '[--format] [--indent] [appname ...]'
args = '[appname ...]'
def handle(self, *app_labels, **options):
from django.db.models import get_app, get_apps, get_models

View File

@@ -1,9 +1,16 @@
from django.core.management.base import NoArgsCommand, CommandError
from django.core.management.color import no_style
from optparse import make_option
class Command(NoArgsCommand):
option_list = NoArgsCommand.option_list + (
make_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'),
make_option('--noinput', action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.'),
)
help = "Executes ``sqlflush`` on the current database."
args = '[--verbosity] [--noinput]'
def handle_noargs(self, **options):
from django.conf import settings

View File

@@ -1,5 +1,6 @@
from django.core.management.base import BaseCommand
from django.core.management.color import no_style
from optparse import make_option
import sys
import os
@@ -9,8 +10,13 @@ except NameError:
from sets import Set as set # Python 2.3 fallback
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
make_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'),
)
help = 'Installs the named fixture(s) in the database.'
args = "[--verbosity] fixture, fixture, ..."
args = "fixture [fixture ...]"
def handle(self, *fixture_labels, **options):
from django.db.models import get_apps

View File

@@ -1,9 +1,14 @@
from django.core.management.base import AppCommand, CommandError
from django.core.management.color import no_style
from optparse import make_option
class Command(AppCommand):
option_list = AppCommand.option_list + (
make_option('--noinput', action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.'),
)
help = "Executes ``sqlreset`` for the given app(s) in the current database."
args = '[--noinput] [appname ...]'
args = '[appname ...]'
output_transaction = True

View File

@@ -14,3 +14,7 @@ class Command(BaseCommand):
pass
from django.core.servers.fastcgi import runfastcgi
runfastcgi(args)
def usage(self):
from django.core.servers.fastcgi import FASTCGI_HELP
return FASTCGI_HELP

View File

@@ -1,10 +1,17 @@
from django.core.management.base import BaseCommand, CommandError
from optparse import make_option
import os
import sys
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
make_option('--noreload', action='store_false', dest='use_reloader', default=True,
help='Tells Django to NOT use the auto-reloader.'),
make_option('--adminmedia', dest='admin_media_path', default='',
help='Specifies the directory from which to serve admin media.'),
)
help = "Starts a lightweight Web server for development."
args = '[--noreload] [--adminmedia=ADMIN_MEDIA_PATH] [optional port number, or ipaddr:port]'
args = '[optional port number, or ipaddr:port]'
# Validation is called explicitly each time the server is reloaded.
requires_model_validation = False

View File

@@ -1,8 +1,12 @@
from django.core.management.base import NoArgsCommand
from optparse import make_option
class Command(NoArgsCommand):
option_list = NoArgsCommand.option_list + (
make_option('--plain', action='store_true', dest='plain',
help='Tells Django to use plain Python, not IPython.'),
)
help = "Runs a Python interactive interpreter. Tries to use IPython, if it's available."
args = '[--plain]'
requires_model_validation = False

View File

@@ -1,5 +1,6 @@
from django.core.management.base import NoArgsCommand
from django.core.management.color import no_style
from optparse import make_option
import sys
try:
@@ -8,8 +9,14 @@ except NameError:
from sets import Set as set # Python 2.3 fallback
class Command(NoArgsCommand):
option_list = NoArgsCommand.option_list + (
make_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'),
make_option('--noinput', action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.'),
)
help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
args = '[--verbosity] [--noinput]'
def handle_noargs(self, **options):
from django.db import connection, transaction, models

View File

@@ -1,9 +1,17 @@
from django.core.management.base import BaseCommand
from optparse import make_option
import sys
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
make_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'),
make_option('--noinput', action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.'),
)
help = 'Runs the test suite for the specified applications, or the entire site if no apps are specified.'
args = '[--verbosity] [--noinput] [appname ...]'
args = '[appname ...]'
requires_model_validation = False

View File

@@ -1,6 +1,13 @@
from django.core.management.base import BaseCommand
from optparse import make_option
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
make_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'),
)
help = 'Runs a development server with data from the given fixture(s).'
args = '[fixture ...]'

View File

@@ -17,14 +17,12 @@ import sys, os
__version__ = "0.1"
__all__ = ["runfastcgi"]
FASTCGI_HELP = r"""runfcgi:
FASTCGI_HELP = r"""
Run this project as a fastcgi (or some other protocol supported
by flup) application. To do this, the flup package from
http://www.saddi.com/software/flup/ is required.
Usage:
django-admin.py runfcgi --settings=yourproject.settings [fcgi settings]
manage.py runfcgi [fcgi settings]
runfcgi [options] [fcgi settings]
Optional Fcgi settings: (setting=value)
protocol=PROTOCOL fcgi, scgi, ajp, ... (default fcgi)