============================ Wednesday, December 31, 2014 ============================ [logos] AttrDict instance has no key 'contacts' =============================================== The online demo of :ref:`logos` had caused a traceback:: AttrDict instance has no key 'contacts' (keys are languages, about, users, sessions, bibles, system, comments, lino, contenttypes, humanize, extjs, bootstrap3) This revealed a subtle problem and inspired me to find a nice solution to it. The :mod:`lino.modlib.languages` is a small plugin which defines only one menu item into the :menuselection:`Configuration` menu. The subtle problem is: into which menu group should the `languages` plugin integrate? It makes no sense (and is irritating for the user) if such a small plugin creates its own menu group. I started to write :lino:`/dev/menu`. For example :ref:`menu.groups`. When the ``languages`` plugin was written, I "spontaneously" imagined that the `Languages` table fits into the `Contacts` menu group. Here is who I wrote this:: def setup_config_menu(site, ui, profile, m): m = m.add_menu('contacts', _("Contacts")) m.add_action(Languages) A bit later (when Lino's plugin system was ready), I changed this to:: def setup_config_menu(site, ui, profile, m): p = dd.plugins.contacts m = m.add_menu(p.app_label, p.verbose_name) m.add_action(Languages) Now I discovered that this caused a problem in :ref:`logos`, because :ref:`logos` has no :mod:`lino.modlib.contacts` installed. The actual question is: How can the `languages` plugin know where I want it to be in the menu tree? The only realistic solution until now was to override :meth:`setup_menu ` for both applications. I would like to avoid this in order to have the ``languages`` plugin more "pluggable". So I had this idea: I wrote a new plugin method :meth:`get_menu_group ` which looks at the :attr:`lino.core.plugin.Plugin.needed_by` attribute. And the :mod:`lino.modlib.languages` plugin is the first usage example. Firstly its :xfile:`models.py` specifies:: def setup_config_menu(site, ui, profile, m): p = dd.plugins.languages.get_menu_group() m = m.add_menu(p.app_label, p.verbose_name) m.add_action('languages.Languages') And secondly, I no longer explicitly yield this plugin in the :meth:`get_installed_plugins ` method of :ref:`welfare` and :ref:`logos`, but (thirdly) add it to the :attr:`needs_plugins ` attribute of :mod:`lino.modlib.cv` and :mod:`lino_logos.apps.bibles`. Cool! Updated :ref:`demos` at :ref:`lf`.