Milimetric has submitted this change and it was merged.

Change subject: timeseries ordering and labeling fixes
......................................................................


timeseries ordering and labeling fixes

Change-Id: Ifc272b374806e38bc6b0d5e5da1bf10c15530e1f
---
M tests/test_metrics/test_bytes_added.py
M tests/test_metrics/test_namespace_edits.py
M tests/test_metrics/test_timeseries.py
M tests/test_models/test_run_report.py
M wikimetrics/config/celery_config.yaml
M wikimetrics/configurables.py
M wikimetrics/metrics/timeseries_metric.py
M wikimetrics/models/report_nodes/aggregate_report.py
M wikimetrics/run.py
9 files changed, 126 insertions(+), 33 deletions(-)

Approvals:
  Milimetric: Verified; Looks good to me, approved



diff --git a/tests/test_metrics/test_bytes_added.py 
b/tests/test_metrics/test_bytes_added.py
index 43f80c5..7da10f4 100644
--- a/tests/test_metrics/test_bytes_added.py
+++ b/tests/test_metrics/test_bytes_added.py
@@ -176,7 +176,7 @@
         results = metric(list(self.cohort), self.mwSession)
         expected1 = {
             'net_sum': {
-                '2012-12-31 00:00:00' : 0,
+                '2012-12-31 09:00:00' : 0,
                 '2013-01-01 00:00:00' : 100,
                 '2013-01-02 00:00:00' : 0,
                 '2013-01-03 00:00:00' : 0,
diff --git a/tests/test_metrics/test_namespace_edits.py 
b/tests/test_metrics/test_namespace_edits.py
index 2f01cb7..9d48d7b 100644
--- a/tests/test_metrics/test_namespace_edits.py
+++ b/tests/test_metrics/test_namespace_edits.py
@@ -206,7 +206,7 @@
     def test_timeseries_day(self):
         metric = NamespaceEdits(
             namespaces=[0],
-            start_date='2012-12-31 00:00:00',
+            start_date='2012-12-31 10:00:00',
             end_date='2013-01-02 00:00:00',
             timeseries=TimeseriesChoices.DAY,
         )
@@ -216,7 +216,7 @@
         assert_equal(
             results[self.editors[0].user_id]['edits'],
             {
-                '2012-12-31 00:00:00' : 1,
+                '2012-12-31 10:00:00' : 1,
                 '2013-01-01 00:00:00' : 2,
             }
         )
diff --git a/tests/test_metrics/test_timeseries.py 
b/tests/test_metrics/test_timeseries.py
index be03f4f..8c6925a 100644
--- a/tests/test_metrics/test_timeseries.py
+++ b/tests/test_metrics/test_timeseries.py
@@ -37,7 +37,7 @@
         )
         assert_equals(t4, '2010-01-02 03:00:00')
     
-    def test_fill_in_missing_datetimes_hour(self):
+    def normalize_datetime_slices(self):
         m = TimeseriesMetric(
             start_date='2013-01-01 23:00:00',
             end_date='2013-01-03 00:00:00',
@@ -52,7 +52,7 @@
                 }
             }
         }
-        r = m.fill_in_missing_datetimes(results, [('test', 1, 0)])
+        r = m.normalize_datetime_slices(results, [('test', 1, 0)])
         assert_equals(r, {
             1: {
                 'test': {
@@ -85,7 +85,7 @@
             }
         })
     
-    def test_fill_in_missing_datetimes_day(self):
+    def test_normalize_datetime_slices_day(self):
         m = TimeseriesMetric(
             start_date='2013-01-01 00:00:00',
             end_date='2013-01-05 00:00:00',
@@ -106,7 +106,7 @@
                 }
             }
         }
-        r = m.fill_in_missing_datetimes(results, [('test', 1, 0)])
+        r = m.normalize_datetime_slices(results, [('test', 1, 0)])
         
         assert_equals(r, {
             1: {
@@ -127,7 +127,7 @@
             }
         })
     
-    def test_fill_in_missing_datetimes_month(self):
+    def test_normalize_datetime_slices_month(self):
         m = TimeseriesMetric(
             start_date='2013-01-02 00:00:00',
             end_date='2013-03-05 00:00:00',
@@ -142,22 +142,19 @@
                 }
             },
         }
-        r = m.fill_in_missing_datetimes(results, [('test', 1, 0)])
-        
-        from pprint import pprint
-        pprint(r)
+        r = m.normalize_datetime_slices(results, [('test', 1, 0)])
         
         assert_equals(r, {
             1: {
                 'test': {
-                    '2013-01-01 00:00:00': 12,
+                    '2013-01-02 00:00:00': 12,
                     '2013-02-01 00:00:00': 0,
                     '2013-03-01 00:00:00': 1,
                 }
             },
         })
     
-    def test_fill_in_missing_datetimes_year(self):
+    def test_normalize_datetime_slices_year(self):
         m = TimeseriesMetric(
             start_date='2013-03-10 00:00:00',
             end_date='2015-03-05 00:00:00',
@@ -171,16 +168,42 @@
                 }
             },
         }
-        r = m.fill_in_missing_datetimes(results, [('test', 1, 0)])
-        from pprint import pprint
-        pprint(r)
+        r = m.normalize_datetime_slices(results, [('test', 1, 0)])
         
         assert_equals(r, {
             1: {
                 'test': {
-                    '2013-01-01 00:00:00': 12,
+                    '2013-03-10 00:00:00': 12,
                     '2014-01-01 00:00:00': 0,
                     '2015-01-01 00:00:00': 0,
                 }
             },
         })
+    
+    def test_normalize_datetime_slices_start_date_forces_first_interval(self):
+        m = TimeseriesMetric(
+            start_date='2013-01-02 00:00:00',
+            end_date='2013-03-05 00:00:00',
+            timeseries=TimeseriesChoices.MONTH,
+        )
+        
+        results = {
+            1: {
+                'test': {
+                    '2013-01-01 00:00:00': 12,
+                    '2013-03-01 00:00:00': 1,
+                }
+            },
+        }
+        r = m.normalize_datetime_slices(results, [('test', 1, 0)])
+        
+        assert_equals(r, {
+            1: {
+                'test': {
+                    # The first interval starts on the 2nd and not the 1st
+                    '2013-01-02 00:00:00': 12,
+                    '2013-02-01 00:00:00': 0,
+                    '2013-03-01 00:00:00': 1,
+                }
+            },
+        })
diff --git a/tests/test_models/test_run_report.py 
b/tests/test_models/test_run_report.py
index 2409012..f74ff24 100644
--- a/tests/test_models/test_run_report.py
+++ b/tests/test_models/test_run_report.py
@@ -1,9 +1,10 @@
 from nose.tools import assert_equals, assert_true, raises
 from celery.exceptions import SoftTimeLimitExceeded
+from tests.fixtures import QueueDatabaseTest
 from wikimetrics.models import (
     RunReport, Aggregation, PersistentReport
 )
-from ..fixtures import QueueDatabaseTest
+from wikimetrics.metrics import TimeseriesChoices
 
 
 class RunReportTest(QueueDatabaseTest):
@@ -82,6 +83,52 @@
             5,
         )
     
+    def test_aggregated_response_namespace_edits_with_timeseries(self):
+        desired_responses = [{
+            'name': 'Edits - test',
+            'cohort': {
+                'id': self.test_cohort_id,
+            },
+            'metric': {
+                'name': 'NamespaceEdits',
+                'namespaces': [0, 1, 2],
+                'start_date': '2013-05-01 10:00:00',
+                'end_date': '2013-09-01 00:00:00',
+                'timeseries': TimeseriesChoices.MONTH,
+                'individualResults': True,
+                'aggregateResults': True,
+                'aggregateSum': True,
+                'aggregateAverage': False,
+                'aggregateStandardDeviation': False,
+            },
+        }]
+        jr = RunReport(desired_responses, user_id=self.test_user_id)
+        results = jr.task.delay(jr).get()
+        self.session.commit()
+        result_key = self.session.query(PersistentReport)\
+            .filter(PersistentReport.id == jr.children[0].persistent_id)\
+            .one()\
+            .result_key
+        results = results[result_key]
+        
+        user_id = self.test_mediawiki_user_id
+        key = results[Aggregation.IND][0][user_id]['edits'].items()[0][0]
+        assert_equals(key, '2013-05-01 10:00:00')
+        
+        assert_equals(
+            results[Aggregation.SUM]['edits'].items()[0][0],
+            '2013-05-01 10:00:00',
+        )
+        
+        assert_equals(
+            results[Aggregation.SUM]['edits']['2013-05-01 10:00:00'],
+            0,
+        )
+        assert_equals(
+            results[Aggregation.SUM]['edits']['2013-06-01 00:00:00'],
+            2,
+        )
+    
     def test_aggregated_response_bytes_added(self):
         desired_responses = [{
             'name': 'Edits - test',
diff --git a/wikimetrics/config/celery_config.yaml 
b/wikimetrics/config/celery_config.yaml
index 0b28098..df8d682 100644
--- a/wikimetrics/config/celery_config.yaml
+++ b/wikimetrics/config/celery_config.yaml
@@ -7,3 +7,4 @@
 CELERYD_TASK_TIME_LIMIT             : 60
 CELERYD_TASK_SOFT_TIME_LIMIT        : 30
 DEBUG                               : True
+LOG_LEVEL                           : 'WARNING'
diff --git a/wikimetrics/configurables.py b/wikimetrics/configurables.py
index 08aa60a..a48ff0e 100644
--- a/wikimetrics/configurables.py
+++ b/wikimetrics/configurables.py
@@ -96,16 +96,25 @@
 def get_absolute_path():
     return os.path.dirname(os.path.abspath(__file__)) + '/'
 
+
 def get_wikimetrics_version():
     """
     Returns
         a tuple of the form (pretty version string, latest commit sha)
     """
     path = get_absolute_path()
-    orig_wd = os.getcwd() # remember our original working directory
+    orig_wd = os.getcwd()  # remember our original working directory
     try:
         os.chdir(path)
-        cmd = ['git', 'log', '--date', 'relative', "--pretty=format:'%an %ar 
%h'", '-n', '1']
+        cmd = [
+            'git',
+            'log',
+            '--date',
+            'relative',
+            "--pretty=format:'%an %ar %h'",
+            '-n',
+            '1',
+        ]
         p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE)
         version, err = p.communicate()
         if err is not None:
diff --git a/wikimetrics/metrics/timeseries_metric.py 
b/wikimetrics/metrics/timeseries_metric.py
index 2834dc7..b83c04d 100644
--- a/wikimetrics/metrics/timeseries_metric.py
+++ b/wikimetrics/metrics/timeseries_metric.py
@@ -1,3 +1,4 @@
+from collections import OrderedDict
 from sqlalchemy import func
 from datetime import datetime
 from dateutil.relativedelta import relativedelta
@@ -130,7 +131,7 @@
         }
         
         # in timeseries results, fill in missing date-times
-        results = self.fill_in_missing_datetimes(results, submetrics)
+        results = self.normalize_datetime_slices(results, submetrics)
         return results
     
     def submetrics_by_user(self, query, submetrics, date_index=None):
@@ -139,17 +140,17 @@
         the query_results list.
         """
         query_results = query.all()
+        results = OrderedDict()
         
         # handle simple cases (no results or no timeseries)
         if not query_results:
-            return dict()
+            return results
         
         # get results by user and by date
-        results = {}
         for row in query_results:
             user_id = row[0]
             if not user_id in results:
-                results[user_id] = {}
+                results[user_id] = OrderedDict()
             
             date_slice = None
             if self.timeseries.data != TimeseriesChoices.NONE:
@@ -165,11 +166,12 @@
         
         return results
     
-    def fill_in_missing_datetimes(self, results_by_user, submetrics):
+    def normalize_datetime_slices(self, results_by_user, submetrics):
         """
         Starting from a sparse set of timeseries results, fill in default 
values
-        for the specified list of sub-metrics.  If self.timeseries is NONE, 
this
-        is a simple identity function.
+        for the specified list of sub-metrics.  Also make sure the 
chronological
+        first timeseries slice is >= self.start_date.
+        If self.timeseries is NONE, this is a simple identity function.
         
         Parameters
             results_by_user : dictionary of submetrics dictionaries by user
@@ -182,8 +184,13 @@
             return results_by_user
         
         slice_delta = self.get_delta_from_choice()
-        timeseries_slices = dict()
-        slice_to_default = self.get_first_slice()
+        timeseries_slices = OrderedDict()
+        start_slice_key = format_pretty_date(self.start_date.data)
+        timeseries_slices[start_slice_key] = None
+        
+        first_slice = self.get_first_slice()
+        first_slice_key = format_pretty_date(first_slice)
+        slice_to_default = first_slice
         while slice_to_default < self.end_date.data:
             date_key = format_pretty_date(slice_to_default)
             timeseries_slices[date_key] = None
@@ -198,6 +205,10 @@
                 for k, v in defaults.iteritems():
                     if not v:
                         defaults[k] = default
+                
+                # coerce the first datetime slice to be self.start_date
+                defaults[start_slice_key] = defaults.pop(first_slice_key)
+                
                 user_submetrics[label] = defaults
         
         return results_by_user
diff --git a/wikimetrics/models/report_nodes/aggregate_report.py 
b/wikimetrics/models/report_nodes/aggregate_report.py
index 1d09f8a..1dfa16a 100644
--- a/wikimetrics/models/report_nodes/aggregate_report.py
+++ b/wikimetrics/models/report_nodes/aggregate_report.py
@@ -1,8 +1,10 @@
+from collections import OrderedDict
 from decimal import Decimal
+from celery.utils.log import get_task_logger
+
 from wikimetrics.utils import stringify
 from report import ReportNode
 from multi_project_metric_report import MultiProjectMetricReport
-from celery.utils.log import get_task_logger
 
 
 __all__ = ['AggregateReport', 'Aggregation']
@@ -106,7 +108,7 @@
                     # handle timeseries aggregation
                     if isinstance(value, dict):
                         if not key in aggregation:
-                            aggregation[key] = dict()
+                            aggregation[key] = OrderedDict()
                             helper[key] = dict()
                         
                         for subkey in value:
diff --git a/wikimetrics/run.py b/wikimetrics/run.py
index d56e569..bab607f 100644
--- a/wikimetrics/run.py
+++ b/wikimetrics/run.py
@@ -22,7 +22,7 @@
 
 def run_celery():
     from configurables import queue
-    queue.start(argv=['celery', 'worker', '-l', 'DEBUG'])
+    queue.start(argv=['celery', 'worker', '-l', queue.conf['LOG_LEVEL']])
 
 
 def setup_parser():

-- 
To view, visit https://gerrit.wikimedia.org/r/86751
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ifc272b374806e38bc6b0d5e5da1bf10c15530e1f
Gerrit-PatchSet: 1
Gerrit-Project: analytics/wikimetrics
Gerrit-Branch: master
Gerrit-Owner: Milimetric <[email protected]>
Gerrit-Reviewer: Milimetric <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to