summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2014-06-06 22:39:33 +0200
committerClaude Paroz <claude@2xlibre.net>2014-06-14 13:43:44 +0200
commitf17b24e407385eb18651bf023a187347aa9c1f75 (patch)
tree1757c5d85629d9cd4b84f60e07aeca5eedd515de
parent4b4524291adbc78ab880317124803fc37a2e414a (diff)
Converted remaining management commands to argparse
-rw-r--r--django/contrib/auth/management/commands/changepassword.py19
-rw-r--r--django/contrib/auth/management/commands/createsuperuser.py43
-rw-r--r--django/contrib/auth/tests/test_management.py8
-rw-r--r--django/contrib/gis/management/commands/ogrinspect.py121
-rw-r--r--django/contrib/staticfiles/management/commands/collectstatic.py55
-rw-r--r--django/contrib/staticfiles/management/commands/findstatic.py14
-rw-r--r--django/contrib/staticfiles/management/commands/runserver.py15
-rw-r--r--django/core/management/commands/check.py14
-rw-r--r--django/core/management/commands/compilemessages.py15
-rw-r--r--django/core/management/commands/createcachetable.py18
-rw-r--r--django/core/management/commands/dbshell.py13
-rw-r--r--django/core/management/commands/diffsettings.py13
-rw-r--r--django/core/management/commands/dumpdata.py54
-rw-r--r--django/core/management/commands/flush.py22
-rw-r--r--django/core/management/commands/inspectdb.py14
-rw-r--r--django/core/management/commands/loaddata.py32
-rw-r--r--django/core/management/commands/makemessages.py64
-rw-r--r--django/core/management/commands/makemigrations.py24
-rw-r--r--django/core/management/commands/migrate.py48
-rw-r--r--django/core/management/commands/runfcgi.py6
-rw-r--r--django/core/management/commands/runserver.py38
-rw-r--r--django/core/management/commands/shell.py32
-rw-r--r--django/core/management/commands/sql.py16
-rw-r--r--django/core/management/commands/sqlall.py16
-rw-r--r--django/core/management/commands/sqlclear.py16
-rw-r--r--django/core/management/commands/sqlcustom.py16
-rw-r--r--django/core/management/commands/sqldropindexes.py17
-rw-r--r--django/core/management/commands/sqlflush.py16
-rw-r--r--django/core/management/commands/sqlindexes.py17
-rw-r--r--django/core/management/commands/sqlmigrate.py50
-rw-r--r--django/core/management/commands/sqlsequencereset.py15
-rw-r--r--django/core/management/commands/squashmigrations.py29
-rw-r--r--django/core/management/commands/startapp.py4
-rw-r--r--django/core/management/commands/startproject.py4
-rw-r--r--django/core/management/commands/syncdb.py18
-rw-r--r--django/core/management/commands/testserver.py31
-rw-r--r--django/core/management/templates.py41
-rw-r--r--tests/admin_scripts/management/commands/base_command.py14
-rw-r--r--tests/admin_scripts/management/commands/custom_startproject.py11
-rw-r--r--tests/admin_scripts/management/commands/label_command.py1
-rw-r--r--tests/admin_scripts/tests.py19
-rw-r--r--tests/bash_completion/management/commands/test_command.py9
-rw-r--r--tests/createsuperuser/tests.py2
-rw-r--r--tests/staticfiles_tests/tests.py6
-rw-r--r--tests/user_commands/management/commands/dance.py9
45 files changed, 493 insertions, 566 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',
+ help = ("Output the contents of the database as a fixture of the given "
+ "format (using each model's default manager unless --all is "
+ "specified).")
+
+ 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.'),
- make_option('-e', '--exclude', dest='exclude', action='append', default=[],
+ '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).'),
- 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,
+ '(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."),
- make_option('--pks', dest='primary_keys',
+ "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."),
- 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 ...]'
+ "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'))
- self.interactive = options.get('interactive')
+ def handle(self, **options):
- if app_label is None or migration_name is None:
- self.stderr.write(self.usage_str)
- sys.exit(1)
+ self.verbosity = options.get('verbosity')
+ self.interactive = options.get('interactive')
+ 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 = '<label>'
def handle_label(self, label, **options):
print('EXECUTE:LabelCommand label=%s, options=%s' % (label, sorted(options.items())))
diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py
index 75c272cf71..48414272ac 100644
--- a/tests/admin_scripts/tests.py
+++ b/tests/admin_scripts/tests.py
@@ -28,7 +28,6 @@ from django.utils._os import npath, upath
from django.utils.six import StringIO
from django.test import LiveServerTestCase, TestCase, override_settings
from django.test.runner import DiscoverRunner
-from django.test.utils import str_prefix
test_dir = os.path.realpath(os.path.join(os.environ['DJANGO_TEST_TEMP_DIR'], 'test_project'))
@@ -1378,7 +1377,8 @@ class CommandTypes(AdminScriptTestCase):
args = ['sqlall', '--help']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL statements for the given model module name(s).")
+ self.assertOutput(out, "Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL statements for the\ngiven model module name(s).")
+ self.assertEqual(out.count('optional arguments'), 1)
def test_no_color(self):
"--no-color prevent colorization of the output"
@@ -1420,12 +1420,11 @@ class CommandTypes(AdminScriptTestCase):
def _test_base_command(self, args, labels, option_a="'1'", option_b="'2'"):
out, err = self.run_manage(args)
- expected_out = str_prefix(
- ("EXECUTE:BaseCommand labels=%%s, "
- "options=[('no_color', False), ('option_a', %%s), ('option_b', %%s), "
- "('option_c', '3'), ('pythonpath', None), ('settings', None), "
- "('traceback', None), ('verbosity', %(_)s'1')]")
- ) % (labels, option_a, option_b)
+ expected_out = (
+ "EXECUTE:BaseCommand labels=%s, "
+ "options=[('no_color', False), ('option_a', %s), ('option_b', %s), "
+ "('option_c', '3'), ('pythonpath', None), ('settings', None), "
+ "('traceback', False), ('verbosity', 1)]") % (labels, option_a, option_b)
self.assertNoOutput(err)
self.assertOutput(out, expected_out)
@@ -1629,7 +1628,7 @@ class ArgumentOrder(AdminScriptTestCase):
def _test(self, args, option_b="'2'"):
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, str_prefix("EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', %%s), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', %(_)s'1')]") % option_b)
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', %s), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', False), ('verbosity', 1)]" % option_b)
@override_settings(ROOT_URLCONF='admin_scripts.urls')
@@ -1646,7 +1645,7 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
"Make sure passing the wrong kinds of arguments raises a CommandError"
out, err = self.run_django_admin(['startproject'])
self.assertNoOutput(out)
- self.assertOutput(err, "you must provide a project name")
+ self.assertOutput(err, "You must provide a project name.")
def test_simple_project(self):
"Make sure the startproject management command creates a project"
diff --git a/tests/bash_completion/management/commands/test_command.py b/tests/bash_completion/management/commands/test_command.py
index 0f5750645c..d2adf91e5a 100644
--- a/tests/bash_completion/management/commands/test_command.py
+++ b/tests/bash_completion/management/commands/test_command.py
@@ -1,13 +1,10 @@
-from optparse import make_option
-
from django.core.management.base import BaseCommand
class Command(BaseCommand):
- option_list = BaseCommand.option_list + (
- make_option("--list", action="store_true", dest="list",
- help="Print all options"),
- )
+ def add_arguments(self, parser):
+ parser.add_argument("--list", action="store_true", dest="list",
+ help="Print all options")
def handle(self, *args, **options):
pass
diff --git a/tests/createsuperuser/tests.py b/tests/createsuperuser/tests.py
index 822f05d01b..b5036c85de 100644
--- a/tests/createsuperuser/tests.py
+++ b/tests/createsuperuser/tests.py
@@ -24,7 +24,7 @@ class MultiDBChangepasswordManagementCommandTestCase(TestCase):
command = changepassword.Command()
command._get_pass = lambda *args: 'not qwerty'
- command.execute("joe", database='other', stdout=self.stdout)
+ command.execute(username="joe", database='other', stdout=self.stdout)
command_output = self.stdout.getvalue().strip()
self.assertEqual(command_output, "Changing password for user 'joe'\nPassword changed successfully for user 'joe'")
diff --git a/tests/staticfiles_tests/tests.py b/tests/staticfiles_tests/tests.py
index afc9b0b17c..df9a6ce3a2 100644
--- a/tests/staticfiles_tests/tests.py
+++ b/tests/staticfiles_tests/tests.py
@@ -128,7 +128,7 @@ class BaseCollectionTestCase(BaseStaticFilesTestCase):
ignore_errors=True, onerror=rmtree_errorhandler)
def run_collectstatic(self, **kwargs):
- call_command('collectstatic', interactive=False, verbosity='0',
+ call_command('collectstatic', interactive=False, verbosity=0,
ignore_patterns=['*.ignoreme'], **kwargs)
def _get_file(self, filepath):
@@ -559,7 +559,7 @@ class TestHashedFiles(object):
"""
collectstatic_args = {
'interactive': False,
- 'verbosity': '0',
+ 'verbosity': 0,
'link': False,
'clear': False,
'dry_run': False,
@@ -952,7 +952,7 @@ class TestStaticFilePermissions(BaseCollectionTestCase, StaticFilesTestCase):
command_params = {'interactive': False,
'post_process': True,
- 'verbosity': '0',
+ 'verbosity': 0,
'ignore_patterns': ['*.ignoreme'],
'use_default_ignore_patterns': True,
'clear': False,
diff --git a/tests/user_commands/management/commands/dance.py b/tests/user_commands/management/commands/dance.py
index 7297568f06..0c47401c25 100644
--- a/tests/user_commands/management/commands/dance.py
+++ b/tests/user_commands/management/commands/dance.py
@@ -1,5 +1,3 @@
-from optparse import make_option
-
from django.core.management.base import BaseCommand, CommandError
@@ -8,10 +6,9 @@ class Command(BaseCommand):
args = ''
requires_system_checks = True
- option_list = BaseCommand.option_list + (
- make_option("-s", "--style", default="Rock'n'Roll"),
- make_option("-x", "--example")
- )
+ def add_arguments(self, parser):
+ parser.add_argument("-s", "--style", default="Rock'n'Roll")
+ parser.add_argument("-x", "--example")
def handle(self, *args, **options):
example = options["example"]