def run(self) -> int: coverage = Coverage() coverage.start() exit_code = main(['-v', 'tests']) coverage.stop() # Early exit if pytest failed if exit_code != 0: return 0 # Generate xml report in StringIO file coverage.get_data() coverage.config.from_args( ignore_errors=None, report_omit=None, report_include=None, xml_output=None, ) data = StringIO() reporter = XmlReporter(coverage, coverage.config) reporter.report(None, data) data.seek(0) # Check diff cover compared to origin/master using xml score = generate_coverage_report(coverage_xml=[data], compare_branch='origin/master', exclude=self.exclude_paths) return score
def run_coverage(self, test_name): cov = Coverage(source=self.config.source, omit=self.config.omit) cov.start() self.map_test(test_name) cov.stop() return cov.get_data()
def read_coverage_data(): """ :rtype: CoverageData or None """ print('Using coverage data from .coverage file') # noinspection PyPackageRequirements,PyUnresolvedReferences from coverage import Coverage cov = Coverage('.coverage') cov.load() return cov.get_data()
class AutotestConfig(AppConfig): name = 'autotest' def __init__(self, *args, **kwargs): super(AutotestConfig, self).__init__(*args, **kwargs) self.coverage = None def coverage_start(self): if coverage and not self.coverage: self.coverage = Coverage() self.coverage.start() return self.coverage def coverage_report(self): if coverage and self.coverage: self.coverage.stop() coverage.stop() self.coverage.get_data().update(coverage.get_data()) self.coverage.html_report()
def read_coverage_data(): """ :rtype: CoverageData or None """ try: # noinspection PyPackageRequirements,PyUnresolvedReferences from coverage import Coverage except ImportError as e: raise ImportError('The --use-coverage feature requires the coverage library. Run "pip install coverage"') from e cov = Coverage('.coverage') cov.load() return cov.get_data()
def read_coverage_data(): """ :rtype: CoverageData or None """ try: # noinspection PyPackageRequirements,PyUnresolvedReferences from coverage import Coverage except ImportError as e: raise ImportError('The --use-coverage feature requires the coverage library. Run "pip install --force-reinstall mutmut[coverage]"') from e cov = Coverage('.coverage') cov.load() data = cov.get_data() return {filepath: data.lines(filepath) for filepath in data.measured_files()}
def coverage_read(root): coverage = Coverage(".coverage") # use pathlib coverage.load() data = coverage.get_data() filepaths = data.measured_files() out = dict() root = root.resolve() for filepath in filepaths: key = str(Path(filepath).relative_to(root)) value = set(data.lines(filepath)) print(key) out[key] = value return out
def run(self) -> int: coverage = Coverage() coverage.start() exit_code = main(['-v', 'tests']) coverage.stop() # Set score to zero if exit code was non-zero if exit_code != 0: return 0 # Generate xml report in StringIO file coverage.get_data() coverage.config.from_args( ignore_errors=None, report_omit=None, report_include=None, xml_output=None, ) data = StringIO() reporter = XmlReporter(coverage, coverage.config) reporter.report(None, data) data.seek(0) return round(coverage.report(show_missing=True))
def test_does_not_trace_files_outside_inclusion(tmpdir, branch, timid): @given(st.booleans()) def test(a): rnd() cov = Coverage( config_file=False, data_file=str(tmpdir.join('.coverage')), branch=branch, timid=timid, include=[__file__], ) cov._warn = escalate_warning cov.start() test() cov.stop() data = cov.get_data() assert len(list(data.measured_files())) == 1
def test_achieves_full_coverage(tmpdir, branch, timid): @given(st.booleans(), st.booleans(), st.booleans()) def test(a, b, c): some_function_to_test(a, b, c) cov = Coverage( config_file=False, data_file=str(tmpdir.join('.coverage')), branch=branch, timid=timid, ) cov._warn = escalate_warning cov.start() test() cov.stop() data = cov.get_data() lines = data.lines(__file__) for i in hrange(LINE_START + 1, LINE_END + 1): assert i in lines
def test_coverage_includes_unexecuted_files(testdir, branch, timid): # Setup two files under test in a Python package. # One will be imported explicitly (foo), one will not (bar) testdir.syspathinsert() testdir.tmpdir.ensure('__init__.py') testdir.tmpdir.ensure('foo.py').write(''' def foo(x): return x ''') testdir.tmpdir.ensure('bar.py').write(''' def bar(x): return x ''') # Setup a function to exercise the functionality in `foo` only @given(st.booleans()) def test(a): package = testdir.tmpdir.pyimport() foo = importlib.import_module('foo', package.__name__) foo.foo(a) # Exercise test function, restricting coverage to just our custom package cov = Coverage( config_file=False, data_file=str(testdir.tmpdir.join('.coverage')), branch=branch, timid=timid, source=[str(testdir.tmpdir)], ) cov._warn = escalate_warning cov.start() test() cov.stop() # Verify data = cov.get_data() filenames = {os.path.split(f)[1] for f in data.measured_files()} assert filenames == {'__init__.py', 'bar.py', 'foo.py'}
test_counter = 0 probability = float(sys.argv[1])/100.0 pathname = os.path.dirname(sys.argv[0]) statement_stats_dict = {} # maps a line number to a list (# successful runs where statement ran, # failed runs where statement ran) for i, arg1 in enumerate(args1): result = 0.0 abserr = 0.0 cov = Coverage() cov.start() bad_outcome = gsl_deriv_central(F, arg1, 1e-8, result, abserr) cov.stop() cov.save() for line_number in cov.get_data().lines(os.path.abspath(pathname)+ "/" + sys.argv[0]): if line_number > 301: continue if line_number not in statement_stats_dict.keys(): statement_stats_dict[line_number] = [0, 0] if bad_outcome == good_dict[i]: statement_stats_dict[line_number][0] = statement_stats_dict[line_number][0] + 1 else: statement_stats_dict[line_number][1] = statement_stats_dict[line_number][1] + 1 bad_dict[test_counter] = bad_outcome test_counter += 1 print(statement_stats_dict) exit() diff_dict = {index : 0.0 if bad_dict[index] == good_dict[index] else 1.0 for index in bad_dict }
def coverage_combine(data_files, output_path, source, process=None): """ Merges multiples reports. @param data_files report files (``.coverage``) @param output_path output path @param source source directory @param process function which processes the coverage report @return coverage report The function *process* should have the signature: :: def process(content): # ... return content On :epkg:`Windows`, file name have to have the right case. If not, coverage reports an empty coverage and raises an exception. """ def raise_exc(exc, content, ex, ex2, outfile, destcov, source, dests, inter, cov, infos): # pragma: no cover def shorten(t): if len(t) > 2000: return t[:2000] + "\n..." else: return t if len(content) > 2000: content = content[:2000] + '\n...' ex = "\n-\n".join(shorten(_) for _ in ex) ex2 = "\n-\n".join(shorten(_) for _ in ex2) rows = [ '-----------------', "destcov='{0}'".format(destcov), "outfile='{0}'".format(outfile), "source='{0}'".format(source), "cov.source={0}".format(get_source(cov)), "dests='{0}'".format(';'.join(dests)), "inter={0}".format(inter) ] for ii, info in enumerate(infos): rows.append('----------------- {}/{}'.format(ii, len(infos))) for k, v in sorted(info.items()): rows.append("{}='{}'".format(k, v)) rows.append('-----------------') if cov is not None and _attr_(cov, '_data', 'data')._lines is not None: rows.append("##### LINES") end = min(5, len(_attr_(cov, '_data', 'data')._lines)) for k, v in list( sorted(_attr_(cov, '_data', 'data')._lines.items()))[:end]: rows.append(' {0}:{1}'.format(k, v)) rows.append("----- RUNS") end = min(5, len(_attr_(cov, '_data', 'data')._runs)) for k in _attr_(cov, '_data', 'data')._runs[:end]: rows.append(' {0}'.format(k)) rows.append("----- END") mes = "{5}. In '{0}'.\n{1}\n{2}\n---AFTER---\n{3}\n---BEGIN---\n{4}" raise RuntimeError( mes.format(output_path, "\n".join(rows), content, ex, ex2, exc, cov)) from exc # We copy the origin coverage if the report is produced # in a folder part of the merge. destcov = os.path.join(output_path, '.coverage') if os.path.exists(destcov): destcov2 = destcov + '_old' shutil.copy(destcov, destcov2) # Starts merging coverage. from coverage import Coverage cov = Coverage(data_file=destcov, source=[source]) cov._init() cov.get_data() if get_source(cov) is None or len(get_source(cov)) == 0: raise_exc( FileNotFoundError("Probably unable to find '{0}'".format(source)), "", [], [], "", destcov, source, [], [], cov, []) inter = [] def find_longest_common_root(names, begin): counts = {} for name in names: spl = name.split(begin) for i in range(1, len(spl) + 1): if spl[i - 1] == 'src': break sub = begin.join(spl[:i]) if sub in counts: counts[sub] += 1 else: counts[sub] = 1 item = max((v, k) for k, v in counts.items()) return item[1] def copy_replace(source, dest, root_source, keep_infos): shutil.copy(source, dest) co = Counter(root_source) slash = co.get('/', 0) >= co.get('\\', 0) if slash: begin = "/" root_source_dup = root_source.replace('\\', '/').replace('//', '/') else: begin = "\\" root_source_dup = root_source.replace("\\", "\\\\") keep_infos["slash"] = slash keep_infos["begin"] = begin keep_infos["root_source_dup"] = root_source_dup keep_infos["root_source"] = root_source keep_infos["source"] = source keep_infos["dest"] = dest conn = sqlite3.connect(dest) sql = [] names = [] for row in conn.execute("select * from file"): names.append(row[1]) name = row[1].replace('/', begin) if not name.startswith(root_source): name = root_source + begin + name s = "UPDATE file SET path='{}' WHERE id={};".format(name, row[0]) sql.append(s) keep_infos['root_common'] = find_longest_common_root(names, begin) c = conn.cursor() for s in sql: c.execute(s) conn.commit() conn.close() # We modify the root in every coverage file. dests = [ os.path.join(output_path, '.coverage{0}'.format(i)) for i in range(len(data_files)) ] infos = [] for fi, de in zip(data_files, dests): keep_infos = {} copy_replace(fi, de, source, keep_infos) infos.append(keep_infos) shutil.copy(de, de + "~") # Keeping information (for exception). ex = [] for d in dests: with open(d, "rb") as f: ex.append(f.read()) ex2 = [] for d in data_files: with open(d, "rb") as f: ex2.append(f.read()) # We replace destcov by destcov2 if found in dests. if destcov in dests: ind = dests.index(destcov) dests[ind] = destcov2 # Let's combine. cov.combine(dests) # dest cov.save() report = True try: from coverage.exceptions import CoverageException except ImportError: # older version of coverage from coverage.misc import CoverageException try: from coverage.exceptions import NoSource except ImportError: # older version of coverage from coverage.misc import NoSource try: cov.html_report(directory=output_path, ignore_errors=True) except NoSource as e: raise_exc(e, "", ex, ex2, "", destcov, source, dests, inter, cov, infos) except CoverageException as e: if "No data to report" in str(e): # issue with path report = False else: msg = pprint.pformat(infos) raise RuntimeError( # pragma: no cover "Unable to process report in '{0}'.\n----\n{1}".format( output_path, msg)) from e if report: outfile = os.path.join(output_path, "coverage_report.xml") cov.xml_report(outfile=outfile) cov.save() # Verifications with open(outfile, "r", encoding="utf-8") as f: content = f.read() if len(content) == 0: raise RuntimeError("No report was generated.") return cov
class CoverageScript(object): """The command-line interface to coverage.py.""" def __init__(self): self.global_option = False self.coverage = None def command_line(self, argv): """The bulk of the command line interface to coverage.py. `argv` is the argument list to process. Returns 0 if all is well, 1 if something went wrong. """ # Collect the command-line options. if not argv: show_help(topic='minimum_help') return OK # The command syntax we parse depends on the first argument. Global # switch syntax always starts with an option. self.global_option = argv[0].startswith('-') if self.global_option: parser = GlobalOptionParser() else: parser = CMDS.get(argv[0]) if not parser: show_help("Unknown command: '%s'" % argv[0]) return ERR argv = argv[1:] ok, options, args = parser.parse_args_ok(argv) if not ok: return ERR # Handle help and version. if self.do_help(options, args, parser): return OK # Listify the list options. source = unshell_list(options.source) omit = unshell_list(options.omit) include = unshell_list(options.include) debug = unshell_list(options.debug) contexts = unshell_list(options.contexts) # Do something. self.coverage = Coverage( data_suffix=options.parallel_mode, cover_pylib=options.pylib, timid=options.timid, branch=options.branch, config_file=options.rcfile, source=source, omit=omit, include=include, debug=debug, concurrency=options.concurrency, check_preimported=True, context=options.context, ) if options.action == "debug": return self.do_debug(args) elif options.action == "erase": self.coverage.erase() return OK elif options.action == "run": return self.do_run(options, args) elif options.action == "combine": if options.append: self.coverage.load() data_dirs = args or None self.coverage.combine(data_dirs, strict=True) self.coverage.save() return OK # Remaining actions are reporting, with some common options. report_args = dict( morfs=unglob_args(args), ignore_errors=options.ignore_errors, omit=omit, include=include, contexts=contexts, ) # We need to be able to import from the current directory, because # plugins may try to, for example, to read Django settings. sys.path.insert(0, '') self.coverage.load() total = None if options.action == "report": total = self.coverage.report(show_missing=options.show_missing, skip_covered=options.skip_covered, **report_args) elif options.action == "annotate": self.coverage.annotate(directory=options.directory, **report_args) elif options.action == "html": total = self.coverage.html_report( directory=options.directory, title=options.title, skip_covered=options.skip_covered, show_contexts=options.show_contexts, **report_args) elif options.action == "xml": outfile = options.outfile total = self.coverage.xml_report(outfile=outfile, **report_args) if total is not None: # Apply the command line fail-under options, and then use the config # value, so we can get fail_under from the config file. if options.fail_under is not None: self.coverage.set_option("report:fail_under", options.fail_under) fail_under = self.coverage.get_option("report:fail_under") precision = self.coverage.get_option("report:precision") if should_fail_under(total, fail_under, precision): return FAIL_UNDER return OK def do_help(self, options, args, parser): """Deal with help requests. Return True if it handled the request, False if not. """ # Handle help. if options.help: if self.global_option: show_help(topic='help') else: show_help(parser=parser) return True if options.action == "help": if args: for a in args: parser = CMDS.get(a) if parser: show_help(parser=parser) else: show_help(topic=a) else: show_help(topic='help') return True # Handle version. if options.version: show_help(topic='version') return True return False def do_run(self, options, args): """Implementation of 'coverage run'.""" if not args: if options.module: # Specified -m with nothing else. show_help("No module specified for -m") return ERR command_line = self.coverage.get_option("run:command_line") if command_line is not None: args = shlex.split(command_line) if args and args[0] == "-m": options.module = True args = args[1:] if not args: show_help("Nothing to do.") return ERR if options.append and self.coverage.get_option("run:parallel"): show_help("Can't append to data files in parallel mode.") return ERR if options.concurrency == "multiprocessing": # Can't set other run-affecting command line options with # multiprocessing. for opt_name in [ 'branch', 'include', 'omit', 'pylib', 'source', 'timid' ]: # As it happens, all of these options have no default, meaning # they will be None if they have not been specified. if getattr(options, opt_name) is not None: show_help( "Options affecting multiprocessing must only be specified " "in a configuration file.\n" "Remove --{} from the command line.".format(opt_name)) return ERR runner = PyRunner(args, as_module=bool(options.module)) runner.prepare() if options.append: self.coverage.load() # Run the script. self.coverage.start() code_ran = True try: runner.run() except NoSource: code_ran = False raise finally: self.coverage.stop() if code_ran: self.coverage.save() return OK def do_debug(self, args): """Implementation of 'coverage debug'.""" if not args: show_help("What information would you like: config, data, sys?") return ERR for info in args: if info == 'sys': sys_info = self.coverage.sys_info() print(info_header("sys")) for line in info_formatter(sys_info): print(" %s" % line) elif info == 'data': self.coverage.load() data = self.coverage.get_data() print(info_header("data")) print("path: %s" % self.coverage.get_data().data_filename()) if data: print("has_arcs: %r" % data.has_arcs()) summary = line_counts(data, fullpath=True) filenames = sorted(summary.keys()) print("\n%d files:" % len(filenames)) for f in filenames: line = "%s: %d lines" % (f, summary[f]) plugin = data.file_tracer(f) if plugin: line += " [%s]" % plugin print(line) else: print("No data collected") elif info == 'config': print(info_header("config")) config_info = self.coverage.config.__dict__.items() for line in info_formatter(config_info): print(" %s" % line) else: show_help("Don't know what you mean by %r" % info) return ERR return OK
def coverage_combine(data_files, output_path, source, process=None, absolute_path=True): """ Merges multiples reports. @param data_files report files (``.coverage``) @param output_path output path @param source source directory @param process function which processes the coverage report @param absolute_path relocate sources with absolute paths @return coverage report The function *process* should have the signature: :: def process(content): # ... return content """ def raise_exc(exc, content, ex, ex2, outfile, destcov, source, dests, inter, cov): from coverage.data import CoverageData def shorten(t): if len(t) > 2000: return t[:2000] + "\n..." else: return t if len(content) > 2000: content = content[:2000] + '\n...' ex = "\n-\n".join(shorten(_) for _ in ex) ex2 = "\n-\n".join(shorten(_) for _ in ex2) rows = ["destcov='{0}'".format(destcov), "outfile='{0}'".format(outfile), "source='{0}'".format(source), "cov.source={0}".format(cov.source), "dests='{0}'".format(';'.join(dests)), "inter={0}".format(inter)] if cov is not None and cov.data is not None and cov.data._lines is not None: rows.append("----- LINES") end = min(5, len(cov.data._lines)) for k, v in list(sorted(cov.data._lines.items()))[:end]: rows.append(' {0}:{1}'.format(k, v)) rows.append("----- RUNS") end = min(5, len(cov.data._runs)) for k in cov.data._runs[:end]: rows.append(' {0}'.format(k)) rows.append("----- END") for d in dests: dd = CoverageData() dd.read_file(d + "~") rows.append("------- LINES - '{0}'".format(d)) end = min(5, len(dd._lines)) for k, v in list(sorted(dd._lines.items()))[:end]: rows.append(' {0}:{1}'.format(k, v)) rows.append("------- RUNS - '{0}'".format(d)) end = min(5, len(dd._runs)) for k in dd._runs[:end]: rows.append(' {0}'.format(k)) rows.append("------- END") mes = "{5}. In '{0}'.\n{1}\n{2}\n---AFTER---\n{3}\n---BEGIN---\n{4}" raise RuntimeError(mes.format(output_path, "\n".join( rows), content, ex, ex2, exc, cov)) from exc # We copy the origin coverage if the report is produced # in a folder part of the merge. destcov = os.path.join(output_path, '.coverage') if os.path.exists(destcov): destcov2 = destcov + '_old' shutil.copy(destcov, destcov2) # Starts merging coverage. from coverage import Coverage cov = Coverage(data_file=destcov, source=[source]) # Module coverage may modify the folder, # we take the one it considers. # On Windows, it has to have the right case. # If not, coverage reports an empty coverage and # raises an exception. cov._init() cov.get_data() if cov.source is None or len(cov.source) == 0: raise_exc(FileNotFoundError("Probably unable to find '{0}'".format(source)), "", [], [], "", destcov, source, [], [], cov) source = cov.source[0] inter = [] reg = re.compile(',\\"(.*?[.]py)\\"') def copy_replace(source, dest, root_source): with open(source, "r") as f: content = f.read() if process is not None: content = process(content) cf = reg.findall(content) co = Counter([_.split('src')[0] for _ in cf]) mx = max((v, k) for k, v in co.items()) root = mx[1].rstrip('\\/') if absolute_path: if '\\\\' in root: s2 = root_source.replace('\\', '\\\\').replace('/', '\\\\') s2 += "\\\\" root += "\\\\" elif '\\' in root: s2 = root_source s2 += "\\\\" root += "\\" else: s2 = root_source s2 += "/" root += "/" else: s2 = "" if '\\\\' in root: root += "\\\\" elif '\\' in root: root += "\\" else: root += "/" inter.append((root, root_source, s2)) content = content.replace(root, s2) with open(dest, "w") as f: f.write(content) # We modify the root in every coverage file. dests = [os.path.join(output_path, '.coverage{0}'.format( i)) for i in range(len(data_files))] for fi, de in zip(data_files, dests): copy_replace(fi, de, source) shutil.copy(de, de + "~") # Keeping information (for exception). ex = [] for d in dests: with open(d, "r") as f: ex.append(f.read()) ex2 = [] for d in data_files: with open(d, "r") as f: ex2.append(f.read()) # We replace destcov by destcov2 if found in dests. if destcov in dests: ind = dests.index(destcov) dests[ind] = destcov2 # Let's combine. cov.combine(dests) from coverage.misc import NoSource try: cov.html_report(directory=output_path) except NoSource as e: raise_exc(e, "", ex, ex2, "", destcov, source, dests, inter, cov) outfile = os.path.join(output_path, "coverage_report.xml") cov.xml_report(outfile=outfile) cov.save() # Verifications with open(outfile, "r", encoding="utf-8") as f: content = f.read() if 'line hits="1"' not in content: raise_exc(Exception("Coverage is empty"), content, ex, ex2, outfile, destcov, source, dests, inter, cov) return cov
class CoverageScript(object): """The command-line interface to coverage.py.""" def __init__(self): self.global_option = False self.coverage = None def command_line(self, argv): """The bulk of the command line interface to coverage.py. `argv` is the argument list to process. Returns 0 if all is well, 1 if something went wrong. """ # Collect the command-line options. if not argv: show_help(topic='minimum_help') return OK # The command syntax we parse depends on the first argument. Global # switch syntax always starts with an option. self.global_option = argv[0].startswith('-') if self.global_option: parser = GlobalOptionParser() else: parser = CMDS.get(argv[0]) if not parser: show_help("Unknown command: '%s'" % argv[0]) return ERR argv = argv[1:] ok, options, args = parser.parse_args_ok(argv) if not ok: return ERR # Handle help and version. if self.do_help(options, args, parser): return OK # Listify the list options. source = unshell_list(options.source) omit = unshell_list(options.omit) include = unshell_list(options.include) debug = unshell_list(options.debug) # Do something. self.coverage = Coverage( data_suffix=options.parallel_mode, cover_pylib=options.pylib, timid=options.timid, branch=options.branch, config_file=options.rcfile, source=source, omit=omit, include=include, debug=debug, concurrency=options.concurrency, check_preimported=True, context=options.context, ) if options.action == "debug": return self.do_debug(args) elif options.action == "erase": self.coverage.erase() return OK elif options.action == "run": return self.do_run(options, args) elif options.action == "combine": if options.append: self.coverage.load() data_dirs = args or None self.coverage.combine(data_dirs, strict=True) self.coverage.save() return OK # Remaining actions are reporting, with some common options. report_args = dict( morfs=unglob_args(args), ignore_errors=options.ignore_errors, omit=omit, include=include, ) # We need to be able to import from the current directory, because # plugins may try to, for example, to read Django settings. sys.path.insert(0, '') self.coverage.load() total = None if options.action == "report": total = self.coverage.report( show_missing=options.show_missing, skip_covered=options.skip_covered, **report_args ) elif options.action == "annotate": self.coverage.annotate(directory=options.directory, **report_args) elif options.action == "html": total = self.coverage.html_report( directory=options.directory, title=options.title, skip_covered=options.skip_covered, **report_args ) elif options.action == "xml": outfile = options.outfile total = self.coverage.xml_report(outfile=outfile, **report_args) if total is not None: # Apply the command line fail-under options, and then use the config # value, so we can get fail_under from the config file. if options.fail_under is not None: self.coverage.set_option("report:fail_under", options.fail_under) fail_under = self.coverage.get_option("report:fail_under") precision = self.coverage.get_option("report:precision") if should_fail_under(total, fail_under, precision): return FAIL_UNDER return OK def do_help(self, options, args, parser): """Deal with help requests. Return True if it handled the request, False if not. """ # Handle help. if options.help: if self.global_option: show_help(topic='help') else: show_help(parser=parser) return True if options.action == "help": if args: for a in args: parser = CMDS.get(a) if parser: show_help(parser=parser) else: show_help(topic=a) else: show_help(topic='help') return True # Handle version. if options.version: show_help(topic='version') return True return False def do_run(self, options, args): """Implementation of 'coverage run'.""" if not args: if options.module: # Specified -m with nothing else. show_help("No module specified for -m") return ERR command_line = self.coverage.get_option("run:command_line") if command_line is not None: args = shlex.split(command_line) if args and args[0] == "-m": options.module = True args = args[1:] if not args: show_help("Nothing to do.") return ERR if options.append and self.coverage.get_option("run:parallel"): show_help("Can't append to data files in parallel mode.") return ERR if options.concurrency == "multiprocessing": # Can't set other run-affecting command line options with # multiprocessing. for opt_name in ['branch', 'include', 'omit', 'pylib', 'source', 'timid']: # As it happens, all of these options have no default, meaning # they will be None if they have not been specified. if getattr(options, opt_name) is not None: show_help( "Options affecting multiprocessing must only be specified " "in a configuration file.\n" "Remove --{} from the command line.".format(opt_name) ) return ERR runner = PyRunner(args, as_module=bool(options.module)) runner.prepare() if options.append: self.coverage.load() # Run the script. self.coverage.start() code_ran = True try: runner.run() except NoSource: code_ran = False raise finally: self.coverage.stop() if code_ran: self.coverage.save() return OK def do_debug(self, args): """Implementation of 'coverage debug'.""" if not args: show_help("What information would you like: config, data, sys?") return ERR for info in args: if info == 'sys': sys_info = self.coverage.sys_info() print(info_header("sys")) for line in info_formatter(sys_info): print(" %s" % line) elif info == 'data': self.coverage.load() data = self.coverage.get_data() print(info_header("data")) print("path: %s" % self.coverage.get_data().data_filename()) if data: print("has_arcs: %r" % data.has_arcs()) summary = line_counts(data, fullpath=True) filenames = sorted(summary.keys()) print("\n%d files:" % len(filenames)) for f in filenames: line = "%s: %d lines" % (f, summary[f]) plugin = data.file_tracer(f) if plugin: line += " [%s]" % plugin print(line) else: print("No data collected") elif info == 'config': print(info_header("config")) config_info = self.coverage.config.__dict__.items() for line in info_formatter(config_info): print(" %s" % line) else: show_help("Don't know what you mean by %r" % info) return ERR return OK