From 1845bc1d1007751a7f65c66aeddc35f032f6bf41 Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Wed, 2 Mar 2016 18:01:36 -0800 Subject: [PATCH] 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(). --- .../management/commands/changepassword.py | 4 +-- .../management/commands/createsuperuser.py | 8 +++--- .../management/commands/runserver.py | 4 +-- django/core/management/base.py | 4 +-- django/core/management/commands/check.py | 4 +-- .../management/commands/compilemessages.py | 8 +++--- .../management/commands/createcachetable.py | 6 ++--- django/core/management/commands/dbshell.py | 2 +- django/core/management/commands/dumpdata.py | 20 +++++++------- django/core/management/commands/flush.py | 6 ++--- django/core/management/commands/loaddata.py | 8 +++--- .../core/management/commands/makemessages.py | 26 +++++++++---------- .../management/commands/makemigrations.py | 14 +++++----- django/core/management/commands/migrate.py | 12 ++++----- django/core/management/commands/runserver.py | 13 +++++----- .../management/commands/showmigrations.py | 4 +-- .../management/commands/sqlsequencereset.py | 2 +- .../management/commands/squashmigrations.py | 4 +-- django/core/management/commands/test.py | 4 +-- django/core/management/commands/testserver.py | 4 +-- docs/releases/1.10.txt | 8 ++++++ 21 files changed, 87 insertions(+), 78 deletions(-) diff --git a/django/contrib/auth/management/commands/changepassword.py b/django/contrib/auth/management/commands/changepassword.py index fd1deada0f..f6a73a8af0 100644 --- a/django/contrib/auth/management/commands/changepassword.py +++ b/django/contrib/auth/management/commands/changepassword.py @@ -29,7 +29,7 @@ class Command(BaseCommand): help='Specifies the database to use. Default is "default".') def handle(self, *args, **options): - if options.get('username'): + if options['username']: username = options['username'] else: username = getpass.getuser() @@ -37,7 +37,7 @@ class Command(BaseCommand): UserModel = get_user_model() try: - u = UserModel._default_manager.using(options.get('database')).get(**{ + u = UserModel._default_manager.using(options['database']).get(**{ UserModel.USERNAME_FIELD: username }) except UserModel.DoesNotExist: diff --git a/django/contrib/auth/management/commands/createsuperuser.py b/django/contrib/auth/management/commands/createsuperuser.py index d318c114e6..30850fd4ac 100644 --- a/django/contrib/auth/management/commands/createsuperuser.py +++ b/django/contrib/auth/management/commands/createsuperuser.py @@ -53,8 +53,8 @@ class Command(BaseCommand): return super(Command, self).execute(*args, **options) def handle(self, *args, **options): - username = options.get(self.UserModel.USERNAME_FIELD) - database = options.get('database') + username = options[self.UserModel.USERNAME_FIELD] + database = options['database'] # If not provided, create the user with an unusable password password = None @@ -72,7 +72,7 @@ class Command(BaseCommand): username = self.username_field.clean(username, None) 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) user_data[field_name] = field.clean(options[field_name], None) else: @@ -118,7 +118,7 @@ class Command(BaseCommand): for field_name in self.UserModel.REQUIRED_FIELDS: 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: message = force_str('%s%s: ' % ( capfirst(field.verbose_name), diff --git a/django/contrib/staticfiles/management/commands/runserver.py b/django/contrib/staticfiles/management/commands/runserver.py index 64ef22818e..b6108b8e97 100644 --- a/django/contrib/staticfiles/management/commands/runserver.py +++ b/django/contrib/staticfiles/management/commands/runserver.py @@ -21,8 +21,8 @@ class Command(RunserverCommand): handler. """ handler = super(Command, self).get_handler(*args, **options) - use_static_handler = options.get('use_static_handler', True) - insecure_serving = options.get('insecure_serving', False) + use_static_handler = options['use_static_handler'] + insecure_serving = options['insecure_serving'] if use_static_handler and (settings.DEBUG or insecure_serving): return StaticFilesHandler(handler) return handler diff --git a/django/core/management/base.py b/django/core/management/base.py index de3591a298..f747e57ab4 100644 --- a/django/core/management/base.py +++ b/django/core/management/base.py @@ -314,13 +314,13 @@ class BaseCommand(object): controlled by the ``requires_system_checks`` attribute, except if force-skipped). """ - if options.get('no_color'): + if options['no_color']: self.style = no_style() self.stderr.style_func = None if options.get('stdout'): self.stdout = OutputWrapper(options['stdout']) 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 if not self.leave_locale_alone: diff --git a/django/core/management/commands/check.py b/django/core/management/commands/check.py index 5a66f7ac59..4f5cc71f43 100644 --- a/django/core/management/commands/check.py +++ b/django/core/management/commands/check.py @@ -33,7 +33,7 @@ class Command(BaseCommand): def handle(self, *app_labels, **options): 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)))) return @@ -42,7 +42,7 @@ class Command(BaseCommand): else: app_configs = None - tags = options.get('tags') + tags = options['tags'] if tags: try: invalid_tag = next( diff --git a/django/core/management/commands/compilemessages.py b/django/core/management/commands/compilemessages.py index 664c96de05..07e108fa1b 100644 --- a/django/core/management/commands/compilemessages.py +++ b/django/core/management/commands/compilemessages.py @@ -45,10 +45,10 @@ class Command(BaseCommand): help='Use fuzzy translations.') def handle(self, **options): - locale = options.get('locale') - exclude = options.get('exclude') - self.verbosity = int(options.get('verbosity')) - if options.get('fuzzy'): + locale = options['locale'] + exclude = options['exclude'] + self.verbosity = options['verbosity'] + if options['fuzzy']: self.program_options = self.program_options + ['-f'] if find_command(self.program) is None: diff --git a/django/core/management/commands/createcachetable.py b/django/core/management/commands/createcachetable.py index fc47cea77d..4a6456b536 100644 --- a/django/core/management/commands/createcachetable.py +++ b/django/core/management/commands/createcachetable.py @@ -27,9 +27,9 @@ class Command(BaseCommand): 'be run.') def handle(self, *tablenames, **options): - db = options.get('database') - self.verbosity = int(options.get('verbosity')) - dry_run = options.get('dry_run') + db = options['database'] + self.verbosity = options['verbosity'] + dry_run = options['dry_run'] if len(tablenames): # Legacy behavior, tablename specified as argument for tablename in tablenames: diff --git a/django/core/management/commands/dbshell.py b/django/core/management/commands/dbshell.py index 9d6097eb47..d2ff81f7ca 100644 --- a/django/core/management/commands/dbshell.py +++ b/django/core/management/commands/dbshell.py @@ -14,7 +14,7 @@ class Command(BaseCommand): 'open a shell. Defaults to the "default" database.') def handle(self, **options): - connection = connections[options.get('database')] + connection = connections[options['database']] try: connection.client.runshell() except OSError: diff --git a/django/core/management/commands/dumpdata.py b/django/core/management/commands/dumpdata.py index 222d1c6f94..f8edcafabb 100644 --- a/django/core/management/commands/dumpdata.py +++ b/django/core/management/commands/dumpdata.py @@ -45,16 +45,16 @@ class Command(BaseCommand): help='Specifies file to which the output is written.') def handle(self, *app_labels, **options): - format = options.get('format') - indent = options.get('indent') - using = options.get('database') - excludes = options.get('exclude') - output = options.get('output') - show_traceback = options.get('traceback') - use_natural_foreign_keys = options.get('use_natural_foreign_keys') - use_natural_primary_keys = options.get('use_natural_primary_keys') - use_base_manager = options.get('use_base_manager') - pks = options.get('primary_keys') + format = options['format'] + indent = options['indent'] + using = options['database'] + excludes = options['exclude'] + output = options['output'] + show_traceback = options['traceback'] + use_natural_foreign_keys = options['use_natural_foreign_keys'] + use_natural_primary_keys = options['use_natural_primary_keys'] + use_base_manager = options['use_base_manager'] + pks = options['primary_keys'] if pks: primary_keys = pks.split(',') diff --git a/django/core/management/commands/flush.py b/django/core/management/commands/flush.py index 018c12ed96..3820f2cce8 100644 --- a/django/core/management/commands/flush.py +++ b/django/core/management/commands/flush.py @@ -25,10 +25,10 @@ class Command(BaseCommand): help='Nominates a database to flush. Defaults to the "default" database.') def handle(self, **options): - database = options.get('database') + database = options['database'] connection = connections[database] - verbosity = options.get('verbosity') - interactive = options.get('interactive') + verbosity = options['verbosity'] + interactive = options['interactive'] # The following are stealth options used by Django's internals. reset_sequences = options.get('reset_sequences', True) allow_cascade = options.get('allow_cascade', False) diff --git a/django/core/management/commands/loaddata.py b/django/core/management/commands/loaddata.py index 3cd92d7d4e..a53270a38b 100644 --- a/django/core/management/commands/loaddata.py +++ b/django/core/management/commands/loaddata.py @@ -50,10 +50,10 @@ class Command(BaseCommand): def handle(self, *fixture_labels, **options): - self.ignore = options.get('ignore') - self.using = options.get('database') - self.app_label = options.get('app_label') - self.verbosity = options.get('verbosity') + self.ignore = options['ignore'] + self.using = options['database'] + self.app_label = options['app_label'] + self.verbosity = options['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 ebec17ff01..cfe6d3d087 100644 --- a/django/core/management/commands/makemessages.py +++ b/django/core/management/commands/makemessages.py @@ -212,13 +212,13 @@ class Command(BaseCommand): default=False, help="Keep .pot file after making messages. Useful when debugging.") def handle(self, *args, **options): - locale = options.get('locale') - exclude = options.get('exclude') - self.domain = options.get('domain') - self.verbosity = options.get('verbosity') - process_all = options.get('all') - extensions = options.get('extensions') - self.symlinks = options.get('symlinks') + locale = options['locale'] + exclude = options['exclude'] + self.domain = options['domain'] + self.verbosity = options['verbosity'] + process_all = options['all'] + extensions = options['extensions'] + self.symlinks = options['symlinks'] # Need to ensure that the i18n framework is enabled if settings.configured: @@ -226,25 +226,25 @@ class Command(BaseCommand): else: settings.configure(USE_I18N=True) - ignore_patterns = options.get('ignore_patterns') - if options.get('use_default_ignore_patterns'): + ignore_patterns = options['ignore_patterns'] + if options['use_default_ignore_patterns']: ignore_patterns += ['CVS', '.*', '*~', '*.pyc'] self.ignore_patterns = list(set(ignore_patterns)) # Avoid messing with mutable class variables - if options.get('no_wrap'): + if options['no_wrap']: self.msgmerge_options = self.msgmerge_options[:] + ['--no-wrap'] self.msguniq_options = self.msguniq_options[:] + ['--no-wrap'] self.msgattrib_options = self.msgattrib_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.msguniq_options = self.msguniq_options[:] + ['--no-location'] self.msgattrib_options = self.msgattrib_options[:] + ['--no-location'] self.xgettext_options = self.xgettext_options[:] + ['--no-location'] - self.no_obsolete = options.get('no_obsolete') - self.keep_pot = options.get('keep_pot') + self.no_obsolete = options['no_obsolete'] + self.keep_pot = options['keep_pot'] if self.domain not in ('django', 'djangojs'): raise CommandError("currently makemessages only supports domains " diff --git a/django/core/management/commands/makemigrations.py b/django/core/management/commands/makemigrations.py index 80e4314b3c..229cb991af 100644 --- a/django/core/management/commands/makemigrations.py +++ b/django/core/management/commands/makemigrations.py @@ -43,13 +43,13 @@ class Command(BaseCommand): help='Exit with a non-zero status if model changes are missing migrations.') def handle(self, *app_labels, **options): - self.verbosity = options.get('verbosity') - self.interactive = options.get('interactive') - self.dry_run = options.get('dry_run', False) - self.merge = options.get('merge', False) - self.empty = options.get('empty', False) - self.migration_name = options.get('name') - self.exit_code = options.get('exit_code', False) + self.verbosity = options['verbosity'] + self.interactive = options['interactive'] + self.dry_run = options['dry_run'] + self.merge = options['merge'] + self.empty = options['empty'] + self.migration_name = options['name'] + self.exit_code = options['exit_code'] check_changes = options['check_changes'] if self.exit_code: diff --git a/django/core/management/commands/migrate.py b/django/core/management/commands/migrate.py index b85021ac72..f78fde3ebb 100644 --- a/django/core/management/commands/migrate.py +++ b/django/core/management/commands/migrate.py @@ -47,8 +47,8 @@ class Command(BaseCommand): def handle(self, *args, **options): - self.verbosity = options.get('verbosity') - self.interactive = options.get('interactive') + self.verbosity = options['verbosity'] + self.interactive = options['interactive'] # Import the 'management' module within each installed app, to register # dispatcher events. @@ -57,7 +57,7 @@ class Command(BaseCommand): import_module('.management', app_config.name) # Get the database we're operating from - db = options.get('database') + db = options['database'] connection = connections[db] # Hook for backends needing any database preparation @@ -114,7 +114,7 @@ class Command(BaseCommand): targets = executor.loader.graph.leaf_nodes() 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 if self.verbosity >= 1: @@ -172,8 +172,8 @@ class Command(BaseCommand): "apply them." )) else: - fake = options.get("fake") - fake_initial = options.get("fake_initial") + fake = options['fake'] + fake_initial = options['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 diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py index 1f5b52f113..d5c8189d6b 100644 --- a/django/core/management/commands/runserver.py +++ b/django/core/management/commands/runserver.py @@ -42,7 +42,7 @@ class Command(BaseCommand): help='Tells Django to NOT use the auto-reloader.') 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 # way to reach WSGIRequestHandler. This seems an acceptable # compromise considering `runserver` runs indefinitely. @@ -61,11 +61,11 @@ class Command(BaseCommand): if not settings.DEBUG and not settings.ALLOWED_HOSTS: 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: raise CommandError('Your Python does not support IPv6.') self._raw_ipv6 = False - if not options.get('addrport'): + if not options['addrport']: self.addr = '' self.port = self.default_port else: @@ -85,14 +85,14 @@ class Command(BaseCommand): raise CommandError('"%s" is not a valid IPv6 address.' % self.addr) if not self.addr: 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) def run(self, **options): """ Runs the server, using the autoreloader if needed """ - use_reloader = options.get('use_reloader') + use_reloader = options['use_reloader'] if use_reloader: autoreload.main(self.inner_run, None, options) @@ -104,7 +104,8 @@ class Command(BaseCommand): # to be raised in the child process, raise it now. 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', '') quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C' diff --git a/django/core/management/commands/showmigrations.py b/django/core/management/commands/showmigrations.py index 254b9c5d4c..0e53e11259 100644 --- a/django/core/management/commands/showmigrations.py +++ b/django/core/management/commands/showmigrations.py @@ -24,10 +24,10 @@ class Command(BaseCommand): parser.set_defaults(format='list') def handle(self, *args, **options): - self.verbosity = options.get('verbosity') + self.verbosity = options['verbosity'] # Get the database we're operating from - db = options.get('database') + db = options['database'] connection = connections[db] if options['format'] == "plan": diff --git a/django/core/management/commands/sqlsequencereset.py b/django/core/management/commands/sqlsequencereset.py index ea7286c6ac..ebb6f9da2e 100644 --- a/django/core/management/commands/sqlsequencereset.py +++ b/django/core/management/commands/sqlsequencereset.py @@ -18,7 +18,7 @@ class Command(AppCommand): 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']] models = app_config.get_models(include_auto_created=True) statements = connection.ops.sequence_reset_sql(self.style, models) return '\n'.join(statements) diff --git a/django/core/management/commands/squashmigrations.py b/django/core/management/commands/squashmigrations.py index 9ad5f60d35..61c99baafd 100644 --- a/django/core/management/commands/squashmigrations.py +++ b/django/core/management/commands/squashmigrations.py @@ -27,8 +27,8 @@ class Command(BaseCommand): def handle(self, **options): - self.verbosity = options.get('verbosity') - self.interactive = options.get('interactive') + self.verbosity = options['verbosity'] + self.interactive = options['interactive'] app_label = options['app_label'] start_migration_name = options['start_migration_name'] migration_name = options['migration_name'] diff --git a/django/core/management/commands/test.py b/django/core/management/commands/test.py index 21f2a97850..2d98abebd0 100644 --- a/django/core/management/commands/test.py +++ b/django/core/management/commands/test.py @@ -57,9 +57,9 @@ class Command(BaseCommand): from django.conf import settings 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'] del options['liveserver'] diff --git a/django/core/management/commands/testserver.py b/django/core/management/commands/testserver.py index 3c14b26181..a241283ce2 100644 --- a/django/core/management/commands/testserver.py +++ b/django/core/management/commands/testserver.py @@ -20,8 +20,8 @@ class Command(BaseCommand): help='Tells Django to use an IPv6 address.') def handle(self, *fixture_labels, **options): - verbosity = options.get('verbosity') - interactive = options.get('interactive') + verbosity = options['verbosity'] + interactive = options['interactive'] # Create a test database. db_name = connection.creation.create_test_db(verbosity=verbosity, autoclobber=not interactive, serialize=False) diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt index 0d1ea5b5d2..e19ecf5662 100644 --- a/docs/releases/1.10.txt +++ b/docs/releases/1.10.txt @@ -640,6 +640,14 @@ Miscellaneous * Tests that violate deferrable database constraints will now error when run on 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: Features deprecated in 1.10