class Analysis(object): """The results of analyzing a code unit.""" 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 find_source(self, filename): """Find the source for `filename`. Returns two values: the actual filename, and the source. The source returned depends on which of these cases holds: * The filename seems to be a non-source file: returns None * The filename is a source file, and actually exists: returns None. * The filename is a source file, and is in a zip file or egg: returns the source. * The filename is a source file, but couldn't be found: raises `NoSource`. """ source = None base, ext = os.path.splitext(filename) TRY_EXTS = { '.py': ['.py', '.pyw'], '.pyw': ['.pyw'], } try_exts = TRY_EXTS.get(ext) if not try_exts: return filename, None for try_ext in try_exts: try_filename = base + try_ext if os.path.exists(try_filename): return try_filename, None source = self.coverage.file_locator.get_zip_data(try_filename) if source: return try_filename, source raise NoSource("No source for code: '%s'" % filename) def missing_formatted(self): """The missing line numbers, formatted nicely. Returns a string like "1-2, 5-11, 13-14". """ return format_lines(self.statements, self.missing) def has_arcs(self): """Were arcs measured in this result?""" return self.coverage.data.has_arcs() def arc_possibilities(self): """Returns a sorted list of the arcs in the code.""" arcs = self.parser.arcs() return arcs def arcs_executed(self): """Returns a sorted list of the arcs actually executed in the code.""" executed = self.coverage.data.executed_arcs(self.filename) m2fl = self.parser.first_line executed = [(m2fl(l1), m2fl(l2)) for (l1, l2) in executed] return sorted(executed) def arcs_missing(self): """Returns a sorted list of the arcs in the code not executed.""" possible = self.arc_possibilities() executed = self.arcs_executed() missing = [ p for p in possible if p not in executed and p[0] not in self.no_branch ] return sorted(missing) def arcs_unpredicted(self): """Returns a sorted list of the executed arcs missing from the code.""" possible = self.arc_possibilities() executed = self.arcs_executed() # Exclude arcs here which connect a line to itself. They can occur # in executed data in some cases. This is where they can cause # trouble, and here is where it's the least burden to remove them. unpredicted = [ e for e in executed if e not in possible and e[0] != e[1] ] return sorted(unpredicted) def branch_lines(self): """Returns a list of line numbers that have more than one exit.""" exit_counts = self.parser.exit_counts() return [l1 for l1, count in iitems(exit_counts) if count > 1] def total_branches(self): """How many total branches are there?""" exit_counts = self.parser.exit_counts() return sum([count for count in exit_counts.values() if count > 1]) def missing_branch_arcs(self): """Return arcs that weren't executed from branch lines. Returns {l1:[l2a,l2b,...], ...} """ missing = self.arcs_missing() branch_lines = set(self.branch_lines()) mba = {} for l1, l2 in missing: if l1 in branch_lines: if l1 not in mba: mba[l1] = [] mba[l1].append(l2) return mba def branch_stats(self): """Get stats about branches. Returns a dict mapping line numbers to a tuple: (total_exits, taken_exits). """ exit_counts = self.parser.exit_counts() missing_arcs = self.missing_branch_arcs() stats = {} for lnum in self.branch_lines(): exits = exit_counts[lnum] try: missing = len(missing_arcs[lnum]) except KeyError: missing = 0 stats[lnum] = (exits, exits - missing) return stats
class Analysis(object): 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 find_source(self, filename): source = None base, ext = os.path.splitext(filename) TRY_EXTS = {'.py': ['.py', '.pyw'], '.pyw': ['.pyw']} try_exts = TRY_EXTS.get(ext) if not try_exts: return (filename, None) for try_ext in try_exts: try_filename = base + try_ext if os.path.exists(try_filename): return (try_filename, None) source = self.coverage.file_locator.get_zip_data(try_filename) if source: return (try_filename, source) raise NoSource("No source for code: '%s'" % filename) def missing_formatted(self): return format_lines(self.statements, self.missing) def has_arcs(self): return self.coverage.data.has_arcs() def arc_possibilities(self): arcs = self.parser.arcs() return arcs def arcs_executed(self): executed = self.coverage.data.executed_arcs(self.filename) m2fl = self.parser.first_line executed = [(m2fl(l1), m2fl(l2)) for l1, l2 in executed] return sorted(executed) def arcs_missing(self): possible = self.arc_possibilities() executed = self.arcs_executed() missing = [ p for p in possible if p not in executed and p[0] not in self.no_branch ] return sorted(missing) def arcs_unpredicted(self): possible = self.arc_possibilities() executed = self.arcs_executed() unpredicted = [ e for e in executed if e not in possible and e[0] != e[1] ] return sorted(unpredicted) def branch_lines(self): exit_counts = self.parser.exit_counts() return [l1 for l1, count in iitems(exit_counts) if count > 1] def total_branches(self): exit_counts = self.parser.exit_counts() return sum([count for count in exit_counts.values() if count > 1]) def missing_branch_arcs(self): missing = self.arcs_missing() branch_lines = set(self.branch_lines()) mba = {} for l1, l2 in missing: if l1 in branch_lines: if l1 not in mba: mba[l1] = [] mba[l1].append(l2) return mba def branch_stats(self): exit_counts = self.parser.exit_counts() missing_arcs = self.missing_branch_arcs() stats = {} for lnum in self.branch_lines(): exits = exit_counts[lnum] try: missing = len(missing_arcs[lnum]) except KeyError: missing = 0 stats[lnum] = (exits, exits - missing) return stats
class Analysis(object): """The results of analyzing a code unit.""" 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 find_source(self, filename): """Find the source for `filename`. Returns two values: the actual filename, and the source. The source returned depends on which of these cases holds: * The filename seems to be a non-source file: returns None * The filename is a source file, and actually exists: returns None. * The filename is a source file, and is in a zip file or egg: returns the source. * The filename is a source file, but couldn't be found: raises `NoSource`. """ source = None base, ext = os.path.splitext(filename) TRY_EXTS = { '.py': ['.py', '.pyw'], '.pyw': ['.pyw'], } try_exts = TRY_EXTS.get(ext) if not try_exts: return filename, None for try_ext in try_exts: try_filename = base + try_ext if os.path.exists(try_filename): return try_filename, None source = self.coverage.file_locator.get_zip_data(try_filename) if source: return try_filename, source raise NoSource("No source for code: '%s'" % filename) def missing_formatted(self): """The missing line numbers, formatted nicely. Returns a string like "1-2, 5-11, 13-14". """ return format_lines(self.statements, self.missing) def has_arcs(self): """Were arcs measured in this result?""" return self.coverage.data.has_arcs() def arc_possibilities(self): """Returns a sorted list of the arcs in the code.""" arcs = self.parser.arcs() return arcs def arcs_executed(self): """Returns a sorted list of the arcs actually executed in the code.""" executed = self.coverage.data.executed_arcs(self.filename) m2fl = self.parser.first_line executed = [(m2fl(l1), m2fl(l2)) for (l1,l2) in executed] return sorted(executed) def arcs_missing(self): """Returns a sorted list of the arcs in the code not executed.""" possible = self.arc_possibilities() executed = self.arcs_executed() missing = [ p for p in possible if p not in executed and p[0] not in self.no_branch ] return sorted(missing) def arcs_unpredicted(self): """Returns a sorted list of the executed arcs missing from the code.""" possible = self.arc_possibilities() executed = self.arcs_executed() # Exclude arcs here which connect a line to itself. They can occur # in executed data in some cases. This is where they can cause # trouble, and here is where it's the least burden to remove them. unpredicted = [ e for e in executed if e not in possible and e[0] != e[1] ] return sorted(unpredicted) def branch_lines(self): """Returns a list of line numbers that have more than one exit.""" exit_counts = self.parser.exit_counts() return [l1 for l1,count in iitems(exit_counts) if count > 1] def total_branches(self): """How many total branches are there?""" exit_counts = self.parser.exit_counts() return sum([count for count in exit_counts.values() if count > 1]) def missing_branch_arcs(self): """Return arcs that weren't executed from branch lines. Returns {l1:[l2a,l2b,...], ...} """ missing = self.arcs_missing() branch_lines = set(self.branch_lines()) mba = {} for l1, l2 in missing: if l1 in branch_lines: if l1 not in mba: mba[l1] = [] mba[l1].append(l2) return mba def branch_stats(self): """Get stats about branches. Returns a dict mapping line numbers to a tuple: (total_exits, taken_exits). """ exit_counts = self.parser.exit_counts() missing_arcs = self.missing_branch_arcs() stats = {} for lnum in self.branch_lines(): exits = exit_counts[lnum] try: missing = len(missing_arcs[lnum]) except KeyError: missing = 0 stats[lnum] = (exits, exits - missing) return stats
class Analysis(object): 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 find_source(self, filename): source = None base, ext = os.path.splitext(filename) TRY_EXTS = {'.py': ['.py', '.pyw'], '.pyw': ['.pyw']} try_exts = TRY_EXTS.get(ext) if not try_exts: return (filename, None) for try_ext in try_exts: try_filename = base + try_ext if os.path.exists(try_filename): return (try_filename, None) source = self.coverage.file_locator.get_zip_data(try_filename) if source: return (try_filename, source) raise NoSource("No source for code: '%s'" % filename) def missing_formatted(self): return format_lines(self.statements, self.missing) def has_arcs(self): return self.coverage.data.has_arcs() def arc_possibilities(self): arcs = self.parser.arcs() return arcs def arcs_executed(self): executed = self.coverage.data.executed_arcs(self.filename) m2fl = self.parser.first_line executed = [ (m2fl(l1), m2fl(l2)) for l1, l2 in executed ] return sorted(executed) def arcs_missing(self): possible = self.arc_possibilities() executed = self.arcs_executed() missing = [ p for p in possible if p not in executed and p[0] not in self.no_branch ] return sorted(missing) def arcs_unpredicted(self): possible = self.arc_possibilities() executed = self.arcs_executed() unpredicted = [ e for e in executed if e not in possible and e[0] != e[1] ] return sorted(unpredicted) def branch_lines(self): exit_counts = self.parser.exit_counts() return [ l1 for l1, count in iitems(exit_counts) if count > 1 ] def total_branches(self): exit_counts = self.parser.exit_counts() return sum([ count for count in exit_counts.values() if count > 1 ]) def missing_branch_arcs(self): missing = self.arcs_missing() branch_lines = set(self.branch_lines()) mba = {} for l1, l2 in missing: if l1 in branch_lines: if l1 not in mba: mba[l1] = [] mba[l1].append(l2) return mba def branch_stats(self): exit_counts = self.parser.exit_counts() missing_arcs = self.missing_branch_arcs() stats = {} for lnum in self.branch_lines(): exits = exit_counts[lnum] try: missing = len(missing_arcs[lnum]) except KeyError: missing = 0 stats[lnum] = (exits, exits - missing) return stats