Welcome | Get started | Dive into Lino | Contribute | Topics | Reference | More
More about plugins¶
A plugin is a Python module that encapsulates a set of functionality designed to be used in more than one application. It can define database models, actors, actions, fixtures, template files, JavaScript snippets, dependencies, and configuration settings. None of these are mandatory.
See Plugins for a list of the plugins defined in Lino and the XL.
A plugin in Lino corresponds to what Django calls an "application". See also What is an application?.
Usage overview¶
The application developer defines which plugins to install in the
application's get_installed_plugins
method.
The plugin developer defines a plugin in the __init__.py
file of the
package. Lino expects this file to define a class named Plugin
, which
inherits from the abstract base Plugin
class.
Your Plugin
class is the central description
of your plugin.
Here is a fictive example:
from lino.api import ad, _
class Plugin(ad.Plugin):
verbose_name = _("Better calendar")
extends = 'mylib.cal'
needs_plugins = ['lino_xl.lib.contacts']
def setup_main_menu(self, site, user_type, m):
m = m.add_menu(self.app_label, self.verbose_name)
m.add_action('cal.Teams')
m.add_action('cal.Agendas')
A plugin can depend on other plugins by specifying them in the
needs_plugins
attribute. This means that when you install this plugin, Lino will
automatically install these other plugins as well
A plugin can define a set of menu commands using methods like
setup_main_menu
. This is explained in
The application menu.
A plugin can extend another plugin by inheriting from its Plugin
class. This is explained in Plugin inheritance.
A plugin that extends another plugin can optionally extend one or multiple
database models defined by the parent plugin. If it does so, it must declare
their names in extends_models
.
Accessing plugins¶
Django developers are used to code like this:
from myapp.models import Foo
def print_foo(pk=1):
print(Foo.objects.get(pk=pk))
In Lino we prefer to use the rt.models
dict as
follows:
from lino.api import rt
def print_foo(pk=1):
Foo = rt.models.myapp.Foo
print(Foo.objects.get(pk=pk))
This approach has the advantage of providing Plugin inheritance. One of the basic reasons for using plugins is that another developer can extend it and use their extension instead of the original plugin. Which means that the plugin developer does not know (and does not want to know) where the model classes are actually defined.
Note that rt.models
is populated only
after having imported the models. So you cannot use it at the
module-level namespace of a models.py
module. For example
the following variant of above code would not work:
from lino.api import rt
Foo = rt.models.foos.Foo # error `AttrDict has no item "foos"`
def print_foo(pk=1):
print(Foo.objects.get(pk=pk))
Plugin descriptors get defined and configured before Django models start to
load. Lino creates one Plugin
instance for every installed plugin and
makes it globally available in dd.plugins.FOO
(where FOO is the app_label
of the plugin).
The Plugin
class is comparable to Django's AppConfig class,
which has been added in version 1.7., but there is at least one
important difference: in Lino the Plugin
instances for
all installed plugins are available (in dd.plugins
) before Django starts to load the
first models.py
. This is possible because Plugins are
defined in __init__.py
files of your plugins. As a
consequence, unlike Django's AppConfig, you cannot define a
Plugin in your models.py
file, you must define it in
your plugins's __init__.py
.
Configuring plugins¶
Plugins can have attributes for holding configuration settings that are not meant to configured by site users via the web interface.
For example, the countries.country_code
setting is defined as
follows:
...
class Plugin(ad.Plugin):
...
country_code = 'BE'
The values of plugin attributes can be configured at three levels.
As a core developer you specify a hard-coded default value.
As an application developer you can specify default values in your
application by overriding the Site.get_plugin_configs()
of your Site
class. For example:
class Site(Site):
def get_plugin_configs(self):
yield super().get_plugin_configs()
yield 'countries', 'country_code', 'FR'
yield 'contacts', 'hide_region', True
As a site maintainer you can override these configuration
defaults in your project's settings.py
The Site.get_plugin_setting()
method¶
Some use cases for testing the Site.get_plugin_setting()
method:
>>> from lino import startup
>>> startup('lino_book.projects.min1.settings')
>>> from lino.api.doctest import *
>>> settings.SITE.get_plugin_setting('foo', 'bar')
Traceback (most recent call last):
...
Exception: Plugin foo is not installed and no default was provided
>>> settings.SITE.get_plugin_setting('contacts', 'bar')
Traceback (most recent call last):
...
AttributeError: 'Plugin' object has no attribute 'bar'
In both cases, you can avoid the traceback by specifying a default value:
>>> print(settings.SITE.get_plugin_setting('foo', 'bar', None))
None
>>> settings.SITE.get_plugin_setting('contacts', 'bar', 'baz')
'baz'
The old style using Site.setup_plugins()
still works but is deprecated:
class Site(Site):
def setup_plugins(self):
super().setup_plugins()
self.plugins.countries.configure(country_code='BE')
self.plugins.contacts.configure(hide_region=True)
Note that Site.setup_plugins()
is called after
Site.get_plugin_configs()
. This can cause unexpected behaviour when you
mix both methods.
using one of the following methods:
by overriding the Site class as described above for application developers
by setting the value directly after instantiation of your
SITE
object.
- plugin configuration setting¶
A setting that can easily be set in a
settings.py
file.
The Plugin class¶
- class lino.core.plugins.Plugin¶
The base class for all plugin descriptors.
- verbose_name¶
The verbose name of this plugin, as shown to the user. This can be a lazily translated string.
- short_name¶
The abbreviated name of this plugin, shown to the user in places where shortness is important, e.g. as the label of the tabs of a detail layout. This can be a lazily translated string. Defaults to
verbose_name
.
- needs_plugins¶
A list of names of plugins needed by this plugin.
The default implementation of
get_required_plugins()
returns this list.
- needed_by¶
If not None, then it is the Plugin instance that caused this plugin to automatically install. As the application developer you do not set this yourself
- extends_models¶
If specified, a list of model names for which this app provides a subclass.
For backwards compatibility this has no effect when
override_modlib_models
is set.
The name of another plugin to be used as menu group.
See
get_menu_group()
, How plugins build the application menu.
- media_base_url¶
Remote URL base for media files.
- media_name¶
Either None (default) or a non-empty string with the name of the subdirectory of your
media
directory which is expected to contain media files for this app.None means that there this app has no media files of her own.
Best practice is to set this to the app_label. Will be ignored if
media_base_url
is nonempty.
- url_prefix¶
The url prefix under which this plugin should ask to install its url patterns.
- site_js_snippets¶
List of js snippets to be injected into the lino_*.js file.
- support_async¶
Whether this plugin uses
lino.core.utils.DelayedValue
.
- renderer¶
The renderer used by this plugin. See Introduction to Front end Renderers.
Whether this plugin is hidden.
- ui_handle_attr_name¶
Currently implemented by
lino.modlib.extjs
,lino.modlib.bootstrap3
.
- __init__(self, site, app_label, app_name, app_module, needed_by, configs: dict)¶
This is called when the Site object instantiates, i.e. you may not yet import django.conf.settings. But you get the site object being instantiated.
Parameters:
- Site:
The
Site
instance- App_label:
e.g. "contacts"
- App_name:
e.g. "lino_xl.lib.contacts"
- App_module:
The module object corresponding to the
__init__.py
file.
- hide(self)¶
Hide this plugin.
Whether this plugin is hidden.
- configure(self, **kw)¶
Set the given parameter(s) of this Plugin instance. Any number of parameters can be specified as keyword arguments.
Raise an exception if caller specified a key that does not have a corresponding attribute.
- get_required_plugins(self)¶
Return a list of names of plugins needed by this plugin.
The default implementation returns
needs_plugins
.Lino will automatically install these plugins if necessary.
Note that Lino will add them before your plugin.
Note that only the app_label (not the full plugin name) is used when testing whether a plugin is installed. In other words, if a plugin says it requires a plugin "stdlib.foo" and an application already has some plugin "mylib.foo" installed, then "mylib.foo" satisfies "stdlib.foo".
- get_used_libs(self, html=None)¶
Yield a series of tuples (verbose_name, version, url) that describe the libraries used by this Lino site.
- get_site_info(self, ar=None)¶
Return a string to show in
lino.modlib.about.About
.TODO: move this and the
use_contacts
setting toabout
.
- on_init(self)¶
This will be called when the Plugin is being instantiated (i.e. even before the
Site
instantiation has finished. Used bylino.modlib.users
to setuser_model
.
- on_plugins_loaded(self, site)¶
Called exactly once on each installed plugin, when the
Site
has loaded all plugins, but before callingsetup_plugins()
. All this happens before settings are ready and long before the models modules start to load.This is used for initializing default values of plugin attributes that (a) depend on other plugins but (b) should be overridable in
lino.core.site.Site.setup_plugins()
.For example
groups
uses this to set a default value to thecommentable_model
forcomments
plugin.Or
lino.modlib.checkdata
uses it to set responsible_user to "robin" when it is a demo site.
- pre_site_startup(self, site)¶
This is called exactly once when models are ready.
- install_django_settings(self, site)¶
Install Django settings
- before_actors_discover(self)¶
This is called exactly once during site startup, when models are ready. Used by lino.modlib.help
- post_site_startup(self, site)¶
This will be called exactly once, when models are ready.
- extends_from(cls)¶
Return the plugin from which this plugin inherits.
- get_subdir(cls, name)¶
Get the absolute path of the named subdirectory if it exists.
- before_analyze(self)¶
This is called during startup, when all models modules have been imported, and before Lino starts to analyze them.
- on_ui_init(self, kernel)¶
This is called when the kernel is being instantiated.
- get_patterns(self)¶
Override this to return a list of url patterns to be added to the Site's patterns.
- get_requirements(self, site)¶
Return a list of optionally required Python packages to be installed during
install
.See also About requirements.
- get_head_lines(cls, site, request)¶
Yield or return a list of textlines to add to the <head> of the html page.
- on_initdb(self, site, force=False, verbosity=1)¶
This is called during SITE.build_site_cache().
Return the plugin (a
Plugin
instance) into the menu of which this plugin should add its menu commands. See How plugins build the application menu.This returns self by default, unless
this plugin defines an explicit
menu_group
. In this case return the named plugin.this plugin was automatically installed because some other plugin needs it. In this case return that other plugin.
- setup_user_prefs(self, up)¶
Called when a
lino.core.userprefs.UserPrefs
get instantiated.
- get_quicklinks(self)¶
Return or yield a sequence of quick link descriptors to be added to the list of quick links.
A quick link descriptor is a string that identifies either an actor or a bound action.
- setup_quicklinks(self, tb)¶
Add quicklinks to the list of quick links.
- get_dashboard_items(self, user)¶
Return or yield a sequence of items to be rendered on the dashboard.
Called by
lino.core.site.Site.get_dashboard_items()
.Every item is expected to be either an instance of
lino.core.dashboard.DashboardItem
, or alino.core.actors.Actor
.Tables are shown with a limit of
lino.core.tables.AbstractTable.preview_limit
rows.
- get_detail_url(self, ar, actor, pk, *args, **kw)¶
Return the URL to the given database row.
This is only a relative URL. Get the fully qualified URI by prefixing
lino.core.site.Site.server_url
.The extjs frontend overrides this and returns different URIs depending on whether ar.request is set or not.