Ticket #4501: 4501-coverage-soc.diff
File 4501-coverage-soc.diff, 26.4 KB (added by , 15 years ago) |
---|
-
django/conf/global_settings.py
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index a195b57..8b536ff 100644
a b MESSAGE_STORAGE = 'django.contrib.messages.storage.user_messages.LegacyFallbackS 410 410 ########### 411 411 412 412 # The name of the method to use to invoke the test suite 413 TEST_RUNNER = 'django.test.simple. run_tests'413 TEST_RUNNER = 'django.test.simple.DefaultTestRunner' 414 414 415 415 # The name of the database to use for testing purposes. 416 416 # If None, a name of 'test_' + DATABASE_NAME will be assumed … … TEST_DATABASE_CHARSET = None 424 424 TEST_DATABASE_COLLATION = None 425 425 426 426 ############ 427 # COVERAGE # 428 ############ 429 430 431 # Specify the coverage test runner 432 COVERAGE_TEST_RUNNER = 'django.test.test_coverage.ConsoleReportCoverageRunner' 433 434 # Specify regular expressions of code blocks the coverage analyzer should 435 # ignore as statements (e.g. ``raise NotImplemented``). 436 # These statements are not figured in as part of the coverage statistics. 437 # This setting is optional. 438 COVERAGE_CODE_EXCLUDES = [ 439 'def __unicode__\(self\):', 'def get_absolute_url\(self\):', 440 'from .* import .*', 'import .*', 441 ] 442 443 # Specify a list of regular expressions of paths to exclude from 444 # coverage analysis. 445 # Note these paths are ignored by the module introspection tool and take 446 # precedence over any package/module settings such as: 447 # TODO: THE SETTING FOR MODULES 448 # Use this to exclude subdirectories like ``r'\.svn'``, for example. 449 # This setting is optional. 450 COVERAGE_PATH_EXCLUDES = [r'\.svn'] 451 452 # Specify a list of additional module paths to include 453 # in the coverage analysis. By default, only modules within installed 454 # apps are reported. If you have utility modules outside of the app 455 # structure, you can include them here. 456 # Note this list is *NOT* regular expression, so you have to be explicit, 457 # such as 'myproject.utils', and not 'utils$'. 458 # This setting is optional. 459 COVERAGE_ADDITIONAL_MODULES = [] 460 461 # Specify a list of regular expressions of module paths to exclude 462 # from the coverage analysis. Examples are ``'tests$'`` and ``'urls$'``. 463 # This setting is optional. 464 COVERAGE_MODULE_EXCLUDES = ['tests$', 'settings$','urls$', 'common.views.test', 465 '__init__', 'django'] 466 467 # Specify the directory where you would like the coverage report to create 468 # the HTML files. 469 # You'll need to make sure this directory exists and is writable by the 470 # user account running the test. 471 # You should probably set this one explicitly in your own settings file. 472 COVERAGE_REPORT_HTML_OUTPUT_DIR = 'test_html' 473 474 475 ############ 427 476 # FIXTURES # 428 477 ############ 429 478 -
django/core/management/commands/test.py
diff --git a/django/core/management/commands/test.py b/django/core/management/commands/test.py index 8ebf3da..1f9edab 100644
a b 1 1 from django.core.management.base import BaseCommand 2 2 from optparse import make_option 3 3 import sys 4 import inspect 4 5 5 6 class Command(BaseCommand): 6 7 option_list = BaseCommand.option_list + ( 7 8 make_option('--noinput', action='store_false', dest='interactive', default=True, 8 9 help='Tells Django to NOT prompt the user for input of any kind.'), 10 make_option('--coverage', action='store_true', dest='coverage', default=False, 11 help='Tells Django to run the coverage runner'), 12 make_option('--reports', action='store_true', dest='reports', default=False, 13 help='Tells Django to output coverage results as HTML reports'), 9 14 ) 10 15 help = 'Runs the test suite for the specified applications, or the entire site if no apps are specified.' 11 16 args = '[appname ...]' … … class Command(BaseCommand): 18 23 19 24 verbosity = int(options.get('verbosity', 1)) 20 25 interactive = options.get('interactive', True) 21 test_runner = get_runner(settings) 22 23 failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive) 26 cover = options.get('coverage', False) 27 report = options.get('reports', False) 28 test_runner = get_runner(settings, coverage=cover, reports=report) 29 if inspect.isclass(test_runner): 30 tr = test_runner() 31 failures = tr.run_tests(test_labels, verbosity=verbosity, interactive=interactive) 32 else: 33 failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive) 24 34 if failures: 25 35 sys.exit(failures) -
django/test/simple.py
diff --git a/django/test/simple.py b/django/test/simple.py index f3c48ba..d79b6ef 100644
a b 1 import unittest1 import sys, time, traceback, unittest 2 2 from django.conf import settings 3 3 from django.db.models import get_app, get_apps 4 4 from django.test import _doctest as doctest … … def reorder_suite(suite, classes): 146 146 bins[0].addTests(bins[i+1]) 147 147 return bins[0] 148 148 149 def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]):149 class DefaultTestRunner(object): 150 150 """ 151 Run the unit tests for all the test labels in the provided list. 152 Labels must be of the form: 153 - app.TestClass.test_method 154 Run a single specific test method 155 - app.TestClass 156 Run all the test methods in a given class 157 - app 158 Search for doctests and unittests in the named application. 159 160 When looking for tests, the test runner will look in the models and 161 tests modules for the application. 162 163 A list of 'extra' tests may also be provided; these tests 164 will be added to the test suite. 165 166 Returns the number of tests that failed. 151 The original test runner. No coverage reporting. 167 152 """ 168 setup_test_environment()169 153 170 settings.DEBUG = False 171 suite = unittest.TestSuite() 172 173 if test_labels: 174 for label in test_labels: 175 if '.' in label: 176 suite.addTest(build_test(label)) 177 else: 178 app = get_app(label) 154 def __init__(self): 155 """ 156 Placeholder constructor. Want to make it obvious that it can 157 be overridden. 158 """ 159 self.isloaded = True 160 161 162 def run_tests(self, test_labels, verbosity=1, interactive=True, extra_tests=[]): 163 """ 164 Run the unit tests for all the test labels in the provided list. 165 Labels must be of the form: 166 - app.TestClass.test_method 167 Run a single specific test method 168 - app.TestClass 169 Run all the test methods in a given class 170 - app 171 Search for doctests and unittests in the named application. 172 173 When looking for tests, the test runner will look in the models and 174 tests modules for the application. 175 176 A list of 'extra' tests may also be provided; these tests 177 will be added to the test suite. 178 179 Returns the number of tests that failed. 180 """ 181 setup_test_environment() 182 183 settings.DEBUG = False 184 suite = unittest.TestSuite() 185 186 if test_labels: 187 for label in test_labels: 188 if '.' in label: 189 suite.addTest(build_test(label)) 190 else: 191 app = get_app(label) 192 suite.addTest(build_suite(app)) 193 else: 194 for app in get_apps(): 179 195 suite.addTest(build_suite(app)) 180 else:181 for app in get_apps():182 suite.addTest(build_suite(app))183 196 184 for test in extra_tests:185 suite.addTest(test)197 for test in extra_tests: 198 suite.addTest(test) 186 199 187 suite = reorder_suite(suite, (TestCase,))200 suite = reorder_suite(suite, (TestCase,)) 188 201 189 old_name = settings.DATABASE_NAME190 from django.db import connection191 connection.creation.create_test_db(verbosity, autoclobber=not interactive)192 result = unittest.TextTestRunner(verbosity=verbosity).run(suite)193 connection.creation.destroy_test_db(old_name, verbosity)202 old_name = settings.DATABASE_NAME 203 from django.db import connection 204 connection.creation.create_test_db(verbosity, autoclobber=not interactive) 205 result = unittest.TextTestRunner(verbosity=verbosity).run(suite) 206 connection.creation.destroy_test_db(old_name, verbosity) 194 207 195 teardown_test_environment()208 teardown_test_environment() 196 209 197 return len(result.failures) + len(result.errors)210 return len(result.failures) + len(result.errors) -
new file django/test/test_coverage.py
diff --git a/django/test/test_coverage.py b/django/test/test_coverage.py new file mode 100644 index 0000000..337350d
- + 1 import coverage, time 2 import os, sys 3 4 from django.conf import settings 5 from django.db.models.loading import get_app, get_apps 6 from django.test.simple import DefaultTestRunner as base_run_tests 7 from django.utils.module_tools import get_all_modules 8 from django.utils.translation import ugettext as _ 9 10 def _get_app_package(app_model_module): 11 """ 12 Returns the app module name from the app model module. 13 """ 14 return '.'.join(app_model_module.__name__.split('.')[:-1]) 15 16 17 class BaseCoverageRunner(object): 18 """ 19 Placeholder class for coverage runners. Intended to be easily extended. 20 """ 21 22 def __init__(self): 23 """Placeholder (since it is overrideable)""" 24 self.cov = coverage.coverage(cover_pylib=True, auto_data=True) 25 self.cov.use_cache(True) 26 self.cov.load() 27 #self.cov.combine() 28 29 def run_tests(self, test_labels, verbosity=1, interactive=True, 30 extra_tests=[]): 31 """ 32 Runs the specified tests while generating code coverage statistics. Upon 33 the tests' completion, the results are printed to stdout. 34 """ 35 36 self.cov.start() 37 brt = base_run_tests() 38 results = brt.run_tests(test_labels, verbosity, interactive, extra_tests) 39 self.cov.stop() 40 coverage_modules = [] 41 if test_labels: 42 for label in test_labels: 43 label = label.split('.')[0] 44 app = get_app(label) 45 coverage_modules.append(_get_app_package(app)) 46 else: 47 for app in get_apps(): 48 coverage_modules.append(_get_app_package(app)) 49 coverage_modules.extend(getattr(settings, 'COVERAGE_ADDITIONAL_MODULES', [])) 50 #This code seems to be a lot a bit magical to include in Django. 51 #Need to look at other implementations and see how they get all the 52 #correct modules to report on. 53 packages, self.modules, self.excludes, self.errors = get_all_modules( 54 coverage_modules, getattr(settings, 'COVERAGE_MODULE_EXCLUDES', []), 55 getattr(settings, 'COVERAGE_PATH_EXCLUDES', [])) 56 57 return results 58 59 class ConsoleReportCoverageRunner(BaseCoverageRunner): 60 61 def run_tests(self, *args, **kwargs): 62 """docstring for run_tests""" 63 res = super(ConsoleReportCoverageRunner, self).run_tests(*args, **kwargs) 64 self.cov.report(self.modules.values(), show_missing=1) 65 if self.excludes: 66 print >> sys.stdout 67 print >> sys.stdout, _("The following packages or modules were excluded:"), 68 for e in self.excludes: 69 print >> sys.stdout, e, 70 print >>sys.stdout 71 if self.errors: 72 print >> sys.stdout 73 print >> sys.stderr, _("There were problems with the following packages or modules:"), 74 for e in self.errors: 75 print >> sys.stderr, e, 76 print >> sys.stdout 77 return res 78 79 class ReportingCoverageRunner(BaseCoverageRunner): 80 """Runs coverage.py analysis, as well as generating detailed HTML reports.""" 81 def __init__(self, outdir = None): 82 """ 83 Constructor, overrides BaseCoverageRunner. Sets output directory 84 for reports. Parameter or setting. 85 """ 86 super(ReportingCoverageRunner, self).__init__() 87 if outdir: 88 self.outdir = outdir 89 else: 90 # Realistically, we aren't going to ship the entire reporting framework.. 91 # but for the time being I have left it in. 92 self.outdir = getattr(settings, 'COVERAGE_REPORT_HTML_OUTPUT_DIR', 'test_html') 93 self.outdir = os.path.abspath(self.outdir) 94 # Create directory 95 if not os.path.exists(self.outdir): 96 os.mkdir(self.outdir) 97 98 def run_tests(self, *args, **kwargs): 99 """ 100 Overrides BaseCoverageRunner.run_tests, and adds html report generation 101 with the results 102 """ 103 res = super(ReportingCoverageRunner, self).run_tests( *args, **kwargs) 104 print _("Outputting HTML reports") 105 self.cov.html_report(self.modules.values(), 106 directory=self.outdir, 107 ignore_errors=True, 108 omit_prefixes=['modeltests']) 109 print _("HTML reports were output to '%s'") % self.outdir 110 return res -
django/test/utils.py
diff --git a/django/test/utils.py b/django/test/utils.py index 9d39eee..1431059 100644
a b def teardown_test_environment(): 68 68 69 69 del mail.outbox 70 70 71 def get_runner(settings): 72 test_path = settings.TEST_RUNNER.split('.') 71 def get_runner(settings, coverage=False, reports=False): 72 """ 73 Based on the settings and parameters, returns the appropriate test 74 runner class. 75 """ 76 if coverage: 77 if reports: 78 test_path = 'django.test.test_coverage.ReportingCoverageRunner'.split('.') 79 else: 80 test_path = settings.COVERAGE_TEST_RUNNER.split('.') 81 else: 82 test_path = settings.TEST_RUNNER.split('.') 73 83 # Allow for Python 2.5 relative paths 74 84 if len(test_path) > 1: 75 85 test_module_name = '.'.join(test_path[:-1]) -
new file django/utils/module_tools/__init__.py
diff --git a/django/utils/module_tools/__init__.py b/django/utils/module_tools/__init__.py new file mode 100644 index 0000000..976d4b5
- + 1 from module_loader import * 2 from module_walker import * 3 -
new file django/utils/module_tools/data_storage.py
diff --git a/django/utils/module_tools/data_storage.py b/django/utils/module_tools/data_storage.py new file mode 100644 index 0000000..aed5980
- + 1 """ 2 Copyright 2009 55 Minutes (http://www.55minutes.com) 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 """ 16 17 __all__ = ('Packages', 'Modules', 'Excluded', 'Errors') 18 19 class SingletonType(type): 20 def __call__(cls, *args, **kwargs): 21 if getattr(cls, '__instance__', None) is None: 22 instance = cls.__new__(cls) 23 instance.__init__(*args, **kwargs) 24 cls.__instance__ = instance 25 return cls.__instance__ 26 27 class Packages(object): 28 __metaclass__ = SingletonType 29 packages = {} 30 31 class Modules(object): 32 __metaclass__ = SingletonType 33 modules = {} 34 35 class Excluded(object): 36 __metaclass__ = SingletonType 37 excluded = [] 38 39 class Errors(object): 40 __metaclass__ = SingletonType 41 errors = [] 42 -
new file django/utils/module_tools/module_loader.py
diff --git a/django/utils/module_tools/module_loader.py b/django/utils/module_tools/module_loader.py new file mode 100644 index 0000000..e6dd6ce
- + 1 """ 2 Copyright 2009 55 Minutes (http://www.55minutes.com) 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 """ 16 17 import imp, sys, types 18 19 __all__ = ('find_or_load_module',) 20 21 def _brute_force_find_module(module_name, module_path, module_type): 22 for m in [m for n, m in sys.modules.iteritems() if type(m) == types.ModuleType]: 23 m_path = [] 24 try: 25 if module_type in (imp.PY_COMPILED, imp.PY_SOURCE): 26 m_path = [m.__file__] 27 elif module_type==imp.PKG_DIRECTORY: 28 m_path = m.__path__ 29 except AttributeError: 30 pass 31 for p in m_path: 32 if p.startswith(module_path): 33 return m 34 return None 35 36 def _load_module(module_name, fo, fp, desc): 37 suffix, mode, mtype = desc 38 if module_name in sys.modules and \ 39 sys.modules[module_name].__file__.startswith(fp): 40 module = sys.modules[module_name] 41 else: 42 module = _brute_force_find_module(module_name, fp, mtype) 43 if not module: 44 try: 45 module = imp.load_module(module_name, fo, fp, desc) 46 except: 47 raise ImportError 48 return module 49 50 def _load_package(pkg_name, fp, desc): 51 suffix, mode, mtype = desc 52 if pkg_name in sys.modules: 53 if fp in sys.modules[pkg_name].__path__: 54 pkg = sys.modules[pkg_name] 55 else: 56 pkg = _brute_force_find_module(pkg_name, fp, mtype) 57 if not pkg: 58 pkg = imp.load_module(pkg_name, None, fp, desc) 59 return pkg 60 61 def find_or_load_module(module_name, path=None): 62 """ 63 Attempts to lookup ``module_name`` in ``sys.modules``, else uses the 64 facilities in the ``imp`` module to load the module. 65 66 If module_name specified is not of type ``imp.PY_SOURCE`` or 67 ``imp.PKG_DIRECTORY``, raise ``ImportError`` since we don't know 68 what to do with those. 69 """ 70 fo, fp, desc = imp.find_module(module_name.split('.')[-1], path) 71 suffix, mode, mtype = desc 72 if mtype in (imp.PY_SOURCE, imp.PY_COMPILED): 73 module = _load_module(module_name, fo, fp, desc) 74 elif mtype==imp.PKG_DIRECTORY: 75 module = _load_package(module_name, fp, desc) 76 else: 77 raise ImportError("Don't know how to handle this module type.") 78 return module 79 -
new file django/utils/module_tools/module_walker.py
diff --git a/django/utils/module_tools/module_walker.py b/django/utils/module_tools/module_walker.py new file mode 100644 index 0000000..442150e
- + 1 """ 2 Copyright 2009 55 Minutes (http://www.55minutes.com) 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 """ 16 17 import os, re, sys 18 from glob import glob 19 20 from data_storage import * 21 from module_loader import find_or_load_module 22 23 try: 24 set 25 except: 26 from sets import Set as set 27 28 __all__ = ('get_all_modules',) 29 30 def _build_pkg_path(pkg_name, pkg, path): 31 for rp in [x for x in pkg.__path__ if path.startswith(x)]: 32 p = path.replace(rp, '').replace(os.path.sep, '.') 33 return pkg_name + p 34 35 def _build_module_path(pkg_name, pkg, path): 36 return _build_pkg_path(pkg_name, pkg, os.path.splitext(path)[0]) 37 38 def _prune_whitelist(whitelist, blacklist): 39 excluded = Excluded().excluded 40 41 for wp in whitelist[:]: 42 for bp in blacklist: 43 if re.search(bp, wp): 44 whitelist.remove(wp) 45 excluded.append(wp) 46 break 47 return whitelist 48 49 def _parse_module_list(m_list): 50 packages = Packages().packages 51 modules = Modules().modules 52 excluded = Excluded().excluded 53 errors = Errors().errors 54 55 for m in m_list: 56 components = m.split('.') 57 m_name = '' 58 search_path = [] 59 processed=False 60 for i, c in enumerate(components): 61 m_name = '.'.join([x for x in m_name.split('.') if x] + [c]) 62 try: 63 module = find_or_load_module(m_name, search_path or None) 64 except ImportError: 65 processed=True 66 errors.append(m) 67 break 68 try: 69 search_path.extend(module.__path__) 70 except AttributeError: 71 processed = True 72 if i+1==len(components): 73 modules[m_name] = module 74 else: 75 errors.append(m) 76 break 77 if not processed: 78 packages[m_name] = module 79 80 def prune_dirs(root, dirs, exclude_dirs): 81 _dirs = [os.path.join(root, d) for d in dirs] 82 for i, p in enumerate(_dirs): 83 for e in exclude_dirs: 84 if re.search(e, p): 85 del dirs[i] 86 break 87 88 def _get_all_packages(pkg_name, pkg, blacklist, exclude_dirs): 89 packages = Packages().packages 90 errors = Errors().errors 91 92 for path in pkg.__path__: 93 for root, dirs, files in os.walk(path): 94 prune_dirs(root, dirs, exclude_dirs or []) 95 m_name = _build_pkg_path(pkg_name, pkg, root) 96 try: 97 if _prune_whitelist([m_name], blacklist): 98 m = find_or_load_module(m_name, [os.path.split(root)[0]]) 99 packages[m_name] = m 100 else: 101 for d in dirs[:]: 102 dirs.remove(d) 103 except ImportError: 104 errors.append(m_name) 105 for d in dirs[:]: 106 dirs.remove(d) 107 108 def _get_all_modules(pkg_name, pkg, blacklist): 109 modules = Modules().modules 110 errors = Errors().errors 111 112 for p in pkg.__path__: 113 for f in glob('%s/*.py' %p): 114 m_name = _build_module_path(pkg_name, pkg, f) 115 try: 116 if _prune_whitelist([m_name], blacklist): 117 m = find_or_load_module(m_name, [p]) 118 modules[m_name] = m 119 except ImportError: 120 errors.append(m_name) 121 122 def get_all_modules(whitelist, blacklist=None, exclude_dirs=None): 123 packages = Packages().packages 124 modules = Modules().modules 125 excluded = Excluded().excluded 126 errors = Errors().errors 127 128 whitelist = _prune_whitelist(whitelist, blacklist or []) 129 _parse_module_list(whitelist) 130 for pkg_name, pkg in packages.copy().iteritems(): 131 _get_all_packages(pkg_name, pkg, blacklist, exclude_dirs) 132 for pkg_name, pkg in packages.copy().iteritems(): 133 _get_all_modules(pkg_name, pkg, blacklist) 134 return packages, modules, list(set(excluded)), list(set(errors)) 135 -
tests/runtests.py
diff --git a/tests/runtests.py b/tests/runtests.py index 9f5b1a6..a5b94c7 100755
a b 1 1 #!/usr/bin/env python 2 2 3 3 import os, sys, traceback 4 import inspect 4 5 import unittest 5 6 6 7 import django.contrib as contrib … … try: 10 11 except NameError: 11 12 from sets import Set as set # For Python 2.3 12 13 13 14 14 CONTRIB_DIR_NAME = 'django.contrib' 15 15 MODEL_TESTS_DIR_NAME = 'modeltests' 16 16 REGRESSION_TESTS_DIR_NAME = 'regressiontests' … … def django_tests(verbosity, interactive, test_labels): 98 98 old_language_code = settings.LANGUAGE_CODE 99 99 old_middleware_classes = settings.MIDDLEWARE_CLASSES 100 100 101 #establish coverage settings for the regression suite 102 settings.COVERAGE_MODULE_EXCLUDES = ['modeltests*', 'regressiontests*'] 103 settings.COVERAGE_CODE_EXCLUDES = ['def __unicode__\(self\):', 104 'def get_absolute_url\(self\):', 105 'from .* import .*', 106 'import .*', 107 'from *'] 108 # depending on how this is run, we might need to tell the coverage libraries to consider django.* 109 settings.COVERAGE_ADDITIONAL_MODULES = ['django'] 110 101 111 # Redirect some settings for the duration of these tests. 102 112 settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS 103 113 settings.ROOT_URLCONF = 'urls' … … def django_tests(verbosity, interactive, test_labels): 158 168 from django.test.utils import get_runner 159 169 if not hasattr(settings, 'TEST_RUNNER'): 160 170 settings.TEST_RUNNER = 'django.test.simple.run_tests' 161 test_runner = get_runner(settings) 162 163 failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive, extra_tests=extra_tests) 171 if do_coverage: 172 test_runner = get_runner(settings, coverage=True, reports=True) 173 else: 174 test_runner = get_runner(settings, coverage=False, reports=False) 175 176 #Check if this is an old-style testrunner, and behave accordingly. 177 if inspect.isclass(test_runner): 178 tr = test_runner() 179 failures = tr.run_tests(test_labels, verbosity=verbosity, interactive=interactive) 180 else: 181 failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive) 164 182 if failures: 165 183 sys.exit(failures) 166 184 … … if __name__ == "__main__": 184 202 help='Tells Django to NOT prompt the user for input of any kind.') 185 203 parser.add_option('--settings', 186 204 help='Python path to settings module, e.g. "myproject.settings". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.') 205 parser.add_option('--coverage', action='store_true', dest='coverage', default=False, 206 help='Tells Django to run the tests with code coverage as well.') 187 207 options, args = parser.parse_args() 188 208 if options.settings: 189 209 os.environ['DJANGO_SETTINGS_MODULE'] = options.settings 190 210 elif "DJANGO_SETTINGS_MODULE" not in os.environ: 191 211 parser.error("DJANGO_SETTINGS_MODULE is not set in the environment. " 192 212 "Set it or use --settings.") 213 do_coverage = options.coverage 193 214 django_tests(int(options.verbosity), options.interactive, args)