1# Copyright 2013 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import numbers
6
7from telemetry import value as value_module
8from telemetry.value import list_of_scalar_values
9from telemetry.value import none_values
10from telemetry.value import summarizable
11
12
13class ScalarValue(summarizable.SummarizableValue):
14  def __init__(self, page, name, units, value, important=True,
15               description=None, tir_label=None,
16               none_value_reason=None, improvement_direction=None,
17               grouping_keys=None):
18    """A single value (float or integer) result from a test.
19
20    A test that counts the number of DOM elements in a page might produce a
21    scalar value:
22       ScalarValue(page, 'num_dom_elements', 'count', num_elements)
23    """
24    super(ScalarValue, self).__init__(page, name, units, important, description,
25                                      tir_label, improvement_direction,
26                                      grouping_keys)
27    assert value is None or isinstance(value, numbers.Number)
28    none_values.ValidateNoneValueReason(value, none_value_reason)
29    self.value = value
30    self.none_value_reason = none_value_reason
31
32  def __repr__(self):
33    if self.page:
34      page_name = self.page.display_name
35    else:
36      page_name = 'None'
37    return ('ScalarValue(%s, %s, %s, %s, important=%s, description=%s, '
38            'tir_label=%s, improvement_direction=%s, grouping_keys=%s') % (
39                page_name,
40                self.name,
41                self.units,
42                self.value,
43                self.important,
44                self.description,
45                self.tir_label,
46                self.improvement_direction,
47                self.grouping_keys)
48
49  def GetBuildbotDataType(self, output_context):
50    if self._IsImportantGivenOutputIntent(output_context):
51      return 'default'
52    return 'unimportant'
53
54  def GetBuildbotValue(self):
55    # Buildbot's print_perf_results method likes to get lists for all values,
56    # even when they are scalar, so list-ize the return value.
57    return [self.value]
58
59  def GetRepresentativeNumber(self):
60    return self.value
61
62  def GetRepresentativeString(self):
63    return str(self.value)
64
65  @staticmethod
66  def GetJSONTypeName():
67    return 'scalar'
68
69  def AsDict(self):
70    d = super(ScalarValue, self).AsDict()
71    d['value'] = self.value
72
73    if self.none_value_reason is not None:
74      d['none_value_reason'] = self.none_value_reason
75
76    return d
77
78  @staticmethod
79  def FromDict(value_dict, page_dict):
80    kwargs = value_module.Value.GetConstructorKwArgs(value_dict, page_dict)
81    kwargs['value'] = value_dict['value']
82
83    if 'improvement_direction' in value_dict:
84      kwargs['improvement_direction'] = value_dict['improvement_direction']
85    if 'none_value_reason' in value_dict:
86      kwargs['none_value_reason'] = value_dict['none_value_reason']
87
88    return ScalarValue(**kwargs)
89
90  @classmethod
91  def MergeLikeValuesFromSamePage(cls, values):
92    assert len(values) > 0
93    v0 = values[0]
94    return cls._MergeLikeValues(values, v0.page, v0.name, v0.tir_label,
95                                v0.grouping_keys)
96
97  @classmethod
98  def MergeLikeValuesFromDifferentPages(cls, values):
99    assert len(values) > 0
100    v0 = values[0]
101    return cls._MergeLikeValues(values, None, v0.name, v0.tir_label,
102                                v0.grouping_keys)
103
104  @classmethod
105  def _MergeLikeValues(cls, values, page, name, tir_label, grouping_keys):
106    v0 = values[0]
107    merged_value = [v.value for v in values]
108    none_value_reason = None
109    if None in merged_value:
110      merged_value = None
111      none_value_reason = none_values.MERGE_FAILURE_REASON
112    return list_of_scalar_values.ListOfScalarValues(
113        page, name, v0.units, merged_value, important=v0.important,
114        description=v0.description,
115        tir_label=tir_label,
116        none_value_reason=none_value_reason,
117        improvement_direction=v0.improvement_direction,
118        grouping_keys=grouping_keys)
119