diff --git a/configurations/importer.py b/configurations/importer.py index ee12d3d..38c08c4 100644 --- a/configurations/importer.py +++ b/configurations/importer.py @@ -4,33 +4,36 @@ import os import sys from optparse import make_option -from django.core.exceptions import ImproperlyConfigured +from django import VERSION as DJ_VERSION from django.conf import ENVIRONMENT_VARIABLE as SETTINGS_ENVIRONMENT_VARIABLE +from django.core.exceptions import ImproperlyConfigured +from django.core.management import base -from .utils import uppercase_attributes, reraise, LaxOptionParser +from .utils import uppercase_attributes, reraise from .values import Value, setup_value installed = False CONFIGURATION_ENVIRONMENT_VARIABLE = 'DJANGO_CONFIGURATION' +CONFIGURATION_ARGUMENT = '--configuration' +CONFIGURATION_ARGUMENT_HELP = ('The name of the configuration class to load, e.g. ' + '"Development". If this isn\'t provided, the ' + 'DJANGO_CONFIGURATION environment variable will ' + 'be used.') -configuration_options = ( - make_option('--configuration', - help='The name of the configuration class to load, e.g. ' - '"Development". If this isn\'t provided, the ' - 'DJANGO_CONFIGURATION environment variable will ' - 'be used.'),) +configuration_options = (make_option(CONFIGURATION_ARGUMENT, + help=CONFIGURATION_ARGUMENT_HELP),) def install(check_options=False): global installed if not installed: - from django.core.management import base - - # add the configuration option to all management commands - base.BaseCommand.option_list += configuration_options - + if DJ_VERSION >= (1, 8): + pass + else: + # add the configuration option to all management commands + base.BaseCommand.option_list += configuration_options importer = ConfigurationImporter(check_options=check_options) sys.meta_path.insert(0, importer) installed = True @@ -67,14 +70,35 @@ class ConfigurationImporter(object): return os.environ.get(self.namevar) def check_options(self): - parser = LaxOptionParser(option_list=configuration_options, - add_help_option=False) - try: - options, args = parser.parse_args(self.argv) - if options.configuration: - os.environ[self.namevar] = options.configuration - except: - pass # Ignore any option errors at this point. + # django switched to argparse in version 1.8 + if DJ_VERSION >= (1, 8): + parser = base.CommandParser(None, + usage="%(prog)s subcommand [options] [args]", + add_help=False) + parser.add_argument('--settings') + parser.add_argument('--pythonpath') + parser.add_argument(CONFIGURATION_ARGUMENT, + help=CONFIGURATION_ARGUMENT_HELP) + + parser.add_argument('args', nargs='*') # catch-all + try: + options, args = parser.parse_known_args(self.argv[2:]) + if options.configuration: + os.environ[self.namevar] = options.configuration + base.handle_default_options(options) + except base.CommandError: + pass # Ignore any option errors at this point. + # django < 1.7 did use optparse + else: + from django.core.management import LaxOptionParser + parser = LaxOptionParser(option_list=configuration_options, + add_help_option=False) + try: + options, args = parser.parse_args(self.argv) + if options.configuration: + os.environ[self.namevar] = options.configuration + except: + pass # Ignore any option errors at this point. def validate(self): if self.name is None: diff --git a/configurations/utils.py b/configurations/utils.py index ea65f5a..b0148f3 100644 --- a/configurations/utils.py +++ b/configurations/utils.py @@ -65,68 +65,6 @@ def reraise(exc, prefix=None, suffix=None): exc.args = ('{0} {1} {2}'.format(prefix, exc.args[0], suffix),) + args[1:] raise -try: - from django.core.management import LaxOptionParser -except ImportError: - from optparse import OptionParser - - class LaxOptionParser(OptionParser): - """ - An option parser that doesn't raise any errors on unknown options. - - This is needed because the --settings and --pythonpath options affect - the commands (and thus the options) that are available to the user. - - Backported from Django 1.7.x - - """ - def error(self, msg): - pass - - def print_help(self): - """Output nothing. - - The lax options are included in the normal option parser, so under - normal usage, we don't need to print the lax options. - """ - pass - - def print_lax_help(self): - """Output the basic options available to every command. - - This just redirects to the default print_help() behavior. - """ - OptionParser.print_help(self) - - def _process_args(self, largs, rargs, values): - """ - Overrides OptionParser._process_args to exclusively handle default - options and ignore args and other options. - - This overrides the behavior of the super class, which stop parsing - at the first unrecognized option. - """ - while rargs: - arg = rargs[0] - try: - if arg[0:2] == "--" and len(arg) > 2: - # process a single long option (possibly with value(s)) - # the superclass code pops the arg off rargs - self._process_long_opt(rargs, values) - elif arg[:1] == "-" and len(arg) > 1: - # process a cluster of short options (possibly with - # value(s) for the last one only) - # the superclass code pops the arg off rargs - self._process_short_opts(rargs, values) - else: - # it's either a non-default option or an arg - # either way, add it to the args list so we can keep - # dealing with options - del rargs[0] - raise Exception - except: # Needed because we might need to catch a SystemExit - largs.append(arg) - # Copied over from Sphinx if sys.version_info >= (3, 0): diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..dade97c --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,17 @@ +import os +import subprocess + +PROJECT_DIR = os.getcwd() +TEST_PROJECT_DIR = os.path.join(PROJECT_DIR, 'test_project') + + +def test_configuration_argument_in_cli(): + """Verify that's configuration option has been added to managements commands""" + os.chdir(TEST_PROJECT_DIR) + p = subprocess.Popen(['python', 'manage.py', 'test', + '--help'], stdout=subprocess.PIPE) + assert '--configuration' in p.communicate()[0].decode('UTF-8') + p = subprocess.Popen(['python', 'manage.py', 'runserver', + '--help'], stdout=subprocess.PIPE) + assert '--configuration' in p.communicate()[0].decode('UTF-8') + os.chdir(PROJECT_DIR) diff --git a/tox.ini b/tox.ini index d3efd31..8e41dc4 100644 --- a/tox.ini +++ b/tox.ini @@ -30,7 +30,8 @@ deps = dj15: https://github.com/django/django/archive/stable/1.5.x.zip#egg=django dj16: https://github.com/django/django/archive/stable/1.6.x.zip#egg=django dj17: https://github.com/django/django/archive/stable/1.7.x.zip#egg=django - dj18: https://github.com/django/django/archive/master.zip#egg=django + dj18: https://github.com/django/django/archive/stable/1.8.x.zip#egg=django + dj19: https://github.com/django/django/archive/master.zip#egg=django flake8: flake8 coverage: coverage @@ -43,8 +44,3 @@ commands = flake8 configurations --ignore=E501,E127,E128,E124 [testenv:flake8-py33] commands = flake8 configurations --ignore=E501,E127,E128,E124 - -[testenv:coverage-py27-dj16] -commands = coverage erase - coverage run manage.py test -v2 {posargs:tests} - coverage report