Blame SOURCES/convert-nose-optparse-options.patch

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),