lino 25.3.0__py3-none-any.whl → 25.3.2__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 (73) hide show
  1. lino/__init__.py +6 -7
  2. lino/api/dd.py +1 -0
  3. lino/api/doctest.py +35 -102
  4. lino/api/rt.py +2 -4
  5. lino/core/actors.py +22 -16
  6. lino/core/boundaction.py +17 -7
  7. lino/core/dashboard.py +5 -4
  8. lino/core/dbtables.py +15 -16
  9. lino/core/fields.py +3 -3
  10. lino/core/inject.py +7 -6
  11. lino/core/kernel.py +0 -46
  12. lino/core/menus.py +1 -1
  13. lino/core/model.py +18 -16
  14. lino/core/plugin.py +4 -4
  15. lino/core/renderer.py +10 -11
  16. lino/core/requests.py +11 -7
  17. lino/core/site.py +84 -30
  18. lino/core/tables.py +2 -2
  19. lino/core/utils.py +3 -3
  20. lino/core/views.py +3 -3
  21. lino/help_texts.py +1 -0
  22. lino/management/commands/buildsite.py +57 -0
  23. lino/management/commands/initdb.py +12 -14
  24. lino/management/commands/prep.py +1 -1
  25. lino/mixins/sequenced.py +1 -1
  26. lino/modlib/comments/models.py +1 -1
  27. lino/modlib/comments/ui.py +2 -2
  28. lino/modlib/extjs/ext_renderer.py +2 -2
  29. lino/modlib/extjs/views.py +50 -48
  30. lino/modlib/help/config/makehelp/model.tpl.rst +1 -1
  31. lino/modlib/help/management/commands/makehelp.py +11 -7
  32. lino/modlib/jinja/mixins.py +2 -2
  33. lino/modlib/jinja/renderer.py +2 -2
  34. lino/modlib/linod/management/commands/linod.py +5 -2
  35. lino/modlib/linod/mixins.py +3 -0
  36. lino/modlib/memo/__init__.py +1 -1
  37. lino/modlib/printing/mixins.py +3 -0
  38. lino/modlib/publisher/choicelists.py +3 -3
  39. lino/modlib/publisher/views.py +2 -2
  40. lino/modlib/search/models.py +5 -5
  41. lino/modlib/system/choicelists.py +6 -3
  42. lino/modlib/tinymce/views.py +1 -1
  43. lino/modlib/uploads/models.py +7 -6
  44. lino/modlib/users/ui.py +2 -3
  45. lino/utils/__init__.py +4 -1
  46. lino/utils/diag.py +1 -1
  47. lino/utils/fieldutils.py +79 -0
  48. {lino-25.3.0.dist-info → lino-25.3.2.dist-info}/METADATA +1 -1
  49. {lino-25.3.0.dist-info → lino-25.3.2.dist-info}/RECORD +52 -71
  50. lino/sandbox/bcss/PerformInvestigation.py +0 -2260
  51. lino/sandbox/bcss/SSDNReply.py +0 -3924
  52. lino/sandbox/bcss/SSDNRequest.py +0 -3723
  53. lino/sandbox/bcss/__init__.py +0 -0
  54. lino/sandbox/bcss/readme.txt +0 -1
  55. lino/sandbox/bcss/test.py +0 -92
  56. lino/sandbox/bcss/test2.py +0 -128
  57. lino/sandbox/bcss/test3.py +0 -161
  58. lino/sandbox/bcss/test4.py +0 -167
  59. lino/sandbox/contacts/__init__.py +0 -0
  60. lino/sandbox/contacts/fixtures/__init__.py +0 -0
  61. lino/sandbox/contacts/fixtures/demo.py +0 -365
  62. lino/sandbox/contacts/manage.py +0 -10
  63. lino/sandbox/contacts/models.py +0 -395
  64. lino/sandbox/contacts/settings.py +0 -67
  65. lino/sandbox/tx25/XSD/RetrieveTIGroupsV3.wsdl +0 -65
  66. lino/sandbox/tx25/XSD/RetrieveTIGroupsV3.xsd +0 -286
  67. lino/sandbox/tx25/XSD/rn25_Release201104.xsd +0 -2855
  68. lino/sandbox/tx25/xsd2py1.py +0 -68
  69. lino/sandbox/tx25/xsd2py2.py +0 -62
  70. lino/sandbox/tx25/xsd2py3.py +0 -56
  71. {lino-25.3.0.dist-info → lino-25.3.2.dist-info}/WHEEL +0 -0
  72. {lino-25.3.0.dist-info → lino-25.3.2.dist-info}/licenses/AUTHORS.rst +0 -0
  73. {lino-25.3.0.dist-info → lino-25.3.2.dist-info}/licenses/COPYING +0 -0
lino/core/model.py CHANGED
@@ -534,6 +534,7 @@ class Model(models.Model, fields.TableRow):
534
534
  """
535
535
  watcher = ChangeWatcher(row)
536
536
  # assert hasattr(row, state_field.attname)
537
+ row.before_ui_save(ar, watcher) # added 20250312 for #5976
537
538
  old = getattr(row, state_field.attname)
538
539
  target_state.choicelist.before_state_change(row, ar, old, target_state)
539
540
  row.before_state_change(ar, old, target_state)
@@ -603,7 +604,7 @@ class Model(models.Model, fields.TableRow):
603
604
  database query and show this value as the search result.
604
605
 
605
606
  """
606
- ar = self.__class__.get_default_table().request()
607
+ ar = self.__class__.get_default_table().create_request()
607
608
  return self.as_search_item(ar)
608
609
 
609
610
  # def summary_row(self, ar, **kw):
@@ -680,21 +681,22 @@ class Model(models.Model, fields.TableRow):
680
681
 
681
682
  df = actor.get_disabled_fields(obj, ar)
682
683
  # print(20170909, df)
683
- for ba in actor.get_actions():
684
- assert ba.actor == actor # 20170102
685
- if ba.action.show_in_workflow:
686
- # if actor.model.__name__ == 'Vote':
687
- # if ba.action.__class__.__name__ == 'MarkVoteAssigned':
688
- # print(20170115, actor, ar.get_user())
689
- if ba.action.action_name not in df:
690
- if actor.get_row_permission(obj, ar, state, ba):
691
- if show and isinstance(ba.action, ChangeStateAction):
692
- show_state()
693
- sep = " \u2192 " # "→"
694
- show = False
695
- l.append(sep)
696
- l.append(ar.action_button(ba, obj))
697
- sep = " "
684
+ if 'workflow_buttons' not in df:
685
+ for ba in actor.get_actions():
686
+ assert ba.actor == actor # 20170102
687
+ if ba.action.show_in_workflow:
688
+ # if actor.model.__name__ == 'Vote':
689
+ # if ba.action.__class__.__name__ == 'MarkVoteAssigned':
690
+ # print(20170115, actor, ar.get_user())
691
+ if ba.action.action_name not in df:
692
+ if actor.get_row_permission(obj, ar, state, ba):
693
+ if show and isinstance(ba.action, ChangeStateAction):
694
+ show_state()
695
+ sep = " \u2192 " # "→"
696
+ show = False
697
+ l.append(sep)
698
+ l.append(ar.action_button(ba, obj))
699
+ sep = " "
698
700
  if state and show:
699
701
  show_state()
700
702
  return E.span(*l)
lino/core/plugin.py CHANGED
@@ -1,10 +1,9 @@
1
1
  # -*- coding: UTF-8 -*-
2
- # Copyright 2008-2024 Rumma & Ko Ltd
2
+ # Copyright 2008-2025 Rumma & Ko Ltd
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
 
5
- import os
6
5
  import inspect
7
- from os.path import exists, join, dirname, isdir, abspath
6
+ from os.path import join, dirname, isdir, abspath
8
7
  from collections.abc import Iterable
9
8
  from urllib.parse import urlencode
10
9
  from lino.core.exceptions import ChangedAPI
@@ -56,7 +55,8 @@ class Plugin:
56
55
 
57
56
  def hide(self):
58
57
  if self.site._startup_done:
59
- raise Exception("Tried to deactivate plugin {} after startup".format(self))
58
+ raise Exception(
59
+ "Tried to deactivate plugin {} after startup".format(self))
60
60
  self.hidden = True
61
61
 
62
62
  def configure(self, **kw):
lino/core/renderer.py CHANGED
@@ -197,7 +197,7 @@ class HtmlRenderer(Renderer):
197
197
  import rstgen
198
198
 
199
199
  if display_mode == constants.DISPLAY_MODE_CARDS:
200
- layout = ar.actor.card_layout # or ar.actor.list_layout
200
+ layout = ar.actor.card_layout # or ar.actor.list_layout
201
201
  lh = layout.get_layout_handle()
202
202
  else:
203
203
  lh = ar.bound_action.get_layout_handel()
@@ -320,13 +320,12 @@ class HtmlRenderer(Renderer):
320
320
  Return a string of Javascript code that would open a detail window
321
321
  on the given database object.
322
322
  """
323
- status.update(record_id=obj.pk)
324
-
325
323
  if ba is None:
326
324
  ba = obj.get_detail_action(ar)
327
325
  # ba = obj.__class__.get_default_table().detail_action
328
- # print(20180831, ba.get_view_permission(ar.get_user().user_type))
329
326
  if ba is not None:
327
+ # print(f"20250319 instance_handler {ba} {status} {self.action_call}")
328
+ status.update(record_id=obj.pk)
330
329
  return self.action_call(ar, ba, status)
331
330
 
332
331
  def href_to(self, ar, obj, text=None):
@@ -641,7 +640,7 @@ class HtmlRenderer(Renderer):
641
640
  # 20200501 elems.append(item)
642
641
  elems.append(tostring(item))
643
642
  elif isinstance(item, type) and issubclass(item, Actor):
644
- ar = item.default_action.request(parent=ar)
643
+ ar = item.default_action.create_request(parent=ar)
645
644
  # 20200501 elems.extend(self.table2story(ar, **kwargs))
646
645
  elems += [tostring(e) for e in self.table2story(ar, **kwargs)]
647
646
  elif isinstance(item, ActionRequest):
@@ -649,12 +648,12 @@ class HtmlRenderer(Renderer):
649
648
  if issubclass(item.actor, AbstractTable):
650
649
  # 20200501 elems.extend(self.table2story(item, **kwargs))
651
650
  elems += [tostring(e)
652
- for e in self.table2story(item, **kwargs)]
651
+ for e in self.table2story(item, **kwargs)]
653
652
  else:
654
653
  # example : courses.StatusReport in dashboard
655
654
  # 20200501 elems.append(self.show_story(ar, item.actor.get_story(None, ar), **kwargs))
656
655
  elems += [tostring(e)
657
- for e in self.show_story(
656
+ for e in self.show_story(
658
657
  ar, item.actor.get_story(None, ar), **kwargs)]
659
658
  elif isinstance(item, DashboardItem):
660
659
  elems.extend(item.render(ar, **kwargs))
@@ -707,7 +706,7 @@ class HtmlRenderer(Renderer):
707
706
  if not isinstance(mnu, Menu):
708
707
  assert isinstance(mnu, MenuItem)
709
708
  if mnu.bound_action:
710
- sar = mnu.bound_action.actor.request(
709
+ sar = mnu.bound_action.actor.create_request(
711
710
  action=mnu.bound_action,
712
711
  user=ar.user,
713
712
  subst_user=ar.subst_user,
@@ -812,7 +811,7 @@ class TextRenderer(HtmlRenderer):
812
811
  header_links=None,
813
812
  nosummary=False,
814
813
  stripped=True,
815
- show_links=False, # added 20241031
814
+ show_links=False, # added 20241031
816
815
  display_mode=None,
817
816
  **kwargs
818
817
  ):
@@ -938,7 +937,7 @@ class TextRenderer(HtmlRenderer):
938
937
  if iselement(item):
939
938
  print(to_rst(item, stripped))
940
939
  elif isinstance(item, type) and issubclass(item, Actor):
941
- ar = item.default_action.request(parent=ar)
940
+ ar = item.default_action.create_request(parent=ar)
942
941
  self.show_table(ar, stripped=stripped, **kwargs)
943
942
  elif isinstance(item, DashboardItem):
944
943
  self.show_story(ar, item.get_story(ar), stripped, **kwargs)
@@ -1029,7 +1028,7 @@ class JsRenderer(HtmlRenderer):
1029
1028
  """Instruct the client to display a detail window on the given
1030
1029
  record.
1031
1030
  """
1032
- # print("20201230a goto_instance", ar.actor, detail_action)
1031
+ # print("20250319 goto_instance", ar.get_user(), obj, detail_action, js)
1033
1032
  js = self.instance_handler(ar, obj, detail_action)
1034
1033
  kw.update(eval_js=js)
1035
1034
  ar.set_response(**kw)
lino/core/requests.py CHANGED
@@ -783,14 +783,14 @@ class BaseRequest:
783
783
  spec.setup_from(self)
784
784
  elif isinstance(spec, BoundAction):
785
785
  kw.update(parent=self)
786
- spec = spec.request(**kw)
786
+ spec = spec.create_request(**kw)
787
787
  else:
788
788
  kw.update(parent=self)
789
789
  ba = resolve_action(spec)
790
- spec = ba.request(**kw)
790
+ spec = ba.create_request(**kw)
791
791
  # from lino.core.menus import create_item
792
792
  # mi = create_item(spec)
793
- # spec = mi.bound_action.request(**kw)
793
+ # spec = mi.bound_action.create_request(**kw)
794
794
  return spec
795
795
 
796
796
  def get_printable_context(self, **kw):
@@ -1011,10 +1011,14 @@ class BaseRequest:
1011
1011
  # # deprecated?
1012
1012
  # self.append_message('warning', msg, *args, **kw)
1013
1013
 
1014
- debug = lambda self, *args, **kwargs: self.logger.debug(*args, **kwargs)
1015
- info = lambda self, *args, **kwargs: self.logger.info(*args, **kwargs)
1016
- warning = lambda self, * \
1017
- args, **kwargs: self.logger.warning(*args, **kwargs)
1014
+ def debug(self, *args, **kwargs):
1015
+ return self.logger.debug(*args, **kwargs)
1016
+
1017
+ def info(self, *args, **kwargs):
1018
+ return self.logger.info(*args, **kwargs)
1019
+
1020
+ def warning(self, *args, **kwargs):
1021
+ return self.logger.warning(*args, **kwargs)
1018
1022
 
1019
1023
  async def adebug(self, *args, **kwargs):
1020
1024
  return await self.alogger.debug(*args, **kwargs)
lino/core/site.py CHANGED
@@ -3,17 +3,37 @@
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
  # doctest lino/core/site.py
5
5
 
6
+ import json
7
+ from lino.core.exceptions import ChangedAPI
8
+ from lino.core.utils import get_models, is_logserver
9
+ from lino.utils.html import E, tostring
10
+ from lino import assert_django_code, DJANGO_DEFAULT_LANGUAGE
11
+ # from lino.core import constants
12
+ from lino.core.plugin import Plugin
13
+ from lino.core.utils import full_model_name as fmn
14
+ from rstgen.confparser import ConfigParser
15
+ from django.utils import translation
16
+ from django.utils.html import mark_safe
17
+ from django.utils.translation import get_language
18
+ from django.utils.translation import gettext_lazy as _
19
+ from django.conf import settings
20
+ import rstgen
21
+ from lino.utils import AttrDict, date_offset, i2d, buildurl
22
+ from lino import logger, __version__
23
+ from importlib.util import find_spec
24
+ from importlib import import_module, reload
25
+ from pathlib import Path
6
26
  import os
7
27
  import re
8
28
  import sys
9
- from os.path import normpath, dirname, join, isdir, relpath, exists, abspath
29
+ from os.path import dirname, join, isdir, relpath, exists
10
30
  import inspect
11
31
  import datetime
12
32
  import warnings
13
33
  import collections
14
34
  import locale
15
35
  import logging
16
- from pprint import pprint
36
+ # from pprint import pprint
17
37
  from logging.handlers import SocketHandler
18
38
  import time
19
39
 
@@ -30,34 +50,12 @@ ASYNC_LOGGING = False
30
50
  # activated, accesses settings.DEFAULT_EXCEPTION_REPORTER, which fails at this
31
51
  # moment because the settings aren't yet loaded.
32
52
 
33
- from pathlib import Path
34
- from importlib import import_module, reload
35
- from importlib.util import find_spec
36
-
37
- from lino import logger, __version__
38
- from lino.utils import AttrDict, date_offset, i2d, buildurl
39
- import rstgen
40
-
41
- from django.conf import settings
42
- from django.utils.translation import gettext_lazy as _
43
- from django.utils.translation import get_language
44
- from django.utils.html import mark_safe
45
- from django.db.utils import DatabaseError
46
- from django.utils import translation
47
53
 
48
54
  has_socialauth = find_spec("social_django") is not None
49
55
  has_elasticsearch = find_spec("elasticsearch_django") is not None
50
56
  has_haystack = find_spec("haystack") is not None
51
57
 
52
- from rstgen.confparser import ConfigParser
53
- from lino.core.plugin import Plugin
54
- from lino.core import constants
55
-
56
- from lino import assert_django_code, DJANGO_DEFAULT_LANGUAGE
57
- from lino.utils.html import E, join_elems, tostring
58
- from lino.core.utils import get_models, is_logserver
59
58
 
60
- from lino.core.exceptions import ChangedAPI
61
59
  # from .roles import SiteUser
62
60
 
63
61
 
@@ -88,14 +86,14 @@ def to_locale(language):
88
86
  p = language.find("-")
89
87
  if p >= 0:
90
88
  # Get correct locale for sr-latn
91
- if len(language[p + 1 :]) > 2:
89
+ if len(language[p + 1:]) > 2:
92
90
  return (
93
91
  language[:p].lower()
94
92
  + "_"
95
93
  + language[p + 1].upper()
96
- + language[p + 2 :].lower()
94
+ + language[p + 2:].lower()
97
95
  )
98
- return language[:p].lower() + "_" + language[p + 1 :].upper()
96
+ return language[:p].lower() + "_" + language[p + 1:].upper()
99
97
  return language.lower()
100
98
 
101
99
 
@@ -103,7 +101,8 @@ def class2str(cl):
103
101
  return cl.__module__ + "." + cl.__name__
104
102
 
105
103
 
106
- gettext_noop = lambda s: s
104
+ def gettext_noop(s): return s
105
+
107
106
 
108
107
  PLUGIN_CONFIGS = {}
109
108
 
@@ -718,7 +717,6 @@ class Site(object):
718
717
  else:
719
718
  d["logger_ok"] = True
720
719
  # self.update_settings(LOGGING=d)
721
- # from pprint import pprint
722
720
  # pprint(d)
723
721
  # print("20161126 Site %s " % d['loggers'].keys())
724
722
  # import yaml
@@ -1796,6 +1794,61 @@ class Site(object):
1796
1794
  # ~ return v
1797
1795
  # ~ return getattr(obj,attrname,*args)
1798
1796
 
1797
+ def mark_virgin(self):
1798
+ """
1799
+ Mark the database as virgin. This is called by :manage:`prep`.
1800
+ """
1801
+ dbhash = self.get_dbhash()
1802
+ fn = self.site_dir / "dbhash.json"
1803
+ with fn.open("w") as fp:
1804
+ json.dump(dbhash, fp)
1805
+ # self.site.logger.info("Wrote %s", fn)
1806
+
1807
+ def check_virgin(self):
1808
+ """
1809
+ Verify whether the database is virgin. Print the differences if there
1810
+ are any.
1811
+ """
1812
+ new = self.get_dbhash()
1813
+ db = self.site_dir
1814
+ fn = db / "dbhash.json"
1815
+ if not fn.exists():
1816
+ raise Exception(
1817
+ f"No `dbhash.json` in {db} (did you run `django-admin prep`?)")
1818
+ with fn.open("r") as fp:
1819
+ old = json.load(fp)
1820
+
1821
+ # noi1r has noi1e as master_site, but the react front end removes the
1822
+ # tinymce plugin, i.e. noi1r doesn't care about
1823
+ # tinymce.TextFieldTemplate model.
1824
+
1825
+ ok = True
1826
+ for k, v in new.items():
1827
+ v = set(v)
1828
+ oldv = set(old.get(k, None))
1829
+ if oldv != v:
1830
+ if ok:
1831
+ print(f"Database {db} isn't virgin:")
1832
+ ok = False
1833
+ diffs = []
1834
+ if (added := len(oldv-v)):
1835
+ diffs.append(f"{added} rows added")
1836
+ if (removed := len(v-oldv)):
1837
+ diffs.append(f"{removed} rows removed")
1838
+ print(f"- {k}: {', '.join(diffs)}")
1839
+
1840
+ def get_dbhash(self):
1841
+ """
1842
+ Return a dictionary with a hash value of the current database content.
1843
+ """
1844
+ rv = dict()
1845
+ for m in get_models(include_auto_created=True):
1846
+ k = fmn(m)
1847
+ if k != "sessions.Session":
1848
+ # rv[k] = m.objects.count()
1849
+ rv[k] = list(m.objects.values_list('pk', flat=True))
1850
+ return rv
1851
+
1799
1852
  def diagnostic_report_rst(self, *args):
1800
1853
  """Returns a string with a diagnostic report about this
1801
1854
  site. :manage:`diag` is a command-line shortcut to this.
@@ -1992,7 +2045,8 @@ class Site(object):
1992
2045
  ):
1993
2046
  yield "social_django.middleware.SocialAuthExceptionMiddleware"
1994
2047
 
1995
- if False: # removed 20240921, see #5755 (Should we remove AjaxExceptionResponse?)
2048
+ # removed 20240921, see #5755 (Should we remove AjaxExceptionResponse?)
2049
+ if False:
1996
2050
  yield "lino.utils.ajax.AjaxExceptionResponse"
1997
2051
 
1998
2052
  if self.use_security_features:
lino/core/tables.py CHANGED
@@ -637,9 +637,9 @@ method in order to sort the rows of the queryset.
637
637
  ba = self.get_action_by_name(an)
638
638
  # ~ print ba
639
639
  if pk is None:
640
- ar = self.request(action=ba)
640
+ ar = self.create_request(action=ba)
641
641
  else:
642
- ar = self.request(action=ba, selected_pks=[pk])
642
+ ar = self.create_request(action=ba, selected_pks=[pk])
643
643
 
644
644
  ba.action.run_from_ui(ar)
645
645
  kw = ar.response
lino/core/utils.py CHANGED
@@ -17,7 +17,7 @@ from django.utils.html import format_html, mark_safe, SafeString
17
17
  from django.db import models
18
18
  from django.db.models import Q
19
19
  from django.core.exceptions import FieldDoesNotExist
20
- from django.utils.functional import lazy
20
+ # from django.utils.functional import lazy
21
21
  from importlib import import_module
22
22
  from django.utils.translation import gettext as _
23
23
  from django.conf import settings
@@ -1046,7 +1046,7 @@ class InstanceAction:
1046
1046
  """
1047
1047
  kwargs.update(selected_rows=[self.instance])
1048
1048
  kwargs.update(parent=ses)
1049
- ar = self.bound_action.request(**kwargs)
1049
+ ar = self.bound_action.create_request(**kwargs)
1050
1050
  return ar
1051
1051
 
1052
1052
  def run_from_session(self, ses, **kwargs):
@@ -1070,7 +1070,7 @@ class InstanceAction:
1070
1070
  """
1071
1071
  if len(args) and isinstance(args[0], BaseRequest):
1072
1072
  raise ChangedAPI("20181004")
1073
- ar = self.bound_action.request(
1073
+ ar = self.bound_action.create_request(
1074
1074
  renderer=settings.SITE.kernel.text_renderer)
1075
1075
  self.run_from_code(ar, *args, **kwargs)
1076
1076
  return ar.response
lino/core/views.py CHANGED
@@ -100,7 +100,7 @@ def action_request(app_label, actor, request, rqdata, is_list, **kw):
100
100
  # internationalized because some error handling code
101
101
  # may want to write it to a plain ascii stream.
102
102
  kw.update(renderer=settings.SITE.kernel.default_renderer)
103
- ar = rpt.request(request=request, action=a, rqdata=rqdata, **kw)
103
+ ar = rpt.create_request(request=request, action=a, rqdata=rqdata, **kw)
104
104
  # print("20210403b", a.action.__class__, rqdata)
105
105
  return ar
106
106
 
@@ -137,7 +137,7 @@ def choices_response(actor, request, qs, row2dict, emptyValue, field=None):
137
137
  count = qs.count()
138
138
 
139
139
  if offset:
140
- qs = qs[int(offset) :]
140
+ qs = qs[int(offset):]
141
141
  # ~ kw.update(offset=int(offset))
142
142
 
143
143
  if limit:
@@ -155,7 +155,7 @@ def choices_response(actor, request, qs, row2dict, emptyValue, field=None):
155
155
  row for row in rows if txt in row[constants.CHOICES_TEXT_FIELD].lower()
156
156
  ]
157
157
  count = len(rows)
158
- rows = rows[int(offset) :] if offset else rows
158
+ rows = rows[int(offset):] if offset else rows
159
159
  rows = rows[: int(limit)] if limit else rows
160
160
 
161
161
  if wt == constants.WINDOW_TYPE_PARAMS and field and field.blank:
lino/help_texts.py CHANGED
@@ -139,6 +139,7 @@ help_texts = {
139
139
  'lino.modlib.extjs.ext_renderer.ExtRenderer.goto_instance' : _("""See JsRenderer.goto_instance(), but when this is called while the detail window is already open (only on another record), then we don’t want to redirect to another page because that would take more time."""),
140
140
  'lino.modlib.extjs.views.AdminIndex' : _("""Similar to PlainIndex"""),
141
141
  'lino.modlib.extjs.views.Restful' : _("""Used to collaborate with a restful Ext.data.Store."""),
142
+ 'lino.modlib.extjs.views.ApiElement' : _("""The view that responds to r'api/(?P<app_label>\w+)/(?P<actor>\w+)/(?P<pk>[^/]+)$'."""),
142
143
  'lino.modlib.gfks.Plugin' : _("""Base class for this plugin."""),
143
144
  'lino.modlib.importfilters.Plugin' : _("""See /dev/plugins."""),
144
145
  'lino.modlib.jinja.Plugin' : _("""See /dev/plugins."""),
@@ -0,0 +1,57 @@
1
+ # -*- coding: UTF-8 -*-
2
+ # Copyright 2009-2023 Rumma & Ko Ltd.
3
+ # License: GNU Affero General Public License v3 (see file COPYING for details)
4
+
5
+ from click import confirm
6
+ from django.core.management.base import BaseCommand, CommandError
7
+ from django.core.management import call_command
8
+ from django.conf import settings
9
+ from lino import logger
10
+
11
+
12
+ class Command(BaseCommand):
13
+ """Run install, buildcache, collectstatic and makehelp after pull."""
14
+
15
+ def add_arguments(self, parser):
16
+ super().add_arguments(parser)
17
+ parser.add_argument(
18
+ "--noinput",
19
+ action="store_false",
20
+ dest="interactive",
21
+ default=True,
22
+ help="Do not prompt for input of any kind.",
23
+ ),
24
+
25
+ def handle(self, *args, **options):
26
+ interactive = options.get("interactive")
27
+ verbosity = options.get("verbosity")
28
+ project_dir = settings.SITE.project_dir
29
+
30
+ if interactive:
31
+ msg = "Build everything for ({})".format(project_dir)
32
+ msg += ".\nAre you sure?"
33
+ if not confirm(msg, default=True):
34
+ raise CommandError("User abort.")
35
+
36
+ # the following log message was useful on Travis 20150104
37
+ if verbosity > 0:
38
+ logger.info("`buildsite` started on %s.", project_dir)
39
+
40
+ pth = project_dir / "settings.py"
41
+ if pth.exists():
42
+ pth.touch()
43
+
44
+ options = dict(interactive=False, verbosity=verbosity)
45
+
46
+ call_command("install", **options)
47
+ call_command("collectstatic", **options)
48
+ call_command("buildcache", verbosity=verbosity)
49
+ if settings.SITE.is_installed("help"):
50
+ call_command("makehelp", verbosity=verbosity)
51
+
52
+ # for p in settings.SITE.installed_plugins:
53
+ # p.on_buildsite(settings.SITE, verbosity=verbosity)
54
+
55
+ settings.SITE.clear_site_config()
56
+
57
+ logger.info("`buildsite` finished on %s.", project_dir)
@@ -1,7 +1,16 @@
1
1
  # -*- coding: UTF-8 -*-
2
- # Copyright 2009-2023 Rumma & Ko Ltd.
2
+ # Copyright 2009-2025 Rumma & Ko Ltd.
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
 
5
+ from click import confirm
6
+ from lino.api import dd
7
+ from django.db import models
8
+ from django.db import connections, transaction, DEFAULT_DB_ALIAS
9
+ from django.core.management.color import no_style
10
+ from django.db.utils import IntegrityError, OperationalError
11
+ from django.core.management.base import BaseCommand, CommandError
12
+ from django.core.management import call_command
13
+ from django.conf import settings
5
14
  import os
6
15
  import shutil
7
16
  from pathlib import Path
@@ -22,20 +31,9 @@ warnings.filterwarnings(
22
31
  "django.core.management.commands.loaddata",
23
32
  )
24
33
 
25
- from django.conf import settings
26
- from django.core.management import call_command
27
- from django.core.management.base import BaseCommand, CommandError
28
- from django.db.utils import IntegrityError, OperationalError
29
- from django.db.migrations.exceptions import CircularDependencyError
30
- from django.core.management.color import no_style
31
34
 
32
35
  # ~ from django.core.management.sql import sql_reset
33
- from django.db import connections, transaction, DEFAULT_DB_ALIAS
34
- from django.db import models
35
-
36
- from lino.api import dd
37
36
 
38
- from rstgen.utils import confirm
39
37
 
40
38
  USE_SQLDELETE = True
41
39
 
@@ -198,8 +196,8 @@ class Command(BaseCommand):
198
196
  msg = "We are going to flush your database ({})".format(dbname)
199
197
  if removemedia:
200
198
  msg += "\nAND REMOVE ALL FILES BELOW {}".format(mroot)
201
- msg += ".\nAre you sure (y/n) ?"
202
- if not confirm(msg):
199
+ msg += ".\nAre you sure?"
200
+ if not confirm(msg, default=True):
203
201
  raise CommandError("User abort.")
204
202
 
205
203
  # mroot = Path(settings.MEDIA_ROOT)
@@ -66,4 +66,4 @@ class Command(BaseCommand):
66
66
  kwargs["removemedia"] = True
67
67
  call_command("initdb", *args, **kwargs)
68
68
 
69
- settings.SITE.kernel.mark_virgin()
69
+ settings.SITE.mark_virgin()
lino/mixins/sequenced.py CHANGED
@@ -524,7 +524,7 @@ class Hierarchical(Duplicable):
524
524
  et.append(ar.goto_pk(c.id, get_text(c)))
525
525
  i -= 1
526
526
  if child == self:
527
- sar = ar.actor.request(
527
+ sar = ar.actor.create_request(
528
528
  parent=ar, master_instance=self, is_on_main_actor=False
529
529
  )
530
530
  # sar = ar.spawn_request(master_instance=self, is_on_main_actor=False)
@@ -257,7 +257,7 @@ class Comment(
257
257
  return format_html("<p>{}</p>", s)
258
258
 
259
259
  htmls = storypar(self.as_paragraph(ar))
260
- for child in RepliesByComment.request(master_instance=self, parent=ar):
260
+ for child in RepliesByComment.create_request(master_instance=self, parent=ar):
261
261
  htmls += storypar(child.as_story_item(ar, indent=indent + 1))
262
262
  # if self.replies_to_this.count():
263
263
  # # s += "<p>{}</p>".format("Replies:")
@@ -129,7 +129,7 @@ class Comments(dd.Table):
129
129
  pv = dict(user=user, start_date=sd, end_date=ed,
130
130
  observed_event=CommentEvents.created)
131
131
  # pv = dict(start_date=sd, end_date=ed, observed_event=CommentEvents.created)
132
- return cls.request(user=user, param_values=pv)
132
+ return cls.create_request(user=user, param_values=pv)
133
133
 
134
134
  # @classmethod
135
135
  # def get_card_title(cls, ar, obj):
@@ -302,7 +302,7 @@ class RepliesByComment(CommentsByX):
302
302
 
303
303
 
304
304
  def comments_by_owner(obj):
305
- return CommentsByRFC.request(master_instance=obj)
305
+ return CommentsByRFC.create_request(master_instance=obj)
306
306
 
307
307
 
308
308
  class Reactions(dd.Table):
@@ -136,7 +136,7 @@ class ExtRenderer(JsCacheRenderer):
136
136
  return self.handler_item(v, js, None)
137
137
  elif v.bound_action is not None:
138
138
  if v.params:
139
- ar = v.bound_action.request(**v.params)
139
+ ar = v.bound_action.create_request(**v.params)
140
140
  js = self.request_handler(ar)
141
141
  # print("20230513", js)
142
142
  else:
@@ -265,7 +265,7 @@ class ExtRenderer(JsCacheRenderer):
265
265
 
266
266
  """
267
267
  if ar is None:
268
- sar = ba.request(**request_kwargs)
268
+ sar = ba.create_request(**request_kwargs)
269
269
  else:
270
270
  sar = ar.spawn(ba, **request_kwargs)
271
271
  return self.ar2js(sar, obj, **status)