| Index: gm/rebaseline_server/imagepairset.py
|
| diff --git a/gm/rebaseline_server/imagepairset.py b/gm/rebaseline_server/imagepairset.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2e173f537f14e78517e9c4c2c7fd94198251b1d4
|
| --- /dev/null
|
| +++ b/gm/rebaseline_server/imagepairset.py
|
| @@ -0,0 +1,122 @@
|
| +#!/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.
|
| +
|
| +ImagePairSet class; see its docstring below.
|
| +"""
|
| +
|
| +import column
|
| +
|
| +# Keys used within dictionary representation of ImagePairSet.
|
| +KEY__COLUMNHEADERS = 'columnHeaders'
|
| +KEY__IMAGEPAIRS = 'imagePairs'
|
| +KEY__IMAGESETS = 'imageSets'
|
| +KEY__IMAGESETS__BASE_URL = 'baseUrl'
|
| +KEY__IMAGESETS__DESCRIPTION = 'description'
|
| +
|
| +DEFAULT_DESCRIPTIONS = ('setA', 'setB')
|
| +
|
| +
|
| +class ImagePairSet(object):
|
| + """A collection of ImagePairs, representing two arbitrary sets of images.
|
| +
|
| + These could be:
|
| + - images generated before and after a code patch
|
| + - expected and actual images for some tests
|
| + - or any other pairwise set of images.
|
| + """
|
| +
|
| + def __init__(self, descriptions=None):
|
| + """
|
| + Args:
|
| + descriptions: a (string, string) tuple describing the two image sets.
|
| + If not specified, DEFAULT_DESCRIPTIONS will be used.
|
| + """
|
| + self._column_header_factories = {}
|
| + self._descriptions = descriptions or DEFAULT_DESCRIPTIONS
|
| + self._extra_column_tallies = {} # maps column_id -> values
|
| + # -> instances_per_value
|
| + self._image_pair_dicts = []
|
| +
|
| + def add_image_pair(self, image_pair):
|
| + """Adds an ImagePair; this may be repeated any number of times."""
|
| + # Special handling when we add the first ImagePair...
|
| + if not self._image_pair_dicts:
|
| + self._base_url = image_pair.base_url
|
| +
|
| + if image_pair.base_url != self._base_url:
|
| + raise Exception('added ImagePair with base_url "%s" instead of "%s"' % (
|
| + image_pair.base_url, self._base_url))
|
| + self._image_pair_dicts.append(image_pair.as_dict())
|
| + extra_columns_dict = image_pair.extra_columns_dict
|
| + if extra_columns_dict:
|
| + for column_id, value in extra_columns_dict.iteritems():
|
| + self._add_extra_column_entry(column_id, value)
|
| +
|
| + def set_column_header_factory(self, column_id, column_header_factory):
|
| + """Overrides the default settings for one of the extraColumn headers.
|
| +
|
| + Args:
|
| + column_id: string; unique ID of this column (must match a key within
|
| + an ImagePair's extra_columns dictionary)
|
| + column_header_factory: a ColumnHeaderFactory object
|
| + """
|
| + self._column_header_factories[column_id] = column_header_factory
|
| +
|
| + def get_column_header_factory(self, column_id):
|
| + """Returns the ColumnHeaderFactory object for a particular extraColumn.
|
| +
|
| + Args:
|
| + column_id: string; unique ID of this column (must match a key within
|
| + an ImagePair's extra_columns dictionary)
|
| + """
|
| + column_header_factory = self._column_header_factories.get(column_id, None)
|
| + if not column_header_factory:
|
| + column_header_factory = column.ColumnHeaderFactory(header_text=column_id)
|
| + self._column_header_factories[column_id] = column_header_factory
|
| + return column_header_factory
|
| +
|
| + def _add_extra_column_entry(self, column_id, value):
|
| + """Records one column_id/value extraColumns pair found within an ImagePair.
|
| +
|
| + We use this information to generate tallies within the column header
|
| + (how many instances we saw of a particular value, within a particular
|
| + extraColumn).
|
| + """
|
| + known_values_for_column = self._extra_column_tallies.get(column_id, None)
|
| + if not known_values_for_column:
|
| + known_values_for_column = {}
|
| + self._extra_column_tallies[column_id] = known_values_for_column
|
| + instances_of_this_value = known_values_for_column.get(value, 0)
|
| + instances_of_this_value += 1
|
| + known_values_for_column[value] = instances_of_this_value
|
| +
|
| + def _column_headers_as_dict(self):
|
| + """Returns all column headers as a dictionary."""
|
| + asdict = {}
|
| + for column_id, values_for_column in self._extra_column_tallies.iteritems():
|
| + column_header_factory = self.get_column_header_factory(column_id)
|
| + asdict[column_id] = column_header_factory.create_as_dict(
|
| + values_for_column)
|
| + return asdict
|
| +
|
| + def as_dict(self):
|
| + """Returns a dictionary describing this package of ImagePairs.
|
| +
|
| + Uses the KEY__* constants as keys.
|
| + """
|
| + return {
|
| + KEY__COLUMNHEADERS: self._column_headers_as_dict(),
|
| + KEY__IMAGEPAIRS: self._image_pair_dicts,
|
| + KEY__IMAGESETS: [{
|
| + KEY__IMAGESETS__BASE_URL: self._base_url,
|
| + KEY__IMAGESETS__DESCRIPTION: self._descriptions[0],
|
| + }, {
|
| + KEY__IMAGESETS__BASE_URL: self._base_url,
|
| + KEY__IMAGESETS__DESCRIPTION: self._descriptions[1],
|
| + }],
|
| + }
|
|
|