Refs #26315 -- Cleaned up argparse options in commands.

* Removed type coercion. Options created by argparse are already coerced
  to the correct type.
* Removed fallback default values. Options created by argparse already
  have a default value.
* Used direct indexing. Options created by argparse are always set. This
  eliminates the need to use dict.get().
This commit is contained in:
Jon Dufresne 2016-03-02 18:01:36 -08:00 committed by Tim Graham
parent 4115288b4f
commit 1845bc1d10
21 changed files with 87 additions and 78 deletions

View File

@ -29,7 +29,7 @@ class Command(BaseCommand):
help='Specifies the database to use. Default is "default".') help='Specifies the database to use. Default is "default".')
def handle(self, *args, **options): def handle(self, *args, **options):
if options.get('username'): if options['username']:
username = options['username'] username = options['username']
else: else:
username = getpass.getuser() username = getpass.getuser()
@ -37,7 +37,7 @@ class Command(BaseCommand):
UserModel = get_user_model() UserModel = get_user_model()
try: try:
u = UserModel._default_manager.using(options.get('database')).get(**{ u = UserModel._default_manager.using(options['database']).get(**{
UserModel.USERNAME_FIELD: username UserModel.USERNAME_FIELD: username
}) })
except UserModel.DoesNotExist: except UserModel.DoesNotExist:

View File

@ -53,8 +53,8 @@ class Command(BaseCommand):
return super(Command, self).execute(*args, **options) return super(Command, self).execute(*args, **options)
def handle(self, *args, **options): def handle(self, *args, **options):
username = options.get(self.UserModel.USERNAME_FIELD) username = options[self.UserModel.USERNAME_FIELD]
database = options.get('database') database = options['database']
# If not provided, create the user with an unusable password # If not provided, create the user with an unusable password
password = None password = None
@ -72,7 +72,7 @@ class Command(BaseCommand):
username = self.username_field.clean(username, None) username = self.username_field.clean(username, None)
for field_name in self.UserModel.REQUIRED_FIELDS: for field_name in self.UserModel.REQUIRED_FIELDS:
if options.get(field_name): if options[field_name]:
field = self.UserModel._meta.get_field(field_name) field = self.UserModel._meta.get_field(field_name)
user_data[field_name] = field.clean(options[field_name], None) user_data[field_name] = field.clean(options[field_name], None)
else: else:
@ -118,7 +118,7 @@ class Command(BaseCommand):
for field_name in self.UserModel.REQUIRED_FIELDS: for field_name in self.UserModel.REQUIRED_FIELDS:
field = self.UserModel._meta.get_field(field_name) field = self.UserModel._meta.get_field(field_name)
user_data[field_name] = options.get(field_name) user_data[field_name] = options[field_name]
while user_data[field_name] is None: while user_data[field_name] is None:
message = force_str('%s%s: ' % ( message = force_str('%s%s: ' % (
capfirst(field.verbose_name), capfirst(field.verbose_name),

View File

@ -21,8 +21,8 @@ class Command(RunserverCommand):
handler. handler.
""" """
handler = super(Command, self).get_handler(*args, **options) handler = super(Command, self).get_handler(*args, **options)
use_static_handler = options.get('use_static_handler', True) use_static_handler = options['use_static_handler']
insecure_serving = options.get('insecure_serving', False) insecure_serving = options['insecure_serving']
if use_static_handler and (settings.DEBUG or insecure_serving): if use_static_handler and (settings.DEBUG or insecure_serving):
return StaticFilesHandler(handler) return StaticFilesHandler(handler)
return handler return handler

View File

@ -314,13 +314,13 @@ class BaseCommand(object):
controlled by the ``requires_system_checks`` attribute, except if controlled by the ``requires_system_checks`` attribute, except if
force-skipped). force-skipped).
""" """
if options.get('no_color'): if options['no_color']:
self.style = no_style() self.style = no_style()
self.stderr.style_func = None self.stderr.style_func = None
if options.get('stdout'): if options.get('stdout'):
self.stdout = OutputWrapper(options['stdout']) self.stdout = OutputWrapper(options['stdout'])
if options.get('stderr'): if options.get('stderr'):
self.stderr = OutputWrapper(options.get('stderr'), self.stderr.style_func) self.stderr = OutputWrapper(options['stderr'], self.stderr.style_func)
saved_locale = None saved_locale = None
if not self.leave_locale_alone: if not self.leave_locale_alone:

View File

@ -33,7 +33,7 @@ class Command(BaseCommand):
def handle(self, *app_labels, **options): def handle(self, *app_labels, **options):
include_deployment_checks = options['deploy'] include_deployment_checks = options['deploy']
if options.get('list_tags'): if options['list_tags']:
self.stdout.write('\n'.join(sorted(registry.tags_available(include_deployment_checks)))) self.stdout.write('\n'.join(sorted(registry.tags_available(include_deployment_checks))))
return return
@ -42,7 +42,7 @@ class Command(BaseCommand):
else: else:
app_configs = None app_configs = None
tags = options.get('tags') tags = options['tags']
if tags: if tags:
try: try:
invalid_tag = next( invalid_tag = next(

View File

@ -45,10 +45,10 @@ class Command(BaseCommand):
help='Use fuzzy translations.') help='Use fuzzy translations.')
def handle(self, **options): def handle(self, **options):
locale = options.get('locale') locale = options['locale']
exclude = options.get('exclude') exclude = options['exclude']
self.verbosity = int(options.get('verbosity')) self.verbosity = options['verbosity']
if options.get('fuzzy'): if options['fuzzy']:
self.program_options = self.program_options + ['-f'] self.program_options = self.program_options + ['-f']
if find_command(self.program) is None: if find_command(self.program) is None:

View File

@ -27,9 +27,9 @@ class Command(BaseCommand):
'be run.') 'be run.')
def handle(self, *tablenames, **options): def handle(self, *tablenames, **options):
db = options.get('database') db = options['database']
self.verbosity = int(options.get('verbosity')) self.verbosity = options['verbosity']
dry_run = options.get('dry_run') dry_run = options['dry_run']
if len(tablenames): if len(tablenames):
# Legacy behavior, tablename specified as argument # Legacy behavior, tablename specified as argument
for tablename in tablenames: for tablename in tablenames:

View File

@ -14,7 +14,7 @@ class Command(BaseCommand):
'open a shell. Defaults to the "default" database.') 'open a shell. Defaults to the "default" database.')
def handle(self, **options): def handle(self, **options):
connection = connections[options.get('database')] connection = connections[options['database']]
try: try:
connection.client.runshell() connection.client.runshell()
except OSError: except OSError:

View File

@ -45,16 +45,16 @@ class Command(BaseCommand):
help='Specifies file to which the output is written.') help='Specifies file to which the output is written.')
def handle(self, *app_labels, **options): def handle(self, *app_labels, **options):
format = options.get('format') format = options['format']
indent = options.get('indent') indent = options['indent']
using = options.get('database') using = options['database']
excludes = options.get('exclude') excludes = options['exclude']
output = options.get('output') output = options['output']
show_traceback = options.get('traceback') show_traceback = options['traceback']
use_natural_foreign_keys = options.get('use_natural_foreign_keys') use_natural_foreign_keys = options['use_natural_foreign_keys']
use_natural_primary_keys = options.get('use_natural_primary_keys') use_natural_primary_keys = options['use_natural_primary_keys']
use_base_manager = options.get('use_base_manager') use_base_manager = options['use_base_manager']
pks = options.get('primary_keys') pks = options['primary_keys']
if pks: if pks:
primary_keys = pks.split(',') primary_keys = pks.split(',')

View File

@ -25,10 +25,10 @@ class Command(BaseCommand):
help='Nominates a database to flush. Defaults to the "default" database.') help='Nominates a database to flush. Defaults to the "default" database.')
def handle(self, **options): def handle(self, **options):
database = options.get('database') database = options['database']
connection = connections[database] connection = connections[database]
verbosity = options.get('verbosity') verbosity = options['verbosity']
interactive = options.get('interactive') interactive = options['interactive']
# The following are stealth options used by Django's internals. # The following are stealth options used by Django's internals.
reset_sequences = options.get('reset_sequences', True) reset_sequences = options.get('reset_sequences', True)
allow_cascade = options.get('allow_cascade', False) allow_cascade = options.get('allow_cascade', False)

View File

@ -50,10 +50,10 @@ class Command(BaseCommand):
def handle(self, *fixture_labels, **options): def handle(self, *fixture_labels, **options):
self.ignore = options.get('ignore') self.ignore = options['ignore']
self.using = options.get('database') self.using = options['database']
self.app_label = options.get('app_label') self.app_label = options['app_label']
self.verbosity = options.get('verbosity') self.verbosity = options['verbosity']
with transaction.atomic(using=self.using): with transaction.atomic(using=self.using):
self.loaddata(fixture_labels) self.loaddata(fixture_labels)

View File

@ -212,13 +212,13 @@ class Command(BaseCommand):
default=False, help="Keep .pot file after making messages. Useful when debugging.") default=False, help="Keep .pot file after making messages. Useful when debugging.")
def handle(self, *args, **options): def handle(self, *args, **options):
locale = options.get('locale') locale = options['locale']
exclude = options.get('exclude') exclude = options['exclude']
self.domain = options.get('domain') self.domain = options['domain']
self.verbosity = options.get('verbosity') self.verbosity = options['verbosity']
process_all = options.get('all') process_all = options['all']
extensions = options.get('extensions') extensions = options['extensions']
self.symlinks = options.get('symlinks') self.symlinks = options['symlinks']
# Need to ensure that the i18n framework is enabled # Need to ensure that the i18n framework is enabled
if settings.configured: if settings.configured:
@ -226,25 +226,25 @@ class Command(BaseCommand):
else: else:
settings.configure(USE_I18N=True) settings.configure(USE_I18N=True)
ignore_patterns = options.get('ignore_patterns') ignore_patterns = options['ignore_patterns']
if options.get('use_default_ignore_patterns'): if options['use_default_ignore_patterns']:
ignore_patterns += ['CVS', '.*', '*~', '*.pyc'] ignore_patterns += ['CVS', '.*', '*~', '*.pyc']
self.ignore_patterns = list(set(ignore_patterns)) self.ignore_patterns = list(set(ignore_patterns))
# Avoid messing with mutable class variables # Avoid messing with mutable class variables
if options.get('no_wrap'): if options['no_wrap']:
self.msgmerge_options = self.msgmerge_options[:] + ['--no-wrap'] self.msgmerge_options = self.msgmerge_options[:] + ['--no-wrap']
self.msguniq_options = self.msguniq_options[:] + ['--no-wrap'] self.msguniq_options = self.msguniq_options[:] + ['--no-wrap']
self.msgattrib_options = self.msgattrib_options[:] + ['--no-wrap'] self.msgattrib_options = self.msgattrib_options[:] + ['--no-wrap']
self.xgettext_options = self.xgettext_options[:] + ['--no-wrap'] self.xgettext_options = self.xgettext_options[:] + ['--no-wrap']
if options.get('no_location'): if options['no_location']:
self.msgmerge_options = self.msgmerge_options[:] + ['--no-location'] self.msgmerge_options = self.msgmerge_options[:] + ['--no-location']
self.msguniq_options = self.msguniq_options[:] + ['--no-location'] self.msguniq_options = self.msguniq_options[:] + ['--no-location']
self.msgattrib_options = self.msgattrib_options[:] + ['--no-location'] self.msgattrib_options = self.msgattrib_options[:] + ['--no-location']
self.xgettext_options = self.xgettext_options[:] + ['--no-location'] self.xgettext_options = self.xgettext_options[:] + ['--no-location']
self.no_obsolete = options.get('no_obsolete') self.no_obsolete = options['no_obsolete']
self.keep_pot = options.get('keep_pot') self.keep_pot = options['keep_pot']
if self.domain not in ('django', 'djangojs'): if self.domain not in ('django', 'djangojs'):
raise CommandError("currently makemessages only supports domains " raise CommandError("currently makemessages only supports domains "

View File

@ -43,13 +43,13 @@ class Command(BaseCommand):
help='Exit with a non-zero status if model changes are missing migrations.') help='Exit with a non-zero status if model changes are missing migrations.')
def handle(self, *app_labels, **options): def handle(self, *app_labels, **options):
self.verbosity = options.get('verbosity') self.verbosity = options['verbosity']
self.interactive = options.get('interactive') self.interactive = options['interactive']
self.dry_run = options.get('dry_run', False) self.dry_run = options['dry_run']
self.merge = options.get('merge', False) self.merge = options['merge']
self.empty = options.get('empty', False) self.empty = options['empty']
self.migration_name = options.get('name') self.migration_name = options['name']
self.exit_code = options.get('exit_code', False) self.exit_code = options['exit_code']
check_changes = options['check_changes'] check_changes = options['check_changes']
if self.exit_code: if self.exit_code:

View File

@ -47,8 +47,8 @@ class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
self.verbosity = options.get('verbosity') self.verbosity = options['verbosity']
self.interactive = options.get('interactive') self.interactive = options['interactive']
# Import the 'management' module within each installed app, to register # Import the 'management' module within each installed app, to register
# dispatcher events. # dispatcher events.
@ -57,7 +57,7 @@ class Command(BaseCommand):
import_module('.management', app_config.name) import_module('.management', app_config.name)
# Get the database we're operating from # Get the database we're operating from
db = options.get('database') db = options['database']
connection = connections[db] connection = connections[db]
# Hook for backends needing any database preparation # Hook for backends needing any database preparation
@ -114,7 +114,7 @@ class Command(BaseCommand):
targets = executor.loader.graph.leaf_nodes() targets = executor.loader.graph.leaf_nodes()
plan = executor.migration_plan(targets) plan = executor.migration_plan(targets)
run_syncdb = options.get('run_syncdb') and executor.loader.unmigrated_apps run_syncdb = options['run_syncdb'] and executor.loader.unmigrated_apps
# Print some useful info # Print some useful info
if self.verbosity >= 1: if self.verbosity >= 1:
@ -172,8 +172,8 @@ class Command(BaseCommand):
"apply them." "apply them."
)) ))
else: else:
fake = options.get("fake") fake = options['fake']
fake_initial = options.get("fake_initial") fake_initial = options['fake_initial']
executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial) executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
# Send the post_migrate signal, so individual apps can do whatever they need # Send the post_migrate signal, so individual apps can do whatever they need

View File

@ -42,7 +42,7 @@ class Command(BaseCommand):
help='Tells Django to NOT use the auto-reloader.') help='Tells Django to NOT use the auto-reloader.')
def execute(self, *args, **options): def execute(self, *args, **options):
if options.get('no_color'): if options['no_color']:
# We rely on the environment because it's currently the only # We rely on the environment because it's currently the only
# way to reach WSGIRequestHandler. This seems an acceptable # way to reach WSGIRequestHandler. This seems an acceptable
# compromise considering `runserver` runs indefinitely. # compromise considering `runserver` runs indefinitely.
@ -61,11 +61,11 @@ class Command(BaseCommand):
if not settings.DEBUG and not settings.ALLOWED_HOSTS: if not settings.DEBUG and not settings.ALLOWED_HOSTS:
raise CommandError('You must set settings.ALLOWED_HOSTS if DEBUG is False.') raise CommandError('You must set settings.ALLOWED_HOSTS if DEBUG is False.')
self.use_ipv6 = options.get('use_ipv6') self.use_ipv6 = options['use_ipv6']
if self.use_ipv6 and not socket.has_ipv6: if self.use_ipv6 and not socket.has_ipv6:
raise CommandError('Your Python does not support IPv6.') raise CommandError('Your Python does not support IPv6.')
self._raw_ipv6 = False self._raw_ipv6 = False
if not options.get('addrport'): if not options['addrport']:
self.addr = '' self.addr = ''
self.port = self.default_port self.port = self.default_port
else: else:
@ -85,14 +85,14 @@ class Command(BaseCommand):
raise CommandError('"%s" is not a valid IPv6 address.' % self.addr) raise CommandError('"%s" is not a valid IPv6 address.' % self.addr)
if not self.addr: if not self.addr:
self.addr = '::1' if self.use_ipv6 else '127.0.0.1' self.addr = '::1' if self.use_ipv6 else '127.0.0.1'
self._raw_ipv6 = bool(self.use_ipv6) self._raw_ipv6 = self.use_ipv6
self.run(**options) self.run(**options)
def run(self, **options): def run(self, **options):
""" """
Runs the server, using the autoreloader if needed Runs the server, using the autoreloader if needed
""" """
use_reloader = options.get('use_reloader') use_reloader = options['use_reloader']
if use_reloader: if use_reloader:
autoreload.main(self.inner_run, None, options) autoreload.main(self.inner_run, None, options)
@ -104,7 +104,8 @@ class Command(BaseCommand):
# to be raised in the child process, raise it now. # to be raised in the child process, raise it now.
autoreload.raise_last_exception() autoreload.raise_last_exception()
threading = options.get('use_threading') threading = options['use_threading']
# 'shutdown_message' is a stealth option.
shutdown_message = options.get('shutdown_message', '') shutdown_message = options.get('shutdown_message', '')
quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C' quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C'

View File

@ -24,10 +24,10 @@ class Command(BaseCommand):
parser.set_defaults(format='list') parser.set_defaults(format='list')
def handle(self, *args, **options): def handle(self, *args, **options):
self.verbosity = options.get('verbosity') self.verbosity = options['verbosity']
# Get the database we're operating from # Get the database we're operating from
db = options.get('database') db = options['database']
connection = connections[db] connection = connections[db]
if options['format'] == "plan": if options['format'] == "plan":

View File

@ -18,7 +18,7 @@ class Command(AppCommand):
def handle_app_config(self, app_config, **options): def handle_app_config(self, app_config, **options):
if app_config.models_module is None: if app_config.models_module is None:
return return
connection = connections[options.get('database')] connection = connections[options['database']]
models = app_config.get_models(include_auto_created=True) models = app_config.get_models(include_auto_created=True)
statements = connection.ops.sequence_reset_sql(self.style, models) statements = connection.ops.sequence_reset_sql(self.style, models)
return '\n'.join(statements) return '\n'.join(statements)

View File

@ -27,8 +27,8 @@ class Command(BaseCommand):
def handle(self, **options): def handle(self, **options):
self.verbosity = options.get('verbosity') self.verbosity = options['verbosity']
self.interactive = options.get('interactive') self.interactive = options['interactive']
app_label = options['app_label'] app_label = options['app_label']
start_migration_name = options['start_migration_name'] start_migration_name = options['start_migration_name']
migration_name = options['migration_name'] migration_name = options['migration_name']

View File

@ -57,9 +57,9 @@ class Command(BaseCommand):
from django.conf import settings from django.conf import settings
from django.test.utils import get_runner from django.test.utils import get_runner
TestRunner = get_runner(settings, options.get('testrunner')) TestRunner = get_runner(settings, options['testrunner'])
if options.get('liveserver') is not None: if options['liveserver'] is not None:
os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS'] = options['liveserver'] os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS'] = options['liveserver']
del options['liveserver'] del options['liveserver']

View File

@ -20,8 +20,8 @@ class Command(BaseCommand):
help='Tells Django to use an IPv6 address.') help='Tells Django to use an IPv6 address.')
def handle(self, *fixture_labels, **options): def handle(self, *fixture_labels, **options):
verbosity = options.get('verbosity') verbosity = options['verbosity']
interactive = options.get('interactive') interactive = options['interactive']
# Create a test database. # Create a test database.
db_name = connection.creation.create_test_db(verbosity=verbosity, autoclobber=not interactive, serialize=False) db_name = connection.creation.create_test_db(verbosity=verbosity, autoclobber=not interactive, serialize=False)

View File

@ -640,6 +640,14 @@ Miscellaneous
* Tests that violate deferrable database constraints will now error when run on * Tests that violate deferrable database constraints will now error when run on
a database that supports deferrable constraints. a database that supports deferrable constraints.
* Built-in management commands now use indexing of keys in ``options``, e.g.
``options['verbosity']``, instead of ``options.get()`` and no longer perform
any type coercion. This could be a problem if you're calling commands using
``Command.execute()`` (which bypasses the argument parser that sets a default
value) instead of :func:`~django.core.management.call_command`. Instead of
calling ``Command.execute()``, pass the command object as the first argument
to ``call_command()``.
.. _deprecated-features-1.10: .. _deprecated-features-1.10:
Features deprecated in 1.10 Features deprecated in 1.10