lino 25.2.1__py3-none-any.whl → 25.2.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.
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.2.1'
29
+ __version__ = '25.2.2'
30
30
 
31
31
  # import setuptools # avoid UserWarning "Distutils was imported before Setuptools"?
32
32
 
lino/core/boundaction.py CHANGED
@@ -184,4 +184,4 @@ class BoundAction(object):
184
184
  return "<%s(%s, %r)>" % (self.__class__.__name__, self.actor, self.action)
185
185
 
186
186
  def __str__(self):
187
- return "{} on {}".format(self.action, self.actor)
187
+ return f"{self.action.__class__.__name__} on {self.actor}"
lino/core/choicelists.py CHANGED
@@ -823,7 +823,7 @@ class ChoiceList(with_metaclass(ChoiceListMeta, tables.AbstractTable)):
823
823
  @classmethod
824
824
  def filter(self, **fkw):
825
825
  def f(item):
826
- for k, v in list(fkw.items()):
826
+ for k, v in fkw.items():
827
827
  if getattr(item, k) != v:
828
828
  return False
829
829
  return True
lino/core/dbtables.py CHANGED
@@ -315,22 +315,22 @@ class Table(AbstractTable):
315
315
  # qs = self.model.get_request_queryset(ar)
316
316
  # str(qs.query)
317
317
 
318
- # return qs.get(pk=pk)
319
- try:
318
+ if not settings.SITE.catch_layout_exceptions:
320
319
  return qs.get(pk=pk)
321
- # except ValueError:
322
- # return None
323
- except self.model.DoesNotExist:
324
- # sql = qs.query
325
- # import sqlparse
326
- # sql = str(sql).replace('"', '')
327
- # sql = sqlparse.format(sql, reindent=True, keyword_case='upper')
328
- # raise self.model.DoesNotExist(f"No row {pk} in {ar} ({sql})")
329
- raise self.model.DoesNotExist(f"No row {pk} in {ar}") from None
330
- # from django.core.exceptions import ObjectDoesNotExist
331
- # assert isinstance(exc, ObjectDoesNotExist)
332
- # raise exc
333
- # return None
320
+ else:
321
+ try:
322
+ return qs.get(pk=pk)
323
+ except self.model.DoesNotExist:
324
+ # sql = qs.query
325
+ # import sqlparse
326
+ # sql = str(sql).replace('"', '')
327
+ # sql = sqlparse.format(sql, reindent=True, keyword_case='upper')
328
+ # raise self.model.DoesNotExist(f"No row {pk} in {ar} ({sql})")
329
+ raise self.model.DoesNotExist(f"No row {pk} in {ar}") from None
330
+ # from django.core.exceptions import ObjectDoesNotExist
331
+ # assert isinstance(exc, ObjectDoesNotExist)
332
+ # raise exc
333
+ # return None
334
334
 
335
335
  # @classmethod
336
336
  # def disabled_actions(self, ar, obj): # no longer used since 20170909
lino/core/requests.py CHANGED
@@ -820,22 +820,29 @@ class BaseRequest:
820
820
  Given a tuple of primary keys, set :attr:`selected_rows` to a list
821
821
  of corresponding database objects.
822
822
 
823
- The special pks's -99998 and -99999 are filtered out.
823
+ TODO: Explain why the special primary keys -99998 and -99999 are
824
+ filtered out.
824
825
 
825
826
  """
826
827
  # ~ print 20131003, selected_pks
827
828
  self.selected_rows = []
828
- # for pk in selected_pks:
829
- # if pk and pk != "-99998" and pk != "-99999":
830
- # self.selected_rows.append(self.get_row_by_pk(pk))
831
- try:
829
+
830
+ # Until 20250212 we catched for ObjectDoesNotExist here in order to
831
+ # reformulate the message. This made #5924 (Menu "My invoicing plan"
832
+ # fails) difficult to diagnose.
833
+ if True:
832
834
  for pk in selected_pks:
833
835
  if pk and pk != "-99998" and pk != "-99999":
834
836
  self.selected_rows.append(self.get_row_by_pk(pk))
835
- except ObjectDoesNotExist:
836
- # raise exceptions.BadRequest(
837
- raise ObjectDoesNotExist(
838
- f"No row with primary key {pk} in {self.actor}") from None
837
+ else:
838
+ try:
839
+ for pk in selected_pks:
840
+ if pk and pk != "-99998" and pk != "-99999":
841
+ self.selected_rows.append(self.get_row_by_pk(pk))
842
+ except ObjectDoesNotExist:
843
+ # raise exceptions.BadRequest(
844
+ raise ObjectDoesNotExist(
845
+ f"No row with primary key {repr(pk)} in {self.actor}") from None
839
846
  # self.selected_rows = filter(lambda x: x, self.selected_rows)
840
847
  # note: ticket #523 was because the GET contained an empty pk ("&sr=")
841
848
 
@@ -1885,10 +1892,13 @@ class ActionRequest(BaseRequest):
1885
1892
  self.set_selected_pks(*selected_pks)
1886
1893
 
1887
1894
  def __str__(self):
1888
- return "{0} {1}".format(self.__class__.__name__, self.bound_action)
1895
+ return f"{self.__class__.__name__} for {self.bound_action}"
1889
1896
 
1890
- def __repr__(self):
1891
- return "{0} {1}".format(self.__class__.__name__, self.bound_action)
1897
+ # def __str__(self):
1898
+ # return "{0} {1}".format(self.__class__.__name__, self.bound_action)
1899
+ #
1900
+ # def __repr__(self):
1901
+ # return "{0} {1}".format(self.__class__.__name__, self.bound_action)
1892
1902
 
1893
1903
  def gen_insert_button(
1894
1904
  self, target=None, button_attrs=dict(style="float: right;"), **values
lino/help_texts.py CHANGED
@@ -374,13 +374,14 @@ help_texts = {
374
374
  'lino.modlib.linod.Procedures' : _("""The choicelist of background procedures available in this application."""),
375
375
  'lino.modlib.linod.LogLevels' : _("""A choicelist of logging levels available in this application."""),
376
376
  'lino.modlib.linod.SystemTask' : _("""Django model used to represent a background task."""),
377
- 'lino.modlib.linod.SystemTask.procedure' : _("""Pointer to an instance of Procedure."""),
378
377
  'lino.modlib.linod.SystemTask.start_datetime' : _("""Tells at what time exactly this job started."""),
379
378
  'lino.modlib.linod.SystemTask.message' : _("""Stores information about the job, mostly logs."""),
380
379
  'lino.modlib.linod.SystemTask.disabled' : _("""Tells whether the task should be ignored."""),
381
380
  'lino.modlib.linod.SystemTask.log_level' : _("""The logging level to apply when running this task."""),
382
381
  'lino.modlib.linod.SystemTask.run' : _("""Performs a routine job."""),
383
382
  'lino.modlib.linod.SystemTasks' : _("""The default actor for the SystemTask model."""),
383
+ 'lino.modlib.linod.Runnable' : _("""Model mixin used by SystemTask and other models."""),
384
+ 'lino.modlib.linod.Runnable.procedure' : _("""The background procedure to run in this task."""),
384
385
  'lino.modlib.periods.StoredYear' : _("""The Django model used to store a fiscal year."""),
385
386
  'lino.modlib.periods.StoredPeriod' : _("""The Django model used to store an accounting period."""),
386
387
  'lino.modlib.periods.StoredYears' : _("""The fiscal years defined in this database."""),
@@ -511,14 +512,14 @@ help_texts = {
511
512
  'lino.modlib.comments.AllComments' : _("""Show all comments."""),
512
513
  'lino.modlib.comments.MyComments' : _("""Show the comments posted by the current user."""),
513
514
  'lino.modlib.comments.RecentComments' : _("""Show the most recent comments that have been posted on this site."""),
514
- 'lino.modlib.comments.CommentsByRFC' : _("""Shows the comments for a given database object."""),
515
+ 'lino.modlib.comments.CommentsByRFC' : _("""Shows the comments about a given database row."""),
515
516
  'lino.modlib.comments.CommentEvents' : _("""The choicelist with selections for Comments.observed_event."""),
516
517
  'lino.modlib.comments.Emotions' : _("""The list of available values for the Comment.emotion field."""),
517
518
  'lino.modlib.comments.CommentType' : _("""The CommentType model is not being used in production, one day we will probably remove it."""),
518
519
  'lino.modlib.comments.CommentTypes' : _("""The table with all existing comment types."""),
519
520
  'lino.modlib.comments.Commentable' : _("""Mixin for models that are commentable, i.e. the rows of which can become discussion topic of comments."""),
520
521
  'lino.modlib.comments.Commentable.add_comments_filter' : _("""Add filters to the given queryset of comments, requested by the given user."""),
521
- 'lino.modlib.comments.Commentable.get_rfc_description' : _("""Return a HTML formatted string with the description of this Commentable as it should be displayed by the slave summary of CommentsByOwner."""),
522
+ 'lino.modlib.comments.Commentable.get_rfc_description' : _("""Return a HTML formatted string with the description of this Commentable as it should be displayed by the slave summary of CommentsByRFC."""),
522
523
  'lino.modlib.comments.Commentable.on_commented' : _("""This is automatically called when a comment has been created or modified."""),
523
524
  'lino.modlib.files.Volume' : _("""The Django model representing a file volume."""),
524
525
  'lino.modlib.files.Volume.id' : _("""The primary key used to point to this volume from a database object."""),
@@ -290,7 +290,7 @@ class Comment(
290
290
  def full_clean(self):
291
291
  super().full_clean()
292
292
  if self.reply_to_id and not self.owner_id:
293
- # added only 2023-11-19
293
+ # added only 2023-11-19, that's why we have CommentChecker
294
294
  self.owner = self.reply_to.owner
295
295
  # self.owner.setup_comment(self)
296
296
 
@@ -206,7 +206,7 @@ class CommentsByType(CommentsByX):
206
206
  master_key = "comment_type"
207
207
  column_names = "body created user *"
208
208
 
209
-
209
+ # TODO: rename CommentsByRFC to CommentsByOwner
210
210
  class CommentsByRFC(CommentsByX):
211
211
  master_key = "owner"
212
212
  details_of_master_template = _("%(details)s about %(master)s")
@@ -1,5 +1,5 @@
1
1
  # -*- coding: UTF-8 -*-
2
- # Copyright 2009-2018 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
5
 
@@ -48,7 +48,8 @@ from lino.utils.html import E, tostring
48
48
  from etgen.html import Document
49
49
 
50
50
  from lino.utils import ucsv
51
- from lino.utils import dblogger
51
+ from lino import logger
52
+ # from lino.utils import dblogger
52
53
  from lino.core import constants
53
54
  from lino.core import actions
54
55
  from lino.core import fields
@@ -57,7 +58,7 @@ from lino.core.views import requested_actor, action_request
57
58
  from lino.core.views import json_response, json_response_kw
58
59
  from lino.core.views import choices_response
59
60
  from lino.core.requests import BaseRequest
60
- from lino.core.utils import PhantomRow
61
+ from lino.core.utils import PhantomRow, is_devserver
61
62
 
62
63
  MAX_ROW_COUNT = 300
63
64
 
@@ -103,7 +104,7 @@ def delete_element(ar, elem):
103
104
  try:
104
105
  elem.delete()
105
106
  except Exception as e:
106
- dblogger.exception(e)
107
+ logger.exception(e)
107
108
  msg = _("Failed to delete %(record)s : %(error)s.") % dict(
108
109
  record=obj2unicode(elem), error=e
109
110
  )
@@ -342,36 +343,56 @@ class ApiElement(View):
342
343
  ba = rpt.detail_action
343
344
  if ba is None:
344
345
  raise http.Http404("%s has no detail_action" % rpt)
345
-
346
- if pk and pk != "-99999" and pk != "-99998":
347
- sr = [pk]
348
- # Until 20240910 we checked for selected_rows (sr) in the URL and
349
- # used the first sr if defined. Don't ask me why we did this. It
350
- # simply made no sense. because the PK is given the url path.
351
- # sr = request.GET.getlist(constants.URL_PARAM_SELECTED)
352
- # if len(sr) == 0:
353
- # sr = [pk]
354
- try:
346
+ try:
347
+ if pk and pk != "-99999" and pk != "-99998":
348
+ sr = [pk]
349
+ # if issubclass(rpt.model, models.Model):
350
+ # try:
351
+ # ar = ba.request(request=request, selected_pks=sr)
352
+ # # except ObjectDoesNotExist as e: # 20250212
353
+ # except rpt.model.DoesNotExist as e:
354
+ # # print("20240911", e)
355
+ # raise http.Http404(f"Object {sr} does not exist on {rpt}")
356
+ # else:
357
+ # ar = ba.request(request=request, selected_pks=sr)
355
358
  ar = ba.request(request=request, selected_pks=sr)
356
- except ObjectDoesNotExist as e:
357
- # print("20240911", e)
358
- raise http.Http404(f"Object {sr} does not exist on {rpt}")
359
- # print(
360
- # "20170116 views.ApiElement.get", ba,
361
- # ar.action_param_values)
362
- if len(ar.selected_rows):
363
359
  elem = ar.selected_rows[0]
360
+ # print(
361
+ # "20170116 views.ApiElement.get", ba,
362
+ # ar.action_param_values)
363
+ # if len(ar.selected_rows):
364
+ # elem = ar.selected_rows[0]
365
+ # else:
366
+ # raise http.Http404(
367
+ # "No permission to see {} {}.".format(rpt, action_name))
364
368
  else:
365
- raise http.Http404(
366
- "No permission to see {} {}.".format(rpt, action_name))
367
- else:
368
- ar = ba.request(request=request)
369
- elem = None
369
+ ar = ba.request(request=request)
370
+ elem = None
371
+ except Exception as e:
372
+
373
+ # Instantiating an action request can cause all kinds of errors,
374
+ # ranging from invalid primary key to subtle bugs like #5924 (Menu
375
+ # "My invoicing plan" fails), which was caused by the custom
376
+ # invoicing.MyPlans.get_row_by_pk() method, which raised a
377
+ # RelatedObjectDoesNotExist when accessing a non-nullable field.
378
+
379
+ # On a production site we turn every exception into a 400 response
380
+ # because otherwise every GET with a wrong pk would cause an email
381
+ # to ADMINS.
382
+
383
+ # logger.exception(e)
384
+ msg = f"Invalid request for {repr(pk)} on {rpt} ({e})"
385
+ logger.info("Error during ApiElement.get(): %s", msg)
386
+ if is_devserver():
387
+ # can be interesting during development but disturbs on a
388
+ # production server
389
+ logger.exception(e)
390
+ raise http.Http404(msg) from None
370
391
 
371
392
  ar.renderer = settings.SITE.kernel.default_renderer
372
393
 
373
394
  if not ar.get_permission():
374
- msg = "No permission to run {}".format(ar)
395
+ msg = f"No permission to run {ar}"
375
396
  # raise Exception(msg)
376
397
  raise PermissionDenied(msg)
377
398
 
@@ -1,5 +1,5 @@
1
1
  # -*- coding: UTF-8 -*-
2
- # Copyright 2023-2024 Rumma & Ko Ltd
2
+ # Copyright 2023-2025 Rumma & Ko Ltd
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
  # See https://dev.lino-framework.org/plugins/linod.html
5
5
 
@@ -13,6 +13,7 @@ from io import StringIO
13
13
  from django.conf import settings
14
14
  from django.db import models
15
15
  from django.utils import timezone
16
+ from django.core.exceptions import ValidationError
16
17
  from asgiref.sync import sync_to_async, async_to_sync
17
18
 
18
19
  from lino import logger
@@ -80,6 +81,9 @@ class Runnable(Sequenced, RecurrenceSet):
80
81
 
81
82
  def full_clean(self, *args, **kwargs):
82
83
  super().full_clean(*args, **kwargs)
84
+ class_name = dd.full_model_name(self.__class__)
85
+ if self.procedure.class_name != class_name:
86
+ raise ValidationError(f"Invalid procedure for {class_name}")
83
87
  if self.every_unit is None:
84
88
  self.every_unit = Recurrences.never
85
89
  if not self.name:
@@ -91,6 +95,11 @@ class Runnable(Sequenced, RecurrenceSet):
91
95
  def run_task(self, ar):
92
96
  raise NotImplementedError()
93
97
 
98
+ @dd.chooser()
99
+ def procedure_choices(cls):
100
+ # print([p.class_name for p in Procedures.get_list_items()])
101
+ return Procedures.filter(class_name=dd.full_model_name(cls))
102
+
94
103
  async def start_task(self, ar):
95
104
  # print("20231102 start_task", self)
96
105
  if self.is_running():
@@ -191,6 +200,9 @@ async def start_task_runner(ar, max_count=None):
191
200
  nst = await sync_to_async(self.get_next_suggested_date)(
192
201
  self.last_end_time, ar.logger
193
202
  )
203
+ if nst is None:
204
+ await ar.adebug("No time suggested to start %s", astr(self))
205
+ continue
194
206
  if nst > now:
195
207
  await ar.adebug("Too early to start %s", astr(self))
196
208
  next_time = min(next_time, nst)
@@ -39,12 +39,19 @@ MARKDOWNCFG = dict(
39
39
 
40
40
 
41
41
  def rich_text_to_elems(ar, description):
42
- if description.startswith("<"):
42
+ description = ar.parse_memo(description)
43
+
44
+ # After 20250213 #5929 (Links in the description of a ticket aren't rendered
45
+ # correctly) we no longer try to automatically detect reSTructuredText
46
+ # markup in a RichTextField (anyway nobody has ever used this feature).
47
+
48
+ # if description.startswith("<"):
49
+ if True:
43
50
  # desc = E.raw('<div>%s</div>' % self.description)
44
- desc = fragments_fromstring(ar.parse_memo(description))
51
+ desc = fragments_fromstring(description)
45
52
  return desc
46
53
  # desc = E.raw('<div>%s</div>' % self.description)
47
- html = restify(ar.parse_memo(description))
54
+ html = restify(description)
48
55
  # logger.info(u"20180320 restify %s --> %s", description, html)
49
56
  # html = html.strip()
50
57
  try:
@@ -271,6 +271,10 @@ class UserPlan(UserAuthored):
271
271
  plan.save()
272
272
  return plan
273
273
 
274
+ def __str__(self):
275
+ return _("{plan} by {user}").format(
276
+ plan=self._meta.verbose_name, user=self.user)
277
+
274
278
  def run_update_plan(self, ar):
275
279
  raise NotImplementedError()
276
280
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lino
3
- Version: 25.2.1
3
+ Version: 25.2.2
4
4
  Summary: A framework for writing desktop-like web applications using Django and ExtJS or React
5
5
  Project-URL: Homepage, https://www.lino-framework.org
6
6
  Project-URL: Repository, https://gitlab.com/lino-framework/lino
@@ -1,10 +1,10 @@
1
1
  lino/.cvsignore,sha256=1vrrWoP-WD8hPfCszHHIiJEi8KUMRCt5WvoKB9TSB1k,28
2
2
  lino/SciTEDirectory.properties,sha256=rCYi_e-6h8Yx5DwXhAa6MBPlVINcl6Vv9BQDYZV2_go,28
3
- lino/__init__.py,sha256=MM2wocDgfKwyG9CmCGFQ2IxrCzVWmRLSCJzGuv2hCgg,5584
3
+ lino/__init__.py,sha256=YtNOcVKh2rB06MddYDsdCB0P7SljYCG4kHzpM-pZy1w,5584
4
4
  lino/ad.py,sha256=AQ-vJ4scac1mx3xegXezxnxyOQpV-a0q3VFMJSDbj2s,142
5
5
  lino/apps.py,sha256=ECq-dPARDkuhngwNrcipse3b4Irj70HxJs44uWEZFc4,27
6
6
  lino/hello.py,sha256=7-PJg7PnEiznyETqGjOwXcKh8rda0qLetpbS2gvRYy0,532
7
- lino/help_texts.py,sha256=WgZHe3ntyEtZ0LiKSIMMEH6OYHq4bFDKj-noKw7LYVQ,91195
7
+ lino/help_texts.py,sha256=yBhYx2QaAHzNOtzvZgoLerNpNAVucak52Dc8q45xeN0,91293
8
8
  lino/api/__init__.py,sha256=WmzHU-rHdZ68se_nI0SmepQTGE8-cd9tPpovHRH9aag,512
9
9
  lino/api/ad.py,sha256=F6SrcKPRRalHKOZ7QLwsRWGq9hhykQIeo0b85cEk9NQ,314
10
10
  lino/api/dd.py,sha256=-mjuoflZilnFM97we-N1H_sEf1TQiNs62JwZ5m4XV1s,7813
@@ -30,13 +30,13 @@ lino/config/unused/500.html,sha256=aWmP37uPoMS-PJgPuBloxdx0nEreU7AvkXxsex3yVYs,5
30
30
  lino/core/__init__.py,sha256=T7106QxQpa3jXAouGTIer6AXEwpkJ0NAQ9B7Q3-K6qE,686
31
31
  lino/core/actions.py,sha256=2QGQYpjQ_Fyvb3wb4TBGj8GO4f857aQ3YX3Uz6u15dw,46622
32
32
  lino/core/actors.py,sha256=0MhLLWf3uXzO5nEV5D8Bc12dedlgLCWVBo4WcJyLQCc,73865
33
- lino/core/boundaction.py,sha256=tb0C4WwbJpAP3yKbR6OaibzcAkwVs3nfeuD0RjXTjIg,6665
33
+ lino/core/boundaction.py,sha256=9LgEsN3pM2DzG28_WZ7DgXKRRMdGW2E5yTVB1uWcsww,6674
34
34
  lino/core/callbacks.py,sha256=uu1-znzxVDD-JETUebw-hYsNg_9ExQb1vfwbc7Psjro,7549
35
- lino/core/choicelists.py,sha256=8FpmfEREj0jITkx3qihjPfg8pPMBHWXprNfuje4b7N4,36525
35
+ lino/core/choicelists.py,sha256=rR1FutDfYRRJUtBPJPl_aMuy6r6vqmZGkatcCe2wSUg,36519
36
36
  lino/core/classproperty.py,sha256=_E95WPAs7BWbAuFpPvoYM2ZwW_mbq3rvF7o43WsMq_8,4316
37
37
  lino/core/constants.py,sha256=chvG1TrwD2gVMmL4nTOZtO8NcffcclcUv3zBE8mMoiQ,4503
38
38
  lino/core/dashboard.py,sha256=p7EevOgKfyq4I_xs5ToXK_MhoivE-tky9YU4-zzGNMg,6514
39
- lino/core/dbtables.py,sha256=bydsaCkQgUg3KlmHajcbZ2oUQdxcSp82nwbvE5uYPDQ,29067
39
+ lino/core/dbtables.py,sha256=nSZgFOar2-XuDX3U5_BLJb7Im7ZvFcyP2iMQCxSTTaA,29134
40
40
  lino/core/dbutils.py,sha256=_QHcWd-ajLUwt5G8uOp8d47lZQKD3VseHnqKJke18rA,263
41
41
  lino/core/ddh.py,sha256=dYScxWKTOCDEgow7wJNJe812ESasmmITPK2ovraBQno,3172
42
42
  lino/core/diff.py,sha256=XQ-oQQDS_v3kXd4eRP9Hwr5UCgp-TPZIPVav9ZblUno,5882
@@ -56,7 +56,7 @@ lino/core/model.py,sha256=wKxb0bWi_5FgcZn8Pz-bjDGo-5Y1cwOVTZPrJbv5ljQ,36408
56
56
  lino/core/permissions.py,sha256=Fnemz3NwWz21X0YATI9Q7ba2FcAdg-EMLHjIcbt_AVU,6840
57
57
  lino/core/plugin.py,sha256=oVvTsGoBBYmjvRgtyiFPIiHZQErH0ZlNjiUFtOk2dOM,6834
58
58
  lino/core/renderer.py,sha256=jIXxNSpljZhb9tBMhUfDNbZD3XmxYzaS6SlipHx29L4,47291
59
- lino/core/requests.py,sha256=kOPN8Eaz55hG9W7lgNh2lN2HBGXlP19GEmHUtq0nR8U,93211
59
+ lino/core/requests.py,sha256=I9feB-w8XnMRF7vkjFs63crzWMkojeLGHlU4ar6joxk,93617
60
60
  lino/core/roles.py,sha256=PXwk436xUupxdbJcygRSYFu7ixfKjAJPQRUQ8sy0lB0,4425
61
61
  lino/core/signals.py,sha256=0JT89mkjSbRm57QZcSI9DoThoKUGkyi-egNhuLUKEds,948
62
62
  lino/core/site.py,sha256=s_kisoL35ZcbFbF18eyvARu7OcNA_61GPE3-_6rNJIc,83136
@@ -175,9 +175,9 @@ lino/modlib/checkdata/management/commands/checkdata.py,sha256=CjtGm26qPxIWgkn5a9
175
175
  lino/modlib/comments/__init__.py,sha256=XoRLIB-pSsz4EfA2FhsbKQ27fsW_AAvS7SyA0_vhHv8,1678
176
176
  lino/modlib/comments/choicelists.py,sha256=SIA7P_KwtaayqOJxCkwyZouK0Z23-2v4ZFV9a0Zexnk,3314
177
177
  lino/modlib/comments/mixins.py,sha256=h1VvM4h-6rEixziz0r7vJCptM7T7K6i4r50Scz5riws,4413
178
- lino/modlib/comments/models.py,sha256=RiAkvHu8wlDqoVJ4ueeIsZBhMj3LpWxVGQvXKeJSua0,15858
178
+ lino/modlib/comments/models.py,sha256=hS8Q1zLHt4WvlNnlhY8T5eRY14j-iKMDI061uAcAKMw,15893
179
179
  lino/modlib/comments/roles.py,sha256=z3gctvlTa_5PAs-D4pounyzNyuEc31jTFq9g33r6Z1w,751
180
- lino/modlib/comments/ui.py,sha256=w72vOmK8fn6H13t2aPS7ydYU1fCsbbMH2-TSNWt3pwA,9799
180
+ lino/modlib/comments/ui.py,sha256=2FY5e1Mki1l4QX8d7LOskZ4b_b2_JON9hJQccjWWaKM,9846
181
181
  lino/modlib/comments/config/comments/comments.js,sha256=7oAnNyx_MKM1iWPu-QSp6iKfnOVdgq7EciQPpxTvYU8,242
182
182
  lino/modlib/comments/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
183
183
  lino/modlib/comments/fixtures/demo2.py,sha256=FGsX1_r9h2Zz11wbemkqx_AcFIRmYKMx9TineWs_ic0,25328
@@ -190,7 +190,7 @@ lino/modlib/export_excel/__init__.py,sha256=k11dEbh1VgA7cMaUdMhiJvHNboX4BqN0Z5Wj
190
190
  lino/modlib/export_excel/models.py,sha256=OaAkt__l-GaqGLMWQiwXHPJOYABkXHUZ7j9DC7uFE08,5078
191
191
  lino/modlib/extjs/__init__.py,sha256=-TfGa8YR8SWuCHkZ2_pFNVBfOhvVfL5ec4zz6_TWeo4,10170
192
192
  lino/modlib/extjs/ext_renderer.py,sha256=SwfikRmAi1FbDXQLsWNgzgkGqIePwL0UTLgQbb05pOE,60600
193
- lino/modlib/extjs/views.py,sha256=hR5h3bcKEjDjSgFj5-gpkfAhnYccy0J9INdqegyBeVQ,22644
193
+ lino/modlib/extjs/views.py,sha256=SFzGLKxuqvR-1PWAJfHWDgra9tcKq8XBppl_IrW7nXk,23760
194
194
  lino/modlib/extjs/config/extjs/index.html,sha256=jO5hdNpFSkm9t0xhHD5hc8Hw1fSr6xb3zYq9aMyOI7Q,8603
195
195
  lino/modlib/extjs/config/extjs/linoweb.js,sha256=I4VYGmkK4htqZvHM9g-6psJF3pp7SvgHEI0I02Sxpvo,175127
196
196
  lino/modlib/extjs/config/extjs/service-worker.js,sha256=KEKWeehTlfBHk3r8NbsP9C5av_DukHORybxFOwbjYaQ,1767
@@ -3534,7 +3534,7 @@ lino/modlib/languages/fixtures/iso-639-3_20100707.tab,sha256=u8PwI2s8shy0_Val5-s
3534
3534
  lino/modlib/linod/__init__.py,sha256=u2XCoHtoGwEpMDLfRnGYxj49s4DWng7vOjRrkS57F00,2607
3535
3535
  lino/modlib/linod/choicelists.py,sha256=Tq3hoK7wHZXR8QruaSkAo1e8vE5qEy1bh5xrb8cPkyw,2147
3536
3536
  lino/modlib/linod/consumers.py,sha256=NMzuLwNDPFyWNtqXXEyDQ3lyoUWniyoVWbRr7URazCM,6451
3537
- lino/modlib/linod/mixins.py,sha256=Nv7eAkWWaCaHmQc2GRYyCkFaLJ2qX8YpcRFvRhbRTxw,9995
3537
+ lino/modlib/linod/mixins.py,sha256=o40iC6z8WheXsJ6hL_Lqbyf8HY_FhCdUAwxZLECPN6k,10570
3538
3538
  lino/modlib/linod/models.py,sha256=n3HhwDJr3fLdD3PHLZyeF4wBrfC2CWY_UdsC3Acuv7U,2295
3539
3539
  lino/modlib/linod/routing.py,sha256=FiG0JVqp9TWWkNpl9Y_50UCAJ7ZEImDXkQUhlg4aGL4,2094
3540
3540
  lino/modlib/linod/utils.py,sha256=dE973Xib6Be1DvNsZ0M5wzY_jpkk35R21WKs-jQPorM,339
@@ -3542,7 +3542,7 @@ lino/modlib/linod/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
3542
3542
  lino/modlib/linod/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3543
3543
  lino/modlib/linod/management/commands/linod.py,sha256=9-zRm-Xgp3uWj6AlDZpjtzo_TqSPyxIkKIrI_jshxVI,3457
3544
3544
  lino/modlib/memo/__init__.py,sha256=Kghjmlz0y1km6SFq5m9nbDqD3CKfSplj57rso3IevLk,5247
3545
- lino/modlib/memo/mixins.py,sha256=Wv844JL6WyvYI56QqcCdiHq8nocs8xcIM_eNzaWu3So,10919
3545
+ lino/modlib/memo/mixins.py,sha256=qDCbUTVBx9Grw_FAgPS40R49mDjOOKPkZuzED4fuxxQ,11183
3546
3546
  lino/modlib/memo/models.py,sha256=2UbKaixPWCnP1ZkoJx_DDTtltpfYVbU3uJ1hmsZDU8A,3146
3547
3547
  lino/modlib/memo/parser.py,sha256=lOSoXY5nj_CaM3jdd2e2s7-MbXCGRQu3SxQ3d1CMkEE,12994
3548
3548
  lino/modlib/memo/views.py,sha256=H3g_nuiMzguptXLSWaWLJClU7BefXPFn9Rh8UIVVBeg,555
@@ -4404,7 +4404,7 @@ lino/modlib/uploads/fixtures/demo3.py,sha256=q0bwZrx5XtRsRlFpsa33fL0sCl7IdCYaP9E
4404
4404
  lino/modlib/users/__init__.py,sha256=40f-PheIyHqAzGXQbkvEKAnZ9_bb8RkaLAKIqNE96qg,3215
4405
4405
  lino/modlib/users/actions.py,sha256=Nik2CoxKZWoGIsPT50mWESzHSTQx9WiBXWG64CUFyS8,18074
4406
4406
  lino/modlib/users/choicelists.py,sha256=-X76C1NxIs5e7rFHp5Z0kjJkA1NlOP2vdLKGkI2wZRU,3876
4407
- lino/modlib/users/mixins.py,sha256=cMmTtR1-w9iWgdPlNF5kMybDR41D5kd1waGxEROSvSE,14150
4407
+ lino/modlib/users/mixins.py,sha256=muW6-LwHF2L6uvGO0h3qIh1_SeJrgaeooPvjqBiXbAI,14277
4408
4408
  lino/modlib/users/models.py,sha256=tdROzvtd3cMxsXKtYZjcUv2XJU7hQLbyBCiE0zVvaOo,16470
4409
4409
  lino/modlib/users/roles.py,sha256=yi29ELbWU1VtteGARaxetxmsCkZQHA2oJiD0dXujMiE,320
4410
4410
  lino/modlib/users/ui.py,sha256=WA1bqVx1Z4yQzydHhvw_d5yE-teKdkHqd36ynz9ivPk,13127
@@ -4649,8 +4649,8 @@ lino/utils/xml.py,sha256=4Z44W1e5HvTVrU8erkohgnwqY-5Cr2NHywaAJ5OgRvw,989
4649
4649
  lino/utils/mldbc/__init__.py,sha256=QqWRlzeXaOmFfbCk-vTY3SZMn1-FCf67XnpZdd_Nim0,1134
4650
4650
  lino/utils/mldbc/fields.py,sha256=tAX8G5UKigr9c6g0F3ARIjZZtg406mdaZ--PWSbiH9E,2873
4651
4651
  lino/utils/mldbc/mixins.py,sha256=CkYe5jDa7xp9fJq_V8zcZf8ocxgIjUgHc9KZccvA_Yw,1945
4652
- lino-25.2.1.dist-info/METADATA,sha256=bX9DvGiv9t8X4rQLln09BkaMe7oMajwotXYox7sxbfs,42534
4653
- lino-25.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
4654
- lino-25.2.1.dist-info/licenses/AUTHORS.rst,sha256=8VEm_G4HOmYEa4oi1nVoKKsdo4JanekEJCefWd2E8vk,981
4655
- lino-25.2.1.dist-info/licenses/COPYING,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
4656
- lino-25.2.1.dist-info/RECORD,,
4652
+ lino-25.2.2.dist-info/METADATA,sha256=zdReU_IERL2XyGbIUuXYmrscWytvSX3KxnxAmZWLT_Q,42534
4653
+ lino-25.2.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
4654
+ lino-25.2.2.dist-info/licenses/AUTHORS.rst,sha256=8VEm_G4HOmYEa4oi1nVoKKsdo4JanekEJCefWd2E8vk,981
4655
+ lino-25.2.2.dist-info/licenses/COPYING,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
4656
+ lino-25.2.2.dist-info/RECORD,,
File without changes