Commits

Brandon Konkle committed 225bd04

Updated for Django 1.2

Comments (0)

Files changed (6)

 George Song of 55 Minutes <george@55minutes.com>
 Mikhail Korobov <kmike84@gmail.com>
+Brandon Konkle <brandon@brandonkonkle.com>
 
 Dependencies
 ============
-* Django_ 1.0.2 and above. It may work with earlier versions, but I
-  haven't tested anything prior to 1.0.2 explicitly.
+* Django_ 1.2 and above. For earlier versions, try version 1.0.1 of
+  django-coverage.
 * coverage.py_
 
 How do I use it?
 ================
 Install as a Django app
 -----------------------
-1. Place the entire ``test_coverage`` app in your third-party apps
+1. Place the entire ``django_coverage`` app in your third-party apps
    directory.
-2. Update your ``settings.INSTALLED_APPS`` to include ``test_coverage``.
+2. Update your ``settings.INSTALLED_APPS`` to include ``django_coverage``.
 3. Include test coverage specific settings in your own settings file.
    See ``settings.py`` for more detail.
 
 to. You can simply use the test runner if you like.
 
 1. Update ``settings.TEST_RUNNER =
-   'test_coverage.coverage_runner.run_tests'``
+   'test_coverage.coverage_runner.CoverageRunner'``
 2. Include test coverage specific settings in your own settings file.
    See ``settings.py`` for more detail.
 3. Run ``manage.py test`` like you normally do.

django_coverage/__init__.py

 limitations under the License.
 """
 
-__version__ = '1.0'
+__version__ = '1.1'

django_coverage/coverage_runner.py

 Changed by Mikhail Korobov.
 """
 
-import coverage, os, sys
+import os
+import sys
+
+from django.db.models import get_app, get_apps
+from django.test.simple import DjangoTestSuiteRunner
+from django.test.utils import get_runner
+
+import coverage
 
 from django_coverage import settings
-from django.db.models import get_app, get_apps
-from django.test.simple import run_tests as base_run_tests
+from django_coverage.utils.coverage_report import html_report
+from django_coverage.utils.module_tools import get_all_modules
 
-from utils.module_tools import get_all_modules
-from utils.coverage_report import html_report
 
-def _get_app_package(app_model_module):
+class CoverageRunner(DjangoTestSuiteRunner):
     """
-    Returns the app module name from the app model module.
+    Test runner which displays a code coverage report at the end of the run.
     """
-    return '.'.join(app_model_module.__name__.split('.')[:-1])
+    
+    def __new__(cls, *args, **kwargs):
+        """
+        Add the original test runner to the front of CoverageRunner's bases,
+        so that CoverageRunner will inherit from it. This allows it to work
+        with customized test runners.
+        """
+        # Change the test runner back to its original value in order to get
+        # the original runner.
+        settings.TEST_RUNNER = settings.ORIG_TEST_RUNNER
+        TestRunner = get_runner(settings)
+        cls.__bases__ = (TestRunner,) + cls.__bases__
+        return super(CoverageRunner, cls).__new__(cls, *args, **kwargs)
 
-def run_tests(test_labels, verbosity=1, interactive=True,
-              extra_tests=[]):
-    """
-    Test runner which displays a code coverage report at the end of the
-    run.
-    """
-    coverage.use_cache(0)
-    for e in settings.COVERAGE_CODE_EXCLUDES:
-        coverage.exclude(e)
-    coverage.start()
-    results = base_run_tests(test_labels, verbosity, interactive, extra_tests)
-    coverage.stop()
+    def _get_app_package(self, app_model_module):
+        """
+        Returns the app module name from the app model module.
+        """
+        return '.'.join(app_model_module.__name__.split('.')[:-1])
 
-    coverage_modules = []
-    if test_labels:
-        for label in test_labels:
-            label = label.split('.')[0]
-            app = get_app(label)
-            coverage_modules.append(_get_app_package(app))
-    else:
-        for app in get_apps():
-            coverage_modules.append(_get_app_package(app))
+    def run_tests(self, test_labels, extra_tests=None, **kwargs):
+        coverage.use_cache(0)
+        for e in settings.COVERAGE_CODE_EXCLUDES:
+            coverage.exclude(e)
+        coverage.start()
+        results = super(CoverageRunner, self).run_tests(test_labels,
+                                                        extra_tests, **kwargs)
+        coverage.stop()
 
-    coverage_modules.extend(settings.COVERAGE_ADDITIONAL_MODULES)
+        coverage_modules = []
+        if test_labels:
+            for label in test_labels:
+                label = label.split('.')[0]
+                app = get_app(label)
+                coverage_modules.append(self._get_app_package(app))
+        else:
+            for app in get_apps():
+                coverage_modules.append(self._get_app_package(app))
 
-    packages, modules, excludes, errors = get_all_modules(
-        coverage_modules, settings.COVERAGE_MODULE_EXCLUDES,
-        settings.COVERAGE_PATH_EXCLUDES)
+        coverage_modules.extend(settings.COVERAGE_ADDITIONAL_MODULES)
 
-    outdir = settings.COVERAGE_REPORT_HTML_OUTPUT_DIR
-    if outdir is None:
-        coverage.report(modules.values(), show_missing=1)
-        if excludes:
+        packages, modules, excludes, errors = get_all_modules(
+            coverage_modules, settings.COVERAGE_MODULE_EXCLUDES,
+            settings.COVERAGE_PATH_EXCLUDES)
+
+        outdir = settings.COVERAGE_REPORT_HTML_OUTPUT_DIR
+        if outdir is None:
+            coverage.report(modules.values(), show_missing=1)
+            if excludes:
+                message = "The following packages or modules were excluded:"
+                print >>sys.stdout
+                print >>sys.stdout, message,
+                for e in excludes:
+                    print >>sys.stdout, e,
+                print >>sys.stdout
+            if errors:
+                message = "There were problems with the following packages "
+                message += "or modules:"
+                print >>sys.stdout
+                print >>sys.stderr, message,
+                for e in errors:
+                    print >>sys.stderr, e,
+                print >>sys.stdout
+        else:
+            outdir = os.path.abspath(outdir)
+            if settings.COVERAGE_CUSTOM_REPORTS:
+                html_report(outdir, modules, excludes, errors)
+            else:
+                coverage._the_coverage.html_report(modules.values(), outdir)
             print >>sys.stdout
-            print >>sys.stdout, "The following packages or modules were excluded:",
-            for e in excludes:
-                print >>sys.stdout, e,
-            print >>sys.stdout
-        if errors:
-            print >>sys.stdout
-            print >>sys.stderr, "There were problems with the following packages or modules:",
-            for e in errors:
-                print >>sys.stderr, e,
-            print >>sys.stdout
-    else:
-        outdir = os.path.abspath(outdir)
-        if settings.COVERAGE_CUSTOM_REPORTS:
-            html_report(outdir, modules, excludes, errors)
-        else:
-            coverage._the_coverage.html_report(modules.values(), outdir)
-        print >>sys.stdout
-        print >>sys.stdout, "HTML reports were output to '%s'" %outdir
+            print >>sys.stdout, "HTML reports were output to '%s'" %outdir
 
-    return results
-
+        return results

django_coverage/management/commands/test_coverage.py

 limitations under the License.
 """
 
-from django.core.management.base import BaseCommand
-from optparse import make_option
-import sys
+from django.conf import settings
+from django.core.management import call_command
+from django.core.management.commands import test
 
-def get_runner(settings):
-    test_path = settings.COVERAGE_TEST_RUNNER.split('.')
-    # Allow for Python 2.5 relative paths
-    if len(test_path) > 1:
-        test_module_name = '.'.join(test_path[:-1])
-    else:
-        test_module_name = '.'
-    test_module = __import__(test_module_name, {}, {}, test_path[-1])
-    test_runner = getattr(test_module, test_path[-1])
-    return test_runner
+from django_coverage import settings as coverage_settings
 
-class Command(BaseCommand):
-    option_list = BaseCommand.option_list + (
-        make_option('--noinput', action='store_false', dest='interactive', default=True,
-            help='Tells Django to NOT prompt the user for input of any kind.'),
-    )
-    help = """\
-Runs the test suite for the specified applications, or the entire site if \
-no apps are specified. Then generates coverage report both onscreen and as HTML.
-"""
-    args = '[appname ...]'
-
-    requires_model_validation = False
+class Command(test.Command):
+    help = ("Runs the test suite for the specified applications, or the "
+            "entire site if no apps are specified. Then generates coverage "
+            "report both onscreen and as HTML.")
 
     def handle(self, *test_labels, **options):
-        from django_coverage import settings
-
-        verbosity = int(options.get('verbosity', 1))
-        interactive = options.get('interactive', True)
-        test_runner = get_runner(settings)
-
-        failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive)
-        if failures:
-            sys.exit(failures)
-
+        """
+        Replaces the original test runner with the coverage test runner, but
+        keeps track of what the original runner was so that the coverage
+        runner can inherit from it.  Then, call the test command. This
+        plays well with apps that override the test command, such as South.
+        """
+        coverage_settings.ORIG_TEST_RUNNER = settings.TEST_RUNNER
+        settings.TEST_RUNNER = coverage_settings.COVERAGE_TEST_RUNNER
+        call_command('test', *test_labels, **options)
+        

django_coverage/settings.py

 
 # Specify the coverage test runner
 COVERAGE_TEST_RUNNER = getattr(settings, 'COVERAGE_TEST_RUNNER',
-                               'django_coverage.coverage_runner.run_tests')
+                             'django_coverage.coverage_runner.CoverageRunner')
 
 # Specify regular expressions of code blocks the coverage analyzer should
 # ignore as statements (e.g. ``raise NotImplemented``).
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.