Repository: census-instrumentation/opencensus-python (python)

Issue:
Stats: ViewData doesn't create new AggregationData
`ViewData` should have a mapping from `TagValue`s to `AggregationData`, rather than `Aggregation`. Calling `add()` on `Aggregation` will cause an error: https://github.com/census-instrumentation/opencensus-python/blob/master/opencensus/stats/view_data.py#L105-L108

Pull request description:
Fix bugs in stats library
Fixes #226 #227 

Patch:
diff --git a/examples/stats/helloworld/main.py b/examples/stats/helloworld/main.py
index f422bac..21fc6b1 100644
--- a/examples/stats/helloworld/main.py
+++ b/examples/stats/helloworld/main.py
@@ -60,7 +60,10 @@ def main():
 
     # Get aggregated stats and print it to console.
     view_data = view_manager.get_view(VIDEO_SIZE_VIEW_NAME)
-    pprint(vars(view_data))   # TODO: print more meaningful info for view_data
+    pprint(vars(view_data))
+    for k, v in view_data._tag_value_aggregation_map.items():
+      pprint(vars(v))
+      pprint(vars(v.aggregation_data))
 
 
 if __name__ == '__main__':
diff --git a/opencensus/stats/aggregation.py b/opencensus/stats/aggregation.py
index 9bced56..43782b3 100644
--- a/opencensus/stats/aggregation.py
+++ b/opencensus/stats/aggregation.py
@@ -75,6 +75,7 @@ class SumAggregation(BaseAggregation):
         super(SumAggregation, self).__init__(aggregation_type=aggregation_type)
         self._sum = aggregation_data.SumAggregationDataFloat(
             sum_data=float(sum or 0))
+        self.aggregation_data = self._sum
 
     @property
     def sum(self):
@@ -97,6 +98,7 @@ class CountAggregation(BaseAggregation):
         super(CountAggregation, self).__init__(
             aggregation_type=aggregation_type)
         self._count = aggregation_data.CountAggregationData(count)
+        self.aggregation_data = self._count
 
     @property
     def count(self):
@@ -128,6 +130,8 @@ class DistributionAggregation(BaseAggregation):
             buckets=boundaries, aggregation_type=aggregation_type)
         self._boundaries = bucket_boundaries.BucketBoundaries(boundaries)
         self._distribution = distribution or {}
+        self.aggregation_data = aggregation_data.DistributionAggregationData(
+            0, 0, 0, 0, 0, None, boundaries)
 
     @property
     def boundaries(self):
diff --git a/opencensus/stats/aggregation_data.py b/opencensus/stats/aggregation_data.py
index 21e1dfd..cc0f3e3 100644
--- a/opencensus/stats/aggregation_data.py
+++ b/opencensus/stats/aggregation_data.py
@@ -107,14 +107,22 @@ class DistributionAggregationData(BaseAggregationData):
                  min_,
                  max_,
                  sum_of_sqd_deviations,
-                 counts_per_bucket,
-                 bounds):
+                 counts_per_bucket=None,
+                 bounds=None):
         super(DistributionAggregationData, self).__init__(mean_data)
         self._mean_data = mean_data
         self._count_data = count_data
         self._min = min_
         self._max = max_
         self._sum_of_sqd_deviations = sum_of_sqd_deviations
+        if bounds is None:
+            bounds = []
+
+        if counts_per_bucket is None:
+            counts_per_bucket = []
+            bucket_size = len(bounds) + 1
+            for i in range(bucket_size):
+                counts_per_bucket.append(0)
         self._counts_per_bucket = counts_per_bucket
         self._bounds = bucket_boundaries.BucketBoundaries(
                                             boundaries=bounds).boundaries
diff --git a/opencensus/stats/view_data.py b/opencensus/stats/view_data.py
index 81bffeb..eeabd5b 100644
--- a/opencensus/stats/view_data.py
+++ b/opencensus/stats/view_data.py
@@ -74,11 +74,11 @@ class ViewData(object):
     def get_tag_map(self, context):
         """function to return the tag map based on the context"""
         if self.tag_map is not None:
-            if context.items() <= self.tag_map.items():
+            if context.map.items() <= self.tag_map.items():
                 return self.tag_map
             else:
                 tags = self.tag_map
-                for tag_key, tag_value in context.items():
+                for tag_key, tag_value in context.map.items():
                     tags[tag_key] = tag_value
                 return tags
         else:  # pragma: NO COVER
@@ -105,4 +105,5 @@ class ViewData(object):
         for val in tuple_vals:
             if val not in self.tag_value_aggregation_map:
                 self.tag_value_aggregation_map[val] = self.view.aggregation
-            self.tag_value_aggregation_map.get(val).add(value)
+            self.tag_value_aggregation_map.get(
+                val).aggregation_data.add_sample(value)


Test patch:
diff --git a/tests/unit/stats/test_view_data.py b/tests/unit/stats/test_view_data.py
index 24d9b02..682f4d2 100644
--- a/tests/unit/stats/test_view_data.py
+++ b/tests/unit/stats/test_view_data.py
@@ -60,18 +60,21 @@ class TestViewData(unittest.TestCase):
         view_data = view_data_module.ViewData(view=view,
                                               start_time=start_time,
                                               end_time=end_time)
-        test_context_1 = {'key1': 'val1'}
+        test_context_1 = mock.Mock()
+        test_context_1.map = {'key1': 'val1'}
         context_map_1 = view_data.get_tag_map(context=test_context_1)
-        self.assertEqual(test_context_1, view_data.tag_map)
-        self.assertEqual(test_context_1, context_map_1)
+        self.assertEqual(test_context_1.map, view_data.tag_map)
+        self.assertEqual(test_context_1.map, context_map_1)
 
-        test_context_2 = {'key1': 'val2'}
+        test_context_2 = mock.Mock()
+        test_context_2.map = {'key1': 'val2'}
         context_map_2 = view_data.get_tag_map(context=test_context_2)
-        self.assertEqual(test_context_2, context_map_2)
+        self.assertEqual(test_context_2.map, context_map_2)
 
-        test_context_3 = {}
+        test_context_3 = mock.Mock()
+        test_context_3.map = {}
         context_map_3 = view_data.get_tag_map(context=test_context_3)
-        self.assertEqual({'key1': 'val2'}, context_map_3)
+        self.assertEqual(test_context_2.map, context_map_3)
 
     def test_get_tag_values(self):
         view = mock.Mock()
@@ -101,7 +104,8 @@ class TestViewData(unittest.TestCase):
                                               start_time=start_time,
                                               end_time=end_time)
 
-        context = {'key1': 'val1', 'key2': 'val2'}
+        context = mock.Mock()
+        context.map = {'key1': 'val1', 'key2': 'val2'}
         time = datetime.utcnow().isoformat() + 'Z'
         value = 1
         self.assertEqual({}, view_data.tag_value_aggregation_map)