Fixed #27881 -- Added diffsettings --output option.

Thanks Haris Ibrahim K. V. for writng docs.
This commit is contained in:
Chris Lamb 2017-03-08 08:54:17 +00:00 committed by Tim Graham
parent af1fa5e7da
commit 2f09a28558
4 changed files with 74 additions and 5 deletions

View File

@ -8,15 +8,17 @@ def module_to_dict(module, omittable=lambda k: k.startswith('_')):
class Command(BaseCommand): class Command(BaseCommand):
help = """Displays differences between the current settings.py and Django's help = """Displays differences between the current settings.py and Django's
default settings. Settings that don't appear in the defaults are default settings."""
followed by "###"."""
requires_system_checks = False requires_system_checks = False
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument( parser.add_argument(
'--all', action='store_true', dest='all', '--all', action='store_true', dest='all',
help='Display all settings, regardless of their value. Default values are prefixed by "###".', help=(
'Display all settings, regardless of their value. In "hash" '
'mode, default values are prefixed by "###".'
),
) )
parser.add_argument( parser.add_argument(
'--default', dest='default', metavar='MODULE', default=None, '--default', dest='default', metavar='MODULE', default=None,
@ -25,9 +27,18 @@ class Command(BaseCommand):
"compare against Django's default settings." "compare against Django's default settings."
), ),
) )
parser.add_argument(
'--output', default='hash', choices=('hash', 'unified'), dest='output',
help=(
"Selects the output format. 'hash' mode displays each changed "
"setting, with the settings that don't appear in the defaults "
"followed by ###. 'unified' mode prefixes the default setting "
"with a minus sign, followed by the changed setting prefixed "
"with a plus sign."
),
)
def handle(self, **options): def handle(self, **options):
# Inspired by Postfix's "postconf -n".
from django.conf import settings, Settings, global_settings from django.conf import settings, Settings, global_settings
# Because settings are imported lazily, we need to explicitly load them. # Because settings are imported lazily, we need to explicitly load them.
@ -36,7 +47,14 @@ class Command(BaseCommand):
user_settings = module_to_dict(settings._wrapped) user_settings = module_to_dict(settings._wrapped)
default = options['default'] default = options['default']
default_settings = module_to_dict(Settings(default) if default else global_settings) default_settings = module_to_dict(Settings(default) if default else global_settings)
output_func = {
'hash': self.output_hash,
'unified': self.output_unified,
}[options['output']]
return '\n'.join(output_func(user_settings, default_settings, **options))
def output_hash(self, user_settings, default_settings, **options):
# Inspired by Postfix's "postconf -n".
output = [] output = []
for key in sorted(user_settings): for key in sorted(user_settings):
if key not in default_settings: if key not in default_settings:
@ -45,4 +63,16 @@ class Command(BaseCommand):
output.append("%s = %s" % (key, user_settings[key])) output.append("%s = %s" % (key, user_settings[key]))
elif options['all']: elif options['all']:
output.append("### %s = %s" % (key, user_settings[key])) output.append("### %s = %s" % (key, user_settings[key]))
return '\n'.join(output) return output
def output_unified(self, user_settings, default_settings, **options):
output = []
for key in sorted(user_settings):
if key not in default_settings:
output.append(self.style.SUCCESS("+ %s = %s" % (key, user_settings[key])))
elif user_settings[key] != default_settings[key]:
output.append(self.style.ERROR("- %s = %s" % (key, default_settings[key])))
output.append(self.style.SUCCESS("+ %s = %s" % (key, user_settings[key])))
elif options['all']:
output.append(" %s = %s" % (key, user_settings[key]))
return output

View File

@ -240,6 +240,16 @@ are prefixed by ``"###"``.
The settings module to compare the current settings against. Leave empty to The settings module to compare the current settings against. Leave empty to
compare against Django's default settings. compare against Django's default settings.
.. django-admin-option:: --output {hash,unified}
.. versionadded:: 2.0
Specifies the output format. Available values are ``hash`` and ``unified``.
``hash`` is the default mode that displays the output that's described above.
``unified`` displays the output similar to ``diff -u``. Default settings are
prefixed with a minus sign, followed by the changed setting prefixed with a
plus sign.
``dumpdata`` ``dumpdata``
------------ ------------

View File

@ -187,6 +187,9 @@ Management Commands
* :djadmin:`loaddata` can now :ref:`read from stdin <loading-fixtures-stdin>`. * :djadmin:`loaddata` can now :ref:`read from stdin <loading-fixtures-stdin>`.
* The new :option:`diffsettings --output` option allows formatting the output
in a unified diff format.
Migrations Migrations
~~~~~~~~~~ ~~~~~~~~~~

View File

@ -2120,6 +2120,32 @@ class DiffSettings(AdminScriptTestCase):
self.assertNotInOutput(out, "FOO") self.assertNotInOutput(out, "FOO")
self.assertOutput(out, "BAR = 'bar2'") self.assertOutput(out, "BAR = 'bar2'")
def test_unified(self):
"""--output=unified emits settings diff in unified mode."""
self.write_settings('settings_to_diff.py', sdict={'FOO': '"bar"'})
self.addCleanup(self.remove_settings, 'settings_to_diff.py')
args = ['diffsettings', '--settings=settings_to_diff', '--output=unified']
out, err = self.run_manage(args)
self.assertNoOutput(err)
self.assertOutput(out, "+ FOO = 'bar'")
self.assertOutput(out, "- SECRET_KEY = ''")
self.assertOutput(out, "+ SECRET_KEY = 'django_tests_secret_key'")
self.assertNotInOutput(out, " APPEND_SLASH = True")
def test_unified_all(self):
"""
--output=unified --all emits settings diff in unified mode and includes
settings with the default value.
"""
self.write_settings('settings_to_diff.py', sdict={'FOO': '"bar"'})
self.addCleanup(self.remove_settings, 'settings_to_diff.py')
args = ['diffsettings', '--settings=settings_to_diff', '--output=unified', '--all']
out, err = self.run_manage(args)
self.assertNoOutput(err)
self.assertOutput(out, " APPEND_SLASH = True")
self.assertOutput(out, "+ FOO = 'bar'")
self.assertOutput(out, "- SECRET_KEY = ''")
class Dumpdata(AdminScriptTestCase): class Dumpdata(AdminScriptTestCase):
"""Tests for dumpdata management command.""" """Tests for dumpdata management command."""