lino 24.10.3__py3-none-any.whl → 24.11.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. lino/__init__.py +1 -1
  2. lino/api/doctest.py +11 -10
  3. lino/api/rt.py +2 -3
  4. lino/config/admin_main_base.html +2 -2
  5. lino/core/actions.py +2 -4
  6. lino/core/actors.py +70 -35
  7. lino/core/choicelists.py +2 -2
  8. lino/core/dashboard.py +2 -1
  9. lino/core/dbtables.py +15 -15
  10. lino/core/elems.py +8 -4
  11. lino/core/fields.py +12 -3
  12. lino/core/inject.py +9 -2
  13. lino/core/kernel.py +11 -11
  14. lino/core/layouts.py +1 -1
  15. lino/core/model.py +25 -36
  16. lino/core/plugin.py +1 -0
  17. lino/core/renderer.py +21 -21
  18. lino/core/requests.py +94 -83
  19. lino/core/site.py +9 -90
  20. lino/core/store.py +16 -19
  21. lino/core/tables.py +0 -17
  22. lino/core/utils.py +32 -2
  23. lino/core/views.py +2 -1
  24. lino/help_texts.py +10 -5
  25. lino/locale/bn/LC_MESSAGES/django.po +1210 -907
  26. lino/locale/de/LC_MESSAGES/django.po +1760 -1375
  27. lino/locale/django.pot +1136 -906
  28. lino/locale/es/LC_MESSAGES/django.po +1709 -1347
  29. lino/locale/et/LC_MESSAGES/django.po +1206 -906
  30. lino/locale/fr/LC_MESSAGES/django.mo +0 -0
  31. lino/locale/fr/LC_MESSAGES/django.po +1193 -923
  32. lino/locale/nl/LC_MESSAGES/django.po +1247 -942
  33. lino/locale/pt_BR/LC_MESSAGES/django.po +1190 -903
  34. lino/locale/zh_Hant/LC_MESSAGES/django.po +1190 -903
  35. lino/management/commands/show.py +2 -4
  36. lino/mixins/periods.py +15 -7
  37. lino/mixins/polymorphic.py +3 -3
  38. lino/mixins/ref.py +6 -3
  39. lino/modlib/checkdata/__init__.py +3 -3
  40. lino/modlib/comments/choicelists.py +1 -1
  41. lino/modlib/comments/fixtures/demo2.py +4 -1
  42. lino/modlib/comments/mixins.py +9 -10
  43. lino/modlib/comments/models.py +4 -4
  44. lino/modlib/comments/ui.py +5 -0
  45. lino/modlib/extjs/ext_renderer.py +1 -1
  46. lino/modlib/linod/consumers.py +2 -3
  47. lino/modlib/linod/mixins.py +3 -2
  48. lino/modlib/memo/mixins.py +11 -209
  49. lino/modlib/notify/mixins.py +33 -32
  50. lino/modlib/periods/__init__.py +12 -1
  51. lino/modlib/periods/fixtures/std.py +2 -1
  52. lino/modlib/periods/mixins.py +0 -1
  53. lino/modlib/periods/models.py +79 -75
  54. lino/modlib/printing/actions.py +2 -0
  55. lino/modlib/printing/choicelists.py +3 -3
  56. lino/modlib/publisher/ui.py +2 -2
  57. lino/modlib/search/models.py +17 -11
  58. lino/modlib/system/__init__.py +0 -2
  59. lino/modlib/system/choicelists.py +55 -1
  60. lino/modlib/system/fixtures/__init__.py +0 -0
  61. lino/modlib/system/fixtures/std.py +5 -0
  62. lino/modlib/system/models.py +4 -2
  63. lino/modlib/uploads/__init__.py +10 -1
  64. lino/modlib/uploads/choicelists.py +3 -3
  65. lino/modlib/uploads/mixins.py +30 -32
  66. lino/modlib/uploads/models.py +89 -56
  67. lino/modlib/uploads/ui.py +12 -6
  68. lino/modlib/uploads/utils.py +107 -0
  69. lino/modlib/users/models.py +2 -2
  70. lino/modlib/weasyprint/__init__.py +2 -0
  71. lino/utils/__init__.py +14 -9
  72. lino/utils/djangotest.py +2 -1
  73. lino/utils/html.py +32 -1
  74. lino/utils/media.py +2 -3
  75. lino/utils/soup.py +311 -0
  76. {lino-24.10.3.dist-info → lino-24.11.1.dist-info}/METADATA +1 -3
  77. {lino-24.10.3.dist-info → lino-24.11.1.dist-info}/RECORD +80 -76
  78. {lino-24.10.3.dist-info → lino-24.11.1.dist-info}/WHEEL +1 -1
  79. {lino-24.10.3.dist-info → lino-24.11.1.dist-info}/licenses/AUTHORS.rst +0 -0
  80. {lino-24.10.3.dist-info → lino-24.11.1.dist-info}/licenses/COPYING +0 -0
lino/__init__.py CHANGED
@@ -26,7 +26,7 @@ defines no models, some template files, a series of :term:`django-admin commands
26
26
 
27
27
  """
28
28
 
29
- __version__ = '24.10.3'
29
+ __version__ = '24.11.1'
30
30
 
31
31
  # import setuptools # avoid UserWarning "Distutils was imported before Setuptools"?
32
32
 
lino/api/doctest.py CHANGED
@@ -478,7 +478,7 @@ def walk_menu_items(username=None, severe=True):
478
478
  print(s)
479
479
 
480
480
  if settings.SITE.user_types_module:
481
- ar = settings.SITE.login(username)
481
+ ar = rt.login(username)
482
482
  with translation.override(ar.user.language):
483
483
  doit(ar)
484
484
  else:
@@ -642,27 +642,28 @@ def pprint_json_string(s):
642
642
  print(json.dumps(json.loads(s), indent=2, sort_keys=True, separators=(",", ": ")))
643
643
 
644
644
 
645
- def show_dashboard(username, **options):
645
+ def show_dashboard(username, show_urls=False, **options):
646
646
  """Show the dashboard of the given user.
647
647
 
648
648
  Useful options:
649
649
 
650
+ - show_urls=False
650
651
  - ignore_links=True
651
652
 
652
653
  For more options, see
653
654
  https://pypi.org/project/html2text/ and
654
655
  https://github.com/Alir3z4/html2text/blob/master/docs/usage.md
655
656
 
656
- Note that this is currently not much used because the result is difficult to
657
- maintain. One reason for this is that :func:`naturaltime` (from
658
- :mod:`django.contrib.humanize.templatetags.humanize`) ignores demo_date and
659
- therefore produces results that depend on the current date/time.
657
+ This is currently not much used because the result is difficult to maintain.
658
+ One reason for this is that :func:`naturaltime` (from
659
+ :mod:`django.contrib.humanize.templatetags.humanize`) ignores
660
+ :attr:`lino.core.site.Site.the_demo_date` and therefore produces results that
661
+ depend on the current date/time.
660
662
 
661
663
  """
662
- # request = PseudoRequest(username)
663
- rnd = settings.SITE.kernel.text_renderer
664
- ar = rt.login(username, renderer=rnd)
665
- html = settings.SITE.get_main_html(ar) # , front_end=rnd.front_end)
664
+ renderer = settings.SITE.kernel.text_renderer
665
+ ar = rt.login(username, renderer=renderer, show_urls=show_urls)
666
+ html = settings.SITE.get_main_html(ar)
666
667
  print(html2text(html, **options).strip())
667
668
 
668
669
 
lino/api/rt.py CHANGED
@@ -15,7 +15,7 @@ from lino.core.exceptions import ChangedAPI
15
15
 
16
16
  # actors = settings.SITE.models
17
17
 
18
- login = settings.SITE.login
18
+ # login = rt.login
19
19
  startup = settings.SITE.startup
20
20
  # get_printable_context = settings.SITE.get_printable_context
21
21
  lookup_filter = settings.SITE.lookup_filter
@@ -32,8 +32,7 @@ def get_template(*args, **kw):
32
32
  return settings.SITE.plugins.jinja.renderer.jinja_env.get_template(*args, **kw)
33
33
 
34
34
 
35
- def show(*args, **kw):
36
- return login().show(*args, **kw)
35
+ from lino.core.utils import login, show, shows
37
36
 
38
37
 
39
38
  # def send_email(*args, **kw):
@@ -100,8 +100,8 @@
100
100
 
101
101
  {% block admin_main_items %}
102
102
  {% if not ar.renderer.support_dashboard_layout %}
103
- {% for i in user.get_preferences().dashboard_items %}
104
- {{''.join(i.render(ar))}}
103
+ {% for di in user.get_preferences().dashboard_items %}
104
+ {{''.join(di.render(ar))}}
105
105
  {% endfor %}
106
106
  {% endif %}
107
107
  {% endblock %}
lino/core/actions.py CHANGED
@@ -87,7 +87,7 @@ def install_layout(cls, k, layout_class, **options):
87
87
  - `cls` is the actor (a class object)
88
88
 
89
89
  - `k` is one of 'grid_layout', 'detail_layout', 'insert_layout',
90
- 'params_layout', 'card_layout', 'list_layout'
90
+ 'params_layout', 'card_layout'
91
91
 
92
92
  - `layout_class`
93
93
 
@@ -575,7 +575,7 @@ class Action(Parametrizable, Permittable):
575
575
 
576
576
  def is_window_action(self):
577
577
  """Return `True` if this is a "window action" (i.e. which opens a GUI
578
- window on the client before executin).
578
+ window on the client before executing).
579
579
 
580
580
  """
581
581
  return self.opens_a_window or (self.parameters and not self.no_params_window)
@@ -805,9 +805,7 @@ class ShowTable(TableAction):
805
805
  return self.label or self.defining_actor.label
806
806
 
807
807
  def get_window_layout(self, actor):
808
- # ~ return self.actor.list_layout
809
808
  return None
810
- # return actor.card_layout or actor.list_layout # 20210910
811
809
 
812
810
  def get_window_size(self, actor):
813
811
  return actor.window_size
lino/core/actors.py CHANGED
@@ -39,7 +39,8 @@ from lino.core.utils import ParameterPanel
39
39
  from lino.core.utils import navinfo, dbfield2params_field
40
40
  from lino.utils import curry, AttrDict, is_string
41
41
 
42
- from lino.utils.html import E, forcetext, tostring, assert_safe
42
+ from lino.utils.html import E, forcetext, tostring, Grouper, SAFE_EMPTY
43
+ # from lino.utils.html import assert_safe
43
44
 
44
45
  from .roles import SiteUser
45
46
 
@@ -283,6 +284,12 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
283
284
  only_fields = None
284
285
 
285
286
  default_display_modes = None
287
+ """
288
+ Which :term:`display mode` to use in a :term:`slave panel`,
289
+ depending on available width.
290
+
291
+ See :ref:`dg.table.default_display_modes`.
292
+ """
286
293
 
287
294
  # extra_display_modes = set()
288
295
  # extra_display_modes = {constants.DISPLAY_MODE_SUMMARY}
@@ -432,11 +439,13 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
432
439
  detail_layout = None
433
440
  insert_layout = None
434
441
  card_layout = None
435
- list_layout = None
442
+ list_layout = None # no longer used
436
443
 
437
444
  detail_template = None # deprecated: use insert_layout instead
438
445
  insert_template = None # deprecated: use detail_layout instead
439
446
 
447
+ row_template = "{row}"
448
+
440
449
  help_text = None
441
450
  detail_action = None
442
451
  update_action = None
@@ -502,6 +511,14 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
502
511
  def is_installed(self):
503
512
  return settings.SITE.is_installed(self.app_label)
504
513
 
514
+ @classmethod
515
+ def before_group_change(cls, gh, row):
516
+ return SAFE_EMPTY
517
+
518
+ @classmethod
519
+ def after_group_change(cls, gh, row):
520
+ return SAFE_EMPTY
521
+
505
522
  @classmethod
506
523
  def is_hidden(self):
507
524
  return settings.SITE.is_hidden_plugin(self.app_label)
@@ -706,8 +723,10 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
706
723
  pass
707
724
 
708
725
  @classmethod
709
- def row_as_summary(cls, ar, obj, *args, **kwargs):
710
- return obj.as_summary_item(ar, *args, **kwargs)
726
+ def row_as_summary(cls, ar, obj, text=None, **kwargs):
727
+ if ar is None:
728
+ return text or str(obj)
729
+ return obj.as_summary_item(ar, text, **kwargs)
711
730
 
712
731
  @classmethod
713
732
  def do_setup(self):
@@ -817,7 +836,7 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
817
836
  window_size=(cls.insert_layout_width, "auto"),
818
837
  )
819
838
  actions.install_layout(cls, "card_layout", layouts.DetailLayout)
820
- actions.install_layout(cls, "list_layout", layouts.DetailLayout)
839
+ # actions.install_layout(cls, "list_layout", layouts.DetailLayout)
821
840
 
822
841
  cls.extra_layouts = dict()
823
842
  for name, main in cls.get_extra_layouts():
@@ -1775,37 +1794,37 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1775
1794
  for k, pf in self.parameters.items():
1776
1795
  # if not isinstance(pf, fields.DummyField):
1777
1796
  kw[k] = pf.get_default()
1797
+ if self.model is not None:
1798
+ kw = self.model.param_defaults(ar, **kw)
1778
1799
  return kw
1779
1800
 
1780
1801
  @classmethod
1781
- def request(self, *args, **kw):
1782
- """
1783
- Return an action request on this actor.
1784
- """
1785
- kw.update(actor=self)
1786
- from lino.core.requests import ActionRequest
1787
- return ActionRequest(*args, **kw)
1802
+ def request(cls, master_instance=None, **kwargs):
1803
+ """Return a new :class:`ActionRequest
1804
+ <lino.core.requests.ActionRequest>` on this actor.
1788
1805
 
1789
- @classmethod
1790
- def request_from(cls, ar, *args, **kwargs):
1791
- """
1792
- Return an action request on this actor which inherits from the
1793
- given parent request.
1806
+ The :attr:`master_instance
1807
+ <lino.core.requests.ActionRequest.master_instance>` can be
1808
+ specified as optional first positional argument.
1794
1809
 
1795
- Deprecated. Rather call cls.request(parent=ar)
1796
1810
  """
1797
- raise Exception(
1798
- "Deprecated (Actor.request_from). Rather call cls.request(parent=ar)"
1799
- )
1800
- # logger.warning("Deprecated (Actor.request_from). Rather call cls.request(parent=ar)")
1801
- sar = cls.request(*args, **kwargs)
1802
- sar.setup_from(ar)
1803
- return sar
1811
+ from lino.core.requests import ActionRequest
1812
+ kwargs.update(actor=cls)
1813
+ kwargs.setdefault("action", cls.default_action)
1814
+ if master_instance is not None:
1815
+ kwargs.update(master_instance=master_instance)
1816
+ # kw.setdefault("renderer", settings.SITE.kernel.text_renderer)
1817
+ return ActionRequest(**kwargs)
1818
+
1819
+ # @classmethod
1820
+ # def show(cls, master_instance=None, renderer=None, **kwargs):
1821
+ # if renderer is None:
1822
+ # renderer = settings.SITE.kernel.text_renderer
1823
+ # ar = cls.request(master_instance, renderer=renderer)
1824
+ # ar.show(**kwargs)
1804
1825
 
1805
1826
  @classmethod
1806
1827
  def to_html(self, **kw):
1807
- """ """
1808
- # ~ settings.SITE.startup()
1809
1828
  return tostring(self.request(**kw).table2xhtml())
1810
1829
 
1811
1830
  @classmethod
@@ -1828,7 +1847,7 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1828
1847
  # print(f"20240914 slave_as_html() {ar.request}")
1829
1848
 
1830
1849
  # 20240911 We don't want to re-parse the original request, especially
1831
- # because it might contain disturbing things like selected_pks. But he
1850
+ # because it might contain disturbing things like selected_pks. But the
1832
1851
  # slave must at least inherit the user, as shown in
1833
1852
  # welfare/docs/specs/weleup/weleup1r.rst
1834
1853
  # kwargs.update(request=ar.request)
@@ -1836,15 +1855,12 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1836
1855
  kwargs.update(renderer=settings.SITE.kernel.default_renderer)
1837
1856
  try:
1838
1857
  ar = cls.request(master_instance=master, **kwargs)
1839
- el = ar.table2xhtml()
1840
- toolbar = ar.plain_toolbar_buttons()
1858
+ el = cls.table_as_html(ar)
1841
1859
  except Exception as e:
1842
1860
  msg = f"20241004 Error in {repr(ar)}: {e}"
1843
1861
  raise Exception(msg) from e
1844
1862
  logger.warning(msg)
1845
1863
  return msg
1846
- if len(toolbar):
1847
- el = E.div(el, E.p(*toolbar))
1848
1864
  return el
1849
1865
 
1850
1866
  # summary_sep = "<br/>"
@@ -1854,7 +1870,8 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1854
1870
  def get_table_as_list(cls, obj, ar):
1855
1871
  # raise Exception("20240316")
1856
1872
  sar = cls.request(parent=ar, master_instance=obj, is_on_main_actor=False)
1857
- html_text = mark_safe("")
1873
+ grp = Grouper(sar)
1874
+ html_text = grp.begin()
1858
1875
  for i, obj in enumerate(sar.data_iterator):
1859
1876
  if i == cls.preview_limit:
1860
1877
  break
@@ -1870,7 +1887,10 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1870
1887
  # else: # a funny way to debug:
1871
1888
  # par = '<a href="{}">{}</a>'.format(str(sar.renderer), par)
1872
1889
 
1890
+ html_text += grp.before_row(obj)
1873
1891
  html_text += par
1892
+ html_text += grp.after_row(obj)
1893
+ html_text += grp.stop()
1874
1894
 
1875
1895
  if cls.editable and cls.insert_action is not None:
1876
1896
  ir = cls.insert_action.request_from(sar)
@@ -1884,7 +1904,7 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1884
1904
  @classmethod
1885
1905
  def get_table_story(cls, obj, ar):
1886
1906
  sar = cls.request(parent=ar, master_instance=obj, is_on_main_actor=False)
1887
- html = mark_safe("")
1907
+ html = SAFE_EMPTY
1888
1908
  for i, obj in enumerate(sar.data_iterator):
1889
1909
  if i == cls.preview_limit:
1890
1910
  break
@@ -1901,7 +1921,7 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1901
1921
  return html
1902
1922
 
1903
1923
  @classmethod
1904
- def get_table_summary(cls, obj, ar):
1924
+ def get_table_summary(cls, obj, ar=None):
1905
1925
  """
1906
1926
  Return the HTML `<div>` to be displayed by
1907
1927
  :class:`lino.core.elems.TableSummaryPanel`.
@@ -1952,6 +1972,21 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1952
1972
  p += tostring(b) + btn_sep
1953
1973
  return p
1954
1974
 
1975
+ @classmethod
1976
+ def table_as_html(cls, ar):
1977
+ """
1978
+ Return an ElementTree element that represents the given action
1979
+ request `ar` on this actor in :term:`display mode` "HTML".
1980
+
1981
+ An :term:`application developer` may override this method. Usage example
1982
+ is :class:`lino_prima.lib.prima.PupilsAndProjects`.
1983
+
1984
+ """
1985
+ el = ar.table2xhtml()
1986
+ if len(toolbar := ar.plain_toolbar_buttons()):
1987
+ el = E.div(el, E.p(*toolbar))
1988
+ return el
1989
+
1955
1990
  @classmethod
1956
1991
  def columns_to_paragraph(cls, self, ar=None, fmt=None):
1957
1992
  """
lino/core/choicelists.py CHANGED
@@ -246,9 +246,9 @@ Django creates copies of them when inheriting models.
246
246
  def get_chooser_for_field(cls, fieldname):
247
247
  return None
248
248
 
249
- def as_summary_item(self, ar, *args, **kwargs):
249
+ def as_summary_item(self, ar, text=None, **kwargs):
250
250
  # needed by `detail_pointer`
251
- return str(self)
251
+ return text or str(self)
252
252
 
253
253
 
254
254
  class UnresolvedValue(Choice):
lino/core/dashboard.py CHANGED
@@ -5,6 +5,7 @@
5
5
 
6
6
  """
7
7
 
8
+ from django.conf import settings
8
9
  from lino.api import _
9
10
  from lino.core.permissions import Permittable
10
11
  from lino.core.requests import ActionRequest
@@ -148,7 +149,7 @@ class ActorItem(DashboardItem):
148
149
  # from lino.core.tables import AbstractTable
149
150
  T = self.actor
150
151
  # if isinstance(T, AbstractTable):
151
- sar = T.request(limit=T.preview_limit, parent=ar)
152
+ sar = T.request(limit=T.preview_limit, parent=ar) #, renderer=settings.SITE.kernel.default_renderer)
152
153
  # sar = ar.spawn(T, limit=T.preview_limit)
153
154
  # sar = ar.spawn_request(actor=T, limit=T.preview_limit)
154
155
  # raise Exception("20230331 {}".format(ar.subst_user))
lino/core/dbtables.py CHANGED
@@ -201,26 +201,26 @@ class Table(AbstractTable):
201
201
  """If when in a detail view will override default param values with the detail's pv values.
202
202
  """
203
203
 
204
- react_responsive = True
205
- """If viewing the grid view on a mobile, should the grid use responsive mode
206
- Default: True"""
204
+ # react_responsive = True
205
+ # """If viewing the grid view on a mobile, should the grid use responsive mode
206
+ # Default: True"""
207
207
 
208
208
  # react_big_search = False
209
209
  """If True will position the quick search input to the bottom of the header and have it full width.
210
210
  Default: False"""
211
211
 
212
- @classmethod
213
- def init_layouts(cls):
214
- if cls.model is not None and issubclass(cls.model, Model):
215
- if not cls.abstract:
216
- for tbl in cls.__mro__:
217
- # print("20210629", tbl)
218
- if "list_layout" in tbl.__dict__:
219
- break
220
- if issubclass(tbl, actors.Actor):
221
- cls.list_layout = "list_item"
222
- break
223
- super().init_layouts()
212
+ # @classmethod
213
+ # def init_layouts(cls):
214
+ # if cls.model is not None and issubclass(cls.model, Model):
215
+ # if not cls.abstract:
216
+ # for tbl in cls.__mro__:
217
+ # # print("20210629", tbl)
218
+ # if "list_layout" in tbl.__dict__:
219
+ # break
220
+ # if issubclass(tbl, actors.Actor):
221
+ # cls.list_layout = "list_item"
222
+ # break
223
+ # super().init_layouts()
224
224
 
225
225
  @classmethod
226
226
  def add_quick_search_filter(cls, qs, search_text):
lino/core/elems.py CHANGED
@@ -671,7 +671,7 @@ class FieldElement(LayoutElement):
671
671
  return kw
672
672
 
673
673
  def ext_options(self, **kw):
674
- kw = LayoutElement.ext_options(self, **kw)
674
+ kw = super().ext_options(**kw)
675
675
  kw.update(self.get_field_options())
676
676
  return kw
677
677
 
@@ -1565,6 +1565,10 @@ class BooleanDisplayElement(DisplayElement):
1565
1565
  # kw.update(always_enabled=True)
1566
1566
  FieldElement.__init__(self, *args, **kw)
1567
1567
 
1568
+ def value2html(self, ar, v, **cellattrs):
1569
+ txt = self.format_value(ar, v)
1570
+ return E.td(txt, **cellattrs)
1571
+
1568
1572
 
1569
1573
  class BooleanFieldElement(FieldElement):
1570
1574
  value_template = "new Ext.form.Checkbox(%s)"
@@ -2534,7 +2538,7 @@ class TabPanel(Panel):
2534
2538
  # self.reactive_elem_name = actor.reactive_elem_name
2535
2539
  # super().__init__(lh, actor, **kw)
2536
2540
 
2537
- _FIELD2ELEM = (
2541
+ _FIELD2ELEM = [
2538
2542
  # (dd.Constant, ConstantElement),
2539
2543
  (fields.RecurrenceField, RecurrenceElement),
2540
2544
  (fields.DelayedHtmlBox, DisplayElement),
@@ -2555,7 +2559,7 @@ _FIELD2ELEM = (
2555
2559
  (models.JSONField, CharFieldElement), # workaround
2556
2560
  (fields.PasswordField, PasswordFieldElement),
2557
2561
  (models.CharField, CharFieldElement),
2558
- (fields.MeasurementField, CharFieldElement),
2562
+ # (fields.MeasurementField, CharFieldElement),
2559
2563
  (fields.MonthField, MonthFieldElement),
2560
2564
  (models.DateTimeField, DateTimeFieldElement),
2561
2565
  (fields.DatePickerField, DatePickerFieldElement),
@@ -2569,7 +2573,7 @@ _FIELD2ELEM = (
2569
2573
  (models.NullBooleanField, BooleanFieldElement),
2570
2574
  # (models.ManyToManyField, M2mGridElement),
2571
2575
  (models.ForeignKey, ForeignKeyElement),
2572
- )
2576
+ ]
2573
2577
 
2574
2578
  TRIGGER_BUTTON_WIDTH = 3
2575
2579
 
lino/core/fields.py CHANGED
@@ -1264,6 +1264,10 @@ class TableRow(object):
1264
1264
  """
1265
1265
  return []
1266
1266
 
1267
+ @classmethod
1268
+ def param_defaults(self, ar, **kw):
1269
+ return kw
1270
+
1267
1271
  @classmethod
1268
1272
  def get_title_tags(self, ar):
1269
1273
  return []
@@ -1353,6 +1357,8 @@ class TableRow(object):
1353
1357
 
1354
1358
  @htmlbox()
1355
1359
  def list_item(self, ar):
1360
+ if ar is None:
1361
+ return escape(str(self))
1356
1362
  return self.as_paragraph(ar)
1357
1363
 
1358
1364
  def get_overview_elems(self, ar):
@@ -1363,9 +1369,15 @@ class TableRow(object):
1363
1369
  # must return an ET element
1364
1370
  if ar is None:
1365
1371
  return text or str(self)
1372
+ if text is None and ar.actor is not None:
1373
+ text = ar.actor.row_template.format(row=self)
1374
+ # raise Exception("20241029")
1366
1375
  return ar.obj2html(self, text, **kwargs)
1367
1376
 
1368
1377
  def as_paragraph(self, ar, **kwargs):
1378
+ # must return a safe html string
1379
+ if ar is None:
1380
+ return escape(str(self))
1369
1381
  return tostring(self.as_summary_item(ar, **kwargs))
1370
1382
 
1371
1383
  def as_story_item(self, ar, **kwargs):
@@ -1752,6 +1764,3 @@ def choices_for_field(ar, holder, field):
1752
1764
  else:
1753
1765
  raise http.Http404("No choices for %s" % field)
1754
1766
  return (qs, row2dict)
1755
-
1756
-
1757
- from lino_xl.lib.measurements.fields import MeasurementField
lino/core/inject.py CHANGED
@@ -111,15 +111,22 @@ def check_pending_injects(sender, models_list=None, **kw):
111
111
  # raise Exception(20150304)
112
112
  # called from kernel.analyze_models()
113
113
  # ~ logger.info("20130212 check_pending_injects()...")
114
+ # if PENDING_INJECTS:
115
+ # for spec, todos in PENDING_INJECTS.items():
116
+ # model = resolve_model(spec, strict=True)
117
+ # if todos is not None:
118
+ # for func, caller in todos:
119
+ # func(model)
120
+
114
121
  if PENDING_INJECTS:
115
122
  msg = ""
116
- for spec, funcs in list(PENDING_INJECTS.items()):
123
+ for spec, funcs in PENDING_INJECTS.items():
117
124
  msg += spec + ": "
118
125
  msg += ", ".join([fmt(f) for f in funcs])
119
126
  # ~ msg += '\n'.join([str(dir(func)) for func in funcs])
120
127
  # ~ msg += '\n'.join([str(func.func_code.co_consts) for func in funcs])
121
128
  # ~ msg += str(funcs)
122
- raise Exception("Oops, there are pending injects: %s" % msg)
129
+ raise Exception(f"Oops, there are pending injects: {msg}")
123
130
  # ~ logger.warning("pending injects: %s", msg)
124
131
 
125
132
  # ~ logger.info("20131110 no pending injects")
lino/core/kernel.py CHANGED
@@ -298,8 +298,11 @@ class Kernel(object):
298
298
  # if f.__class__ is models.CharField and f.null:
299
299
  # msg = "Nullable CharField %s in %s" % (f.name, model)
300
300
  # raise Exception(msg)
301
+
301
302
  if isinstance(f, models.ForeignKey):
303
+ # f.remote_field.model = resolve_model(f.remote_field.model)
302
304
  if isinstance(f.remote_field.model, str):
305
+ # models_list = [f"{m}({m._meta.abstract})".format(m) for m in models_list]
303
306
  raise Exception(
304
307
  "Could not resolve target %r of "
305
308
  "ForeignKey '%s' in %s "
@@ -308,12 +311,10 @@ class Kernel(object):
308
311
  )
309
312
 
310
313
  set_default_verbose_name(f)
311
- """
312
- If JobProvider is an MTI child of Company,
313
- then mti.delete_child(JobProvider) must not fail on a
314
- JobProvider being referred only by objects that can refer
315
- to a Company as well.
316
- """
314
+ # If JobProvider is an MTI child of Company,
315
+ # then mti.delete_child(JobProvider) must not fail on a
316
+ # JobProvider being referred only by objects that can refer
317
+ # to a Company as well.
317
318
  if not hasattr(f.remote_field.model, "_lino_ddh"):
318
319
  msg = "20150824 {1} (needed by {0}) " "has no _lino_ddh"
319
320
  raise Exception(
@@ -867,7 +868,7 @@ class Kernel(object):
867
868
  every actor handle because it potentially requires other actor
868
869
  handles to be instantiated.
869
870
 
870
- ar is usually None, except for actors with dynamic handle
871
+ `ar` is usually None, except for actors with dynamic handle
871
872
  """
872
873
  # logger.info('20121010 Kernel.setup_handle() %s', h.actor)
873
874
 
@@ -877,10 +878,9 @@ class Kernel(object):
877
878
 
878
879
  if isinstance(h, tables.TableHandle):
879
880
  he = set(h.actor.hidden_columns | h.actor.hidden_elements)
880
- gl = layouts.ColumnsLayout(
881
- h.actor.get_column_names(ar), h.actor, hidden_elements=he
882
- )
883
- h.grid_layout = gl.get_layout_handle()
881
+ cl = layouts.ColumnsLayout(
882
+ h.actor.get_column_names(ar), h.actor, hidden_elements=he)
883
+ h.grid_layout = cl.get_layout_handle()
884
884
  else:
885
885
  h.grid_layout = None
886
886
 
lino/core/layouts.py CHANGED
@@ -785,7 +785,7 @@ class ColumnsLayout(FieldLayout):
785
785
  def set_datasource(self, ds):
786
786
  if ds is None:
787
787
  raise Exception("20130327 No datasource for %r" % self)
788
- super(ColumnsLayout, self).set_datasource(ds)
788
+ super().set_datasource(ds)
789
789
 
790
790
 
791
791
  class ParamsLayout(BaseLayout):