.. doctest docs/dev/actors.rst .. _dev.actors: ====================== Introduction to actors ====================== *Tables* and *choicelists* have certain things in common. When we refer to them in general, then we call them :term:`actors `. .. contents:: :depth: 1 :local: .. include:: /../docs/shared/include/tested.rst >>> from lino import startup >>> startup('lino_book.projects.noi1e.settings.demo') >>> from lino.api.doctest import * Actor types =========== The most common type of actors :term:`table actors `. But not all actors are tables. Another type of actors are *frames*, display some data in some other form. One such frame actor is the calendar panel, another one is :class:`lino.utils.report.EmptyTable`, used to display reports. .. glossary:: 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 :term:`database table`. database actor A :term:`table actor` that is connected to a :term:`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 :term:`site startup` in a way similar to how Django collects models. Every subclass of :class:`lino.core.actors.Actor` that is defined somewhere in your code, will be "registered" into the global models namespace :data:`rt.models`. It makes no difference wheter you import them or access them via :data:`rt.models`. >>> from lino_xl.lib.working.ui import WorkedHours >>> rt.models.working.WorkedHours is WorkedHours True The advantage of accessing them via :data:`rt.models` is that your code is open to extensions. Actors are never instantiated, we use only the class objects. >>> str(WorkedHours) 'working.WorkedHours' >>> repr(WorkedHours) 'lino_xl.lib.working.ui.WorkedHours' Getting a list of all actors ============================ When Lino starts up, it automatically discovers the installed plugins and registers each subclass of :class:`Actor` as an actor. >>> len(actors.actors_list) 350 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.abstract]) 32 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) 153 >>> kernel.master_tables[0] lino.modlib.system.models.SiteConfigs >>> len(kernel.slave_tables) 77 >>> kernel.slave_tables[0] lino_xl.lib.countries.models.PlacesByPlace >>> list(sorted(kernel.generic_slaves.values(), key=str)) [lino_xl.lib.cal.ui.EntriesByController, lino_xl.lib.cal.ui.TasksByController, lino.modlib.changes.models.ChangesByMaster, lino.modlib.changes.models.ChangesByObject, lino.modlib.checkdata.models.ProblemsByOwner, lino.modlib.comments.ui.CommentsByRFC, lino.modlib.comments.ui.MentionsByOwner, lino_xl.lib.excerpts.models.ExcerptsByOwner, lino.modlib.gfks.models.HelpTextsByModel, lino_xl.lib.invoicing.models.InvoicingsByGenerator, lino.modlib.uploads.models.UploadsByController] >>> for a in kernel.generic_slaves.values(): ... assert a not in kernel.slave_tables ... assert a in actors.actors_list Another category are :term:`virtual tables `. For example :class:`lino.modlib.users.UserRoles` :class:`lino_xl.lib.working.WorkedHours` :class:`lino.modlib.gfks.BrokenGFKs` :class:`lino.modlib.gfks.BrokenGFKs` >>> kernel.virtual_tables #doctest: +NORMALIZE_WHITESPACE [lino.modlib.about.models.SiteSearch, lino.modlib.gfks.models.BrokenGFKs, lino.modlib.gfks.models.BrokenGFKsByModel, lino_xl.lib.calview.ui.MonthlySlave, lino_xl.lib.calview.ui.DailyView, lino_xl.lib.calview.ui.WeeklyView, lino_xl.lib.calview.ui.MonthlyView, lino_xl.lib.working.ui.WorkedHours, lino_xl.lib.ledger.ui.ExpectedMovements, lino_xl.lib.ledger.ui.DebtsByAccount, lino_xl.lib.ledger.ui.DebtsByPartner, lino_xl.lib.ledger.ui.Debtors, lino_xl.lib.ledger.ui.Creditors, lino.modlib.users.desktop.UserRoles, lino_xl.lib.vat.desktop.VouchersByPartner] Another category are choicelists >>> len(kernel.CHOICELISTS) 54 >>> list(sorted(kernel.CHOICELISTS.items()))[6] ('cal.GuestStates', lino_xl.lib.cal.choicelists.GuestStates) >>> 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_xl.lib.ledger.ui.Situation]