:date: 2018-10-04 ========================= Thursday, October 4, 2018 ========================= I started working for :ticket:`2495`. - In :class:`lino_xl.lib.cal.GuestStates`. They asked to change the text for guest state "absent" from "Abwesend" (absent) to "Fehlt" (missing). I thought that this is a good vocabulary change and renamed "absent" to "missing" for the :mod:`voga ` workflow in general. Which means also for :ref:`voga` and :ref:`tera`. But not for :ref:`welfare` who use the :mod:`feedback ` workflow. This is confirmed by what we have in :ref:`tera` where I changed:: EntryStates.missed.guest_state = GuestStates.absent to:: EntryStates.missed.guest_state = GuestStates.missing I updated :ref:`avanti.specs.cal` while working. I wrote a new function :func:`lino.api.doctest.show_workflow`. Test failures in Welfare ======================== I saw some `failures in Welfare `__ but don't see why they are there. I opened a separate ticket :ticket:`2565` for this. Looks as if there's one calendar more, and :class:`pcsw.Client` has a changed content type id. I don't remember any code change that might have caused these. Aha, I then saw that in `Python 3 `__ it is the opposite. The number of calendars changes when migrating from Python 2 to 3 (or from Django 1 to 2). Maybe the loading order of plugins is changed. Hamza had observed that the difference comes because Django 2 for some reason creates content types in a different order than Django 1. So the ContentType.id of a given table varies depending on whether :cmd:`inv prep` has been run under Py3 or Py2. Resolution --> use ellipsis in these doctests for the contenttype id. Importing invoices for :ref:`tera` ================================== I started spzloader3.py and tl3.py. MyCoachedEnrolments for Avanti ============================== How to do a gfklookup for remote fields:: flt = {'event__'+k: v for k, v in gfk2lookup(Event.owner, self).items()} Changes in action API ===================== The new action :meth:`lino_avanti.lib.courses.Course.update_missing_rates` triggered me to start reviewing this part of the action API. At some moment I had this code:: class UpdateMissingRates(dd.Action): ... def run_from_ui(self, ar, ...): for obj in ar.selected_rows: obj.run_update_missing_rates(ar) class Course(Course): update_missing_rates = UpdateMissingRates() def run_update_missing_rates(self, ar): ... do the actual thing @dd.schedule_daily() def update_missing_rates(): for obj in ...: obj.run_update_missing_rates() These were too many names for the same thing. For simple actions without custom permission handling there should be no need to create a class. The action on the model should be callable more naturally from code. Do we need all these methods run_from_code, run_from_ui and run_from_session? Here is what I changed: when calling an :class:`InstanceAction ` directly (i.e. using its :meth:`__call__` method), you may no longer specify an action request as first argument (if you want to do that, you call :meth:`run_from_ui ` or :meth:`run_from_session `). These action methods run_from_code, run_from_ui and run_from_session are still there but they now have a docstring. And because an instance action is callable, I can now write above code more concisely:: class Course(Course): update_missing_rates = UpdateMissingRates() @dd.action(...) def update_missing_rates(self, ar): ... do the actual thing @dd.schedule_daily() def update_missing_rates(): for obj in ...: obj.update_missing_rates() En passant an internal optimization: `dd.action` no longer is a function in :mod:`lino.core.actions` but a shortcut to the :meth:`lino.core.actions.Action.decorator` class method. This might be useful of somebody wants to have an action class and still use the decorated model method:: class MyAction(dd.Action): ... class MyModel(dd.Model): ... @MyAction.decorate() def update_missing_rates(self, ar): ... do the actual thing Help texts from Sphinx ====================== I had some fun because I wanted the help_text for our new action to show up. I noticed that the :xfile:`help_texts.py` files had not been updated for some time. I think I fixed it but don't understand all the details. It seems that Sphinx now stores its pickles (:xfile:`.doctrees`) in the source directory, as a sibling of the output path (:xfile:`.build`). And because of this :cmd:`inv clean` did not delete them. So Sphinx did not process all documents after a clean. And that's why :mod:`help_text_extractor` never generated any :xfile:`help_texts.py` files. 'Course' object has no attribute 'get_date_formatter' ===================================================== Occured during :meth:`lino_xl.lib.cal.EventGenerator.update_all_guests`, which is not covered by the test suite.