Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(317)

Side by Side Diff: appengine/findit/crash/results.py

Issue 2414523002: [Findit] Reorganizing findit_for_*.py (Closed)
Patch Set: Finally fixed the mock tests! Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2016 The Chromium Authors. All rights reserved. 1 # Copyright 2016 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 5
6 from collections import namedtuple
7
6 # TODO(http://crbug.com/644476): this class needs a better name. 8 # TODO(http://crbug.com/644476): this class needs a better name.
9 class AnalysisInfo(namedtuple('AnalysisInfo',
10 ['min_distance', 'min_distance_frame'])):
11 __slots__ = ()
12
13
14 # TODO(http://crbug.com/644476): this class needs a better name.
15 # TODO(wrengr): subclass namedtuple, so most things are immutable.
7 class Result(object): 16 class Result(object):
8 """Represents findit culprit result.""" 17 """Represents findit culprit result."""
9 18
10 def __init__(self, changelog, dep_path, 19 def __init__(self, changelog, dep_path,
11 confidence=None, reasons=None, changed_files=None): 20 confidence=None, reasons=None, changed_files=None):
12 self.changelog = changelog 21 self.changelog = changelog
13 self.dep_path = dep_path 22 self.dep_path = dep_path
14 self.confidence = confidence 23 self.confidence = confidence
15 self.reasons = reasons 24 self.reasons = reasons
16 self.changed_files = changed_files 25 self.changed_files = changed_files
17 26
27 # TODO(wrengr): (a) make these two fields private/readonly
28 # TODO(wrengr): (b) zip them together.
29 # TODO(wrengr): replace "stack_info" pair with a namedtuple.
18 self.file_to_stack_infos = {} 30 self.file_to_stack_infos = {}
31 # TODO(wrengr): replace "analysis_info" dict with a namedtuple.
19 self.file_to_analysis_info = {} 32 self.file_to_analysis_info = {}
20 33
21 def ToDict(self): 34 def ToDict(self):
22 return { 35 return {
23 'url': self.changelog.commit_url, 36 'url': self.changelog.commit_url,
24 'review_url': self.changelog.code_review_url, 37 'review_url': self.changelog.code_review_url,
25 'revision': self.changelog.revision, 38 'revision': self.changelog.revision,
26 'project_path': self.dep_path, 39 'project_path': self.dep_path,
27 'author': self.changelog.author_email, 40 'author': self.changelog.author_email,
28 'time': str(self.changelog.author_time), 41 'time': str(self.changelog.author_time),
29 'reasons': self.reasons, 42 'reasons': self.reasons,
30 'changed_files': self.changed_files, 43 'changed_files': self.changed_files,
31 'confidence': self.confidence, 44 'confidence': self.confidence,
32 } 45 }
33 46
47 # TODO(katesonia): This is unusable for logging because in all the
48 # cases that need logging it returns the empty string! We should print
49 # this out in a more useful way (e.g., how CrashConfig is printed)
50 # so that callers don't have to use |str(result.ToDict())| instead. If
51 # we want a method that does what this one does, we should give it a
52 # different name that indicates what it's actually printing out.
34 def ToString(self): 53 def ToString(self):
35 if not self.file_to_stack_infos: 54 if not self.file_to_stack_infos:
36 return '' 55 return ''
37 56
38 lines = [] 57 lines = []
39 for file_path, stack_infos in self.file_to_stack_infos.iteritems(): 58 for file_path, stack_infos in self.file_to_stack_infos.iteritems():
40 line_parts = [] 59 line_parts = []
41 for frame, _ in stack_infos: 60 for frame, _ in stack_infos:
42 line_parts.append('frame #%d' % frame.index) 61 line_parts.append('frame #%d' % frame.index)
43 62
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 region_end = region_start + region.count - 1 104 region_end = region_start + region.count - 1
86 for frame, _ in stack_infos: 105 for frame, _ in stack_infos:
87 frame_start = frame.crashed_line_numbers[0] 106 frame_start = frame.crashed_line_numbers[0]
88 frame_end = frame.crashed_line_numbers[-1] 107 frame_end = frame.crashed_line_numbers[-1]
89 distance = _DistanceBetweenLineRanges((frame_start, frame_end), 108 distance = _DistanceBetweenLineRanges((frame_start, frame_end),
90 (region_start, region_end)) 109 (region_start, region_end))
91 if distance < min_distance: 110 if distance < min_distance:
92 min_distance = distance 111 min_distance = distance
93 min_distance_frame = frame 112 min_distance_frame = frame
94 113
95 self.file_to_analysis_info[file_path] = { 114 self.file_to_analysis_info[file_path] = AnalysisInfo(
96 'min_distance': min_distance, 115 min_distance = min_distance,
97 'min_distance_frame': min_distance_frame, 116 min_distance_frame = min_distance_frame,
98 } 117 )
99 118
100 119
101 def _DistanceBetweenLineRanges((start1, end1), (start2, end2)): 120 def _DistanceBetweenLineRanges((start1, end1), (start2, end2)):
102 """Given two ranges, compute the (unsigned) distance between them. 121 """Given two ranges, compute the (unsigned) distance between them.
103 122
104 Args: 123 Args:
105 start1: the start of the first range 124 start1: the start of the first range
106 end1: the end of the first range. Must be greater than start1. 125 end1: the end of the first range. Must be greater than start1.
107 start2: the start of the second range 126 start2: the start of the second range
108 end2: the end of the second range. Must be greater than start2. 127 end2: the end of the second range. Must be greater than start2.
109 128
110 Returns: 129 Returns:
111 If the end of the earlier range comes before the start of the later 130 If the end of the earlier range comes before the start of the later
112 range, then the difference between those points. Otherwise, returns 131 range, then the difference between those points. Otherwise, returns
113 zero (because the ranges overlap).""" 132 zero (because the ranges overlap)."""
114 assert end1 >= start1 133 assert end1 >= start1
115 assert end2 >= start2 134 assert end2 >= start2
116 # There are six possible cases, but in all the cases where the two 135 # There are six possible cases, but in all the cases where the two
117 # ranges overlap, the latter two differences will be negative. 136 # ranges overlap, the latter two differences will be negative.
118 return max(0, start2 - end1, start1 - end2) 137 return max(0, start2 - end1, start1 - end2)
119 138
120 139
121 class MatchResults(dict): 140 class MatchResults(dict):
122 """A dict indexing MatchResult with its revision.""" 141 """A dict indexing MatchResult with its revision."""
123 142
124 def __init__(self, ignore_cls=None): 143 def __init__(self, ignore_cls=None):
125 super(MatchResults, self).__init__() 144 super(MatchResults, self).__init__()
126 self.ignore_cls = ignore_cls 145 self._ignore_cls = ignore_cls
127 146
128 def GenerateMatchResults(self, file_path, dep_path, 147 def GenerateMatchResults(self, file_path, dep_path,
129 stack_infos, changelogs, blame): 148 stack_infos, changelogs, blame):
130 """Generates match results. 149 """Generates match results.
131 150
132 Match results are generated based on newly found file path, its stack_infos, 151 Match results are generated based on newly found file path, its stack_infos,
133 and all the changelogs that touched this file in the dep in regression 152 and all the changelogs that touched this file in the dep in regression
134 ranges, those reverted changelogs should be ignored. 153 ranges, those reverted changelogs should be ignored.
135 154
136 Args: 155 Args:
137 file_path (str): File path of the crashed file. 156 file_path (str): File path of the crashed file.
138 dep_path (str): Path of the dependency of the file. 157 dep_path (str): Path of the dependency of the file.
139 stack_infos (list): List of stack_info dicts, represents frames of this 158 stack_infos (list): List of stack_info dicts, represents frames of this
140 file and the callstack priorities of those frames. 159 file and the callstack priorities of those frames.
141 changelogs (list): List of Changelog objects in the dep in regression 160 changelogs (list): List of Changelog objects in the dep in regression
142 range which touched the file. 161 range which touched the file.
143 blame (Blame): Blame of the file. 162 blame (Blame): Blame of the file.
144 """ 163 """
145 for changelog in changelogs: 164 for changelog in changelogs:
146 if self.ignore_cls and changelog.revision in self.ignore_cls: 165 if self._ignore_cls and changelog.revision in self._ignore_cls:
147 continue 166 continue
148 167
149 if changelog.revision not in self: 168 if changelog.revision not in self:
150 self[changelog.revision] = MatchResult(changelog, dep_path) 169 self[changelog.revision] = MatchResult(changelog, dep_path)
151 170
152 match_result = self[changelog.revision] 171 match_result = self[changelog.revision]
153 match_result.Update(file_path, stack_infos, blame) 172 match_result.Update(file_path, stack_infos, blame)
OLDNEW
« no previous file with comments | « appengine/findit/crash/project_classifier.py ('k') | appengine/findit/crash/test/changelist_classifier_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698