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

Side by Side Diff: gm/rebaseline_server/imagepairset.py

Issue 424263005: teach rebaseline_server to generate diffs of rendered SKPs (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Ravi comments Created 6 years, 4 months 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
« no previous file with comments | « gm/rebaseline_server/imagepair.py ('k') | gm/rebaseline_server/results.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 2
3 """ 3 """
4 Copyright 2014 Google Inc. 4 Copyright 2014 Google Inc.
5 5
6 Use of this source code is governed by a BSD-style license that can be 6 Use of this source code is governed by a BSD-style license that can be
7 found in the LICENSE file. 7 found in the LICENSE file.
8 8
9 ImagePairSet class; see its docstring below. 9 ImagePairSet class; see its docstring below.
10 """ 10 """
11 11
12 # System-level imports 12 # System-level imports
13 import posixpath 13 import posixpath
14 14
15 # Local imports 15 # Must fix up PYTHONPATH before importing from within Skia
16 import fix_pythonpath # pylint: disable=W0611
17
18 # Imports from within Skia
16 import column 19 import column
17 import imagediffdb 20 import imagediffdb
21 from py.utils import gs_utils
18 22
19 # Keys used within dictionary representation of ImagePairSet. 23 # Keys used within dictionary representation of ImagePairSet.
20 # NOTE: Keep these in sync with static/constants.js 24 # NOTE: Keep these in sync with static/constants.js
21 KEY__ROOT__EXTRACOLUMNHEADERS = 'extraColumnHeaders' 25 KEY__ROOT__EXTRACOLUMNHEADERS = 'extraColumnHeaders'
22 KEY__ROOT__EXTRACOLUMNORDER = 'extraColumnOrder' 26 KEY__ROOT__EXTRACOLUMNORDER = 'extraColumnOrder'
23 KEY__ROOT__HEADER = 'header' 27 KEY__ROOT__HEADER = 'header'
24 KEY__ROOT__IMAGEPAIRS = 'imagePairs' 28 KEY__ROOT__IMAGEPAIRS = 'imagePairs'
25 KEY__ROOT__IMAGESETS = 'imageSets' 29 KEY__ROOT__IMAGESETS = 'imageSets'
26 KEY__IMAGESETS__FIELD__BASE_URL = 'baseUrl' 30 KEY__IMAGESETS__FIELD__BASE_URL = 'baseUrl'
27 KEY__IMAGESETS__FIELD__DESCRIPTION = 'description' 31 KEY__IMAGESETS__FIELD__DESCRIPTION = 'description'
(...skipping 18 matching lines...) Expand all
46 """ 50 """
47 Args: 51 Args:
48 diff_base_url: base URL indicating where diff images can be loaded from 52 diff_base_url: base URL indicating where diff images can be loaded from
49 descriptions: a (string, string) tuple describing the two image sets. 53 descriptions: a (string, string) tuple describing the two image sets.
50 If not specified, DEFAULT_DESCRIPTIONS will be used. 54 If not specified, DEFAULT_DESCRIPTIONS will be used.
51 """ 55 """
52 self._column_header_factories = {} 56 self._column_header_factories = {}
53 self._descriptions = descriptions or DEFAULT_DESCRIPTIONS 57 self._descriptions = descriptions or DEFAULT_DESCRIPTIONS
54 self._extra_column_tallies = {} # maps column_id -> values 58 self._extra_column_tallies = {} # maps column_id -> values
55 # -> instances_per_value 59 # -> instances_per_value
56 self._image_pair_dicts = []
57 self._image_base_url = None 60 self._image_base_url = None
58 self._diff_base_url = diff_base_url 61 self._diff_base_url = diff_base_url
59 62
63 # We build self._image_pair_objects incrementally as calls come into
64 # add_image_pair(); self._image_pair_dicts is filled in lazily (so that
65 # we put off asking ImageDiffDB for results as long as possible).
66 self._image_pair_objects = []
67 self._image_pair_dicts = None
68
60 def add_image_pair(self, image_pair): 69 def add_image_pair(self, image_pair):
61 """Adds an ImagePair; this may be repeated any number of times.""" 70 """Adds an ImagePair; this may be repeated any number of times."""
62 # Special handling when we add the first ImagePair... 71 # Special handling when we add the first ImagePair...
63 if not self._image_pair_dicts: 72 if not self._image_pair_objects:
64 self._image_base_url = image_pair.base_url 73 self._image_base_url = image_pair.base_url
65 74
66 if image_pair.base_url != self._image_base_url: 75 if image_pair.base_url != self._image_base_url:
67 raise Exception('added ImagePair with base_url "%s" instead of "%s"' % ( 76 raise Exception('added ImagePair with base_url "%s" instead of "%s"' % (
68 image_pair.base_url, self._image_base_url)) 77 image_pair.base_url, self._image_base_url))
69 self._image_pair_dicts.append(image_pair.as_dict()) 78 self._image_pair_objects.append(image_pair)
70 extra_columns_dict = image_pair.extra_columns_dict 79 extra_columns_dict = image_pair.extra_columns_dict
71 if extra_columns_dict: 80 if extra_columns_dict:
72 for column_id, value in extra_columns_dict.iteritems(): 81 for column_id, value in extra_columns_dict.iteritems():
73 self._add_extra_column_value_to_summary(column_id, value) 82 self._add_extra_column_value_to_summary(column_id, value)
74 83
75 def set_column_header_factory(self, column_id, column_header_factory): 84 def set_column_header_factory(self, column_id, column_header_factory):
76 """Overrides the default settings for one of the extraColumn headers. 85 """Overrides the default settings for one of the extraColumn headers.
77 86
78 Args: 87 Args:
79 column_id: string; unique ID of this column (must match a key within 88 column_id: string; unique ID of this column (must match a key within
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 column_header_factory = self.get_column_header_factory(column_id) 143 column_header_factory = self.get_column_header_factory(column_id)
135 asdict[column_id] = column_header_factory.create_as_dict( 144 asdict[column_id] = column_header_factory.create_as_dict(
136 values_for_column) 145 values_for_column)
137 return asdict 146 return asdict
138 147
139 def as_dict(self, column_ids_in_order=None): 148 def as_dict(self, column_ids_in_order=None):
140 """Returns a dictionary describing this package of ImagePairs. 149 """Returns a dictionary describing this package of ImagePairs.
141 150
142 Uses the KEY__* constants as keys. 151 Uses the KEY__* constants as keys.
143 152
144 Params: 153 Args:
145 column_ids_in_order: A list of all extracolumn IDs in the desired display 154 column_ids_in_order: A list of all extracolumn IDs in the desired display
146 order. If unspecified, they will be displayed in alphabetical order. 155 order. If unspecified, they will be displayed in alphabetical order.
147 If specified, this list must contain all the extracolumn IDs! 156 If specified, this list must contain all the extracolumn IDs!
148 (It may contain extra column IDs; they will be ignored.) 157 (It may contain extra column IDs; they will be ignored.)
149 """ 158 """
150 all_column_ids = set(self._extra_column_tallies.keys()) 159 all_column_ids = set(self._extra_column_tallies.keys())
151 if column_ids_in_order == None: 160 if column_ids_in_order == None:
152 column_ids_in_order = sorted(all_column_ids) 161 column_ids_in_order = sorted(all_column_ids)
153 else: 162 else:
154 # Make sure the caller listed all column IDs, and throw away any extras. 163 # Make sure the caller listed all column IDs, and throw away any extras.
155 specified_column_ids = set(column_ids_in_order) 164 specified_column_ids = set(column_ids_in_order)
156 forgotten_column_ids = all_column_ids - specified_column_ids 165 forgotten_column_ids = all_column_ids - specified_column_ids
157 assert not forgotten_column_ids, ( 166 assert not forgotten_column_ids, (
158 'column_ids_in_order %s missing these column_ids: %s' % ( 167 'column_ids_in_order %s missing these column_ids: %s' % (
159 column_ids_in_order, forgotten_column_ids)) 168 column_ids_in_order, forgotten_column_ids))
160 column_ids_in_order = [c for c in column_ids_in_order 169 column_ids_in_order = [c for c in column_ids_in_order
161 if c in all_column_ids] 170 if c in all_column_ids]
162 171
163 key_description = KEY__IMAGESETS__FIELD__DESCRIPTION 172 key_description = KEY__IMAGESETS__FIELD__DESCRIPTION
164 key_base_url = KEY__IMAGESETS__FIELD__BASE_URL 173 key_base_url = KEY__IMAGESETS__FIELD__BASE_URL
174 if gs_utils.GSUtils.is_gs_url(self._image_base_url):
175 value_base_url = self._convert_gs_url_to_http_url(self._image_base_url)
176 else:
177 value_base_url = self._image_base_url
178
179 # We've waited as long as we can to ask ImageDiffDB for details of the
180 # image diffs, so that it has time to compute them.
181 if self._image_pair_dicts == None:
182 self._image_pair_dicts = [ip.as_dict() for ip in self._image_pair_objects]
183
165 return { 184 return {
166 KEY__ROOT__EXTRACOLUMNHEADERS: self._column_headers_as_dict(), 185 KEY__ROOT__EXTRACOLUMNHEADERS: self._column_headers_as_dict(),
167 KEY__ROOT__EXTRACOLUMNORDER: column_ids_in_order, 186 KEY__ROOT__EXTRACOLUMNORDER: column_ids_in_order,
168 KEY__ROOT__IMAGEPAIRS: self._image_pair_dicts, 187 KEY__ROOT__IMAGEPAIRS: self._image_pair_dicts,
169 KEY__ROOT__IMAGESETS: { 188 KEY__ROOT__IMAGESETS: {
170 KEY__IMAGESETS__SET__IMAGE_A: { 189 KEY__IMAGESETS__SET__IMAGE_A: {
171 key_description: self._descriptions[0], 190 key_description: self._descriptions[0],
172 key_base_url: self._image_base_url, 191 key_base_url: value_base_url,
173 }, 192 },
174 KEY__IMAGESETS__SET__IMAGE_B: { 193 KEY__IMAGESETS__SET__IMAGE_B: {
175 key_description: self._descriptions[1], 194 key_description: self._descriptions[1],
176 key_base_url: self._image_base_url, 195 key_base_url: value_base_url,
177 }, 196 },
178 KEY__IMAGESETS__SET__DIFFS: { 197 KEY__IMAGESETS__SET__DIFFS: {
179 key_description: 'color difference per channel', 198 key_description: 'color difference per channel',
180 key_base_url: posixpath.join( 199 key_base_url: posixpath.join(
181 self._diff_base_url, imagediffdb.RGBDIFFS_SUBDIR), 200 self._diff_base_url, imagediffdb.RGBDIFFS_SUBDIR),
182 }, 201 },
183 KEY__IMAGESETS__SET__WHITEDIFFS: { 202 KEY__IMAGESETS__SET__WHITEDIFFS: {
184 key_description: 'differing pixels in white', 203 key_description: 'differing pixels in white',
185 key_base_url: posixpath.join( 204 key_base_url: posixpath.join(
186 self._diff_base_url, imagediffdb.WHITEDIFFS_SUBDIR), 205 self._diff_base_url, imagediffdb.WHITEDIFFS_SUBDIR),
187 }, 206 },
188 }, 207 },
189 } 208 }
209
210 @staticmethod
211 def _convert_gs_url_to_http_url(gs_url):
212 """Returns HTTP URL that can be used to download this Google Storage file.
213
214 TODO(epoger): Create functionality like this within gs_utils.py instead of
215 here? See https://codereview.chromium.org/428493005/ ('create
216 anyfile_utils.py for copying files between HTTP/GS/local filesystem')
217
218 Args:
219 gs_url: "gs://bucket/path" format URL
220 """
221 bucket, path = gs_utils.GSUtils.split_gs_url(gs_url)
222 http_url = 'http://storage.cloud.google.com/' + bucket
223 if path:
224 http_url += '/' + path
225 return http_url
OLDNEW
« no previous file with comments | « gm/rebaseline_server/imagepair.py ('k') | gm/rebaseline_server/results.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698