lino 25.5.2__py3-none-any.whl → 25.6.0__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 (53) hide show
  1. lino/__init__.py +1 -1
  2. lino/api/dd.py +5 -3
  3. lino/api/doctest.py +2 -2
  4. lino/core/__init__.py +3 -3
  5. lino/core/actions.py +62 -582
  6. lino/core/actors.py +66 -32
  7. lino/core/atomizer.py +355 -0
  8. lino/core/boundaction.py +8 -4
  9. lino/core/constants.py +23 -1
  10. lino/core/dbtables.py +4 -3
  11. lino/core/elems.py +33 -21
  12. lino/core/fields.py +45 -210
  13. lino/core/kernel.py +18 -13
  14. lino/core/layouts.py +30 -57
  15. lino/core/model.py +6 -4
  16. lino/core/permissions.py +18 -0
  17. lino/core/renderer.py +15 -1
  18. lino/core/requests.py +19 -8
  19. lino/core/signals.py +1 -1
  20. lino/core/site.py +1 -1
  21. lino/core/store.py +13 -156
  22. lino/core/tables.py +5 -2
  23. lino/core/utils.py +124 -1
  24. lino/locale/bn/LC_MESSAGES/django.po +1034 -868
  25. lino/locale/de/LC_MESSAGES/django.mo +0 -0
  26. lino/locale/de/LC_MESSAGES/django.po +996 -892
  27. lino/locale/django.pot +968 -869
  28. lino/locale/es/LC_MESSAGES/django.po +1032 -869
  29. lino/locale/et/LC_MESSAGES/django.po +1032 -866
  30. lino/locale/fr/LC_MESSAGES/django.po +1034 -866
  31. lino/locale/nl/LC_MESSAGES/django.po +1040 -868
  32. lino/locale/pt_BR/LC_MESSAGES/django.po +1029 -868
  33. lino/locale/zh_Hant/LC_MESSAGES/django.po +1029 -868
  34. lino/mixins/duplicable.py +8 -2
  35. lino/mixins/registrable.py +1 -1
  36. lino/modlib/changes/utils.py +4 -3
  37. lino/modlib/extjs/ext_renderer.py +1 -1
  38. lino/modlib/extjs/views.py +6 -1
  39. lino/modlib/help/config/makehelp/plugin.tpl.rst +3 -1
  40. lino/modlib/help/management/commands/makehelp.py +1 -0
  41. lino/modlib/memo/mixins.py +1 -3
  42. lino/modlib/uploads/ui.py +6 -8
  43. lino/modlib/users/fixtures/demo_users.py +16 -13
  44. lino/utils/choosers.py +11 -1
  45. lino/utils/diag.py +17 -8
  46. lino/utils/fieldutils.py +14 -11
  47. lino/utils/instantiator.py +4 -2
  48. lino/utils/report.py +5 -3
  49. {lino-25.5.2.dist-info → lino-25.6.0.dist-info}/METADATA +1 -1
  50. {lino-25.5.2.dist-info → lino-25.6.0.dist-info}/RECORD +53 -52
  51. {lino-25.5.2.dist-info → lino-25.6.0.dist-info}/WHEEL +0 -0
  52. {lino-25.5.2.dist-info → lino-25.6.0.dist-info}/licenses/AUTHORS.rst +0 -0
  53. {lino-25.5.2.dist-info → lino-25.6.0.dist-info}/licenses/COPYING +0 -0
lino/core/utils.py CHANGED
@@ -640,7 +640,7 @@ def navinfo(qs, elem, limit=None):
640
640
  )
641
641
 
642
642
 
643
- class Parametrizable(object):
643
+ class Parametrizable:
644
644
  """
645
645
  Base class for both Actors and Actions. See :doc:`/dev/parameters`.
646
646
 
@@ -1129,3 +1129,126 @@ def show(*args, **kwargs):
1129
1129
  def shows(*args, **kwargs):
1130
1130
  """Return the output of :func:`show`."""
1131
1131
  return capture_output(show, *args, **kwargs)
1132
+
1133
+
1134
+ class Panel:
1135
+ """
1136
+ To be used when a panel cannot be expressed using a simple
1137
+ template string because it requires one or more options. These
1138
+ `options` parameters can be:
1139
+
1140
+ - label
1141
+ - required_roles
1142
+ - window_size
1143
+ - label_align
1144
+
1145
+ Unlike a :class:`BaseLayout` it cannot have any child panels
1146
+ and cannot become a tabbed panel.
1147
+ """
1148
+
1149
+ def __init__(self, desc, label=None, **options):
1150
+ # assert not 'required' in options
1151
+ self.desc = desc
1152
+ if label is not None:
1153
+ options.update(label=label)
1154
+ self.options = options
1155
+
1156
+ def replace(self, *args, **kw):
1157
+ """
1158
+ Calls the standard :meth:`string.replace`
1159
+ method on this Panel's template.
1160
+ """
1161
+ self.desc = self.desc.replace(*args, **kw)
1162
+
1163
+
1164
+ def resolve_layout(cls, k, spec, layout_class, **options):
1165
+ # k: just for naming the culprit in error messages
1166
+ if isinstance(spec, str):
1167
+ if "\n" in spec or "." not in spec:
1168
+ return layout_class(spec, cls, **options)
1169
+ else:
1170
+ layout_class = settings.SITE.models.resolve(spec)
1171
+ if layout_class is None:
1172
+ raise Exception(
1173
+ "Unresolved {} {!r} for {}".format(k, spec, cls))
1174
+ return layout_class(None, cls, **options)
1175
+ elif isinstance(spec, Panel):
1176
+ options.update(spec.options)
1177
+ return layout_class(spec.desc, cls, **options)
1178
+ else:
1179
+ if not isinstance(spec, layout_class):
1180
+ if not isinstance(cls, type):
1181
+ # cls is an action instance
1182
+ cls = cls.__class__
1183
+ msg = (
1184
+ "{}.{}.{} must be a string, " "a Panel or an instance of {} (not {!r})"
1185
+ )
1186
+ raise Exception(
1187
+ msg.format(cls.__module__, cls.__name__,
1188
+ k, layout_class.__name__, spec)
1189
+ )
1190
+ if spec._datasource is None:
1191
+ spec.set_datasource(cls)
1192
+ return spec
1193
+ elif not issubclass(cls, spec._datasource):
1194
+ raise Exception(
1195
+ "Cannot reuse %s instance (%s of %r) for %r"
1196
+ % (spec.__class__, k, spec._datasource, cls)
1197
+ )
1198
+ return spec
1199
+
1200
+
1201
+ def install_layout(cls, k, layout_class, **options):
1202
+ """
1203
+ - `cls` is the actor (a class object)
1204
+
1205
+ - `k` is one of 'grid_layout', 'detail_layout', 'insert_layout',
1206
+ 'params_layout', 'card_layout'
1207
+
1208
+ - `layout_class`
1209
+
1210
+ """
1211
+ # if str(cls) == 'courses.Pupils':
1212
+ # print("20160329 install_layout", k, layout_class)
1213
+ dl = cls.__dict__.get(k, None)
1214
+ if dl is None: # and not cls._class_init_done:
1215
+ dl = getattr(cls, k, None)
1216
+ if dl is None:
1217
+ return
1218
+ setattr(cls, k, resolve_layout(cls, k, dl, layout_class, **options))
1219
+
1220
+
1221
+ def register_params(cls):
1222
+ """`cls` is either an actor (a class object) or an action (an
1223
+ instance).
1224
+
1225
+ """
1226
+ if cls.parameters is not None:
1227
+ for k, v in cls.parameters.items():
1228
+ v.set_attributes_from_name(k)
1229
+ v.table = cls
1230
+ # v.model = cls # 20181023 experimentally
1231
+
1232
+ if cls.params_layout is None:
1233
+ if cls._params_layout_class is None:
1234
+ raise Exception(f"{cls} has no _params_layout_class")
1235
+ cls.params_layout = cls._params_layout_class.join_str.join(
1236
+ cls.parameters.keys()
1237
+ )
1238
+ install_layout(cls, "params_layout", cls._params_layout_class)
1239
+
1240
+ # e.g. accounting.ByJournal is just a mixin but provides a default value for its children
1241
+ elif cls.params_layout is not None:
1242
+ raise Exception("{} has a params_layout but no parameters".format(cls))
1243
+
1244
+ # if isinstance(cls, type) and cls.__name__.endswith("Users"):
1245
+ # # if isinstance(cls, type) and cls.model is not None and cls.model.__name__ == "User":
1246
+ # # if str(cls.model) != "users.User":
1247
+ # # raise Exception("{} {}".format(cls, cls.model))
1248
+ # print("20200825 {}.register_params {} {}".format(
1249
+ # cls, cls.parameters, cls.params_layout))
1250
+
1251
+
1252
+ def make_params_layout_handle(self):
1253
+ # `self` is either an Action instance or an Actor class object
1254
+ return self.params_layout.get_layout_handle()