def __init__(self, cov, code_unit): self.coverage = cov self.code_unit = code_unit self.filename = self.code_unit.filename actual_filename, source = self.find_source(self.filename) self.parser = CodeParser( text=source, filename=actual_filename, exclude=self.coverage._exclude_regex('exclude')) self.statements, self.excluded = self.parser.parse_source() executed = self.coverage.data.executed_lines(self.filename) exec1 = self.parser.first_lines(executed) self.missing = sorted(set(self.statements) - set(exec1)) if self.coverage.data.has_arcs(): self.no_branch = self.parser.lines_matching( join_regex(self.coverage.config.partial_list), join_regex(self.coverage.config.partial_always_list)) n_branches = self.total_branches() mba = self.missing_branch_arcs() n_partial_branches = sum( [len(v) for k, v in iitems(mba) if k not in self.missing]) n_missing_branches = sum([len(v) for k, v in iitems(mba)]) else: n_branches = n_partial_branches = n_missing_branches = 0 self.no_branch = set() self.numbers = Numbers(n_files=1, n_statements=len(self.statements), n_excluded=len(self.excluded), n_missing=len(self.missing), n_branches=n_branches, n_partial_branches=n_partial_branches, n_missing_branches=n_missing_branches)
def read_fileobj(self, file_obj): """Read the coverage data from the given file object. Should only be used on an empty CoverageData object. """ data = self._read_raw_data(file_obj) self._lines = self._arcs = None if 'lines' in data: self._lines = dict( (fname.encode(sys.getfilesystemencoding()), linenos) for fname, linenos in iitems(data['lines']) ) if 'arcs' in data: self._arcs = dict( (fname.encode(sys.getfilesystemencoding()), [tuple(pair) for pair in arcs]) for fname, arcs in iitems(data['arcs']) ) self._file_tracers = data.get('file_tracers', {}) self._runs = data.get('runs', []) self._validate()
def _read_file(self, filename): """Return the stored coverage data from the given file. Returns two values, suitable for assigning to `self.lines` and `self.arcs`. """ lines = {} arcs = {} try: data = self.raw_data(filename) if isinstance(data, dict): # Unpack the 'lines' item. lines = dict([ (f, dict.fromkeys(linenos, None)) for f, linenos in iitems(data.get('lines', {})) ]) # Unpack the 'arcs' item. arcs = dict([ (f, dict.fromkeys(arcpairs, None)) for f, arcpairs in iitems(data.get('arcs', {})) ]) except Exception: pass return lines, arcs
def __init__(self, data, file_reporter): self.data = data self.file_reporter = file_reporter self.filename = self.file_reporter.filename self.statements = self.file_reporter.lines() self.excluded = self.file_reporter.excluded_lines() # Identify missing statements. executed = self.data.lines(self.filename) or [] executed = self.file_reporter.translate_lines(executed) self.missing = self.statements - executed if self.data.has_arcs(): self._arc_possibilities = sorted(self.file_reporter.arcs()) self.exit_counts = self.file_reporter.exit_counts() self.no_branch = self.file_reporter.no_branch_lines() n_branches = self.total_branches() mba = self.missing_branch_arcs() n_partial_branches = sum(len(v) for k,v in iitems(mba) if k not in self.missing) n_missing_branches = sum(len(v) for k,v in iitems(mba)) else: self._arc_possibilities = [] self.exit_counts = {} self.no_branch = set() n_branches = n_partial_branches = n_missing_branches = 0 self.numbers = Numbers( n_files=1, n_statements=len(self.statements), n_excluded=len(self.excluded), n_missing=len(self.missing), n_branches=n_branches, n_partial_branches=n_partial_branches, n_missing_branches=n_missing_branches, )
def combine_parallel_data(self, aliases=None): """Combine a number of data files together. Treat `self.filename` as a file prefix, and combine the data from all of the data files starting with that prefix plus a dot. If `aliases` is provided, it's a `PathAliases` object that is used to re-map paths to match the local machine's. """ aliases = aliases or PathAliases() data_dir, local = os.path.split(self.filename) localdot = local + '.' for f in os.listdir(data_dir or '.'): if f.startswith(localdot): full_path = os.path.join(data_dir, f) new_lines, new_arcs, new_plugins = self._read_file(full_path) for filename, file_data in iitems(new_lines): filename = aliases.map(filename) self.lines.setdefault(filename, {}).update(file_data) for filename, file_data in iitems(new_arcs): filename = aliases.map(filename) self.arcs.setdefault(filename, {}).update(file_data) self.plugins.update(new_plugins) if f != local: os.remove(full_path)
def _validate_invariants(self): """Validate internal invariants.""" # Only one of _lines or _arcs should exist. assert not (self._has_lines() and self._has_arcs()), "Shouldn't have both _lines and _arcs" # _lines should be a dict of lists of ints. if self._has_lines(): for fname, lines in iitems(self._lines): assert isinstance(fname, string_class), "Key in _lines shouldn't be %r" % (fname,) assert all(isinstance(x, int) for x in lines), "_lines[%r] shouldn't be %r" % (fname, lines) # _arcs should be a dict of lists of pairs of ints. if self._has_arcs(): for fname, arcs in iitems(self._arcs): assert isinstance(fname, string_class), "Key in _arcs shouldn't be %r" % (fname,) assert all(isinstance(x, int) and isinstance(y, int) for x, y in arcs), "_arcs[%r] shouldn't be %r" % ( fname, arcs, ) # _file_tracers should have only non-empty strings as values. for fname, plugin in iitems(self._file_tracers): assert isinstance(fname, string_class), "Key in _file_tracers shouldn't be %r" % (fname,) assert plugin and isinstance(plugin, string_class), "_file_tracers[%r] shoudn't be %r" % (fname, plugin) # _runs should be a list of dicts. for val in self._runs: assert isinstance(val, dict) for key in val: assert isinstance(key, string_class), "Key in _runs shouldn't be %r" % (key,)
def __init__(self, cov, code_unit): self.coverage = cov self.file_reporter = code_unit self.filename = self.file_reporter.filename self.statements = self.file_reporter.statements() self.excluded = self.file_reporter.excluded_statements() # Identify missing statements. executed = self.coverage.data.executed_lines(self.filename) executed = self.file_reporter.translate_lines(executed) self.missing = self.statements - executed if self.coverage.data.has_arcs(): self.no_branch = self.file_reporter.no_branch_lines() n_branches = self.total_branches() mba = self.missing_branch_arcs() n_partial_branches = sum( len(v) for k,v in iitems(mba) if k not in self.missing ) n_missing_branches = sum(len(v) for k,v in iitems(mba)) else: n_branches = n_partial_branches = n_missing_branches = 0 self.no_branch = set() self.numbers = Numbers( n_files=1, n_statements=len(self.statements), n_excluded=len(self.excluded), n_missing=len(self.missing), n_branches=n_branches, n_partial_branches=n_partial_branches, n_missing_branches=n_missing_branches, )
def combine_parallel_data(self, aliases=None, data_dirs=None): """Combine a number of data files together. Treat `self.filename` as a file prefix, and combine the data from all of the data files starting with that prefix plus a dot. If `aliases` is provided, it's a `PathAliases` object that is used to re-map paths to match the local machine's. If `data_dirs` is provided, then it combines the data files from each directory into a single file. """ aliases = aliases or PathAliases() data_dir, local = os.path.split(self.filename) localdot = local + '.*' data_dirs = data_dirs or [data_dir] files_to_combine = [] for d in data_dirs: pattern = os.path.join(os.path.abspath(d), localdot) files_to_combine.extend(glob.glob(pattern)) for f in files_to_combine: new_lines, new_arcs, new_plugins = self._read_file(f) for filename, file_data in iitems(new_lines): filename = aliases.map(filename) self.lines.setdefault(filename, {}).update(file_data) for filename, file_data in iitems(new_arcs): filename = aliases.map(filename) self.arcs.setdefault(filename, {}).update(file_data) self.plugins.update(new_plugins) os.remove(f)
def combine_parallel_data(self, aliases=None): """Combine a number of data files together. Treat `self.filename` as a file prefix, and combine the data from all of the data files starting with that prefix plus a dot. If `aliases` is provided, it's a `PathAliases` object that is used to re-map paths to match the local machine's. """ aliases = aliases or PathAliases() data_dir, local = os.path.split(self.filename) localdot = local + '.' for f in os.listdir(data_dir or '.'): if f.startswith(localdot): full_path = os.path.join(data_dir, f) new_lines, new_arcs = self._read_file(full_path) for filename, file_data in iitems(new_lines): filename = aliases.map(filename) self.lines.setdefault(filename, {}).update(file_data) for filename, file_data in iitems(new_arcs): filename = aliases.map(filename) self.arcs.setdefault(filename, {}).update(file_data) if f != local: os.remove(full_path)
def update(self, other_data, aliases=None): """Update this data with data from another `CoverageData`. If `aliases` is provided, it's a `PathAliases` object that is used to re-map paths to match the local machine's. """ if self._has_lines() and other_data._has_arcs(): raise CoverageException("Can't combine arc data with line data") if self._has_arcs() and other_data._has_lines(): raise CoverageException("Can't combine line data with arc data") aliases = aliases or PathAliases() # _file_tracers: only have a string, so they have to agree. # Have to do these first, so that our examination of self._arcs and # self._lines won't be confused by data updated from other_data. for filename in other_data.measured_files(): other_plugin = other_data.file_tracer(filename) filename = aliases.map(filename) this_plugin = self.file_tracer(filename) if this_plugin is None: if other_plugin: self._file_tracers[filename] = other_plugin elif this_plugin != other_plugin: raise CoverageException( "Conflicting file tracer name for '%s': %r vs %r" % ( filename, this_plugin, other_plugin, )) # _runs: add the new runs to these runs. self._runs.extend(other_data._runs) # _lines: merge dicts. if other_data._has_lines(): if self._lines is None: self._lines = {} for filename, file_lines in iitems(other_data._lines): filename = aliases.map(filename) if filename in self._lines: lines = set(self._lines[filename]) lines.update(file_lines) file_lines = list(lines) self._lines[filename] = file_lines # _arcs: merge dicts. if other_data._has_arcs(): if self._arcs is None: self._arcs = {} for filename, file_arcs in iitems(other_data._arcs): filename = aliases.map(filename) if filename in self._arcs: arcs = set(self._arcs[filename]) arcs.update(file_arcs) file_arcs = list(arcs) self._arcs[filename] = file_arcs self._validate()
def write_fileobj(self, file_obj): """Write the coverage data to `file_obj`.""" # Create the file data. file_data = {} if self._has_arcs(): file_data['arcs'] = dict( (fname.decode(sys.getfilesystemencoding()), [tuple(pair) for pair in self._arcs]) for fname, arcs in iitems(data['arcs']) ) if self._has_lines(): file_data['lines'] = dict( (fname.decode(sys.getfilesystemencoding()), linenos) for fname, linenos in iitems(self._lines) ) if self._file_tracers: file_data['file_tracers'] = self._file_tracers if self._runs: file_data['runs'] = self._runs # Write the data to the file. file_obj.write(self._GO_AWAY) json.dump(file_data, file_obj)
def write_fileobj(self, file_obj): """Write the coverage data to `file_obj`.""" # Create the file data. file_data = {} if self._has_arcs(): file_data['arcs'] = dict( (fname.decode(sys.getfilesystemencoding()), [tuple(pair) for pair in self._arcs]) for fname, arcs in iitems(data['arcs'])) if self._has_lines(): file_data['lines'] = dict( (fname.decode(sys.getfilesystemencoding()), linenos) for fname, linenos in iitems(self._lines)) if self._file_tracers: file_data['file_tracers'] = self._file_tracers if self._runs: file_data['runs'] = self._runs # Write the data to the file. file_obj.write(self._GO_AWAY) json.dump(file_data, file_obj)
def update(self, other_data, aliases=None): """Update this data with data from another `CoverageData`. If `aliases` is provided, it's a `PathAliases` object that is used to re-map paths to match the local machine's. """ if self._has_lines() and other_data._has_arcs(): raise CoverageException("Can't combine arc data with line data") if self._has_arcs() and other_data._has_lines(): raise CoverageException("Can't combine line data with arc data") aliases = aliases or PathAliases() # _file_tracers: only have a string, so they have to agree. # Have to do these first, so that our examination of self._arcs and # self._lines won't be confused by data updated from other_data. for filename in other_data.measured_files(): other_plugin = other_data.file_tracer(filename) filename = aliases.map(filename) this_plugin = self.file_tracer(filename) if this_plugin is None: if other_plugin: self._file_tracers[filename] = other_plugin elif this_plugin != other_plugin: raise CoverageException( "Conflicting file tracer name for '%s': %r vs %r" % ( filename, this_plugin, other_plugin, ) ) # _runs: add the new runs to these runs. self._runs.extend(other_data._runs) # _lines: merge dicts. if other_data._has_lines(): if self._lines is None: self._lines = {} for filename, file_lines in iitems(other_data._lines): filename = aliases.map(filename) if filename in self._lines: lines = set(self._lines[filename]) lines.update(file_lines) file_lines = list(lines) self._lines[filename] = file_lines # _arcs: merge dicts. if other_data._has_arcs(): if self._arcs is None: self._arcs = {} for filename, file_arcs in iitems(other_data._arcs): filename = aliases.map(filename) if filename in self._arcs: arcs = set(self._arcs[filename]) arcs.update(file_arcs) file_arcs = list(arcs) self._arcs[filename] = file_arcs self._validate()
def _read_file(self, filename): lines = {} arcs = {} try: data = self.raw_data(filename) if isinstance(data, dict): lines = dict([ (f, dict.fromkeys(linenos, None)) for f, linenos in iitems(data.get('lines', {})) ]) arcs = dict([ (f, dict.fromkeys(arcpairs, None)) for f, arcpairs in iitems(data.get('arcs', {})) ]) except Exception: pass return (lines, arcs)
def write_pickled_file(self, covdata, filename): """Write coverage data as pickled `filename`.""" # Create the file data. file_data = {} if covdata._arcs: file_data['arcs'] = dict((f, list(amap)) for f, amap in iitems(covdata._arcs)) else: file_data['lines'] = dict((f, list(lmap)) for f, lmap in iitems(covdata._lines)) # Write the pickle to the file. with open(filename, 'wb') as file_obj: pickle.dump(file_data, file_obj, 2)
def _read_file(self, filename): lines = {} arcs = {} try: data = self.raw_data(filename) if isinstance(data, dict): lines = dict([(f, dict.fromkeys(linenos, None)) for f, linenos in iitems(data.get('lines', {}))]) arcs = dict([(f, dict.fromkeys(arcpairs, None)) for f, arcpairs in iitems(data.get('arcs', {}))]) except Exception: pass return (lines, arcs)
def update(self, other_data, aliases=None): """Update this data with data from another `CoverageData`. If `aliases` is provided, it's a `PathAliases` object that is used to re-map paths to match the local machine's. """ aliases = aliases or PathAliases() for filename, file_data in iitems(other_data._lines): filename = aliases.map(filename) self._lines.setdefault(filename, {}).update(file_data) for filename, file_data in iitems(other_data._arcs): filename = aliases.map(filename) self._arcs.setdefault(filename, {}).update(file_data) self._plugins.update(other_data._plugins)
def write_pickled_file(self, covdata, filename): """Write coverage data as pickled `filename`.""" # Create the file data. file_data = {} if covdata._arcs: file_data['arcs'] = dict( (f, list(amap)) for f, amap in iitems(covdata._arcs)) else: file_data['lines'] = dict( (f, list(lmap)) for f, lmap in iitems(covdata._lines)) # Write the pickle to the file. with open(filename, 'wb') as file_obj: pickle.dump(file_data, file_obj, 2)
def __init__(self, cov, code_unit): self.coverage = cov self.code_unit = code_unit self.filename = self.code_unit.filename ext = os.path.splitext(self.filename)[1] source = None if ext == '.py': if not os.path.exists(self.filename): source = self.coverage.file_locator.get_zip_data(self.filename) if not source: raise NoSource("No source for code: '%s'" % self.filename) self.parser = CodeParser( text=source, filename=self.filename, exclude=self.coverage._exclude_regex('exclude') ) self.statements, self.excluded = self.parser.parse_source() # Identify missing statements. executed = self.coverage.data.executed_lines(self.filename) exec1 = self.parser.first_lines(executed) self.missing = sorted(set(self.statements) - set(exec1)) if self.coverage.data.has_arcs(): self.no_branch = self.parser.lines_matching( join_regex(self.coverage.config.partial_list), join_regex(self.coverage.config.partial_always_list) ) n_branches = self.total_branches() mba = self.missing_branch_arcs() n_partial_branches = sum( [len(v) for k,v in iitems(mba) if k not in self.missing] ) n_missing_branches = sum([len(v) for k,v in iitems(mba)]) else: n_branches = n_partial_branches = n_missing_branches = 0 self.no_branch = set() self.numbers = Numbers( n_files=1, n_statements=len(self.statements), n_excluded=len(self.excluded), n_missing=len(self.missing), n_branches=n_branches, n_partial_branches=n_partial_branches, n_missing_branches=n_missing_branches, )
def sysinfo(self): import coverage as covmod import platform, re try: implementation = platform.python_implementation() except AttributeError: implementation = 'unknown' info = [('version', covmod.__version__), ('coverage', covmod.__file__), ('cover_dir', self.cover_dir), ('pylib_dirs', self.pylib_dirs), ('tracer', self.collector.tracer_name()), ('config_files', self.config.attempted_config_files), ('configs_read', self.config.config_files), ('data_path', self.data.filename), ('python', sys.version.replace('\n', '')), ('platform', platform.platform()), ('implementation', implementation), ('executable', sys.executable), ('cwd', os.getcwd()), ('path', sys.path), ('environment', sorted([ '%s = %s' % (k, v) for k, v in iitems(os.environ) if re.search('^COV|^PY', k) ])), ('command_line', ' '.join(getattr(sys, 'argv', ['???'])))] if self.source_match: info.append(('source_match', self.source_match.info())) if self.include_match: info.append(('include_match', self.include_match.info())) if self.omit_match: info.append(('omit_match', self.omit_match.info())) if self.cover_match: info.append(('cover_match', self.cover_match.info())) if self.pylib_match: info.append(('pylib_match', self.pylib_match.info())) return info
def sysinfo(self): """Return a list of (key, value) pairs showing internal information.""" import coverage as covmod import platform, re try: implementation = platform.python_implementation() except AttributeError: implementation = "unknown" info = [ ("version", covmod.__version__), ("coverage", covmod.__file__), ("cover_dir", self.cover_dir), ("pylib_dirs", self.pylib_dirs), ("tracer", self.collector.tracer_name()), ("config_files", self.config.attempted_config_files), ("configs_read", self.config.config_files), ("data_path", self.data.filename), ("python", sys.version.replace("\n", "")), ("platform", platform.platform()), ("implementation", implementation), ("executable", sys.executable), ("cwd", os.getcwd()), ("path", sys.path), ("environment", [("%s = %s" % (k, v)) for k, v in iitems(os.environ) if re.search(r"^COV|^PY", k)]), ] return info
def sysinfo(self): """Return a list of (key, value) pairs showing internal information.""" import coverage as covmod import platform, re try: implementation = platform.python_implementation() except AttributeError: implementation = "unknown" info = [ ('version', covmod.__version__), ('coverage', covmod.__file__), ('cover_dir', self.cover_dir), ('pylib_dirs', self.pylib_dirs), ('tracer', self.collector.tracer_name()), ('data_path', self.data.filename), ('python', sys.version.replace('\n', '')), ('platform', platform.platform()), ('implementation', implementation), ('executable', sys.executable), ('cwd', os.getcwd()), ('path', sys.path), ('environment', [ ("%s = %s" % (k, v)) for k, v in iitems(os.environ) if re.search(r"^COV|^PY", k) ]), ] return info
def add_file_tracers(self, file_tracers): """Add per-file plugin information. `file_tracers` is { filename: plugin_name, ... } """ self._start_using() with self._connect() as con: for filename, plugin_name in iitems(file_tracers): file_id = self._file_id(filename) if file_id is None: raise CoverageException( "Can't add file tracer data for unmeasured file '%s'" % (filename,) ) existing_plugin = self.file_tracer(filename) if existing_plugin: if existing_plugin != plugin_name: raise CoverageException( "Conflicting file tracer name for '%s': %r vs %r" % ( filename, existing_plugin, plugin_name, ) ) elif plugin_name: con.execute( "insert into tracer (file_id, tracer) values (?, ?)", (file_id, plugin_name) )
def from_args(self, **kwargs): """Read config values from `kwargs`.""" for k, v in iitems(kwargs): if v is not None: if k in self.MUST_BE_LIST and isinstance(v, string_class): v = [v] setattr(self, k, v)
def add_lines(self, line_data): """Add measured line data. `line_data` is a dictionary mapping file names to dictionaries:: { filename: { lineno: None, ... }, ...} """ if self._debug.should('dataop'): self._debug.write("Adding lines: %d files, %d lines total" % (len(line_data), sum(len(lines) for lines in line_data.values()))) self._start_using() self._choose_lines_or_arcs(lines=True) if not line_data: return with self._connect() as con: self._set_context_id() for filename, linenos in iitems(line_data): linemap = nums_to_numbits(linenos) file_id = self._file_id(filename, add=True) query = "select numbits from line_bits where file_id = ? and context_id = ?" existing = list( con.execute(query, (file_id, self._current_context_id))) if existing: linemap = numbits_union(linemap, existing[0][0]) con.execute( "insert or replace into line_bits " " (file_id, context_id, numbits) values (?, ?, ?)", (file_id, self._current_context_id, linemap), )
def sysinfo(self): """Return a list of (key, value) pairs showing internal information.""" import coverage as covmod import platform, re try: implementation = platform.python_implementation() except AttributeError: implementation = "unknown" info = [ ('version', covmod.__version__), ('coverage', covmod.__file__), ('cover_dir', self.cover_dir), ('pylib_dirs', self.pylib_dirs), ('tracer', self.collector.tracer_name()), ('data_path', self.data.filename), ('python', sys.version.replace('\n', '')), ('platform', platform.platform()), ('implementation', implementation), ('executable', sys.executable), ('cwd', os.getcwd()), ('path', sys.path), ('environment', [("%s = %s" % (k, v)) for k, v in iitems(os.environ) if re.search(r"^COV|^PY", k)]), ] return info
def add_file_tracers(self, file_tracers): """Add per-file plugin information. `file_tracers` is { filename: plugin_name, ... } """ if self._debug and self._debug.should('dataop'): self._debug.write("Adding file tracers: %d files" % (len(file_tracers), )) existing_files = self._arcs or self._lines or {} for filename, plugin_name in iitems(file_tracers): if filename not in existing_files: raise CoverageException( "Can't add file tracer data for unmeasured file '%s'" % (filename, )) existing_plugin = self._file_tracers.get(filename) if existing_plugin is not None and plugin_name != existing_plugin: raise CoverageException( "Conflicting file tracer name for '%s': %r vs %r" % ( filename, existing_plugin, plugin_name, )) self._file_tracers[filename] = plugin_name self._validate()
def add_arcs(self, arc_data): """Add measured arc data. `arc_data` is a dictionary mapping file names to dictionaries:: { filename: { (l1,l2): None, ... }, ...} """ if self._debug.should('dataop'): self._debug.write( "Adding arcs: %d files, %d arcs total" % (len(arc_data), sum(len(arcs) for arcs in arc_data.values()))) self._start_using() self._choose_lines_or_arcs(arcs=True) if not arc_data: return with self._connect() as con: self._set_context_id() for filename, arcs in iitems(arc_data): file_id = self._file_id(filename, add=True) data = [(file_id, self._current_context_id, fromno, tono) for fromno, tono in arcs] con.executemany( "insert or ignore into arc " "(file_id, context_id, fromno, tono) values (?, ?, ?, ?)", data, )
def add_lines(self, line_data): """Add measured line data. `line_data` is a dictionary mapping file names to dictionaries:: { filename: { lineno: None, ... }, ...} """ if self._debug and self._debug.should('dataop'): self._debug.write("Adding lines: %d files, %d lines total" % (len(line_data), sum(len(lines) for lines in line_data.values()))) if self._has_arcs(): raise CoverageException("Can't add lines to existing arc data") if self._lines is None: self._lines = {} for filename, linenos in iitems(line_data): if filename in self._lines: new_linenos = set(self._lines[filename]) new_linenos.update(linenos) linenos = new_linenos self._lines[filename] = list(linenos) self._validate()
def add_arcs(self, arc_data): """Add measured arc data. `arc_data` is a dictionary mapping file names to dictionaries:: { filename: { (l1,l2): None, ... }, ...} """ if self._debug and self._debug.should('dataop'): self._debug.write( "Adding arcs: %d files, %d arcs total" % (len(arc_data), sum(len(arcs) for arcs in arc_data.values()))) if self._has_lines(): raise CoverageException("Can't add arcs to existing line data") if self._arcs is None: self._arcs = {} for filename, arcs in iitems(arc_data): if filename in self._arcs: new_arcs = set(self._arcs[filename]) new_arcs.update(arcs) arcs = new_arcs self._arcs[filename] = list(arcs) self._validate()
def add_lines(self, line_data): """Add measured line data. `line_data` is a dictionary mapping file names to dictionaries:: { filename: { lineno: None, ... }, ...} """ if self._debug and self._debug.should('dataop'): self._debug.write("Adding lines: %d files, %d lines total" % ( len(line_data), sum(len(lines) for lines in line_data.values()) )) if self._has_arcs(): raise CoverageException("Can't add lines to existing arc data") if self._lines is None: self._lines = {} for filename, linenos in iitems(line_data): if filename in self._lines: new_linenos = set(self._lines[filename]) new_linenos.update(linenos) linenos = new_linenos self._lines[filename] = list(linenos) self._validate()
def add_arcs(self, arc_data): """Add measured arc data. `arc_data` is a dictionary mapping file names to dictionaries:: { filename: { (l1,l2): None, ... }, ...} """ if self._debug and self._debug.should('dataop'): self._debug.write("Adding arcs: %d files, %d arcs total" % ( len(arc_data), sum(len(arcs) for arcs in arc_data.values()) )) if self._has_lines(): raise CoverageException("Can't add arcs to existing line data") if self._arcs is None: self._arcs = {} for filename, arcs in iitems(arc_data): if filename in self._arcs: new_arcs = set(self._arcs[filename]) new_arcs.update(arcs) arcs = new_arcs self._arcs[filename] = list(arcs) self._validate()
def add_file_tracers(self, file_tracers): """Add per-file plugin information. `file_tracers` is { filename: plugin_name, ... } """ if self._debug and self._debug.should('dataop'): self._debug.write("Adding file tracers: %d files" % (len(file_tracers),)) existing_files = self._arcs or self._lines or {} for filename, plugin_name in iitems(file_tracers): if filename not in existing_files: raise CoverageException( "Can't add file tracer data for unmeasured file '%s'" % (filename,) ) existing_plugin = self._file_tracers.get(filename) if existing_plugin is not None and plugin_name != existing_plugin: raise CoverageException( "Conflicting file tracer name for '%s': %r vs %r" % ( filename, existing_plugin, plugin_name, ) ) self._file_tracers[filename] = plugin_name self._validate()
def add_lines(self, line_data): """Add measured line data. `line_data` is a dictionary mapping file names to dictionaries:: { filename: { lineno: None, ... }, ...} """ if self._debug.should('dataop'): self._debug.write("Adding lines: %d files, %d lines total" % (len(line_data), sum(len(lines) for lines in line_data.values()))) self._start_using() self._choose_lines_or_arcs(lines=True) self._set_context_id() with self._connect() as con: for filename, linenos in iitems(line_data): file_id = self._file_id(filename, add=True) data = [(file_id, self._current_context_id, lineno) for lineno in linenos] con.executemany( "insert or ignore into line (file_id, context_id, lineno) values (?, ?, ?)", data, )
def add_line_data(self, line_data): """Add executed line data. `line_data` is { filename: { lineno: None, ... }, ...} """ for filename, linenos in iitems(line_data): self.lines.setdefault(filename, {}).update(linenos)
def __init__(self, cov, code_unit): self.coverage = cov self.code_unit = code_unit self.filename = self.code_unit.filename ext = os.path.splitext(self.filename)[1] source = None if ext == '.py': if not os.path.exists(self.filename): source = self.coverage.file_locator.get_zip_data(self.filename) if not source: raise NoSource("No source for code: '%s'" % self.filename) self.parser = CodeParser( text=source, filename=self.filename, exclude=self.coverage._exclude_regex('exclude')) self.statements, self.excluded = self.parser.parse_source() # Identify missing statements. executed = self.coverage.data.executed_lines(self.filename) exec1 = self.parser.first_lines(executed) self.missing = sorted(set(self.statements) - set(exec1)) if self.coverage.data.has_arcs(): self.no_branch = self.parser.lines_matching( join_regex(self.coverage.config.partial_list), join_regex(self.coverage.config.partial_always_list)) n_branches = self.total_branches() mba = self.missing_branch_arcs() n_partial_branches = sum( [len(v) for k, v in iitems(mba) if k not in self.missing]) n_missing_branches = sum([len(v) for k, v in iitems(mba)]) else: n_branches = n_partial_branches = n_missing_branches = 0 self.no_branch = set() self.numbers = Numbers( n_files=1, n_statements=len(self.statements), n_excluded=len(self.excluded), n_missing=len(self.missing), n_branches=n_branches, n_partial_branches=n_partial_branches, n_missing_branches=n_missing_branches, )
def add_arcs(self, arc_data): """Add measured arc data. `arc_data` is { filename: { (l1,l2): None, ... }, ...} """ for filename, arcs in iitems(arc_data): self._arcs.setdefault(filename, {}).update(arcs)
def add_arc_data(self, arc_data): """Add measured arc data. `arc_data` is { filename: { (l1,l2): None, ... }, ...} """ for filename, arcs in iitems(arc_data): self.arcs.setdefault(filename, {}).update(arcs)
def add_lines(self, line_data): """Add executed line data. `line_data` is { filename: { lineno: None, ... }, ...} """ for filename, linenos in iitems(line_data): self._lines.setdefault(filename, {}).update(linenos)
def sys_info(self): """Return a list of (key, value) pairs showing internal information.""" import coverage as covmod self._init() self._post_init() def plugin_info(plugins): """Make an entry for the sys_info from a list of plug-ins.""" entries = [] for plugin in plugins: entry = plugin._coverage_plugin_name if not plugin._coverage_enabled: entry += " (disabled)" entries.append(entry) return entries info = [ ('version', covmod.__version__), ('coverage', covmod.__file__), ('tracer', self._collector.tracer_name() if self._collector else "-none-"), ('CTracer', 'available' if CTracer else "unavailable"), ('plugins.file_tracers', plugin_info(self._plugins.file_tracers)), ('plugins.configurers', plugin_info(self._plugins.configurers)), ('plugins.context_switchers', plugin_info(self._plugins.context_switchers)), ('configs_attempted', self.config.attempted_config_files), ('configs_read', self.config.config_files_read), ('config_file', self.config.config_file), ('config_contents', repr(self.config._config_contents) if self.config._config_contents else '-none-' ), ('data_file', self._data.data_filename() if self._data is not None else "-none-"), ('python', sys.version.replace('\n', '')), ('platform', platform.platform()), ('implementation', platform.python_implementation()), ('executable', sys.executable), ('def_encoding', sys.getdefaultencoding()), ('fs_encoding', sys.getfilesystemencoding()), ('pid', os.getpid()), ('cwd', os.getcwd()), ('path', sys.path), ('environment', sorted( ("%s = %s" % (k, v)) for k, v in iitems(os.environ) if any(slug in k for slug in ("COV", "PY")) )), ('command_line', " ".join(getattr(sys, 'argv', ['-none-']))), ] if self._inorout: info.extend(self._inorout.sys_info()) info.extend(CoverageData.sys_info()) return info
def sys_info(self): """Return a list of (key, value) pairs showing internal information.""" import coverage as covmod self._init() def plugin_info(plugins): """Make an entry for the sys_info from a list of plug-ins.""" entries = [] for plugin in plugins: entry = plugin._coverage_plugin_name if not plugin._coverage_enabled: entry += " (disabled)" entries.append(entry) return entries info = [ ('version', covmod.__version__), ('coverage', covmod.__file__), ('cover_paths', self.cover_paths), ('pylib_paths', self.pylib_paths), ('tracer', self.collector.tracer_name()), ('plugins.file_tracers', plugin_info(self.plugins.file_tracers)), ('plugins.configurers', plugin_info(self.plugins.configurers)), ('config_files', self.config.attempted_config_files), ('configs_read', self.config.config_files), ('data_path', self.data_files.filename), ('python', sys.version.replace('\n', '')), ('platform', platform.platform()), ('implementation', platform.python_implementation()), ('executable', sys.executable), ('cwd', os.getcwd()), ('path', sys.path), ('environment', sorted(("%s = %s" % (k, v)) for k, v in iitems(os.environ) if k.startswith(("COV", "PY")))), ('command_line', " ".join(getattr(sys, 'argv', ['???']))), ] matcher_names = [ 'source_match', 'source_pkgs_match', 'include_match', 'omit_match', 'cover_match', 'pylib_match', ] for matcher_name in matcher_names: matcher = getattr(self, matcher_name) if matcher: matcher_info = matcher.info() else: matcher_info = '-none-' info.append((matcher_name, matcher_info)) return info
def __init__(self, cov, code_unit): self.coverage = cov self.code_unit = code_unit self.filename = self.code_unit.filename self.parser = code_unit.get_parser( exclude=self.coverage._exclude_regex('exclude') ) self.statements, self.excluded = self.parser.parse_source() self.callers_data = self.coverage.data.callers_data().get(self.filename, {}) # Identify missing statements. executed = self.coverage.data.executed_lines(self.filename) executed = self.parser.translate_lines(executed) self.missing = self.statements - executed if self.coverage.data.has_arcs(): self.no_branch = self.parser.lines_matching( join_regex(self.coverage.config.partial_list), join_regex(self.coverage.config.partial_always_list) ) n_branches = self.total_branches() mba = self.missing_branch_arcs() n_partial_branches = sum( len(v) for k,v in iitems(mba) if k not in self.missing ) n_missing_branches = sum(len(v) for k,v in iitems(mba)) else: n_branches = n_partial_branches = n_missing_branches = 0 self.no_branch = set() unique_tests = set() if self.callers_data: unique_tests = get_unique_tests(self.callers_data) self.numbers = Numbers( n_files=1, n_statements=len(self.statements), n_excluded=len(self.excluded), n_missing=len(self.missing), n_branches=n_branches, n_partial_branches=n_partial_branches, n_missing_branches=n_missing_branches, calling_tests=unique_tests, )
def write(self, file_obj): """Write the coverage data to `file_obj`.""" # Create the file data. file_data = {} file_data['lines'] = dict((f, list(lmap.keys())) for f, lmap in iitems(self._lines)) if self._arcs: file_data['arcs'] = dict((f, list(amap.keys())) for f, amap in iitems(self._arcs)) if self._collector: file_data['collector'] = self._collector file_data['plugins'] = self._plugins # Write the pickle to the file. pickle.dump(file_data, file_obj, 2)
def combine_parallel_data(self, aliases=None): aliases = aliases or PathAliases() data_dir, local = os.path.split(self.filename) localdot = local + '.' for f in os.listdir(data_dir or '.'): if f.startswith(localdot): full_path = os.path.join(data_dir, f) new_lines, new_arcs = self._read_file(full_path) for filename, file_data in iitems(new_lines): filename = aliases.map(filename) self.lines.setdefault(filename, {}).update(file_data) for filename, file_data in iitems(new_arcs): filename = aliases.map(filename) self.arcs.setdefault(filename, {}).update(file_data) if f != local: os.remove(full_path)
def sys_info(self): """Return a list of (key, value) pairs showing internal information.""" import coverage as covmod self._init() def plugin_info(plugins): """Make an entry for the sys_info from a list of plug-ins.""" entries = [] for plugin in plugins: entry = plugin._coverage_plugin_name if not plugin._coverage_enabled: entry += " (disabled)" entries.append(entry) return entries info = [ ('version', covmod.__version__), ('coverage', covmod.__file__), ('cover_paths', self.cover_paths), ('pylib_paths', self.pylib_paths), ('tracer', self.collector.tracer_name()), ('plugins.file_tracers', plugin_info(self.plugins.file_tracers)), ('plugins.configurers', plugin_info(self.plugins.configurers)), ('config_files', self.config.attempted_config_files), ('configs_read', self.config.config_files), ('data_path', self.data_files.filename), ('python', sys.version.replace('\n', '')), ('platform', platform.platform()), ('implementation', platform.python_implementation()), ('executable', sys.executable), ('cwd', os.getcwd()), ('path', sys.path), ('environment', sorted( ("%s = %s" % (k, v)) for k, v in iitems(os.environ) if k.startswith(("COV", "PY")) )), ('command_line', " ".join(getattr(sys, 'argv', ['???']))), ] matcher_names = [ 'source_match', 'source_pkgs_match', 'include_match', 'omit_match', 'cover_match', 'pylib_match', ] for matcher_name in matcher_names: matcher = getattr(self, matcher_name) if matcher: matcher_info = matcher.info() else: matcher_info = '-none-' info.append((matcher_name, matcher_info)) return info
def sys_info(self): """Return a list of (key, value) pairs showing internal information.""" import coverage as covmod self._init() try: implementation = platform.python_implementation() except AttributeError: implementation = "unknown" ft_plugins = [] for ft in self.file_tracing_plugins: ft_name = ft._coverage_plugin_name if not ft._coverage_enabled: ft_name += " (disabled)" ft_plugins.append(ft_name) info = [ ('version', covmod.__version__), ('coverage', covmod.__file__), ('cover_dirs', self.cover_dirs), ('pylib_dirs', self.pylib_dirs), ('tracer', self.collector.tracer_name()), ('file_tracing_plugins', ft_plugins), ('config_files', self.config.attempted_config_files), ('configs_read', self.config.config_files), ('data_path', self.data.filename), ('python', sys.version.replace('\n', '')), ('platform', platform.platform()), ('implementation', implementation), ('executable', sys.executable), ('cwd', os.getcwd()), ('path', sys.path), ('environment', sorted( ("%s = %s" % (k, v)) for k, v in iitems(os.environ) if k.startswith(("COV", "PY")) )), ('command_line', " ".join(getattr(sys, 'argv', ['???']))), ] matcher_names = [ 'source_match', 'source_pkgs_match', 'include_match', 'omit_match', 'cover_match', 'pylib_match', ] for matcher_name in matcher_names: matcher = getattr(self, matcher_name) if matcher: matcher_info = matcher.info() else: matcher_info = '-none-' info.append((matcher_name, matcher_info)) return info
def sys_info(self): """Return a list of (key, value) pairs showing internal information.""" import coverage as covmod self._init() try: implementation = platform.python_implementation() except AttributeError: implementation = "unknown" ft_plugins = [] for ft in self.file_tracing_plugins: ft_name = ft._coverage_plugin_name if not ft._coverage_enabled: ft_name += " (disabled)" ft_plugins.append(ft_name) info = [ ('version', covmod.__version__), ('coverage', covmod.__file__), ('cover_dir', self.cover_dir), ('pylib_dirs', self.pylib_dirs), ('tracer', self.collector.tracer_name()), ('file_tracing_plugins', ft_plugins), ('config_files', self.config.attempted_config_files), ('configs_read', self.config.config_files), ('data_path', self.data.filename), ('python', sys.version.replace('\n', '')), ('platform', platform.platform()), ('implementation', implementation), ('executable', sys.executable), ('cwd', os.getcwd()), ('path', sys.path), ('environment', sorted( ("%s = %s" % (k, v)) for k, v in iitems(os.environ) if k.startswith(("COV", "PY")) )), ('command_line', " ".join(getattr(sys, 'argv', ['???']))), ] matcher_names = [ 'source_match', 'source_pkgs_match', 'include_match', 'omit_match', 'cover_match', 'pylib_match', ] for matcher_name in matcher_names: matcher = getattr(self, matcher_name) if matcher: matcher_info = matcher.info() else: matcher_info = '-none-' info.append((matcher_name, matcher_info)) return info
def combine_parallel_data(self, aliases = None): aliases = aliases or PathAliases() data_dir, local = os.path.split(self.filename) localdot = local + '.' for f in os.listdir(data_dir or '.'): if f.startswith(localdot): full_path = os.path.join(data_dir, f) new_lines, new_arcs = self._read_file(full_path) for filename, file_data in iitems(new_lines): filename = aliases.map(filename) self.lines.setdefault(filename, {}).update(file_data) for filename, file_data in iitems(new_arcs): filename = aliases.map(filename) self.arcs.setdefault(filename, {}).update(file_data) if f != local: os.remove(full_path)
def summary(self, fullpath=False): summ = {} if fullpath: filename_fn = lambda f: f else: filename_fn = os.path.basename for filename, lines in iitems(self.lines): summ[filename_fn(filename)] = len(lines) return summ
def summary(self, fullpath = False): summ = {} if fullpath: filename_fn = lambda f: f else: filename_fn = os.path.basename for filename, lines in iitems(self.lines): summ[filename_fn(filename)] = len(lines) return summ
def sys_info(self): """Return a list of (key, value) pairs showing internal information.""" import coverage as covmod self._init() self._post_init() def plugin_info(plugins): """Make an entry for the sys_info from a list of plug-ins.""" entries = [] for plugin in plugins: entry = plugin._coverage_plugin_name if not plugin._coverage_enabled: entry += " (disabled)" entries.append(entry) return entries info = [ ('version', covmod.__version__), ('coverage', covmod.__file__), ('tracer', self._collector.tracer_name() if self._collector else "-none-"), ('CTracer', 'available' if CTracer else "unavailable"), ('plugins.file_tracers', plugin_info(self._plugins.file_tracers)), ('plugins.configurers', plugin_info(self._plugins.configurers)), ('configs_attempted', self.config.attempted_config_files), ('configs_read', self.config.config_files_read), ('config_file', self.config.config_file), ('config_contents', repr(self.config._config_contents) if self.config._config_contents else '-none-' ), ('data_file', self._data.filename if self._data else "-none-"), ('python', sys.version.replace('\n', '')), ('platform', platform.platform()), ('implementation', platform.python_implementation()), ('executable', sys.executable), ('def_encoding', sys.getdefaultencoding()), ('fs_encoding', sys.getfilesystemencoding()), ('pid', os.getpid()), ('cwd', os.getcwd()), ('path', sys.path), ('environment', sorted( ("%s = %s" % (k, v)) for k, v in iitems(os.environ) if any(slug in k for slug in ("COV", "PY")) )), ('command_line', " ".join(getattr(sys, 'argv', ['-none-']))), ] if self._inorout: info.extend(self._inorout.sys_info()) return info
def _validate_invariants(self): """Validate internal invariants.""" # Only one of _lines or _arcs should exist. assert not (self._has_lines() and self._has_arcs()), ( "Shouldn't have both _lines and _arcs") # _lines should be a dict of lists of ints. if self._has_lines(): for fname, lines in iitems(self._lines): assert isinstance( fname, string_class), "Key in _lines shouldn't be %r" % (fname, ) assert all(isinstance(x, int) for x in lines), ("_lines[%r] shouldn't be %r" % (fname, lines)) # _arcs should be a dict of lists of pairs of ints. if self._has_arcs(): for fname, arcs in iitems(self._arcs): assert isinstance( fname, string_class), "Key in _arcs shouldn't be %r" % (fname, ) assert all( isinstance(x, int) and isinstance(y, int) for x, y in arcs), ("_arcs[%r] shouldn't be %r" % (fname, arcs)) # _file_tracers should have only non-empty strings as values. for fname, plugin in iitems(self._file_tracers): assert isinstance( fname, string_class), ("Key in _file_tracers shouldn't be %r" % (fname, )) assert plugin and isinstance(plugin, string_class), ( "_file_tracers[%r] shoudn't be %r" % (fname, plugin)) # _runs should be a list of dicts. for val in self._runs: assert isinstance(val, dict) for key in val: assert isinstance( key, string_class), "Key in _runs shouldn't be %r" % (key, )
def __init__(self, cov, code_unit): self.coverage = cov self.code_unit = code_unit self.filename = self.code_unit.filename actual_filename, source = self.find_source(self.filename) self.parser = CodeParser( text=source, filename=actual_filename, exclude=self.coverage._exclude_regex('exclude') ) self.statements, self.excluded = self.parser.parse_source() # Identify missing statements. executed = self.coverage.data.executed_lines(self.filename) exec1 = self.parser.first_lines(executed) self.missing = self.statements - exec1 if self.coverage.data.has_arcs(): self.no_branch = self.parser.lines_matching( join_regex(self.coverage.config.partial_list), join_regex(self.coverage.config.partial_always_list) ) n_branches = self.total_branches() mba = self.missing_branch_arcs() n_partial_branches = sum( [len(v) for k,v in iitems(mba) if k not in self.missing] ) n_missing_branches = sum([len(v) for k,v in iitems(mba)]) else: n_branches = n_partial_branches = n_missing_branches = 0 self.no_branch = set() self.numbers = Numbers( n_files=1, n_statements=len(self.statements), n_excluded=len(self.excluded), n_missing=len(self.missing), n_branches=n_branches, n_partial_branches=n_partial_branches, n_missing_branches=n_missing_branches, )
def from_file(self, filename, section_prefix=""): """Read configuration from a .rc file. `filename` is a file name to read. Returns True or False, whether the file could be read. """ self.attempted_config_files.append(filename) cp = HandyConfigParser(section_prefix) try: files_read = cp.read(filename) except configparser.Error as err: raise CoverageException("Couldn't read config file %s: %s" % (filename, err)) if not files_read: return False self.config_files.extend(files_read) try: for option_spec in self.CONFIG_FILE_OPTIONS: self._set_attr_from_config_option(cp, *option_spec) except ValueError as err: raise CoverageException("Couldn't read config file %s: %s" % (filename, err)) # Check that there are no unrecognized options. all_options = collections.defaultdict(set) for option_spec in self.CONFIG_FILE_OPTIONS: section, option = option_spec[1].split(":") all_options[section].add(option) for section, options in iitems(all_options): if cp.has_section(section): for unknown in set(cp.options(section)) - options: if section_prefix: section = section_prefix + section raise CoverageException( "Unrecognized option '[%s] %s=' in config file %s" % ( section, unknown, filename ) ) # [paths] is special if cp.has_section('paths'): for option in cp.options('paths'): self.paths[option] = cp.getlist('paths', option) # plugins can have options for plugin in self.plugins: if cp.has_section(plugin): self.plugin_options[plugin] = cp.get_section(plugin) return True
def _read_file(self, filename): """Return the stored coverage data from the given file. Returns two values, suitable for assigning to `self.lines` and `self.arcs`. """ lines = {} arcs = {} try: data = self.raw_data(filename) if isinstance(data, dict): lines = dict([(f, dict.fromkeys(linenos, None)) for f, linenos in iitems(data.get('lines', {}))]) arcs = dict([(f, dict.fromkeys(arcpairs, None)) for f, arcpairs in iitems(data.get('arcs', {}))]) except Exception: pass return (lines, arcs)
def coverage3x_combine(files, data): """ Combine all coverage files from @files into @data. Note: this works with coverage 3.6 (and possibly older) versions. """ aliases = PathAliases() for f in files: new_lines, new_arcs = data._read_file(f) for filename, file_data in iitems(new_lines): filename = aliases.map(filename) data.lines.setdefault(filename, {}).update(file_data) for filename, file_data in iitems(new_arcs): filename = aliases.map(filename) data.arcs.setdefault(filename, {}).update(file_data) return data
def _read_file(self, filename): """Return the stored coverage data from the given file. Returns three values, suitable for assigning to `self.lines`, `self.arcs`, and `self.plugins`. """ lines = {} arcs = {} plugins = {} try: data = self.raw_data(filename) if isinstance(data, dict): # Unpack the 'lines' item. lines = dict([(f, dict.fromkeys(linenos, None)) for f, linenos in iitems(data.get('lines', {}))]) # Unpack the 'arcs' item. arcs = dict([(f, dict.fromkeys(arcpairs, None)) for f, arcpairs in iitems(data.get('arcs', {}))]) plugins = data.get('plugins', {}) except Exception: pass return lines, arcs, plugins
def missing_formatted(self, branches=False): """The missing line numbers, formatted nicely. Returns a string like "1-2, 5-11, 13-14". If `branches` is true, includes the missing branch arcs also. """ if branches and self.has_arcs(): arcs = iitems(self.missing_branch_arcs()) else: arcs = None return format_lines(self.statements, self.missing, arcs=arcs)