bug 1361037, Cleanup stats handling, r=flod, stas
authorAxel Hecht <axel@pike.org>
Wed, 17 May 2017 15:43:56 +0200
changeset 239 24750ee963fd51e76410593f1ed5d703b6545bc2
parent 238 af79116532204027f849c5c673b1f0fad9e39b1c
child 240 34d99a0dd563d4939b8c9e13fc60591e24243014
push id48
push useraxel@mozilla.com
push dateFri, 26 May 2017 11:10:47 +0000
reviewersflod, stas
bugs1361037
bug 1361037, Cleanup stats handling, r=flod, stas Make the stats update an explicit API on Observer, instead of an overly generic notification mechanism. MozReview-Commit-ID: 2eYvBtmstxc
compare_locales/compare.py
compare_locales/tests/test_compare.py
--- a/compare_locales/compare.py
+++ b/compare_locales/compare.py
@@ -189,36 +189,38 @@ class Observer(object):
     def toJSON(self):
         # Don't export file stats, even if we collected them.
         # Those are not part of the data we use toJSON for.
         return {
             'summary': self._dictify(self.summary),
             'details': self.details.toJSON()
         }
 
+    def updateStats(self, file, stats):
+        # in multi-project scenarios, this file might not be ours,
+        # check that.
+        if (self.filter is not None and
+                self.filter(file) in (None, 'ignore')):
+            return
+        for category, value in stats.iteritems():
+            self.summary[file.locale][category] += value
+        if self.file_stats is None:
+            return
+        if 'missingInFiles' in stats:
+            # keep track of how many strings are in a missing file
+            # we got the {'missingFile': 'error'} from the notify pass
+            self.details[file]['strings'] = stats['missingInFiles']
+            # missingInFiles should just be "missing" in file stats
+            self.file_stats[file.locale][file.localpath]['missing'] = \
+                stats['missingInFiles']
+            return  # there are no other stats for missing files
+        self.file_stats[file.locale][file.localpath].update(stats)
+
     def notify(self, category, file, data):
-        rv = "error"
-        if category in self.stat_cats:
-            # these get called post reporting just for stats
-            # return "error" to forward them to other other_observers
-            # in multi-project scenarios, this file might not be ours,
-            # check that.
-            if (self.filter is not None and
-                    self.filter(file) in (None, 'ignore')):
-                return 'ignore'
-            self.summary[file.locale][category] += data
-            if self.file_stats is not None:
-                # missingInFiles should just be "missing" in file stats
-                cat = category if category != 'missingInFiles' else 'missing'
-                self.file_stats[file.locale][file.localpath][cat] = data
-            # keep track of how many strings are in a missing file
-            # we got the {'missingFile': 'error'} from the first pass
-            if category == 'missingInFiles':
-                self.details[file]['strings'] = data
-            return "error"
+        rv = 'error'
         if category in ['missingFile', 'obsoleteFile']:
             if self.filter is not None:
                 rv = self.filter(file)
             if rv != "ignore":
                 self.details[file][category] = rv
             return rv
         if category in ['missingEntity', 'obsoleteEntity']:
             if self.filter is not None:
@@ -421,16 +423,23 @@ class ContentComparer:
         for obs in self.other_observers:
             # non-filtering other_observers, ignore results
             obs.notify(category, file, data)
         if 'error' in rvs:
             return 'error'
         assert len(rvs) == 1
         return rvs.pop()
 
+    def updateStats(self, file, stats):
+        """Check observer for the found data, and if it's
+        not to ignore, notify other_observers.
+        """
+        for observer in self.observers + self.other_observers:
+            observer.updateStats(file, stats)
+
     def remove(self, obsolete):
         self.notify('obsoleteFile', obsolete, None)
         pass
 
     def compare(self, ref_file, l10n, extra_tests=None):
         try:
             p = parser.getParser(ref_file.file)
         except UserWarning:
@@ -520,33 +529,32 @@ class ContentComparer:
                             _l, col = l10nent.value_position(pos)
                         # skip error entities when merging
                         if tp == 'error' and self.merge_stage is not None:
                             skips.append(l10nent)
                         self.notify(tp, l10n,
                                     u"%s at line %d, column %d for %s" %
                                     (msg, _l, col, refent.key))
                 pass
-        if missing:
-            self.notify('missing', l10n, missing)
         if self.merge_stage is not None and (missings or skips):
             self.merge(
                 ref[0], ref[1], ref_file,
                 l10n, missings, skips, l10n_ctx,
                 p.canMerge, p.encoding)
-        if report:
-            self.notify('report', l10n, report)
-        if obsolete:
-            self.notify('obsolete', l10n, obsolete)
-        if changed:
-            self.notify('changed', l10n, changed)
-        if unchanged:
-            self.notify('unchanged', l10n, unchanged)
-        if keys:
-            self.notify('keys', l10n, keys)
+        stats = {}
+        for cat, value in (
+                ('missing', missing),
+                ('report', report),
+                ('obsolete', obsolete),
+                ('changed', changed),
+                ('unchanged', unchanged),
+                ('keys', keys)):
+            if value:
+                stats[cat] = value
+        self.updateStats(l10n, stats)
         pass
 
     def add(self, orig, missing):
         if self.notify('missingFile', missing, None) == "ignore":
             # filter said that we don't need this file, don't count it
             return
         f = orig
         try:
@@ -554,17 +562,17 @@ class ContentComparer:
         except UserWarning:
             return
         try:
             p.readContents(f.getContents())
             entities, map = p.parse()
         except Exception, e:
             self.notify('error', f, str(e))
             return
-        self.notify('missingInFiles', missing, len(map))
+        self.updateStats(missing, {'missingInFiles': len(map)})
 
     def doUnchanged(self, entity):
         # overload this if needed
         pass
 
     def doChanged(self, file, ref_entity, l10n_entity):
         # overload this if needed
         pass
--- a/compare_locales/tests/test_compare.py
+++ b/compare_locales/tests/test_compare.py
@@ -91,17 +91,17 @@ two/other
         )
 
 
 class TestObserver(unittest.TestCase):
     def test_simple(self):
         obs = compare.Observer()
         f = paths.File('/some/real/sub/path', 'sub/path', locale='de')
         obs.notify('missingEntity', f, ['one', 'two'])
-        obs.notify('missing', f, 15)
+        obs.updateStats(f, {'missing': 15})
         self.assertDictEqual(obs.toJSON(), {
             'summary': {
                 'de': {
                     'missing': 15
                 }
             },
             'details': {
                 'children': [
@@ -116,17 +116,17 @@ class TestObserver(unittest.TestCase):
         self.assertDictEqual(clone.details.toJSON(), obs.details.toJSON())
         self.assertIsNone(clone.file_stats)
 
     def test_module(self):
         obs = compare.Observer(file_stats=True)
         f = paths.File('/some/real/sub/path', 'path',
                        module='sub', locale='de')
         obs.notify('missingEntity', f, ['one', 'two'])
-        obs.notify('missing', f, 15)
+        obs.updateStats(f, {'missing': 15})
         self.assertDictEqual(obs.toJSON(), {
             'summary': {
                 'de': {
                     'missing': 15
                 }
             },
             'details': {
                 'children': [
@@ -147,17 +147,17 @@ class TestObserver(unittest.TestCase):
         self.assertDictEqual(clone.summary, obs.summary)
         self.assertDictEqual(clone.details.toJSON(), obs.details.toJSON())
         self.assertDictEqual(clone.file_stats, obs.file_stats)
 
     def test_file_stats(self):
         obs = compare.Observer(file_stats=True)
         f = paths.File('/some/real/sub/path', 'sub/path', locale='de')
         obs.notify('missingEntity', f, ['one', 'two'])
-        obs.notify('missing', f, 15)
+        obs.updateStats(f, {'missing': 15})
         self.assertDictEqual(obs.toJSON(), {
             'summary': {
                 'de': {
                     'missing': 15
                 }
             },
             'details': {
                 'children': [