Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More

Introduction to actors

data tables and choicelists have certain things in common. When we refer to them in general, then we call them actors.

Side note: Code snippets (lines starting with >>>) in this document get tested as part of our development workflow. The following initialization snippet tells you which demo project is being used in this document.

>>> from lino import startup
>>> startup('lino_book.projects.chatter.settings')
>>> from lino.api.doctest import *

Actor types

The most common type of actors are data tables.

But not all actors show tabular data. Another type of actors are frames, which display some data in some other form. One example of a frame actor is the Site ‣ About dialog window (lino.modlib.about.About). Another example is the dashboard (lino.modlib.system.Dashboard). These actors inherit from lino.utils.report.EmptyTable.

The lino_xl.lib.calview plugin uses a complex set of actors. They all are actually table actors, but that’s not always visible because they use display mode “detail”.

table actor

An actor that operates on a list of “rows”.

We happen to simply refer to a table actor as “table”, but of course we must not mix them up with database table.

database actor

A table actor that is connected to a database table.

Identifying actors

Actors are identified by their app_label.ClassName. Similar to Django’s models they are globally known unique class objects.

Lino collects actors during site startup in a way similar to how Django collects models. Every subclass of lino.core.actors.Actor that is defined somewhere in your code, will be “registered” into the global models namespace rt.models.

It makes no difference whether you import them or access them via rt.models. Let’s verify this for the lino_xl.lib.contacts.Persons actor:

>>> from lino.modlib.users.models import Users
>>> rt.models.users.Users is Users
True

The advantage of accessing them via rt.models is that your code is open to extensions.

Actors are never instantiated, we use only the class objects.

>>> str(Users)
'users.Users'
>>> repr(Users)
'lino.modlib.users.ui.Users'

Getting a list of all actors

When Lino starts up, it automatically discovers the installed plugins and registers each subclass of Actor as an actor.

>>> len(actors.actors_list)
70

Some of the actors are abstract, i.e. they are used as base classes for other actors:

>>> len([a for a in actors.actors_list if a.is_abstract()])
14

The actors aren’t collected only in this global list but also at different places depending on their type.

The most common actors are database tables. Here we differentiate between “master tables”, “slave tables” and “generic slave tables”:

>>> from lino.core import kernel
>>> len(kernel.master_tables)
23
>>> kernel.master_tables[1]
lino.modlib.users.ui.AllUsers
>>> len(kernel.slave_tables)
8
>>> kernel.slave_tables[0]
lino.modlib.users.ui.AuthoritiesGiven
>>> list(sorted(kernel.generic_slaves.values(), key=str))
... 
[lino.modlib.comments.ui.CommentsByRFC, lino.modlib.memo.models.MentionsByTarget]
>>> for a in kernel.generic_slaves.values():
...    assert a not in kernel.slave_tables
...    assert a in actors.actors_list

Another category are virtual tables. For example lino.modlib.users.UserRoles lino_xl.lib.working.WorkedHours lino.modlib.gfks.BrokenGFKs lino.modlib.gfks.BrokenGFKs

>>> kernel.virtual_tables  
[lino.modlib.users.ui.UserRoles, lino.modlib.gfks.models.BrokenGFKs,
lino.modlib.gfks.models.BrokenGFKsByModel]

Another category of actors are choicelists

>>> len(kernel.CHOICELISTS)
18
>>> list(sorted(kernel.CHOICELISTS.items()))[6]
('notify.MailModes', lino.modlib.notify.choicelists.MailModes)

Choicelists are stored in both kernel.CHOICELISTS and actors.actors_list:

>>> for a in kernel.CHOICELISTS.values():
...    if a not in actors.actors_list:
...        print(a)

And a last category are what we call “frames”:

>>> kernel.frames_list
[lino.modlib.about.models.About, lino.modlib.system.models.Dashboard]