lino 25.1.6__py3-none-any.whl → 25.2.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 (43) hide show
  1. lino/__init__.py +1 -1
  2. lino/core/actions.py +6 -0
  3. lino/core/actors.py +9 -3
  4. lino/core/callbacks.py +3 -2
  5. lino/core/elems.py +1 -1
  6. lino/core/fields.py +4 -0
  7. lino/core/keyboard.py +7 -2
  8. lino/core/model.py +1 -0
  9. lino/core/requests.py +19 -7
  10. lino/core/site.py +1 -2
  11. lino/core/store.py +2 -2
  12. lino/help_texts.py +3 -1
  13. lino/locale/bn/LC_MESSAGES/django.po +782 -710
  14. lino/locale/de/LC_MESSAGES/django.mo +0 -0
  15. lino/locale/de/LC_MESSAGES/django.po +1259 -1280
  16. lino/locale/django.pot +751 -702
  17. lino/locale/es/LC_MESSAGES/django.po +777 -708
  18. lino/locale/et/LC_MESSAGES/django.po +784 -709
  19. lino/locale/fr/LC_MESSAGES/django.po +1339 -1191
  20. lino/locale/nl/LC_MESSAGES/django.po +787 -712
  21. lino/locale/pt_BR/LC_MESSAGES/django.po +769 -700
  22. lino/locale/zh_Hant/LC_MESSAGES/django.po +769 -700
  23. lino/management/commands/demotest.py +2 -1
  24. lino/mixins/__init__.py +1 -1
  25. lino/modlib/checkdata/choicelists.py +5 -4
  26. lino/modlib/checkdata/models.py +9 -8
  27. lino/modlib/help/models.py +5 -0
  28. lino/modlib/jinja/__init__.py +0 -4
  29. lino/modlib/memo/__init__.py +1 -1
  30. lino/modlib/notify/mixins.py +6 -8
  31. lino/modlib/periods/mixins.py +1 -25
  32. lino/modlib/periods/models.py +42 -9
  33. lino/modlib/system/choicelists.py +12 -11
  34. lino/modlib/uploads/fixtures/demo.py +1 -1
  35. lino/modlib/uploads/models.py +2 -1
  36. lino/utils/config.py +2 -0
  37. lino/utils/dpy.py +15 -3
  38. lino/utils/soup.py +136 -103
  39. {lino-25.1.6.dist-info → lino-25.2.1.dist-info}/METADATA +1 -1
  40. {lino-25.1.6.dist-info → lino-25.2.1.dist-info}/RECORD +43 -43
  41. {lino-25.1.6.dist-info → lino-25.2.1.dist-info}/WHEEL +0 -0
  42. {lino-25.1.6.dist-info → lino-25.2.1.dist-info}/licenses/AUTHORS.rst +0 -0
  43. {lino-25.1.6.dist-info → lino-25.2.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__ = '25.1.6'
29
+ __version__ = '25.2.1'
30
30
 
31
31
  # import setuptools # avoid UserWarning "Distutils was imported before Setuptools"?
32
32
 
lino/core/actions.py CHANGED
@@ -1069,6 +1069,9 @@ class CreateRow(Action):
1069
1069
 
1070
1070
  # select_rows = False
1071
1071
  def run_from_ui(self, ar, **kwargs):
1072
+ if (msg := ar.actor.model.disable_create(ar)) is not None:
1073
+ ar.error(msg)
1074
+ return
1072
1075
  elem = ar.create_instance_from_request(**kwargs)
1073
1076
  self.save_new_instance(ar, elem)
1074
1077
 
@@ -1140,6 +1143,9 @@ class SubmitInsert(CreateRow):
1140
1143
  # button actions would try to refer the requesting panel which
1141
1144
  # is going to be closed (this disturbs at least in ticket
1142
1145
  # #219)
1146
+ if (msg := ar.actor.model.disable_create(ar)) is not None:
1147
+ ar.error(msg)
1148
+ return
1143
1149
  ar.requesting_panel = None
1144
1150
 
1145
1151
  if ar.actor.handle_uploaded_files is not None:
lino/core/actors.py CHANGED
@@ -975,10 +975,16 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
975
975
 
976
976
  @classmethod
977
977
  def get_create_permission(self, ar):
978
- if not settings.SITE.user_types_module:
979
- return True
980
- if ar.get_user().user_type.readonly:
978
+ if not self.allow_create:
979
+ return False
980
+ if settings.SITE.readonly:
981
981
  return False
982
+ if settings.SITE.user_types_module:
983
+ user = ar.get_user()
984
+ if user.user_type.readonly:
985
+ return False
986
+ if self.hide_editing(user.user_type):
987
+ return False
982
988
  return True
983
989
 
984
990
  @classmethod
lino/core/callbacks.py CHANGED
@@ -52,9 +52,10 @@ class Callback(object):
52
52
  self.choices_dict = {}
53
53
  self.ar = ar
54
54
 
55
- str_msg = tostring(message).encode()
55
+ str_msg = f"{ar.get_user().username}:{tostring(message)}"
56
+
56
57
  # self.uid = uid if uid is not None else str(md5(str_msg).digest())
57
- self.uid = uid if uid is not None else md5(str_msg).hexdigest()
58
+ self.uid = uid if uid is not None else md5(str_msg.encode()).hexdigest()
58
59
  # 20240407 .digest() returned bytestrings, yielding strings of style
59
60
  # "b'8\x04\xeb\xf53\x9f\xf2\x90\x82l\x81~s\xe8\x90\xa6'"
60
61
 
lino/core/elems.py CHANGED
@@ -1090,7 +1090,7 @@ class ForeignKeyElement(ComplexRemoteComboFieldElement):
1090
1090
  options = dict(
1091
1091
  related_actor_id=actor.actor_id, allowBlank=kw.get("allowBlank", False)
1092
1092
  )
1093
- da = actor.default_action
1093
+ da = actor.detail_action
1094
1094
  options.update(
1095
1095
  view_permission=bool(da) and da.get_view_permission(get_user_profile())
1096
1096
  )
lino/core/fields.py CHANGED
@@ -1299,6 +1299,10 @@ class TableRow(object):
1299
1299
  # return v
1300
1300
  # raise Exception("Oops, {} on {} is {}".format(name, cls, v))
1301
1301
 
1302
+ @classmethod
1303
+ def disable_create(self, ar):
1304
+ return None
1305
+
1302
1306
  def get_detail_action(self, ar):
1303
1307
  """Return the (bound) detail action to use for showing this object in
1304
1308
  a detail window. Return `None` when no detail form exists or
lino/core/keyboard.py CHANGED
@@ -6,6 +6,12 @@ This defines the :class:`Hotkey` class and some keystrokes.
6
6
 
7
7
  The system is not yet heavily used.
8
8
 
9
+ React uses the attributes `ctrl`, `shift`, `alt` and `code`.
10
+
11
+ For the `code`, see:
12
+ https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
13
+
14
+
9
15
  """
10
16
 
11
17
 
@@ -23,7 +29,7 @@ class Hotkey(object):
23
29
  if key:
24
30
  self.key = key.upper()
25
31
  self.keycode = ord(self.key)
26
- for k, v in list(kw.items()):
32
+ for k, v in kw.items():
27
33
  setattr(self, k, v)
28
34
 
29
35
  self.__dict__.update(
@@ -35,7 +41,6 @@ class Hotkey(object):
35
41
  alt=self.alt,
36
42
  )
37
43
 
38
-
39
44
  # ExtJS src/core/EventManager-more.js
40
45
  RETURN = Hotkey(keycode=13, code="Enter")
41
46
  ESCAPE = Hotkey(keycode=27, code="Escape")
lino/core/model.py CHANGED
@@ -969,6 +969,7 @@ LINO_MODEL_ATTRIBS = (
969
969
  "on_create",
970
970
  "error2str",
971
971
  "print_subclasses_graph",
972
+ "disable_create",
972
973
  "grid_post",
973
974
  "submit_insert",
974
975
  "delete_veto_message",
lino/core/requests.py CHANGED
@@ -102,6 +102,7 @@ def mi2bp(master_instance, bp):
102
102
  # raise Exception("No master key for {} {!r}".format(
103
103
  # self.master_instance.__class__, self.master_instance))
104
104
 
105
+
105
106
  class StringLogger(logging.Logger):
106
107
  # Instantiated by BaseRequest.capture_logger()
107
108
 
@@ -542,6 +543,17 @@ class BaseRequest:
542
543
  self.logger.streamer.flush()
543
544
  self.logger = old_logger
544
545
 
546
+ @contextmanager
547
+ def override_attrs(self, **kwargs):
548
+ old_values = {k: getattr(self, k) for k in kwargs.keys()}
549
+ for k, v in kwargs.items():
550
+ setattr(self, k, v)
551
+ try:
552
+ yield
553
+ finally:
554
+ for k, v in old_values.items():
555
+ setattr(self, k, v)
556
+
545
557
  def get_row_classes(self, row):
546
558
  if self.actor is None or self.actor.get_row_classes is None:
547
559
  return
@@ -2061,20 +2073,20 @@ class ActionRequest(BaseRequest):
2061
2073
  return
2062
2074
  # if self.actor.insert_layout is not None: # and not self.actor.stay_in_grid \
2063
2075
  # return
2064
- if (
2065
- self.create_kw is None
2066
- or self.actor.hide_editing(self.get_user().user_type)
2067
- or not self.actor.allow_create
2068
- ):
2076
+ if self.create_kw is None:
2077
+ # print("20250127 self.create_kw is None")
2069
2078
  return
2070
2079
  if not self.actor.get_create_permission(self):
2071
2080
  return
2081
+ # raise Exception("20250127 create_phantom_rows")
2082
+ if self.actor.model is not None:
2083
+ if self.actor.model.disable_create(self) is not None:
2084
+ return
2072
2085
  yield PhantomRow(self, **kw)
2073
2086
 
2074
2087
  def create_instance(self, **kw):
2075
2088
  """
2076
- Create a row (a model instance if this is a database table) using
2077
- the specified keyword arguments.
2089
+ Create a database row using the specified keyword arguments.
2078
2090
  """
2079
2091
  if self.create_kw:
2080
2092
  kw.update(self.create_kw)
lino/core/site.py CHANGED
@@ -96,8 +96,7 @@ def to_locale(language):
96
96
  + language[p + 2 :].lower()
97
97
  )
98
98
  return language[:p].lower() + "_" + language[p + 1 :].upper()
99
- else:
100
- return language.lower()
99
+ return language.lower()
101
100
 
102
101
 
103
102
  def class2str(cl):
lino/core/store.py CHANGED
@@ -576,11 +576,11 @@ class DisabledFieldsStoreField(SpecialStoreField):
576
576
 
577
577
  """
578
578
 
579
- name = str("disabled_fields")
579
+ name = "disabled_fields"
580
580
 
581
581
  def __init__(self, store):
582
582
  # from lino.core.gfks import GenericForeignKey
583
- SpecialStoreField.__init__(self, store)
583
+ super().__init__(store)
584
584
  self.always_disabled = set()
585
585
  for f in self.store.all_fields:
586
586
  if f.field is not None:
lino/help_texts.py CHANGED
@@ -8,7 +8,7 @@ help_texts = {
8
8
  'lino.mixins.Contactable' : _("""Mixin for models that represent somebody who can be contacted by email."""),
9
9
  'lino.mixins.Contactable.get_as_user' : _("""Return the user object representing this contactable."""),
10
10
  'lino.mixins.Phonable' : _("""Mixin for models that represent somebody who can be contacted by phone."""),
11
- 'lino.mixins.Modified' : _("""Adds a a timestamp field which holds the last modification time of every individual database object."""),
11
+ 'lino.mixins.Modified' : _("""Adds a a timestamp field that holds the last modification time of every individual database object."""),
12
12
  'lino.mixins.Modified.modified' : _("""The time when this database object was last modified."""),
13
13
  'lino.mixins.Modified.auto_touch' : _("""Whether to touch objects automatically when saving them."""),
14
14
  'lino.mixins.Created' : _("""Adds a timestamp field which holds the creation time of every individual database object."""),
@@ -315,6 +315,7 @@ help_texts = {
315
315
  'lino.utils.ucsv.UTF8Recoder' : _("""Iterator that reads an encoded stream and reencodes the input to UTF-8"""),
316
316
  'lino.utils.ucsv.UnicodeReader' : _("""A CSV reader which will iterate over lines in the CSV file “f”, which is encoded in the given encoding."""),
317
317
  'lino.utils.ucsv.UnicodeWriter' : _("""A CSV writer which will write rows to CSV file “f”, which is encoded in the given encoding."""),
318
+ 'lino.core.model.Model.disable_create' : _("""Return a veto message if you want to refuse creating rows on this model in the given action request even when permission has been given."""),
318
319
  'lino.core.model.Model.on_create' : _("""Override this to set default values that depend on the request."""),
319
320
  'lino.core.model.Model.after_ui_create' : _("""Hook to define custom behaviour to run when a user has created a new instance of this model."""),
320
321
  'lino.core.model.Model.submit_insert' : _("""The SubmitInsert action to be executed when the when the users submits an insert window."""),
@@ -354,6 +355,7 @@ help_texts = {
354
355
  'lino.modlib.checkdata.Checkers' : _("""The list of data checkers known by this application."""),
355
356
  'lino.modlib.checkdata.Checker' : _("""Base class for all data checkers."""),
356
357
  'lino.modlib.checkdata.Checker.model' : _("""The model to be checked. If this is a string, Lino will resolve it at startup."""),
358
+ 'lino.modlib.checkdata.Checker.no_auto' : _("""Whether this checker should be ignored by checkdata."""),
357
359
  'lino.modlib.checkdata.Checker.check_instance' : _("""Run get_checkdata_problems() on this checker for the given database object."""),
358
360
  'lino.modlib.checkdata.Checker.get_checkable_models' : _("""Return a list of the models to check."""),
359
361
  'lino.modlib.checkdata.Checker.activate' : _("""Creates an instance of this class and adds it as a choice to the Checkers choicelist."""),