20130220
========

Why Django needs a `populated` signal
----------------------------------------

:mod:`lino.projects.homeworkschool` had a problem with the new version,
caused by the Ross McFarland's trick of having :mod:`lino` as the last installed_app 
and calling :mod:`lino.Lino.startup` automatically from :mod:`lino.models`.

The problem is that 
:mod:`lino.projects.homeworkschool` has apps which don't import at first run.
The `populate` function in 
`django.db.models.loading`
"postpones" them and gives them a second chance.

The order of installed applications is:

  | ...
  | :mod:`lino.modlib.school`
  | ...
  | :mod:`lino.projects.homeworkschool`

These two modules have the following interdependency:

- `homeworkschool` defines the concrete implementation of `contacts.Person`
  (which is declared in :attr:`override_modlib_models
  <lino.Lino.override_modlib_models>`)
- `school` needs 
  the concrete implementation of `contacts.Person`
  at module-level to define the `Pupil` and `Teacher` classes.

This means that `school` will get postponed until `homeworkschool` has been loaded.

All the above is rather trivial, but it took me a lot of time to 
understand the problem because of a "little bug":

  The :func:`resolve_model <lino.core.modeltools.resolve_model>`
  function may not use `seed_cache=True` (which causes Django 
  to populate the models cache before looking for the model)
  since we want to have it usable at the top-level of ``models`` 
  modules.
  Which is what :mod:`lino.projects.homeworkschool` did.
  This caused a recursive populate, leading to very confusing error messages.

Another piece of time went into finding out how to cope with this situation.
Which you can admire nor in :mod:`lino.models`.

All this shows how regrettable it is that Django doesn't provide a 
`populated` signal. 
It would be so easy,
just two lines of code in `/django/db/models/loading.py`
that wouldn't hurt anybody::

  populated = signals.Signal() # <<<<<<<<<<<<<<<<<<<<<<<<< first line

  class AppCache(object): 

      ...
      
      def _populate(self):
          if self.loaded:
              return
          imp.acquire_lock()
          try:
              if self.loaded:
                  return
              for app_name in settings.INSTALLED_APPS:
                  if app_name in self.handled:
                      continue
                  self.load_app(app_name, True)
              if not self.nesting_level:
                  for app_name in self.postponed:
                      self.load_app(app_name)
                  self.loaded = True
              populated.send(sender=self)  # <<<<<<<<<<<<< second line
          finally:
              imp.release_lock() 
              

A test suite for `watch_tim`
----------------------------

A first bug in yesterday's release occured. Here is my first reaction:

  Patsch, der erste Bug in der neuen Version: diese Fehlermeldung kommt,
  wenn man in TIM einen Partner mit leerem PAR->IdUsr bearbeitet, der in
  Lino als Klient existiert und noch keine Begleitungen hat... Im
  vorliegenden Fall war es Partner Nummer 23633 (Kurt Sch.).

  Die Unstabilität von watch_tim ist normal. Eigentlich müsste ich eine
  ganze Latte von unit tests schreiben. Das ist technisch nicht sehr
  kompliziert, würde aber viel Aufwand bedeuten, weil alle möglichen
  Normal- und Sonderfälle darin vorkommen müssten. Angesichts der
  Tatsache, dass watch_tim voraussichtlich bei euch schon bald
  Vergangenheit ist und auch garantiert nie bei irgendeinem anderen
  TIM-Benutzer jemals Verwendung finden wird finde ich, dass wir das
  einfach aushalten müssen...

After having written this, I nevertheless decided to start a unit test suite:
:mod:`watchtim_tests <lino_welfare.modlib.pcsw.tests.watchtim_tests>`.

This took only 5 minutes, and at least this special case is now covered.
I won't invest much energy into getting everything covered for the said 
reasons, but who knows...

à propos test suite
-------------------

Damit der obige Test in der Praxis taugt, müsste ich freilich erstmal 
die Testsuite wieder aufpäppeln,
die ich in letzter Zeit vernachlässigt habe.
Also ran an den Speck. Jetzt oder nie. 
Zumal ich vor dem Release heute abend sowieso 
nichts großes Neues anfangen will.

Eine zeitraubende Sache war folgendes: 
In einem Demo-Test (:func:`test002
<lino_welfare.modlib.pcsw.tests.pcsw_demo_tests.test002>`)
machte er eine Abfrage nach `/api/cv/SoftSkillsByPerson`.
Nun ist :class:`SoftSkillsByPerson <lino_welfare.modlib.cv.models.SoftSkillsByPerson>`
eine dynamische Tabelle, deren Titel und Inhalt von der SiteConfig abhängt.
Und die SiteConfig kriegt sinnvolle Werte erst wenn die Demo-Daten 
eingelesen werden.
Wenn ich aber die gesamte Test-Suite laufen lasse, 
wurde vorher 
(:mod:`quick_tests <lino_welfare.modlib.pcsw.tests.pcsw_tests>`)
schon das UI initialisiert, und zwar ohne Demo-Daten.
Und unsere dynamische Tabelle wurde natürlich nur ein einziges Mal pro Prozess 
generiert: wenn man in den Site-Parametern eines der Felder 
"Eigenschaftsgruppe Fähigkeiten",
"Eigenschaftsgruppe Sozialkompetenzen"
oder
"Eigenschaftsgruppe Hindernisse"
verändert hätte, muss man anschließend den Server neustarten, 
damit es aktiv wird.
So war das schon immer gewesen.
Wer will denn auch was Feineres.
Jawohl, unsere Testsuite will das.