Repository: translate/pootle

Issue:
Calculate checks doesnt update stat data
After running calculate_checks, it seems that stats are not updated.

This might be due to cache/revisions not getting expired, altho the stats themselves might also not be getting updated.


Discussion:

Resolving patch:
diff --git a/pootle/apps/pootle_checks/utils.py b/pootle/apps/pootle_checks/utils.py
--- a/pootle/apps/pootle_checks/utils.py
+++ b/pootle/apps/pootle_checks/utils.py
@@ -15,6 +15,7 @@
 from django.utils.functional import cached_property
 from django.utils.lru_cache import lru_cache
 
+from pootle.core.signals import update_data
 from pootle_store.constants import UNTRANSLATED
 from pootle_store.models import QualityCheck, Unit
 from pootle_store.unit import UnitProxy
@@ -140,6 +141,7 @@ def __init__(self, check_names=None, translation_project=None, units=None):
         self.stores = set()
         self._units = units
         self._store_to_expire = None
+        self._updated_stores = {}
 
     @cached_property
     def checks(self):
@@ -159,7 +161,7 @@ def checks(self):
                 check['unit_id'], {})[check['name']] = check
         return all_units_checks
 
-    @cached_property
+    @property
     def checks_qs(self):
         """QualityCheck queryset for all units, restricted to TP if set
         """
@@ -220,13 +222,39 @@ def expire_store_cache(self, store_pk=None):
         # remember the new store_pk
         self._store_to_expire = store_pk
 
+    @property
+    def tp_qs(self):
+        return TranslationProject.objects.all()
+
+    @property
+    def updated_stores(self):
+        return self._updated_stores
+
     def update(self):
         """Update/purge all QualityChecks for Units, and expire Store caches.
         """
         self.clear_unknown_checks()
         self.update_untranslated()
         self.update_translated()
+        self.update_data()
+
+    def update_data(self):
+        if not self.updated_stores:
+            return
+        if self.translation_project:
+            tps = {
+                self.translation_project.id: self.translation_project}
+        else:
+            tps = self.tp_qs.filter(
+                id__in=self.updated_stores.keys()).in_bulk()
+        for tp, stores in self.updated_stores.items():
+            tp = tps[tp]
+            update_data.send(
+                tp.__class__,
+                instance=tp,
+                object_list=tp.stores.filter(id__in=stores))
         del self.__dict__["checks"]
+        self._updated_stores = {}
 
     def update_translated_unit(self, unit, checker=None):
         """Update checks for a translated Unit
@@ -238,6 +266,7 @@ def update_translated_unit(self, unit, checker=None):
             self.checks.get(unit.id, {}),
             self.check_names)
         if checker.update():
+            self.update_store(unit.tp, unit.store)
             self.expire_store_cache(unit.store)
             return True
         return False
@@ -275,10 +304,20 @@ def update_translated(self):
         self.expire_store_cache()
         return updated_count
 
+    def update_store(self, tp, store):
+        self._updated_stores[tp] = (
+            self._updated_stores.get(tp, set()))
+        self._updated_stores[tp].add(store)
+
     def update_untranslated(self):
         """Delete QualityChecks for untranslated Units
         """
-        return self.checks_qs.exclude(unit__state__gt=UNTRANSLATED).delete()
+        untranslated = self.checks_qs.exclude(unit__state__gt=UNTRANSLATED)
+        untranslated_stores = untranslated.values_list(
+            "unit__store__translation_project", "unit__store").distinct()
+        for tp, store in untranslated_stores.iterator():
+            self.update_store(tp, store)
+        return untranslated.delete()
 
 
 def get_category_id(code):
diff --git a/pootle/apps/pootle_data/tp_data.py b/pootle/apps/pootle_data/tp_data.py
--- a/pootle/apps/pootle_data/tp_data.py
+++ b/pootle/apps/pootle_data/tp_data.py
@@ -172,4 +172,5 @@ def update(self):
         if dirs:
             update_revisions.send(
                 Directory,
-                object_list=Directory.objects.filter(id__in=dirs))
+                object_list=Directory.objects.filter(id__in=dirs),
+                keys=["stats", "checks"])


Test patch:
diff --git a/tests/pootle_checks/checks.py b/tests/pootle_checks/checks.py
--- a/tests/pootle_checks/checks.py
+++ b/tests/pootle_checks/checks.py
@@ -23,11 +23,16 @@ def test_tp_qualitycheck_updater(tp0):
     updater.update()
     assert checks.count() == original_checks
     # make unit obsolete
+    original_revision = tp0.directory.revisions.filter(
+        key="stats").values_list("value", flat=True).first()
     check = checks[0]
     unit = check.unit
     unit.__class__.objects.filter(pk=unit.pk).update(state=OBSOLETE)
     updater.update()
     assert check.__class__.objects.filter(pk=check.pk).count() == 0
+    new_revision = tp0.directory.revisions.filter(
+        key="stats").values_list("value", flat=True).first()
+    assert original_revision != new_revision
     # set to unknown check
     check = checks[0]
     check.name = "DOES_NOT_EXIST"