|
|
5561db |
From 5c936915b3964e7f71c568219693e43f319b50ca Mon Sep 17 00:00:00 2001
|
|
|
5561db |
From: John Whitlock <John-Whitlock@ieee.org>
|
|
|
5561db |
Date: Wed, 8 Apr 2015 17:19:43 -0500
|
|
|
5561db |
Subject: [PATCH] Convert nose optparse options to argparse
|
|
|
5561db |
|
|
|
5561db |
When django.core.management.base.BaseCommand includes 'use_argparse',
|
|
|
5561db |
then nose's optparse options are merged using argparse's
|
|
|
5561db |
parser.add_argument in BaseCommand's overriden add_arguments method.
|
|
|
5561db |
|
|
|
5561db |
For Django 1.7 and earlier, the current .options method is used to set
|
|
|
5561db |
the options.
|
|
|
5561db |
|
|
|
5561db |
Fixes #178.
|
|
|
5561db |
---
|
|
|
5561db |
django_nose/runner.py | 134 +++++++++++++++++++++++++++++++++++++++++++++++---
|
|
|
5561db |
1 file changed, 126 insertions(+), 8 deletions(-)
|
|
|
5561db |
|
|
|
5561db |
diff --git a/django_nose/runner.py b/django_nose/runner.py
|
|
|
5561db |
index b99d7fb..b30fdb3 100644
|
|
|
5561db |
--- a/django_nose/runner.py
|
|
|
5561db |
+++ b/django_nose/runner.py
|
|
|
5561db |
@@ -143,7 +143,132 @@ def _get_options():
|
|
|
5561db |
o.action != 'help')
|
|
|
5561db |
|
|
|
5561db |
|
|
|
5561db |
-class BasicNoseRunner(DiscoverRunner):
|
|
|
5561db |
+if hasattr(BaseCommand, 'use_argparse'):
|
|
|
5561db |
+ # Django 1.8 and later uses argparse.ArgumentParser
|
|
|
5561db |
+ # Translate nose optparse arguments to argparse
|
|
|
5561db |
+ class BaseRunner(DiscoverRunner):
|
|
|
5561db |
+
|
|
|
5561db |
+ # Don't pass the following options to nosetests
|
|
|
5561db |
+ django_opts = [
|
|
|
5561db |
+ '--noinput', '--liveserver', '-p', '--pattern', '--testrunner',
|
|
|
5561db |
+ '--settings']
|
|
|
5561db |
+
|
|
|
5561db |
+ #
|
|
|
5561db |
+ # For optparse -> argparse conversion
|
|
|
5561db |
+ #
|
|
|
5561db |
+ # Option strings to remove from Django options if found
|
|
|
5561db |
+ _argparse_remove_options = (
|
|
|
5561db |
+ '-p', # Short arg for nose's --plugins, not Django's --patterns
|
|
|
5561db |
+ '-d', # Short arg for nose's --detailed-errors, not Django's
|
|
|
5561db |
+ # --debug-sql
|
|
|
5561db |
+ )
|
|
|
5561db |
+
|
|
|
5561db |
+ # Convert nose optparse options to argparse options
|
|
|
5561db |
+ _argparse_type = {
|
|
|
5561db |
+ 'int': int,
|
|
|
5561db |
+ 'float': float,
|
|
|
5561db |
+ 'complex': complex,
|
|
|
5561db |
+ 'string': str,
|
|
|
5561db |
+ }
|
|
|
5561db |
+ # If optparse has a None argument, omit from call to add_argument
|
|
|
5561db |
+ _argparse_omit_if_none = (
|
|
|
5561db |
+ 'action', 'nargs', 'const', 'default', 'type', 'choices',
|
|
|
5561db |
+ 'required', 'help', 'metavar', 'dest', 'callback', 'callback_args',
|
|
|
5561db |
+ 'callback_kwargs')
|
|
|
5561db |
+
|
|
|
5561db |
+ # Translating callbacks is not supported, because none of the built-in
|
|
|
5561db |
+ # plugins uses one. If you have a plugin that uses a callback, please
|
|
|
5561db |
+ # open a ticket or submit a working implementation.
|
|
|
5561db |
+ _argparse_fail_if_not_none = (
|
|
|
5561db |
+ 'callback', 'callback_args', 'callback_kwargs')
|
|
|
5561db |
+
|
|
|
5561db |
+ @classmethod
|
|
|
5561db |
+ def add_arguments(cls, parser):
|
|
|
5561db |
+ """Convert nose's optparse arguments to argparse"""
|
|
|
5561db |
+ super(BaseRunner, cls).add_arguments(parser)
|
|
|
5561db |
+
|
|
|
5561db |
+ # Read optparse options for nose and plugins
|
|
|
5561db |
+ cfg_files = nose.core.all_config_files()
|
|
|
5561db |
+ manager = nose.core.DefaultPluginManager()
|
|
|
5561db |
+ config = nose.core.Config(
|
|
|
5561db |
+ env=os.environ, files=cfg_files, plugins=manager)
|
|
|
5561db |
+ config.plugins.addPlugins(list(_get_plugins_from_settings()))
|
|
|
5561db |
+ options = config.getParser()._get_all_options()
|
|
|
5561db |
+
|
|
|
5561db |
+ # Gather existing option strings`
|
|
|
5561db |
+ django_options = set()
|
|
|
5561db |
+ for action in parser._actions:
|
|
|
5561db |
+ for override in cls._argparse_remove_options:
|
|
|
5561db |
+ if override in action.option_strings:
|
|
|
5561db |
+ # Emulate parser.conflict_handler='resolve'
|
|
|
5561db |
+ parser._handle_conflict_resolve(
|
|
|
5561db |
+ None, ((override, action),))
|
|
|
5561db |
+ django_options.update(action.option_strings)
|
|
|
5561db |
+
|
|
|
5561db |
+ # Process nose optparse options
|
|
|
5561db |
+ for option in options:
|
|
|
5561db |
+ # Skip any options also in Django options
|
|
|
5561db |
+ opt_long = option.get_opt_string()
|
|
|
5561db |
+ if opt_long in django_options:
|
|
|
5561db |
+ continue
|
|
|
5561db |
+ if option._short_opts:
|
|
|
5561db |
+ opt_short = option._short_opts[0]
|
|
|
5561db |
+ if opt_short in django_options:
|
|
|
5561db |
+ continue
|
|
|
5561db |
+ else:
|
|
|
5561db |
+ opt_short = None
|
|
|
5561db |
+
|
|
|
5561db |
+ # Rename nose's --verbosity to --nose-verbosity
|
|
|
5561db |
+ if opt_long == '--verbosity':
|
|
|
5561db |
+ opt_long = '--nose-verbosity'
|
|
|
5561db |
+
|
|
|
5561db |
+ # Convert optparse attributes to argparse attributes
|
|
|
5561db |
+ option_attrs = {}
|
|
|
5561db |
+ for attr in option.ATTRS:
|
|
|
5561db |
+ value = getattr(option, attr)
|
|
|
5561db |
+
|
|
|
5561db |
+ # Rename options for nose's --verbosity
|
|
|
5561db |
+ if opt_long == '--nose-verbosity':
|
|
|
5561db |
+ if attr == 'dest':
|
|
|
5561db |
+ value = 'nose_verbosity'
|
|
|
5561db |
+ elif attr == 'metavar':
|
|
|
5561db |
+ value = 'NOSE_VERBOSITY'
|
|
|
5561db |
+
|
|
|
5561db |
+ # Omit arguments that are None, use default
|
|
|
5561db |
+ if attr in cls._argparse_omit_if_none and value is None:
|
|
|
5561db |
+ continue
|
|
|
5561db |
+
|
|
|
5561db |
+ # Translating callbacks is not supported
|
|
|
5561db |
+ if attr in cls._argparse_fail_if_not_none:
|
|
|
5561db |
+ assert value is None, (
|
|
|
5561db |
+ 'argparse option %s=%s is not supported' %
|
|
|
5561db |
+ (attr, value))
|
|
|
5561db |
+ continue
|
|
|
5561db |
+
|
|
|
5561db |
+ # Convert type from optparse string to argparse type
|
|
|
5561db |
+ if attr == 'type':
|
|
|
5561db |
+ value = cls._argparse_type[value]
|
|
|
5561db |
+
|
|
|
5561db |
+ # Pass converted attribute to optparse option
|
|
|
5561db |
+ option_attrs[attr] = value
|
|
|
5561db |
+
|
|
|
5561db |
+ # Add the optparse argument
|
|
|
5561db |
+ if opt_short:
|
|
|
5561db |
+ parser.add_argument(opt_short, opt_long, **option_attrs)
|
|
|
5561db |
+ else:
|
|
|
5561db |
+ parser.add_argument(opt_long, **option_attrs)
|
|
|
5561db |
+else:
|
|
|
5561db |
+ # Django 1.7 and earlier use optparse
|
|
|
5561db |
+ class BaseRunner(DiscoverRunner):
|
|
|
5561db |
+ # Replace the builtin options with the merged django/nose options:
|
|
|
5561db |
+ options = _get_options()
|
|
|
5561db |
+
|
|
|
5561db |
+ # Not add following options to nosetests
|
|
|
5561db |
+ django_opts = ['--noinput', '--liveserver', '-p', '--pattern',
|
|
|
5561db |
+ '--testrunner']
|
|
|
5561db |
+
|
|
|
5561db |
+
|
|
|
5561db |
+class BasicNoseRunner(BaseRunner):
|
|
|
5561db |
"""Facade that implements a nose runner in the guise of a Django runner
|
|
|
5561db |
|
|
|
5561db |
You shouldn't have to use this directly unless the additions made by
|
|
|
5561db |
@@ -153,13 +278,6 @@ class BasicNoseRunner(DiscoverRunner):
|
|
|
5561db |
"""
|
|
|
5561db |
__test__ = False
|
|
|
5561db |
|
|
|
5561db |
- # Replace the builtin command options with the merged django/nose options:
|
|
|
5561db |
- options = _get_options()
|
|
|
5561db |
-
|
|
|
5561db |
- # Not add following options to nosetests
|
|
|
5561db |
- django_opts = ['--noinput', '--liveserver', '-p', '--pattern',
|
|
|
5561db |
- '--testrunner']
|
|
|
5561db |
-
|
|
|
5561db |
def run_suite(self, nose_argv):
|
|
|
5561db |
result_plugin = ResultPlugin()
|
|
|
5561db |
plugins_to_add = [DjangoSetUpPlugin(self),
|