1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
#!/usr/bin/python
"""
Copyright 2014 Google Inc.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
ImagePair class (see class docstring for details)
"""
import posixpath
# Keys used within ImagePair dictionary representations.
# NOTE: Keep these in sync with static/constants.js
KEY__IMAGEPAIRS__DIFFERENCES = 'differenceData'
KEY__IMAGEPAIRS__EXPECTATIONS = 'expectations'
KEY__IMAGEPAIRS__EXTRACOLUMNS = 'extraColumns'
KEY__IMAGEPAIRS__IMAGE_A_URL = 'imageAUrl'
KEY__IMAGEPAIRS__IMAGE_B_URL = 'imageBUrl'
KEY__IMAGEPAIRS__IS_DIFFERENT = 'isDifferent'
class ImagePair(object):
"""Describes a pair of images, pixel difference info, and optional metadata.
"""
def __init__(self, image_diff_db,
base_url, imageA_relative_url, imageB_relative_url,
expectations=None, extra_columns=None):
"""
Args:
image_diff_db: ImageDiffDB instance we use to generate/store image diffs
base_url: base of all image URLs
imageA_relative_url: string; URL pointing at an image, relative to
base_url; or None, if this image is missing
imageB_relative_url: string; URL pointing at an image, relative to
base_url; or None, if this image is missing
expectations: optional dictionary containing expectations-specific
metadata (ignore-failure, bug numbers, etc.)
extra_columns: optional dictionary containing more metadata (test name,
builder name, etc.)
"""
self.base_url = base_url
self.imageA_relative_url = imageA_relative_url
self.imageB_relative_url = imageB_relative_url
self.expectations_dict = expectations
self.extra_columns_dict = extra_columns
if not imageA_relative_url or not imageB_relative_url:
self._is_different = True
self.diff_record = None
elif imageA_relative_url == imageB_relative_url:
self._is_different = False
self.diff_record = None
else:
# TODO(epoger): Rather than blocking until image_diff_db can read in
# the image pair and generate diffs, it would be better to do it
# asynchronously: tell image_diff_db to download a bunch of file pairs,
# and only block later if we're still waiting for diff_records to come
# back.
self._is_different = True
image_diff_db.add_image_pair(
expected_image_locator=imageA_relative_url,
expected_image_url=posixpath.join(base_url, imageA_relative_url),
actual_image_locator=imageB_relative_url,
actual_image_url=posixpath.join(base_url, imageB_relative_url))
self.diff_record = image_diff_db.get_diff_record(
expected_image_locator=imageA_relative_url,
actual_image_locator=imageB_relative_url)
if self.diff_record and self.diff_record.get_num_pixels_differing() == 0:
self._is_different = False
def as_dict(self):
"""Returns a dictionary describing this ImagePair.
Uses the KEY__IMAGEPAIRS__* constants as keys.
"""
asdict = {
KEY__IMAGEPAIRS__IMAGE_A_URL: self.imageA_relative_url,
KEY__IMAGEPAIRS__IMAGE_B_URL: self.imageB_relative_url,
}
asdict[KEY__IMAGEPAIRS__IS_DIFFERENT] = self._is_different
if self.expectations_dict:
asdict[KEY__IMAGEPAIRS__EXPECTATIONS] = self.expectations_dict
if self.extra_columns_dict:
asdict[KEY__IMAGEPAIRS__EXTRACOLUMNS] = self.extra_columns_dict
if self.diff_record and (self.diff_record.get_num_pixels_differing() > 0):
asdict[KEY__IMAGEPAIRS__DIFFERENCES] = self.diff_record.as_dict()
return asdict
|