From f17b24e407385eb18651bf023a187347aa9c1f75 Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Fri, 6 Jun 2014 22:39:33 +0200 Subject: [PATCH] Converted remaining management commands to argparse --- .../management/commands/changepassword.py | 19 ++- .../management/commands/createsuperuser.py | 43 +++---- django/contrib/auth/tests/test_management.py | 8 +- .../gis/management/commands/ogrinspect.py | 121 +++++++++--------- .../management/commands/collectstatic.py | 55 ++++---- .../management/commands/findstatic.py | 14 +- .../management/commands/runserver.py | 15 +-- django/core/management/commands/check.py | 14 +- .../management/commands/compilemessages.py | 15 +-- .../management/commands/createcachetable.py | 18 +-- django/core/management/commands/dbshell.py | 13 +- .../core/management/commands/diffsettings.py | 13 +- django/core/management/commands/dumpdata.py | 60 ++++----- django/core/management/commands/flush.py | 22 ++-- django/core/management/commands/inspectdb.py | 14 +- django/core/management/commands/loaddata.py | 32 ++--- .../core/management/commands/makemessages.py | 64 ++++----- .../management/commands/makemigrations.py | 24 ++-- django/core/management/commands/migrate.py | 48 +++---- django/core/management/commands/runfcgi.py | 6 +- django/core/management/commands/runserver.py | 38 +++--- django/core/management/commands/shell.py | 32 ++--- django/core/management/commands/sql.py | 16 +-- django/core/management/commands/sqlall.py | 16 +-- django/core/management/commands/sqlclear.py | 16 +-- django/core/management/commands/sqlcustom.py | 16 +-- .../management/commands/sqldropindexes.py | 17 +-- django/core/management/commands/sqlflush.py | 16 +-- django/core/management/commands/sqlindexes.py | 17 +-- django/core/management/commands/sqlmigrate.py | 50 ++++---- .../management/commands/sqlsequencereset.py | 15 +-- .../management/commands/squashmigrations.py | 29 ++--- django/core/management/commands/startapp.py | 4 +- .../core/management/commands/startproject.py | 4 +- django/core/management/commands/syncdb.py | 18 ++- django/core/management/commands/testserver.py | 31 ++--- django/core/management/templates.py | 41 +++--- .../management/commands/base_command.py | 14 +- .../commands/custom_startproject.py | 11 +- .../management/commands/label_command.py | 1 - tests/admin_scripts/tests.py | 19 ++- .../management/commands/test_command.py | 9 +- tests/createsuperuser/tests.py | 2 +- tests/staticfiles_tests/tests.py | 6 +- .../management/commands/dance.py | 9 +- 45 files changed, 496 insertions(+), 569 deletions(-) diff --git a/django/contrib/auth/management/commands/changepassword.py b/django/contrib/auth/management/commands/changepassword.py index 97a0a32fc0..647b7b1728 100644 --- a/django/contrib/auth/management/commands/changepassword.py +++ b/django/contrib/auth/management/commands/changepassword.py @@ -1,7 +1,6 @@ from __future__ import unicode_literals import getpass -from optparse import make_option from django.contrib.auth import get_user_model from django.core.management.base import BaseCommand, CommandError @@ -10,10 +9,6 @@ from django.utils.encoding import force_str class Command(BaseCommand): - option_list = BaseCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Specifies the database to use. Default is "default".'), - ) help = "Change a user's password for django.contrib.auth." requires_system_checks = False @@ -24,12 +19,16 @@ class Command(BaseCommand): raise CommandError("aborted") return p - def handle(self, *args, **options): - if len(args) > 1: - raise CommandError("need exactly one or zero arguments for username") + def add_arguments(self, parser): + parser.add_argument('username', nargs='?', + help='Username to change password for; by default, it\'s the current username.') + parser.add_argument('--database', action='store', dest='database', + default=DEFAULT_DB_ALIAS, + help='Specifies the database to use. Default is "default".') - if args: - username, = args + def handle(self, *args, **options): + if options.get('username'): + username = options['username'] else: username = getpass.getuser() diff --git a/django/contrib/auth/management/commands/createsuperuser.py b/django/contrib/auth/management/commands/createsuperuser.py index 0ec4ec39b5..5b660031ba 100644 --- a/django/contrib/auth/management/commands/createsuperuser.py +++ b/django/contrib/auth/management/commands/createsuperuser.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals import getpass import sys -from optparse import make_option from django.contrib.auth import get_user_model from django.contrib.auth.management import get_default_username @@ -22,33 +21,29 @@ class NotRunningInTTYException(Exception): class Command(BaseCommand): + help = 'Used to create a superuser.' def __init__(self, *args, **kwargs): - # Options are defined in an __init__ method to support swapping out - # custom user models in tests. super(Command, self).__init__(*args, **kwargs) self.UserModel = get_user_model() self.username_field = self.UserModel._meta.get_field(self.UserModel.USERNAME_FIELD) - self.option_list = BaseCommand.option_list + ( - make_option('--%s' % self.UserModel.USERNAME_FIELD, dest=self.UserModel.USERNAME_FIELD, default=None, - help='Specifies the login for the superuser.'), - make_option('--noinput', action='store_false', dest='interactive', default=True, - help=('Tells Django to NOT prompt the user for input of any kind. ' - 'You must use --%s with --noinput, along with an option for ' - 'any other required field. Superusers created with --noinput will ' - ' not be able to log in until they\'re given a valid password.' % - self.UserModel.USERNAME_FIELD)), - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Specifies the database to use. Default is "default".'), - ) + tuple( - make_option('--%s' % field, dest=field, default=None, + def add_arguments(self, parser): + parser.add_argument('--%s' % self.UserModel.USERNAME_FIELD, + dest=self.UserModel.USERNAME_FIELD, default=None, + help='Specifies the login for the superuser.') + parser.add_argument('--noinput', action='store_false', dest='interactive', default=True, + help=('Tells Django to NOT prompt the user for input of any kind. ' + 'You must use --%s with --noinput, along with an option for ' + 'any other required field. Superusers created with --noinput will ' + ' not be able to log in until they\'re given a valid password.' % + self.UserModel.USERNAME_FIELD)) + parser.add_argument('--database', action='store', dest='database', + default=DEFAULT_DB_ALIAS, + help='Specifies the database to use. Default is "default".') + for field in self.UserModel.REQUIRED_FIELDS: + parser.add_argument('--%s' % field, dest=field, default=None, help='Specifies the %s for the superuser.' % field) - for field in self.UserModel.REQUIRED_FIELDS - ) - - option_list = BaseCommand.option_list - help = 'Used to create a superuser.' def execute(self, *args, **options): self.stdin = options.get('stdin', sys.stdin) # Used for testing @@ -56,8 +51,6 @@ class Command(BaseCommand): def handle(self, *args, **options): username = options.get(self.UserModel.USERNAME_FIELD, None) - interactive = options.get('interactive') - verbosity = int(options.get('verbosity', 1)) database = options.get('database') # If not provided, create the user with an unusable password @@ -65,7 +58,7 @@ class Command(BaseCommand): user_data = {} # Do quick and dirty validation if --noinput - if not interactive: + if not options['interactive']: try: if not username: raise CommandError("You must use --%s with --noinput." % @@ -158,5 +151,5 @@ class Command(BaseCommand): user_data[self.UserModel.USERNAME_FIELD] = username user_data['password'] = password self.UserModel._default_manager.db_manager(database).create_superuser(**user_data) - if verbosity >= 1: + if options['verbosity'] >= 1: self.stdout.write("Superuser created successfully.") diff --git a/django/contrib/auth/tests/test_management.py b/django/contrib/auth/tests/test_management.py index 7fd41b9e8b..a800b7379a 100644 --- a/django/contrib/auth/tests/test_management.py +++ b/django/contrib/auth/tests/test_management.py @@ -118,7 +118,7 @@ class ChangepasswordManagementCommandTestCase(TestCase): command = changepassword.Command() command._get_pass = lambda *args: 'not qwerty' - command.execute("joe", stdout=self.stdout) + command.execute(username="joe", stdout=self.stdout) command_output = self.stdout.getvalue().strip() self.assertEqual(command_output, "Changing password for user 'joe'\nPassword changed successfully for user 'joe'") @@ -133,7 +133,7 @@ class ChangepasswordManagementCommandTestCase(TestCase): command._get_pass = lambda *args: args or 'foo' with self.assertRaises(CommandError): - command.execute("joe", stdout=self.stdout, stderr=self.stderr) + command.execute(username="joe", stdout=self.stdout, stderr=self.stderr) def test_that_changepassword_command_works_with_nonascii_output(self): """ @@ -146,7 +146,7 @@ class ChangepasswordManagementCommandTestCase(TestCase): command = changepassword.Command() command._get_pass = lambda *args: 'not qwerty' - command.execute("J\xfalia", stdout=self.stdout) + command.execute(username="J\xfalia", stdout=self.stdout) @skipIfCustomUser @@ -333,6 +333,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase): stdin=sentinel, stdout=six.StringIO(), interactive=False, + verbosity=0, username='janet', email='janet@example.com', ) @@ -342,6 +343,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase): command.execute( stdout=six.StringIO(), interactive=False, + verbosity=0, username='joe', email='joe@example.com', ) diff --git a/django/contrib/gis/management/commands/ogrinspect.py b/django/contrib/gis/management/commands/ogrinspect.py index 8926bc2131..e1f5829718 100644 --- a/django/contrib/gis/management/commands/ogrinspect.py +++ b/django/contrib/gis/management/commands/ogrinspect.py @@ -1,87 +1,82 @@ +import argparse import inspect -from optparse import make_option from django.contrib.gis import gdal -from django.core.management.base import LabelCommand, CommandError +from django.core.management.base import BaseCommand, CommandError -def layer_option(option, opt, value, parser): +class LayerOptionAction(argparse.Action): """ - Callback for `make_option` for the `ogrinspect` `layer_key` - keyword option which may be an integer or a string. + Custom argparse action for the `ogrinspect` `layer_key` keyword option + which may be an integer or a string. """ - try: - dest = int(value) - except ValueError: - dest = value - setattr(parser.values, option.dest, dest) + def __call__(self, parser, namespace, value, option_string=None): + try: + setattr(namespace, self.dest, int(value)) + except ValueError: + setattr(namespace, self.dest, value) -def list_option(option, opt, value, parser): +class ListOptionAction(argparse.Action): """ - Callback for `make_option` for `ogrinspect` keywords that require - a string list. If the string is 'True'/'true' then the option + Custom argparse action for `ogrinspect` keywords that require + a string list. If the string is 'True'/'true' then the option value will be a boolean instead. """ - if value.lower() == 'true': - dest = True - else: - dest = [s for s in value.split(',')] - setattr(parser.values, option.dest, dest) + def __call__(self, parser, namespace, value, option_string=None): + if value.lower() == 'true': + setattr(namespace, self.dest, True) + else: + setattr(namespace, self.dest, value.split(',')) -class Command(LabelCommand): +class Command(BaseCommand): help = ('Inspects the given OGR-compatible data source (e.g., a shapefile) and outputs\n' 'a GeoDjango model with the given model name. For example:\n' ' ./manage.py ogrinspect zipcode.shp Zipcode') - args = '[data_source] [model_name]' - - option_list = LabelCommand.option_list + ( - make_option('--blank', dest='blank', type='string', action='callback', - callback=list_option, default=False, - help='Use a comma separated list of OGR field names to add ' - 'the `blank=True` option to the field definition. Set with' - '`true` to apply to all applicable fields.'), - make_option('--decimal', dest='decimal', type='string', action='callback', - callback=list_option, default=False, - help='Use a comma separated list of OGR float fields to ' - 'generate `DecimalField` instead of the default ' - '`FloatField`. Set to `true` to apply to all OGR float fields.'), - make_option('--geom-name', dest='geom_name', type='string', default='geom', - help='Specifies the model name for the Geometry Field ' - '(defaults to `geom`)'), - make_option('--layer', dest='layer_key', type='string', action='callback', - callback=layer_option, default=0, - help='The key for specifying which layer in the OGR data ' - 'source to use. Defaults to 0 (the first layer). May be ' - 'an integer or a string identifier for the layer.'), - make_option('--multi-geom', action='store_true', dest='multi_geom', default=False, - help='Treat the geometry in the data source as a geometry collection.'), - make_option('--name-field', dest='name_field', - help='Specifies a field name to return for the `__unicode__`/`__str__` function.'), - make_option('--no-imports', action='store_false', dest='imports', default=True, - help='Do not include `from django.contrib.gis.db import models` ' - 'statement.'), - make_option('--null', dest='null', type='string', action='callback', - callback=list_option, default=False, - help='Use a comma separated list of OGR field names to add ' - 'the `null=True` option to the field definition. Set with' - '`true` to apply to all applicable fields.'), - make_option('--srid', dest='srid', - help='The SRID to use for the Geometry Field. If it can be ' - 'determined, the SRID of the data source is used.'), - make_option('--mapping', action='store_true', dest='mapping', - help='Generate mapping dictionary for use with `LayerMapping`.') - ) requires_system_checks = False - def handle(self, *args, **options): - try: - data_source, model_name = args - except ValueError: - raise CommandError('Invalid arguments, must provide: %s' % self.args) + def add_arguments(self, parser): + parser.add_argument('data_source', help='Path to the data source.') + parser.add_argument('model_name', help='Name of the model to create.') + parser.add_argument('--blank', dest='blank', + action=ListOptionAction, default=False, + help='Use a comma separated list of OGR field names to add ' + 'the `blank=True` option to the field definition. Set to `true` ' + 'to apply to all applicable fields.') + parser.add_argument('--decimal', dest='decimal', + action=ListOptionAction, default=False, + help='Use a comma separated list of OGR float fields to ' + 'generate `DecimalField` instead of the default ' + '`FloatField`. Set to `true` to apply to all OGR float fields.') + parser.add_argument('--geom-name', dest='geom_name', default='geom', + help='Specifies the model name for the Geometry Field ' + '(defaults to `geom`)') + parser.add_argument('--layer', dest='layer_key', + action=LayerOptionAction, default=0, + help='The key for specifying which layer in the OGR data ' + 'source to use. Defaults to 0 (the first layer). May be ' + 'an integer or a string identifier for the layer.') + parser.add_argument('--multi-geom', action='store_true', + dest='multi_geom', default=False, + help='Treat the geometry in the data source as a geometry collection.') + parser.add_argument('--name-field', dest='name_field', + help='Specifies a field name to return for the `__unicode__`/`__str__` function.') + parser.add_argument('--no-imports', action='store_false', dest='imports', default=True, + help='Do not include `from django.contrib.gis.db import models` statement.') + parser.add_argument('--null', dest='null', action=ListOptionAction, default=False, + help='Use a comma separated list of OGR field names to add ' + 'the `null=True` option to the field definition. Set to `true` ' + 'to apply to all applicable fields.') + parser.add_argument('--srid', dest='srid', + help='The SRID to use for the Geometry Field. If it can be ' + 'determined, the SRID of the data source is used.') + parser.add_argument('--mapping', action='store_true', dest='mapping', + help='Generate mapping dictionary for use with `LayerMapping`.') + def handle(self, *args, **options): + data_source, model_name = options.pop('data_source'), options.pop('model_name') if not gdal.HAS_GDAL: raise CommandError('GDAL is required to inspect geospatial data sources.') diff --git a/django/contrib/staticfiles/management/commands/collectstatic.py b/django/contrib/staticfiles/management/commands/collectstatic.py index 0a1463426e..714f36e1de 100644 --- a/django/contrib/staticfiles/management/commands/collectstatic.py +++ b/django/contrib/staticfiles/management/commands/collectstatic.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals import os from collections import OrderedDict -from optparse import make_option from django.core.files.storage import FileSystemStorage from django.core.management.base import CommandError, NoArgsCommand @@ -18,32 +17,6 @@ class Command(NoArgsCommand): Command that allows to copy or symlink static files from different locations to the settings.STATIC_ROOT. """ - option_list = NoArgsCommand.option_list + ( - make_option('--noinput', - action='store_false', dest='interactive', default=True, - help="Do NOT prompt the user for input of any kind."), - make_option('--no-post-process', - action='store_false', dest='post_process', default=True, - help="Do NOT post process collected files."), - make_option('-i', '--ignore', action='append', default=[], - dest='ignore_patterns', metavar='PATTERN', - help="Ignore files or directories matching this glob-style " - "pattern. Use multiple times to ignore more."), - make_option('-n', '--dry-run', - action='store_true', dest='dry_run', default=False, - help="Do everything except modify the filesystem."), - make_option('-c', '--clear', - action='store_true', dest='clear', default=False, - help="Clear the existing files using the storage " - "before trying to copy or link the original file."), - make_option('-l', '--link', - action='store_true', dest='link', default=False, - help="Create a symbolic link to each file instead of copying."), - make_option('--no-default-ignore', action='store_false', - dest='use_default_ignore_patterns', default=True, - help="Don't ignore the common private glob-style patterns 'CVS', " - "'.*' and '*~'."), - ) help = "Collect static files in a single location." requires_system_checks = False @@ -61,12 +34,38 @@ class Command(NoArgsCommand): else: self.local = True + def add_arguments(self, parser): + parser.add_argument('--noinput', + action='store_false', dest='interactive', default=True, + help="Do NOT prompt the user for input of any kind.") + parser.add_argument('--no-post-process', + action='store_false', dest='post_process', default=True, + help="Do NOT post process collected files.") + parser.add_argument('-i', '--ignore', action='append', default=[], + dest='ignore_patterns', metavar='PATTERN', + help="Ignore files or directories matching this glob-style " + "pattern. Use multiple times to ignore more.") + parser.add_argument('-n', '--dry-run', + action='store_true', dest='dry_run', default=False, + help="Do everything except modify the filesystem.") + parser.add_argument('-c', '--clear', + action='store_true', dest='clear', default=False, + help="Clear the existing files using the storage " + "before trying to copy or link the original file.") + parser.add_argument('-l', '--link', + action='store_true', dest='link', default=False, + help="Create a symbolic link to each file instead of copying.") + parser.add_argument('--no-default-ignore', action='store_false', + dest='use_default_ignore_patterns', default=True, + help="Don't ignore the common private glob-style patterns 'CVS', " + "'.*' and '*~'.") + def set_options(self, **options): """ Set instance variables based on an options dict """ self.interactive = options['interactive'] - self.verbosity = int(options.get('verbosity', 1)) + self.verbosity = options['verbosity'] self.symlink = options['link'] self.clear = options['clear'] self.dry_run = options['dry_run'] diff --git a/django/contrib/staticfiles/management/commands/findstatic.py b/django/contrib/staticfiles/management/commands/findstatic.py index 7da7041c9b..658ac3f248 100644 --- a/django/contrib/staticfiles/management/commands/findstatic.py +++ b/django/contrib/staticfiles/management/commands/findstatic.py @@ -1,7 +1,6 @@ from __future__ import unicode_literals import os -from optparse import make_option from django.core.management.base import LabelCommand from django.utils.encoding import force_text @@ -10,15 +9,16 @@ from django.contrib.staticfiles import finders class Command(LabelCommand): help = "Finds the absolute paths for the given static file(s)." - args = "[file ...]" label = 'static file' - option_list = LabelCommand.option_list + ( - make_option('--first', action='store_false', dest='all', default=True, - help="Only return the first match for each static file."), - ) + + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument('--first', action='store_false', dest='all', + default=True, + help="Only return the first match for each static file.") def handle_label(self, path, **options): - verbosity = int(options.get('verbosity', 1)) + verbosity = options['verbosity'] result = finders.find(path, all=options['all']) path = force_text(path) if verbosity >= 2: diff --git a/django/contrib/staticfiles/management/commands/runserver.py b/django/contrib/staticfiles/management/commands/runserver.py index 64c711ae54..fd358bee3d 100644 --- a/django/contrib/staticfiles/management/commands/runserver.py +++ b/django/contrib/staticfiles/management/commands/runserver.py @@ -1,5 +1,3 @@ -from optparse import make_option - from django.conf import settings from django.core.management.commands.runserver import Command as RunserverCommand @@ -7,14 +5,15 @@ from django.contrib.staticfiles.handlers import StaticFilesHandler class Command(RunserverCommand): - option_list = RunserverCommand.option_list + ( - make_option('--nostatic', action="store_false", dest='use_static_handler', default=True, - help='Tells Django to NOT automatically serve static files at STATIC_URL.'), - make_option('--insecure', action="store_true", dest='insecure_serving', default=False, - help='Allows serving static files even if DEBUG is False.'), - ) help = "Starts a lightweight Web server for development and also serves static files." + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument('--nostatic', action="store_false", dest='use_static_handler', default=True, + help='Tells Django to NOT automatically serve static files at STATIC_URL.') + parser.add_argument('--insecure', action="store_true", dest='insecure_serving', default=False, + help='Allows serving static files even if DEBUG is False.') + def get_handler(self, *args, **options): """ Returns the static files serving handler wrapping the default handler, diff --git a/django/core/management/commands/check.py b/django/core/management/commands/check.py index 3532ab4fa9..be9b49d54a 100644 --- a/django/core/management/commands/check.py +++ b/django/core/management/commands/check.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from optparse import make_option - from django.apps import apps from django.core import checks from django.core.checks.registry import registry @@ -14,12 +12,12 @@ class Command(BaseCommand): requires_system_checks = False - option_list = BaseCommand.option_list + ( - make_option('--tag', '-t', action='append', dest='tags', - help='Run only checks labeled with given tag.'), - make_option('--list-tags', action='store_true', dest='list_tags', - help='List available tags.'), - ) + def add_arguments(self, parser): + parser.add_argument('args', metavar='app_label', nargs='*') + parser.add_argument('--tag', '-t', action='append', dest='tags', + help='Run only checks labeled with given tag.') + parser.add_argument('--list-tags', action='store_true', dest='list_tags', + help='List available tags.') def handle(self, *app_labels, **options): if options.get('list_tags'): diff --git a/django/core/management/commands/compilemessages.py b/django/core/management/commands/compilemessages.py index 50cc1c9c93..71a52d1d6f 100644 --- a/django/core/management/commands/compilemessages.py +++ b/django/core/management/commands/compilemessages.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals import codecs import glob import os -from optparse import make_option from django.core.management.base import BaseCommand, CommandError from django.core.management.utils import find_command, popen_wrapper @@ -30,13 +29,6 @@ def is_writable(path): class Command(BaseCommand): - option_list = BaseCommand.option_list + ( - make_option('--locale', '-l', dest='locale', action='append', default=[], - help='Locale(s) to process (e.g. de_AT). Default is to process all. Can be ' - 'used multiple times.'), - make_option('--exclude', '-x', dest='exclude', action='append', default=[], - help='Locales to exclude. Default is none. Can be used multiple times.'), - ) help = 'Compiles .po files to .mo files for use with builtin gettext support.' requires_system_checks = False @@ -45,6 +37,13 @@ class Command(BaseCommand): program = 'msgfmt' program_options = ['--check-format'] + def add_arguments(self, parser): + parser.add_argument('--locale', '-l', dest='locale', action='append', default=[], + help='Locale(s) to process (e.g. de_AT). Default is to process all. ' + 'Can be used multiple times.') + parser.add_argument('--exclude', '-x', dest='exclude', action='append', default=[], + help='Locales to exclude. Default is none. Can be used multiple times.') + def handle(self, **options): locale = options.get('locale') exclude = options.get('exclude') diff --git a/django/core/management/commands/createcachetable.py b/django/core/management/commands/createcachetable.py index 3eb4a84057..da39e9ad1e 100644 --- a/django/core/management/commands/createcachetable.py +++ b/django/core/management/commands/createcachetable.py @@ -1,5 +1,3 @@ -from optparse import make_option - from django.conf import settings from django.core.cache import caches from django.core.cache.backends.db import BaseDatabaseCache @@ -12,15 +10,17 @@ from django.utils.encoding import force_text class Command(BaseCommand): help = "Creates the tables needed to use the SQL cache backend." - option_list = BaseCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database onto ' - 'which the cache tables will be installed. ' - 'Defaults to the "default" database.'), - ) - requires_system_checks = False + def add_arguments(self, parser): + parser.add_argument('args', metavar='table_name', nargs='*', + help='Optional table names. Otherwise, settings.CACHES is used to ' + 'find cache tables.') + parser.add_argument('--database', action='store', dest='database', + default=DEFAULT_DB_ALIAS, + help='Nominates a database onto which the cache tables will be ' + 'installed. Defaults to the "default" database.') + def handle(self, *tablenames, **options): db = options.get('database') self.verbosity = int(options.get('verbosity')) diff --git a/django/core/management/commands/dbshell.py b/django/core/management/commands/dbshell.py index 5cb0a411a5..b771585bef 100644 --- a/django/core/management/commands/dbshell.py +++ b/django/core/management/commands/dbshell.py @@ -1,5 +1,3 @@ -from optparse import make_option - from django.core.management.base import BaseCommand, CommandError from django.db import connections, DEFAULT_DB_ALIAS @@ -8,14 +6,13 @@ class Command(BaseCommand): help = ("Runs the command-line client for specified database, or the " "default database if none is provided.") - option_list = BaseCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database onto which to ' - 'open a shell. Defaults to the "default" database.'), - ) - requires_system_checks = False + def add_arguments(self, parser): + parser.add_argument('--database', action='store', dest='database', + default=DEFAULT_DB_ALIAS, help='Nominates a database onto which to ' + 'open a shell. Defaults to the "default" database.') + def handle(self, **options): connection = connections[options.get('database')] try: diff --git a/django/core/management/commands/diffsettings.py b/django/core/management/commands/diffsettings.py index c346b14fff..cb31894aa8 100644 --- a/django/core/management/commands/diffsettings.py +++ b/django/core/management/commands/diffsettings.py @@ -1,5 +1,3 @@ -from optparse import make_option - from django.core.management.base import NoArgsCommand @@ -13,14 +11,13 @@ class Command(NoArgsCommand): default settings. Settings that don't appear in the defaults are followed by "###".""" - option_list = NoArgsCommand.option_list + ( - make_option('--all', action='store_true', dest='all', default=False, - help='Display all settings, regardless of their value. ' - 'Default values are prefixed by "###".'), - ) - requires_system_checks = False + def add_arguments(self, parser): + parser.add_argument('--all', action='store_true', dest='all', default=False, + help='Display all settings, regardless of their value. ' + 'Default values are prefixed by "###".') + def handle_noargs(self, **options): # Inspired by Postfix's "postconf -n". from django.conf import settings, global_settings diff --git a/django/core/management/commands/dumpdata.py b/django/core/management/commands/dumpdata.py index 1611e9c03a..b5a3de5fd4 100644 --- a/django/core/management/commands/dumpdata.py +++ b/django/core/management/commands/dumpdata.py @@ -1,7 +1,6 @@ import warnings from collections import OrderedDict -from optparse import make_option from django.apps import apps from django.core.management.base import BaseCommand, CommandError @@ -11,38 +10,39 @@ from django.utils.deprecation import RemovedInDjango19Warning class Command(BaseCommand): - option_list = 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'), - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, - help='Nominates a specific database to dump fixtures from. ' - 'Defaults to the "default" database.'), - make_option('-e', '--exclude', dest='exclude', action='append', default=[], - help='An app_label or app_label.ModelName to exclude ' - '(use multiple --exclude to exclude multiple apps/models).'), - make_option('-n', '--natural', action='store_true', dest='use_natural_keys', default=False, - help='Use natural keys if they are available (deprecated: use --natural-foreign instead).'), - make_option('--natural-foreign', action='store_true', dest='use_natural_foreign_keys', default=False, - help='Use natural foreign keys if they are available.'), - make_option('--natural-primary', action='store_true', dest='use_natural_primary_keys', default=False, - help='Use natural primary keys if they are available.'), - make_option('-a', '--all', action='store_true', dest='use_base_manager', default=False, - help="Use Django's base manager to dump all models stored in the database, " - "including those that would otherwise be filtered or modified by a custom manager."), - make_option('--pks', dest='primary_keys', - help="Only dump objects with given primary keys. " - "Accepts a comma separated list of keys. " - "This option will only work when you specify one model."), - make_option('-o', '--output', default=None, dest='output', - help='Specifies file to which the output is written.'), - ) help = ("Output the contents of the database as a fixture of the given " "format (using each model's default manager unless --all is " "specified).") - args = '[app_label app_label.ModelName ...]' + + def add_arguments(self, parser): + parser.add_argument('args', metavar='app_label[.ModelName]', nargs='*', + help='Restricts dumped data to the specified app_label or app_label.ModelName.') + parser.add_argument('--format', default='json', dest='format', + help='Specifies the output serialization format for fixtures.') + parser.add_argument('--indent', default=None, dest='indent', type=int, + help='Specifies the indent level to use when pretty-printing output.') + parser.add_argument('--database', action='store', dest='database', + default=DEFAULT_DB_ALIAS, + help='Nominates a specific database to dump fixtures from. ' + 'Defaults to the "default" database.') + parser.add_argument('-e', '--exclude', dest='exclude', action='append', default=[], + help='An app_label or app_label.ModelName to exclude ' + '(use multiple --exclude to exclude multiple apps/models).') + parser.add_argument('-n', '--natural', action='store_true', dest='use_natural_keys', default=False, + help='Use natural keys if they are available (deprecated: use --natural-foreign instead).') + parser.add_argument('--natural-foreign', action='store_true', dest='use_natural_foreign_keys', default=False, + help='Use natural foreign keys if they are available.') + parser.add_argument('--natural-primary', action='store_true', dest='use_natural_primary_keys', default=False, + help='Use natural primary keys if they are available.') + parser.add_argument('-a', '--all', action='store_true', dest='use_base_manager', default=False, + help="Use Django's base manager to dump all models stored in the database, " + "including those that would otherwise be filtered or modified by a custom manager.") + parser.add_argument('--pks', dest='primary_keys', + help="Only dump objects with given primary keys. " + "Accepts a comma separated list of keys. " + "This option will only work when you specify one model.") + parser.add_argument('-o', '--output', default=None, dest='output', + help='Specifies file to which the output is written.') def handle(self, *app_labels, **options): format = options.get('format') diff --git a/django/core/management/commands/flush.py b/django/core/management/commands/flush.py index 29e3a8ec58..fc2256d2e0 100644 --- a/django/core/management/commands/flush.py +++ b/django/core/management/commands/flush.py @@ -1,6 +1,5 @@ import sys from importlib import import_module -from optparse import make_option from django.apps import apps from django.db import connections, router, transaction, DEFAULT_DB_ALIAS @@ -13,23 +12,24 @@ from django.utils import six class Command(NoArgsCommand): - option_list = NoArgsCommand.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.'), - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to flush. ' - 'Defaults to the "default" database.'), - make_option('--no-initial-data', action='store_false', dest='load_initial_data', default=True, - help='Tells Django not to load any initial data after database synchronization.'), - ) help = ('Removes ALL DATA from the database, including data added during ' 'migrations. Unmigrated apps will also have their initial_data ' 'fixture reloaded. Does not achieve a "fresh install" state.') + def add_arguments(self, parser): + parser.add_argument('--noinput', action='store_false', dest='interactive', default=True, + help='Tells Django to NOT prompt the user for input of any kind.') + parser.add_argument('--database', action='store', dest='database', + default=DEFAULT_DB_ALIAS, + help='Nominates a database to flush. Defaults to the "default" database.') + parser.add_argument('--no-initial-data', action='store_false', + dest='load_initial_data', default=True, + help='Tells Django not to load any initial data after database synchronization.') + def handle_noargs(self, **options): database = options.get('database') connection = connections[database] - verbosity = int(options.get('verbosity')) + verbosity = options.get('verbosity') interactive = options.get('interactive') # The following are stealth options used by Django's internals. reset_sequences = options.get('reset_sequences', True) diff --git a/django/core/management/commands/inspectdb.py b/django/core/management/commands/inspectdb.py index 52e75c21de..783dcc06f3 100644 --- a/django/core/management/commands/inspectdb.py +++ b/django/core/management/commands/inspectdb.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals from collections import OrderedDict import keyword import re -from optparse import make_option from django.core.management.base import NoArgsCommand, CommandError from django.db import connections, DEFAULT_DB_ALIAS @@ -12,16 +11,15 @@ from django.db import connections, DEFAULT_DB_ALIAS class Command(NoArgsCommand): help = "Introspects the database tables in the given database and outputs a Django model module." - option_list = NoArgsCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to ' - 'introspect. Defaults to using the "default" database.'), - ) - requires_system_checks = False db_module = 'django.db' + def add_arguments(self, parser): + parser.add_argument('--database', action='store', dest='database', + default=DEFAULT_DB_ALIAS, help='Nominates a database to ' + 'introspect. Defaults to using the "default" database.') + def handle_noargs(self, **options): try: for line in self.handle_inspection(options): @@ -30,7 +28,7 @@ class Command(NoArgsCommand): raise CommandError("Database inspection isn't supported for the currently selected database backend.") def handle_inspection(self, options): - connection = connections[options.get('database')] + connection = connections[options['database']] # 'table_name_filter' is a stealth option table_name_filter = options.get('table_name_filter') diff --git a/django/core/management/commands/loaddata.py b/django/core/management/commands/loaddata.py index bac4dd0c67..b6a1e1df38 100644 --- a/django/core/management/commands/loaddata.py +++ b/django/core/management/commands/loaddata.py @@ -5,7 +5,6 @@ import gzip import os import warnings import zipfile -from optparse import make_option from django.apps import apps from django.conf import settings @@ -29,18 +28,21 @@ except ImportError: class Command(BaseCommand): help = 'Installs the named fixture(s) in the database.' - args = "fixture [fixture ...]" + missing_args_message = ("No database fixture specified. Please provide the " + "path of at least one fixture in the command line.") - option_list = BaseCommand.option_list + ( - make_option('--database', action='store', dest='database', + def add_arguments(self, parser): + parser.add_argument('args', metavar='fixture', nargs='+', + help='Fixture labels.') + parser.add_argument('--database', action='store', dest='database', default=DEFAULT_DB_ALIAS, help='Nominates a specific database to load ' - 'fixtures into. Defaults to the "default" database.'), - make_option('--app', action='store', dest='app_label', - default=None, help='Only look for fixtures in the specified app.'), - make_option('--ignorenonexistent', '-i', action='store_true', dest='ignore', - default=False, help='Ignores entries in the serialized data for fields' - ' that do not currently exist on the model.'), - ) + 'fixtures into. Defaults to the "default" database.') + parser.add_argument('--app', action='store', dest='app_label', + default=None, help='Only look for fixtures in the specified app.') + parser.add_argument('--ignorenonexistent', '-i', action='store_true', + dest='ignore', default=False, + help='Ignores entries in the serialized data for fields that do not ' + 'currently exist on the model.') def handle(self, *fixture_labels, **options): @@ -48,13 +50,7 @@ class Command(BaseCommand): self.using = options.get('database') self.app_label = options.get('app_label') self.hide_empty = options.get('hide_empty', False) - - if not len(fixture_labels): - raise CommandError( - "No database fixture specified. Please provide the path " - "of at least one fixture in the command line.") - - self.verbosity = int(options.get('verbosity')) + self.verbosity = options.get('verbosity') with transaction.atomic(using=self.using): self.loaddata(fixture_labels) diff --git a/django/core/management/commands/makemessages.py b/django/core/management/commands/makemessages.py index cd9f8c9e52..7f3f24428d 100644 --- a/django/core/management/commands/makemessages.py +++ b/django/core/management/commands/makemessages.py @@ -7,7 +7,6 @@ import os import re import sys from itertools import dropwhile -from optparse import make_option import django from django.core.management.base import CommandError, NoArgsCommand @@ -164,34 +163,6 @@ def write_pot_file(potfile, msgs): class Command(NoArgsCommand): - option_list = NoArgsCommand.option_list + ( - make_option('--locale', '-l', default=[], dest='locale', action='append', - help='Creates or updates the message files for the given locale(s) (e.g. pt_BR). ' - 'Can be used multiple times.'), - make_option('--exclude', '-x', default=[], dest='exclude', action='append', - help='Locales to exclude. Default is none. Can be used multiple times.'), - make_option('--domain', '-d', default='django', dest='domain', - help='The domain of the message files (default: "django").'), - make_option('--all', '-a', action='store_true', dest='all', - default=False, help='Updates the message files for all existing locales.'), - make_option('--extension', '-e', dest='extensions', - help='The file extension(s) to examine (default: "html,txt", or "js" if the domain is "djangojs"). Separate multiple extensions with commas, or use -e multiple times.', - action='append'), - make_option('--symlinks', '-s', action='store_true', dest='symlinks', - default=False, help='Follows symlinks to directories when examining source code and templates for translation strings.'), - make_option('--ignore', '-i', action='append', dest='ignore_patterns', - default=[], metavar='PATTERN', help='Ignore files or directories matching this glob-style pattern. Use multiple times to ignore more.'), - make_option('--no-default-ignore', action='store_false', dest='use_default_ignore_patterns', - default=True, help="Don't ignore the common glob-style patterns 'CVS', '.*', '*~' and '*.pyc'."), - make_option('--no-wrap', action='store_true', dest='no_wrap', - default=False, help="Don't break long message lines into several lines."), - make_option('--no-location', action='store_true', dest='no_location', - default=False, help="Don't write '#: filename:line' lines."), - make_option('--no-obsolete', action='store_true', dest='no_obsolete', - default=False, help="Remove obsolete message strings."), - make_option('--keep-pot', action='store_true', dest='keep_pot', - default=False, help="Keep .pot file after making messages. Useful when debugging."), - ) help = ("Runs over the entire source tree of the current directory and " "pulls out all strings marked for translation. It creates (or updates) a message " "file in the conf/locale (in the django tree) or locale (for projects and " @@ -206,11 +177,44 @@ class Command(NoArgsCommand): msgattrib_options = ['--no-obsolete'] xgettext_options = ['--from-code=UTF-8', '--add-comments=Translators'] + def add_arguments(self, parser): + parser.add_argument('--locale', '-l', default=[], dest='locale', action='append', + help='Creates or updates the message files for the given locale(s) (e.g. pt_BR). ' + 'Can be used multiple times.') + parser.add_argument('--exclude', '-x', default=[], dest='exclude', action='append', + help='Locales to exclude. Default is none. Can be used multiple times.') + parser.add_argument('--domain', '-d', default='django', dest='domain', + help='The domain of the message files (default: "django").') + parser.add_argument('--all', '-a', action='store_true', dest='all', + default=False, help='Updates the message files for all existing locales.') + parser.add_argument('--extension', '-e', dest='extensions', + help='The file extension(s) to examine (default: "html,txt", or "js" ' + 'if the domain is "djangojs"). Separate multiple extensions with ' + 'commas, or use -e multiple times.', + action='append') + parser.add_argument('--symlinks', '-s', action='store_true', dest='symlinks', + default=False, help='Follows symlinks to directories when examining ' + 'source code and templates for translation strings.') + parser.add_argument('--ignore', '-i', action='append', dest='ignore_patterns', + default=[], metavar='PATTERN', + help='Ignore files or directories matching this glob-style pattern. ' + 'Use multiple times to ignore more.') + parser.add_argument('--no-default-ignore', action='store_false', dest='use_default_ignore_patterns', + default=True, help="Don't ignore the common glob-style patterns 'CVS', '.*', '*~' and '*.pyc'.") + parser.add_argument('--no-wrap', action='store_true', dest='no_wrap', + default=False, help="Don't break long message lines into several lines.") + parser.add_argument('--no-location', action='store_true', dest='no_location', + default=False, help="Don't write '#: filename:line' lines.") + parser.add_argument('--no-obsolete', action='store_true', dest='no_obsolete', + default=False, help="Remove obsolete message strings.") + parser.add_argument('--keep-pot', action='store_true', dest='keep_pot', + default=False, help="Keep .pot file after making messages. Useful when debugging.") + def handle_noargs(self, *args, **options): locale = options.get('locale') exclude = options.get('exclude') self.domain = options.get('domain') - self.verbosity = int(options.get('verbosity')) + self.verbosity = options.get('verbosity') process_all = options.get('all') extensions = options.get('extensions') self.symlinks = options.get('symlinks') diff --git a/django/core/management/commands/makemigrations.py b/django/core/management/commands/makemigrations.py index 38ed9db473..e172213176 100644 --- a/django/core/management/commands/makemigrations.py +++ b/django/core/management/commands/makemigrations.py @@ -1,7 +1,6 @@ import sys import os import operator -from optparse import make_option from django.apps import apps from django.core.management.base import BaseCommand, CommandError @@ -15,22 +14,21 @@ from django.utils.six.moves import reduce class Command(BaseCommand): - option_list = BaseCommand.option_list + ( - make_option('--dry-run', action='store_true', dest='dry_run', default=False, - help="Just show what migrations would be made; don't actually write them."), - make_option('--merge', action='store_true', dest='merge', default=False, - help="Enable fixing of migration conflicts."), - make_option('--empty', action='store_true', dest='empty', default=False, - help="Create an empty migration."), - ) - help = "Creates new migration(s) for apps." - usage_str = "Usage: ./manage.py makemigrations [--dry-run] [app [app ...]]" - args = "[app_label [app_label ...]]" + + def add_arguments(self, parser): + parser.add_argument('args', metavar='app_label', nargs='*', + help='Specify the app label(s) to create migrations for.') + parser.add_argument('--dry-run', action='store_true', dest='dry_run', default=False, + help="Just show what migrations would be made; don't actually write them.") + parser.add_argument('--merge', action='store_true', dest='merge', default=False, + help="Enable fixing of migration conflicts.") + parser.add_argument('--empty', action='store_true', dest='empty', default=False, + help="Create an empty migration.") def handle(self, *app_labels, **options): - self.verbosity = int(options.get('verbosity')) + self.verbosity = options.get('verbosity') self.interactive = options.get('interactive') self.dry_run = options.get('dry_run', False) self.merge = options.get('merge', False) diff --git a/django/core/management/commands/migrate.py b/django/core/management/commands/migrate.py index fffa1ebe6e..8fc6f7c3cb 100644 --- a/django/core/management/commands/migrate.py +++ b/django/core/management/commands/migrate.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from optparse import make_option + from collections import OrderedDict from importlib import import_module import itertools @@ -20,26 +20,28 @@ from django.utils.module_loading import module_has_submodule class Command(BaseCommand): - option_list = BaseCommand.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.'), - make_option('--no-initial-data', action='store_false', dest='load_initial_data', default=True, - help='Tells Django not to load any initial data after database synchronization.'), - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to synchronize. ' - 'Defaults to the "default" database.'), - make_option('--fake', action='store_true', dest='fake', default=False, - help='Mark migrations as run without actually running them'), - make_option('--list', '-l', action='store_true', dest='list', default=False, - help='Show a list of all known migrations and which are applied'), - ) - help = "Updates database schema. Manages both apps with migrations and those without." - args = "[app_label] [migration_name]" + + def add_arguments(self, parser): + parser.add_argument('app_label', nargs='?', + help='App label of an application to synchronize the state.') + parser.add_argument('migration_name', nargs='?', + help='Database state will be brought to the state after that migration.') + parser.add_argument('--noinput', action='store_false', dest='interactive', default=True, + help='Tells Django to NOT prompt the user for input of any kind.') + parser.add_argument('--no-initial-data', action='store_false', dest='load_initial_data', default=True, + help='Tells Django not to load any initial data after database synchronization.') + parser.add_argument('--database', action='store', dest='database', + default=DEFAULT_DB_ALIAS, help='Nominates a database to synchronize. ' + 'Defaults to the "default" database.') + parser.add_argument('--fake', action='store_true', dest='fake', default=False, + help='Mark migrations as run without actually running them') + parser.add_argument('--list', '-l', action='store_true', dest='list', default=False, + help='Show a list of all known migrations and which are applied') def handle(self, *args, **options): - self.verbosity = int(options.get('verbosity')) + self.verbosity = options.get('verbosity') self.interactive = options.get('interactive') self.show_traceback = options.get('traceback') self.load_initial_data = options.get('load_initial_data') @@ -57,7 +59,7 @@ class Command(BaseCommand): # If they asked for a migration listing, quit main execution flow and show it if options.get("list", False): - return self.show_migration_list(connection, args) + return self.show_migration_list(connection, [options['app_label']] if options['app_label'] else None) # Work out which apps have migrations and which do not executor = MigrationExecutor(connection, self.migration_progress_callback) @@ -75,10 +77,8 @@ class Command(BaseCommand): # If they supplied command line arguments, work out what they mean. run_syncdb = False target_app_labels_only = True - if len(args) > 2: - raise CommandError("Too many command-line arguments (expecting 'app_label' or 'app_label migrationname')") - elif len(args) == 2: - app_label, migration_name = args + if options['app_label'] and options['migration_name']: + app_label, migration_name = options['app_label'], options['migration_name'] if app_label not in executor.loader.migrated_apps: raise CommandError("App '%s' does not have migrations (you cannot selectively sync unmigrated apps)" % app_label) if migration_name == "zero": @@ -92,8 +92,8 @@ class Command(BaseCommand): raise CommandError("Cannot find a migration matching '%s' from app '%s'." % (app_label, migration_name)) targets = [(app_label, migration.name)] target_app_labels_only = False - elif len(args) == 1: - app_label = args[0] + elif options['app_label']: + app_label = options['app_label'] if app_label not in executor.loader.migrated_apps: raise CommandError("App '%s' does not have migrations (you cannot selectively sync unmigrated apps)" % app_label) targets = [key for key in executor.loader.graph.leaf_nodes() if key[0] == app_label] diff --git a/django/core/management/commands/runfcgi.py b/django/core/management/commands/runfcgi.py index e701a64fba..98de800503 100644 --- a/django/core/management/commands/runfcgi.py +++ b/django/core/management/commands/runfcgi.py @@ -1,3 +1,4 @@ +import argparse import warnings from django.core.management.base import BaseCommand @@ -6,7 +7,10 @@ from django.utils.deprecation import RemovedInDjango19Warning class Command(BaseCommand): help = "Runs this project as a FastCGI application. Requires flup." - args = '[various KEY=val options, use `runfcgi help` for help]' + + def add_arguments(self, parser): + parser.add_argument('args', nargs=argparse.REMAINDER, + help='Various KEY=val options.') def handle(self, *args, **options): warnings.warn( diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py index 2d7d6bffde..5211c25b8e 100644 --- a/django/core/management/commands/runserver.py +++ b/django/core/management/commands/runserver.py @@ -1,6 +1,5 @@ from __future__ import unicode_literals -from optparse import make_option from datetime import datetime import errno import os @@ -26,27 +25,28 @@ DEFAULT_PORT = "8000" class Command(BaseCommand): - option_list = BaseCommand.option_list + ( - make_option('--ipv6', '-6', action='store_true', dest='use_ipv6', default=False, - help='Tells Django to use an IPv6 address.'), - make_option('--nothreading', action='store_false', dest='use_threading', default=True, - help='Tells Django to NOT use threading.'), - make_option('--noreload', action='store_false', dest='use_reloader', default=True, - help='Tells Django to NOT use the auto-reloader.'), - ) help = "Starts a lightweight Web server for development." - args = '[optional port number, or ipaddr:port]' # Validation is called explicitly each time the server is reloaded. requires_system_checks = False + def add_arguments(self, parser): + parser.add_argument('addrport', nargs='?', + help='Optional port number, or ipaddr:port') + parser.add_argument('--ipv6', '-6', action='store_true', dest='use_ipv6', default=False, + help='Tells Django to use an IPv6 address.') + parser.add_argument('--nothreading', action='store_false', dest='use_threading', default=True, + help='Tells Django to NOT use threading.') + parser.add_argument('--noreload', action='store_false', dest='use_reloader', default=True, + help='Tells Django to NOT use the auto-reloader.') + def get_handler(self, *args, **options): """ Returns the default WSGI handler for the runner. """ return get_internal_wsgi_application() - def handle(self, addrport='', *args, **options): + def handle(self, *args, **options): from django.conf import settings if not settings.DEBUG and not settings.ALLOWED_HOSTS: @@ -55,17 +55,15 @@ class Command(BaseCommand): self.use_ipv6 = options.get('use_ipv6') if self.use_ipv6 and not socket.has_ipv6: raise CommandError('Your Python does not support IPv6.') - if args: - raise CommandError('Usage is runserver %s' % self.args) self._raw_ipv6 = False - if not addrport: + if not options.get('addrport'): self.addr = '' self.port = DEFAULT_PORT else: - m = re.match(naiveip_re, addrport) + m = re.match(naiveip_re, options['addrport']) if m is None: raise CommandError('"%s" is not a valid port number ' - 'or address:port pair.' % addrport) + 'or address:port pair.' % options['addrport']) self.addr, _ipv4, _ipv6, _fqdn, self.port = m.groups() if not self.port.isdigit(): raise CommandError("%r is not a valid port number." % self.port) @@ -79,18 +77,18 @@ class Command(BaseCommand): if not self.addr: self.addr = '::1' if self.use_ipv6 else '127.0.0.1' self._raw_ipv6 = bool(self.use_ipv6) - self.run(*args, **options) + self.run(**options) - def run(self, *args, **options): + def run(self, **options): """ Runs the server, using the autoreloader if needed """ use_reloader = options.get('use_reloader') if use_reloader: - autoreload.main(self.inner_run, args, options) + autoreload.main(self.inner_run, None, options) else: - self.inner_run(*args, **options) + self.inner_run(None, **options) def inner_run(self, *args, **options): from django.conf import settings diff --git a/django/core/management/commands/shell.py b/django/core/management/commands/shell.py index 5e833a29e5..d0c03030af 100644 --- a/django/core/management/commands/shell.py +++ b/django/core/management/commands/shell.py @@ -1,24 +1,20 @@ -from optparse import make_option import os from django.core.management.base import NoArgsCommand class Command(NoArgsCommand): - shells = ['ipython', 'bpython'] - - option_list = NoArgsCommand.option_list + ( - make_option('--plain', action='store_true', dest='plain', - help='Tells Django to use plain Python, not IPython or bpython.'), - make_option('--no-startup', action='store_true', dest='no_startup', - help='When using plain Python, ignore the PYTHONSTARTUP environment variable and ~/.pythonrc.py script.'), - make_option('-i', '--interface', action='store', type='choice', choices=shells, - dest='interface', - help='Specify an interactive interpreter interface. Available options: "ipython" and "bpython"'), - - ) help = "Runs a Python interactive interpreter. Tries to use IPython or bpython, if one of them is available." requires_system_checks = False + shells = ['ipython', 'bpython'] + + def add_arguments(self, parser): + parser.add_argument('--plain', action='store_true', dest='plain', + help='Tells Django to use plain Python, not IPython or bpython.') + parser.add_argument('--no-startup', action='store_true', dest='no_startup', + help='When using plain Python, ignore the PYTHONSTARTUP environment variable and ~/.pythonrc.py script.') + parser.add_argument('-i', '--interface', choices=self.shells, dest='interface', + help='Specify an interactive interpreter interface. Available options: "ipython" and "bpython"') def _ipython_pre_011(self): """Start IPython pre-0.11""" @@ -65,16 +61,12 @@ class Command(NoArgsCommand): raise ImportError def handle_noargs(self, **options): - use_plain = options.get('plain', False) - no_startup = options.get('no_startup', False) - interface = options.get('interface', None) - try: - if use_plain: + if options['plain']: # Don't bother loading IPython, because the user wants plain Python. raise ImportError - self.run_shell(shell=interface) + self.run_shell(shell=options['interface']) except ImportError: import code # Set up a dictionary to serve as the environment for the shell, so @@ -94,7 +86,7 @@ class Command(NoArgsCommand): # We want to honor both $PYTHONSTARTUP and .pythonrc.py, so follow system # conventions and get $PYTHONSTARTUP first then .pythonrc.py. - if not no_startup: + if not options['no_startup']: for pythonrc in (os.environ.get("PYTHONSTARTUP"), '~/.pythonrc.py'): if not pythonrc: continue diff --git a/django/core/management/commands/sql.py b/django/core/management/commands/sql.py index 3fd081940d..4308c04adc 100644 --- a/django/core/management/commands/sql.py +++ b/django/core/management/commands/sql.py @@ -1,7 +1,5 @@ from __future__ import unicode_literals -from optparse import make_option - from django.core.management.base import AppCommand from django.core.management.sql import sql_create from django.db import connections, DEFAULT_DB_ALIAS @@ -10,17 +8,17 @@ from django.db import connections, DEFAULT_DB_ALIAS class Command(AppCommand): help = "Prints the CREATE TABLE SQL statements for the given app name(s)." - option_list = AppCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to print the ' - 'SQL for. Defaults to the "default" database.'), - ) - output_transaction = True + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument('--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to print the SQL for. Defaults to the ' + '"default" database.') + def handle_app_config(self, app_config, **options): if app_config.models_module is None: return - connection = connections[options.get('database')] + connection = connections[options['database']] statements = sql_create(app_config, self.style, connection) return '\n'.join(statements) diff --git a/django/core/management/commands/sqlall.py b/django/core/management/commands/sqlall.py index 69746f1c3d..e7d7d0564d 100644 --- a/django/core/management/commands/sqlall.py +++ b/django/core/management/commands/sqlall.py @@ -1,7 +1,5 @@ from __future__ import unicode_literals -from optparse import make_option - from django.core.management.base import AppCommand from django.core.management.sql import sql_all from django.db import connections, DEFAULT_DB_ALIAS @@ -10,17 +8,17 @@ from django.db import connections, DEFAULT_DB_ALIAS class Command(AppCommand): help = "Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL statements for the given model module name(s)." - option_list = AppCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to print the ' - 'SQL for. Defaults to the "default" database.'), - ) - output_transaction = True + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument('--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to print the SQL for. Defaults to the ' + '"default" database.') + def handle_app_config(self, app_config, **options): if app_config.models_module is None: return - connection = connections[options.get('database')] + connection = connections[options['database']] statements = sql_all(app_config, self.style, connection) return '\n'.join(statements) diff --git a/django/core/management/commands/sqlclear.py b/django/core/management/commands/sqlclear.py index e611390533..e2d32e9618 100644 --- a/django/core/management/commands/sqlclear.py +++ b/django/core/management/commands/sqlclear.py @@ -1,7 +1,5 @@ from __future__ import unicode_literals -from optparse import make_option - from django.core.management.base import AppCommand from django.core.management.sql import sql_delete from django.db import connections, DEFAULT_DB_ALIAS @@ -10,17 +8,17 @@ from django.db import connections, DEFAULT_DB_ALIAS class Command(AppCommand): help = "Prints the DROP TABLE SQL statements for the given app name(s)." - option_list = AppCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to print the ' - 'SQL for. Defaults to the "default" database.'), - ) - output_transaction = True + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument('--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to print the SQL for. Defaults to the ' + '"default" database.') + def handle_app_config(self, app_config, **options): if app_config.models_module is None: return - connection = connections[options.get('database')] + connection = connections[options['database']] statements = sql_delete(app_config, self.style, connection) return '\n'.join(statements) diff --git a/django/core/management/commands/sqlcustom.py b/django/core/management/commands/sqlcustom.py index bfc6f395d4..84f213ca60 100644 --- a/django/core/management/commands/sqlcustom.py +++ b/django/core/management/commands/sqlcustom.py @@ -1,7 +1,5 @@ from __future__ import unicode_literals -from optparse import make_option - from django.core.management.base import AppCommand from django.core.management.sql import sql_custom from django.db import connections, DEFAULT_DB_ALIAS @@ -10,17 +8,17 @@ from django.db import connections, DEFAULT_DB_ALIAS class Command(AppCommand): help = "Prints the custom table modifying SQL statements for the given app name(s)." - option_list = AppCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to print the ' - 'SQL for. Defaults to the "default" database.'), - ) - output_transaction = True + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument('--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to print the SQL for. Defaults to the ' + '"default" database.') + def handle_app_config(self, app_config, **options): if app_config.models_module is None: return - connection = connections[options.get('database')] + connection = connections[options['database']] statements = sql_custom(app_config, self.style, connection) return '\n'.join(statements) diff --git a/django/core/management/commands/sqldropindexes.py b/django/core/management/commands/sqldropindexes.py index 4bdb42d608..f4789377d4 100644 --- a/django/core/management/commands/sqldropindexes.py +++ b/django/core/management/commands/sqldropindexes.py @@ -1,7 +1,5 @@ from __future__ import unicode_literals -from optparse import make_option - from django.core.management.base import AppCommand from django.core.management.sql import sql_destroy_indexes from django.db import connections, DEFAULT_DB_ALIAS @@ -10,18 +8,17 @@ from django.db import connections, DEFAULT_DB_ALIAS class Command(AppCommand): help = "Prints the DROP INDEX SQL statements for the given model module name(s)." - option_list = AppCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to print the ' - 'SQL for. Defaults to the "default" database.'), - - ) - output_transaction = True + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument('--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to print the SQL for. Defaults to the ' + '"default" database.') + def handle_app_config(self, app_config, **options): if app_config.models_module is None: return - connection = connections[options.get('database')] + connection = connections[options['database']] statements = sql_destroy_indexes(app_config, self.style, connection) return '\n'.join(statements) diff --git a/django/core/management/commands/sqlflush.py b/django/core/management/commands/sqlflush.py index 8ccc61e9a8..48bc693611 100644 --- a/django/core/management/commands/sqlflush.py +++ b/django/core/management/commands/sqlflush.py @@ -1,7 +1,5 @@ from __future__ import unicode_literals -from optparse import make_option - from django.core.management.base import NoArgsCommand from django.core.management.sql import sql_flush from django.db import connections, DEFAULT_DB_ALIAS @@ -10,13 +8,13 @@ from django.db import connections, DEFAULT_DB_ALIAS class Command(NoArgsCommand): help = "Returns a list of the SQL statements required to return all tables in the database to the state they were in just after they were installed." - option_list = NoArgsCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to print the ' - 'SQL for. Defaults to the "default" database.'), - ) - output_transaction = True + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument('--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to print the SQL for. Defaults to the ' + '"default" database.') + def handle_noargs(self, **options): - return '\n'.join(sql_flush(self.style, connections[options.get('database')], only_django=True)) + return '\n'.join(sql_flush(self.style, connections[options['database']], only_django=True)) diff --git a/django/core/management/commands/sqlindexes.py b/django/core/management/commands/sqlindexes.py index 2f1fd8d103..0fbbb0cdb9 100644 --- a/django/core/management/commands/sqlindexes.py +++ b/django/core/management/commands/sqlindexes.py @@ -1,7 +1,5 @@ from __future__ import unicode_literals -from optparse import make_option - from django.core.management.base import AppCommand from django.core.management.sql import sql_indexes from django.db import connections, DEFAULT_DB_ALIAS @@ -10,18 +8,17 @@ from django.db import connections, DEFAULT_DB_ALIAS class Command(AppCommand): help = "Prints the CREATE INDEX SQL statements for the given model module name(s)." - option_list = AppCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to print the ' - 'SQL for. Defaults to the "default" database.'), - - ) - output_transaction = True + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument('--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to print the SQL for. Defaults to the ' + '"default" database.') + def handle_app_config(self, app_config, **options): if app_config.models_module is None: return - connection = connections[options.get('database')] + connection = connections[options['database']] statements = sql_indexes(app_config, self.style, connection) return '\n'.join(statements) diff --git a/django/core/management/commands/sqlmigrate.py b/django/core/management/commands/sqlmigrate.py index e8ced69c21..eb43cec351 100644 --- a/django/core/management/commands/sqlmigrate.py +++ b/django/core/management/commands/sqlmigrate.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from optparse import make_option from django.core.management.base import BaseCommand, CommandError from django.db import connections, DEFAULT_DB_ALIAS @@ -9,44 +8,41 @@ from django.db.migrations.loader import AmbiguityError class Command(BaseCommand): - - option_list = BaseCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to create SQL for. ' - 'Defaults to the "default" database.'), - make_option('--backwards', action='store_true', dest='backwards', - default=False, help='Creates SQL to unapply the migration, rather than to apply it'), - ) - help = "Prints the SQL statements for the named migration." - def handle(self, *args, **options): + def add_arguments(self, parser): + parser.add_argument('app_label', + help='App label of the application containing the migration.') + parser.add_argument('migration_name', + help='Migration name to print the SQL for.') + parser.add_argument('--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to create SQL for. Defaults to the ' + '"default" database.') + parser.add_argument('--backwards', action='store_true', dest='backwards', + default=False, help='Creates SQL to unapply the migration, rather than to apply it') + def handle(self, *args, **options): # Get the database we're operating from - db = options.get('database') - connection = connections[db] + connection = connections[options['database']] # Load up an executor to get all the migration data executor = MigrationExecutor(connection) # Resolve command-line arguments into a migration - if len(args) != 2: - raise CommandError("Wrong number of arguments (expecting 'sqlmigrate app_label migrationname')") - else: - app_label, migration_name = args - if app_label not in executor.loader.migrated_apps: - raise CommandError("App '%s' does not have migrations" % app_label) - try: - migration = executor.loader.get_migration_by_prefix(app_label, migration_name) - except AmbiguityError: - raise CommandError("More than one migration matches '%s' in app '%s'. Please be more specific." % (app_label, migration_name)) - except KeyError: - raise CommandError("Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?" % (app_label, migration_name)) - targets = [(app_label, migration.name)] + app_label, migration_name = options['app_label'], options['migration_name'] + if app_label not in executor.loader.migrated_apps: + raise CommandError("App '%s' does not have migrations" % app_label) + try: + migration = executor.loader.get_migration_by_prefix(app_label, migration_name) + except AmbiguityError: + raise CommandError("More than one migration matches '%s' in app '%s'. Please be more specific." % (app_label, migration_name)) + except KeyError: + raise CommandError("Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?" % (app_label, migration_name)) + targets = [(app_label, migration.name)] # Make a plan that represents just the requested migrations and show SQL # for it - plan = [(executor.loader.graph.nodes[targets[0]], options.get("backwards", False))] + plan = [(executor.loader.graph.nodes[targets[0]], options['backwards'])] sql_statements = executor.collect_sql(plan) for statement in sql_statements: self.stdout.write(statement) diff --git a/django/core/management/commands/sqlsequencereset.py b/django/core/management/commands/sqlsequencereset.py index 4f7ce4492a..729267bb73 100644 --- a/django/core/management/commands/sqlsequencereset.py +++ b/django/core/management/commands/sqlsequencereset.py @@ -1,7 +1,5 @@ from __future__ import unicode_literals -from optparse import make_option - from django.core.management.base import AppCommand from django.core.management.sql import check_for_migrations from django.db import connections, DEFAULT_DB_ALIAS @@ -10,15 +8,14 @@ from django.db import connections, DEFAULT_DB_ALIAS class Command(AppCommand): help = 'Prints the SQL statements for resetting sequences for the given app name(s).' - option_list = AppCommand.option_list + ( - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to print the ' - 'SQL for. Defaults to the "default" database.'), - - ) - output_transaction = True + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument('--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to print the SQL for. Defaults to the ' + '"default" database.') + def handle_app_config(self, app_config, **options): if app_config.models_module is None: return diff --git a/django/core/management/commands/squashmigrations.py b/django/core/management/commands/squashmigrations.py index 3101ca0b14..53e094a01b 100644 --- a/django/core/management/commands/squashmigrations.py +++ b/django/core/management/commands/squashmigrations.py @@ -1,5 +1,4 @@ import sys -from optparse import make_option from django.core.management.base import BaseCommand, CommandError from django.utils import six @@ -11,25 +10,23 @@ from django.db.migrations.optimizer import MigrationOptimizer class Command(BaseCommand): - option_list = BaseCommand.option_list + ( - make_option('--no-optimize', action='store_true', dest='no_optimize', default=False, - help='Do not try to optimize the squashed operations.'), - make_option('--noinput', action='store_false', dest='interactive', default=True, - help='Tells Django to NOT prompt the user for input of any kind.'), - ) - help = "Squashes an existing set of migrations (from first until specified) into a single new one." - usage_str = "Usage: ./manage.py squashmigrations app migration_name" - args = "app_label migration_name" - def handle(self, app_label=None, migration_name=None, **options): + def add_arguments(self, parser): + parser.add_argument('app_label', + help='App label of the application to squash migrations for.') + parser.add_argument('migration_name', + help='Migrations will be squashed until and including this migration.') + parser.add_argument('--no-optimize', action='store_true', dest='no_optimize', default=False, + help='Do not try to optimize the squashed operations.') + parser.add_argument('--noinput', action='store_false', dest='interactive', default=True, + help='Tells Django to NOT prompt the user for input of any kind.') - self.verbosity = int(options.get('verbosity')) + def handle(self, **options): + + self.verbosity = options.get('verbosity') self.interactive = options.get('interactive') - - if app_label is None or migration_name is None: - self.stderr.write(self.usage_str) - sys.exit(1) + app_label, migration_name = options['app_label'], options['migration_name'] # Load the current graph state, check the app and migration they asked for exists executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS]) diff --git a/django/core/management/commands/startapp.py b/django/core/management/commands/startapp.py index 77e884ca5a..23ae25446b 100644 --- a/django/core/management/commands/startapp.py +++ b/django/core/management/commands/startapp.py @@ -8,8 +8,10 @@ class Command(TemplateCommand): help = ("Creates a Django app directory structure for the given app " "name in the current directory or optionally in the given " "directory.") + missing_args_message = "You must provide an application name." - def handle(self, app_name=None, target=None, **options): + def handle(self, **options): + app_name, target = options.pop('name'), options.pop('directory') self.validate_name(app_name, "app") # Check that the app_name cannot be imported. diff --git a/django/core/management/commands/startproject.py b/django/core/management/commands/startproject.py index 19eca8e018..f9c89d7493 100644 --- a/django/core/management/commands/startproject.py +++ b/django/core/management/commands/startproject.py @@ -9,8 +9,10 @@ class Command(TemplateCommand): help = ("Creates a Django project directory structure for the given " "project name in the current directory or optionally in the " "given directory.") + missing_args_message = "You must provide a project name." - def handle(self, project_name=None, target=None, *args, **options): + def handle(self, **options): + project_name, target = options.pop('name'), options.pop('directory') self.validate_name(project_name, "project") # Check that the project_name cannot be imported. diff --git a/django/core/management/commands/syncdb.py b/django/core/management/commands/syncdb.py index 5b4791618f..52b9dde956 100644 --- a/django/core/management/commands/syncdb.py +++ b/django/core/management/commands/syncdb.py @@ -1,5 +1,4 @@ import warnings -from optparse import make_option from django.apps import apps from django.contrib.auth import get_user_model @@ -11,17 +10,16 @@ from django.utils.six.moves import input class Command(NoArgsCommand): - option_list = NoArgsCommand.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.'), - make_option('--no-initial-data', action='store_false', dest='load_initial_data', default=True, - help='Tells Django not to load any initial data after database synchronization.'), - make_option('--database', action='store', dest='database', - default=DEFAULT_DB_ALIAS, help='Nominates a database to synchronize. ' - 'Defaults to the "default" database.'), - ) help = "Deprecated - use 'migrate' instead." + def add_arguments(self, parser): + parser.add_argument('--noinput', action='store_false', dest='interactive', default=True, + help='Tells Django to NOT prompt the user for input of any kind.') + parser.add_argument('--no-initial-data', action='store_false', dest='load_initial_data', default=True, + help='Tells Django not to load any initial data after database synchronization.') + parser.add_argument('--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to synchronize. Defaults to the "default" database.') + def handle_noargs(self, **options): warnings.warn("The syncdb command will be removed in Django 1.9", RemovedInDjango19Warning) call_command("migrate", **options) diff --git a/django/core/management/commands/testserver.py b/django/core/management/commands/testserver.py index 78885bbdb2..0be8cb421a 100644 --- a/django/core/management/commands/testserver.py +++ b/django/core/management/commands/testserver.py @@ -1,30 +1,27 @@ +from django.core.management import call_command from django.core.management.base import BaseCommand - -from optparse import make_option +from django.db import connection class Command(BaseCommand): - option_list = BaseCommand.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.'), - make_option('--addrport', action='store', dest='addrport', - type='string', default='', - help='port number or ipaddr:port to run the server on'), - make_option('--ipv6', '-6', action='store_true', dest='use_ipv6', default=False, - help='Tells Django to use an IPv6 address.'), - ) help = 'Runs a development server with data from the given fixture(s).' args = '[fixture ...]' requires_system_checks = False - def handle(self, *fixture_labels, **options): - from django.core.management import call_command - from django.db import connection + def add_arguments(self, parser): + parser.add_argument('args', metavar='fixture', nargs='*', + help='Path(s) to fixtures to load before running the server.') + parser.add_argument('--noinput', action='store_false', dest='interactive', default=True, + help='Tells Django to NOT prompt the user for input of any kind.') + parser.add_argument('--addrport', default='', + help='Port number or ipaddr:port to run the server on.') + parser.add_argument('--ipv6', '-6', action='store_true', dest='use_ipv6', default=False, + help='Tells Django to use an IPv6 address.') - verbosity = int(options.get('verbosity')) + def handle(self, *fixture_labels, **options): + verbosity = options.get('verbosity') interactive = options.get('interactive') - addrport = options.get('addrport') # Create a test database. db_name = connection.creation.create_test_db(verbosity=verbosity, autoclobber=not interactive, serialize=False) @@ -39,7 +36,7 @@ class Command(BaseCommand): use_threading = connection.features.test_db_allows_multiple_connections call_command( 'runserver', - addrport=addrport, + addrport=options['addrport'], shutdown_message=shutdown_message, use_reloader=False, use_ipv6=options['use_ipv6'], diff --git a/django/core/management/templates.py b/django/core/management/templates.py index d1044cbfab..d514c84755 100644 --- a/django/core/management/templates.py +++ b/django/core/management/templates.py @@ -9,7 +9,6 @@ import stat import sys import tempfile -from optparse import make_option from os import path import django @@ -36,22 +35,6 @@ class TemplateCommand(BaseCommand): :param directory: The directory to which the template should be copied. :param options: The additional variables passed to project or app templates """ - args = "[name] [optional destination directory]" - option_list = BaseCommand.option_list + ( - make_option('--template', - action='store', dest='template', - help='The path or URL to load the template from.'), - make_option('--extension', '-e', dest='extensions', - action='append', default=['py'], - help='The file extension(s) to render (default: "py"). ' - 'Separate multiple extensions with commas, or use ' - '-e multiple times.'), - make_option('--name', '-n', dest='files', - action='append', default=[], - help='The file name(s) to render. ' - 'Separate multiple extensions with commas, or use ' - '-n multiple times.') - ) requires_system_checks = False # Can't import settings during this command, because they haven't # necessarily been created. @@ -62,10 +45,26 @@ class TemplateCommand(BaseCommand): # setting might not be available at all. leave_locale_alone = True + def add_arguments(self, parser): + parser.add_argument('name', help='Name of the application or project.') + parser.add_argument('directory', nargs='?', help='Optional destination directory') + parser.add_argument('--template', + help='The path or URL to load the template from.') + parser.add_argument('--extension', '-e', dest='extensions', + action='append', default=['py'], + help='The file extension(s) to render (default: "py"). ' + 'Separate multiple extensions with commas, or use ' + '-e multiple times.') + parser.add_argument('--name', '-n', dest='files', + action='append', default=[], + help='The file name(s) to render. ' + 'Separate multiple extensions with commas, or use ' + '-n multiple times.') + def handle(self, app_or_project, name, target=None, **options): self.app_or_project = app_or_project self.paths_to_remove = [] - self.verbosity = int(options.get('verbosity')) + self.verbosity = options['verbosity'] self.validate_name(name, app_or_project) @@ -87,9 +86,9 @@ class TemplateCommand(BaseCommand): "exist, please create it first." % top_dir) extensions = tuple( - handle_extensions(options.get('extensions'), ignored=())) + handle_extensions(options['extensions'], ignored=())) extra_files = [] - for file in options.get('files'): + for file in options['files']: extra_files.extend(map(lambda x: x.strip(), file.split(','))) if self.verbosity >= 2: self.stdout.write("Rendering %s template files with " @@ -118,7 +117,7 @@ class TemplateCommand(BaseCommand): if not settings.configured: settings.configure() - template_dir = self.handle_template(options.get('template'), + template_dir = self.handle_template(options['template'], base_subdir) prefix_length = len(template_dir) + 1 diff --git a/tests/admin_scripts/management/commands/base_command.py b/tests/admin_scripts/management/commands/base_command.py index c313235ead..14e9152d9d 100644 --- a/tests/admin_scripts/management/commands/base_command.py +++ b/tests/admin_scripts/management/commands/base_command.py @@ -1,17 +1,15 @@ -from optparse import make_option - from django.core.management.base import BaseCommand class Command(BaseCommand): - option_list = BaseCommand.option_list + ( - make_option('--option_a', '-a', action='store', dest='option_a', default='1'), - make_option('--option_b', '-b', action='store', dest='option_b', default='2'), - make_option('--option_c', '-c', action='store', dest='option_c', default='3'), - ) help = 'Test basic commands' requires_system_checks = False - args = '[labels ...]' + + def add_arguments(self, parser): + parser.add_argument('args', nargs='*') + parser.add_argument('--option_a', '-a', default='1') + parser.add_argument('--option_b', '-b', default='2') + parser.add_argument('--option_c', '-c', default='3') def handle(self, *labels, **options): print('EXECUTE:BaseCommand labels=%s, options=%s' % (labels, sorted(options.items()))) diff --git a/tests/admin_scripts/management/commands/custom_startproject.py b/tests/admin_scripts/management/commands/custom_startproject.py index 8144b5b69c..0d9c7d339e 100644 --- a/tests/admin_scripts/management/commands/custom_startproject.py +++ b/tests/admin_scripts/management/commands/custom_startproject.py @@ -1,11 +1,8 @@ -from optparse import make_option - from django.core.management.commands.startproject import Command as BaseCommand class Command(BaseCommand): - option_list = BaseCommand.option_list + ( - make_option('--extra', - action='store', dest='extra', - help='An arbitrary extra value passed to the context'), - ) + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument('--extra', + help='An arbitrary extra value passed to the context') diff --git a/tests/admin_scripts/management/commands/label_command.py b/tests/admin_scripts/management/commands/label_command.py index 9bba413ff3..5bffeb3ae2 100644 --- a/tests/admin_scripts/management/commands/label_command.py +++ b/tests/admin_scripts/management/commands/label_command.py @@ -4,7 +4,6 @@ from django.core.management.base import LabelCommand class Command(LabelCommand): help = "Test Label-based commands" requires_system_checks = False - args = '