lino 25.7.2__py3-none-any.whl → 25.7.3__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 +1 -1
- lino/api/doctest.py +28 -2
- lino/core/actions.py +10 -0
- lino/core/atomizer.py +9 -8
- lino/core/auth/utils.py +9 -1
- lino/core/callbacks.py +2 -2
- lino/core/fields.py +0 -1
- lino/core/kernel.py +9 -19
- lino/core/model.py +11 -3
- lino/core/store.py +3 -3
- lino/core/utils.py +14 -13
- lino/help_texts.py +8 -6
- lino/mixins/__init__.py +3 -2
- lino/mixins/{duplicable.py → clonable.py} +45 -50
- lino/mixins/dupable.py +2 -2
- lino/mixins/registrable.py +3 -3
- lino/mixins/sequenced.py +12 -14
- lino/modlib/dupable/models.py +2 -2
- lino/modlib/notify/api.py +5 -0
- lino/modlib/printing/mixins.py +2 -2
- lino/modlib/summaries/mixins.py +6 -4
- lino/modlib/users/actions.py +5 -0
- lino/sphinxcontrib/__init__.py +1 -1
- lino/sphinxcontrib/actordoc.py +1 -1
- lino/utils/diag.py +2 -2
- lino/utils/instantiator.py +21 -1
- {lino-25.7.2.dist-info → lino-25.7.3.dist-info}/METADATA +1 -1
- {lino-25.7.2.dist-info → lino-25.7.3.dist-info}/RECORD +31 -31
- {lino-25.7.2.dist-info → lino-25.7.3.dist-info}/WHEEL +0 -0
- {lino-25.7.2.dist-info → lino-25.7.3.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-25.7.2.dist-info → lino-25.7.3.dist-info}/licenses/COPYING +0 -0
lino/__init__.py
CHANGED
@@ -31,7 +31,7 @@ from django import VERSION
|
|
31
31
|
from django.apps import AppConfig
|
32
32
|
from django.conf import settings
|
33
33
|
import warnings
|
34
|
-
__version__ = '25.7.
|
34
|
+
__version__ = '25.7.3'
|
35
35
|
|
36
36
|
# import setuptools # avoid UserWarning "Distutils was imported before Setuptools"?
|
37
37
|
|
lino/api/doctest.py
CHANGED
@@ -14,6 +14,7 @@ tested document. It includes
|
|
14
14
|
|
15
15
|
"""
|
16
16
|
|
17
|
+
from lino.mixins.clonable import Clonable
|
17
18
|
from lino.utils.fieldutils import get_fields, fields_help
|
18
19
|
from lino.core.boundaction import BoundAction
|
19
20
|
from lino.core.tables import AbstractTable
|
@@ -23,7 +24,9 @@ from lino.core.actions import ShowTable
|
|
23
24
|
from lino.core.menus import Menu
|
24
25
|
from lino.utils.html import html2text
|
25
26
|
from lino.utils import dbhash
|
26
|
-
from lino.core.utils import
|
27
|
+
from lino.core.utils import get_models
|
28
|
+
from lino.core.utils import full_model_name
|
29
|
+
from lino.core.utils import full_model_name as fmn
|
27
30
|
from lino.utils.diag import visible_for
|
28
31
|
from lino.sphinxcontrib.actordoc import menuselection_text
|
29
32
|
from lino import logger
|
@@ -746,7 +749,7 @@ def show_change_watchers():
|
|
746
749
|
ws = m.change_watcher_spec
|
747
750
|
if ws:
|
748
751
|
rows.append(
|
749
|
-
[
|
752
|
+
[fmn(m), ws.master_key, " ".join(sorted(ws.ignored_fields))]
|
750
753
|
)
|
751
754
|
print(rstgen.table(headers, rows, max_width=40))
|
752
755
|
|
@@ -801,3 +804,26 @@ def checkdb(m, num):
|
|
801
804
|
if m.objects.count() != num:
|
802
805
|
raise Exception(
|
803
806
|
f"Model {m} should have {num} rows but has {m.objects.count()}")
|
807
|
+
|
808
|
+
|
809
|
+
def show_clonables():
|
810
|
+
"""
|
811
|
+
Print a list of all :class:`Clonable <lino.mixins.clonable.Clonable>`
|
812
|
+
models, together with their related slaves, i.e. the data that will be
|
813
|
+
cloned in cascade with their master.
|
814
|
+
"""
|
815
|
+
items = []
|
816
|
+
for m in get_models():
|
817
|
+
if issubclass(m, Clonable):
|
818
|
+
rels = []
|
819
|
+
if (obj := m.objects.first()) is not None:
|
820
|
+
new, related = obj.duplication_plan()
|
821
|
+
for fk, qs in related:
|
822
|
+
rels.append(f"{fmn(qs.model)}.{fk.name}")
|
823
|
+
if len(rels):
|
824
|
+
x = ", ".join(rels)
|
825
|
+
items.append(f"{fmn(m)} : {x}")
|
826
|
+
else:
|
827
|
+
items.append(fmn(m))
|
828
|
+
items = sorted(items)
|
829
|
+
print(rstgen.ul(items).strip())
|
lino/core/actions.py
CHANGED
@@ -98,6 +98,13 @@ class Action(Parametrizable, Permittable):
|
|
98
98
|
raise Exception(
|
99
99
|
"Unkonwn icon_name '{0}'".format(self.icon_name))
|
100
100
|
|
101
|
+
params = {}
|
102
|
+
if self.parameters is not None:
|
103
|
+
params.update(self.parameters)
|
104
|
+
self.setup_parameters(params)
|
105
|
+
if len(params):
|
106
|
+
self.parameters = params
|
107
|
+
|
101
108
|
register_params(self)
|
102
109
|
|
103
110
|
if self.callable_from is not None:
|
@@ -151,6 +158,9 @@ class Action(Parametrizable, Permittable):
|
|
151
158
|
|
152
159
|
return decorator
|
153
160
|
|
161
|
+
def setup_parameters(self, params):
|
162
|
+
pass
|
163
|
+
|
154
164
|
def get_help_text(self, ba):
|
155
165
|
if ba is ba.actor.default_action:
|
156
166
|
if self.default_record_id is not None:
|
lino/core/atomizer.py
CHANGED
@@ -309,10 +309,10 @@ def fields_list(model, field_names):
|
|
309
309
|
Return a set with the names of the specified fields, checking
|
310
310
|
whether each of them exists.
|
311
311
|
|
312
|
-
Arguments: `model` is any subclass of `django.db.models.Model`. It
|
313
|
-
|
314
|
-
|
315
|
-
|
312
|
+
Arguments: `model` is any subclass of `django.db.models.Model`. It may be a
|
313
|
+
string with the full name of a model (e.g. ``"myapp.MyModel"``).
|
314
|
+
`field_names` is an iterable of field names or a single string with a
|
315
|
+
space-separated list of field names.
|
316
316
|
|
317
317
|
If one of the names refers to a dummy field, this name will be ignored
|
318
318
|
silently.
|
@@ -326,16 +326,17 @@ def fields_list(model, field_names):
|
|
326
326
|
iterable on the fields.
|
327
327
|
"""
|
328
328
|
lst = set()
|
329
|
-
|
329
|
+
if isinstance(field_names, str):
|
330
|
+
field_names = field_names.split()
|
330
331
|
|
331
|
-
for name in
|
332
|
+
for name in field_names:
|
332
333
|
if name == "*":
|
333
334
|
explicit_names = set()
|
334
335
|
for name in names_list:
|
335
336
|
if name != "*":
|
336
337
|
explicit_names.add(name)
|
337
338
|
for de in fields.wildcard_data_elems(model):
|
338
|
-
if not isinstance(de, DummyField):
|
339
|
+
if not isinstance(de, fields.DummyField):
|
339
340
|
if de.name not in explicit_names:
|
340
341
|
if fields.use_as_wildcard(de):
|
341
342
|
lst.add(de.name)
|
@@ -343,7 +344,7 @@ def fields_list(model, field_names):
|
|
343
344
|
e = model.get_data_elem(name)
|
344
345
|
if e is None:
|
345
346
|
raise fields.FieldDoesNotExist(
|
346
|
-
"No data element
|
347
|
+
f"No data element '{name}' in {model}")
|
347
348
|
if not hasattr(e, "name"):
|
348
349
|
raise fields.FieldDoesNotExist(
|
349
350
|
"%s %r in %s has no name" % (e.__class__, name, model)
|
lino/core/auth/utils.py
CHANGED
@@ -73,7 +73,8 @@ class AnonymousUser:
|
|
73
73
|
|
74
74
|
|
75
75
|
def activate_social_auth_testing(
|
76
|
-
globals_dict, google=True, github=True, wikimedia=True, facebook=True
|
76
|
+
globals_dict, google=True, github=True, wikimedia=True, facebook=True,
|
77
|
+
smart_id=False
|
77
78
|
):
|
78
79
|
"""
|
79
80
|
Used for testing a development server.
|
@@ -97,6 +98,13 @@ def activate_social_auth_testing(
|
|
97
98
|
# 'social_core.backends.google.GoogleOAuth2',
|
98
99
|
# 'social_core.backends.google.GoogleOAuth',
|
99
100
|
# 'social_core.backends.facebook.FacebookOAuth2',
|
101
|
+
if smart_id:
|
102
|
+
Site.social_auth_backends.append("lino.utils.smart_id.SmartID")
|
103
|
+
# https://oauth.ee/docs
|
104
|
+
globals_dict.update(
|
105
|
+
SOCIAL_AUTH_SMART_ID_KEY="xxx",
|
106
|
+
SOCIAL_AUTH_SMART_ID_SECRET="yyy",
|
107
|
+
)
|
100
108
|
if wikimedia:
|
101
109
|
Site.social_auth_backends.append("social_core.backends.mediawiki.MediaWiki")
|
102
110
|
globals_dict.update(
|
lino/core/callbacks.py
CHANGED
@@ -72,9 +72,9 @@ class Callback(object):
|
|
72
72
|
- func: a callable to be executed when user selects this choice
|
73
73
|
- the label of the button
|
74
74
|
"""
|
75
|
-
assert not
|
75
|
+
assert name not in self.choices_dict
|
76
76
|
allowed_names = ("yes", "no", "ok", "cancel")
|
77
|
-
if not
|
77
|
+
if name not in allowed_names:
|
78
78
|
raise Exception("Sorry, name must be one of %s" % allowed_names)
|
79
79
|
cbc = CallbackChoice(name, func, label)
|
80
80
|
self.choices.append(cbc)
|
lino/core/fields.py
CHANGED
@@ -1492,7 +1492,6 @@ class TableRow(object):
|
|
1492
1492
|
|
1493
1493
|
def save_existing_instance(self, ar):
|
1494
1494
|
watcher = ChangeWatcher(self)
|
1495
|
-
# print("20210213 save_existing_instance", ar.ah, ar.rqdata, self.disabled_fields)
|
1496
1495
|
ar.ah.store.form2obj(ar, ar.rqdata, self, False)
|
1497
1496
|
self.full_clean()
|
1498
1497
|
pre_ui_save.send(sender=self.__class__, instance=self, ar=ar)
|
lino/core/kernel.py
CHANGED
@@ -230,25 +230,15 @@ class Kernel(object):
|
|
230
230
|
|
231
231
|
Model.django2lino(model)
|
232
232
|
|
233
|
-
if
|
234
|
-
model.
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
model
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
if isinstance(model.allow_cascaded_delete, str):
|
244
|
-
model.allow_cascaded_delete = frozenset(
|
245
|
-
atomizer.fields_list(model, model.allow_cascaded_delete)
|
246
|
-
)
|
247
|
-
|
248
|
-
if isinstance(model.allow_cascaded_copy, str):
|
249
|
-
model.allow_cascaded_copy = frozenset(
|
250
|
-
atomizer.fields_list(model, model.allow_cascaded_copy)
|
251
|
-
)
|
233
|
+
if model.allow_cascaded_copy is None:
|
234
|
+
model.allow_cascaded_copy = model.allow_cascaded_delete
|
235
|
+
|
236
|
+
# 'suppress_cascaded_copy'
|
237
|
+
for k in ('hidden_columns', 'active_fields',
|
238
|
+
'allow_cascaded_delete', 'allow_cascaded_copy'):
|
239
|
+
# resolve_fields_list(model, k, frozenset, frozenset())
|
240
|
+
if (v := getattr(model, k, None)) is not None:
|
241
|
+
setattr(model, k, atomizer.fields_list(model, v))
|
252
242
|
|
253
243
|
# Note how to inherit this from from parent model.
|
254
244
|
if model.quick_search_fields is None:
|
lino/core/model.py
CHANGED
@@ -47,8 +47,9 @@ class Model(models.Model, fields.TableRow):
|
|
47
47
|
class Meta(object):
|
48
48
|
abstract = True
|
49
49
|
|
50
|
-
allow_cascaded_copy = frozenset()
|
51
50
|
allow_cascaded_delete = frozenset()
|
51
|
+
allow_cascaded_copy = None
|
52
|
+
# suppress_cascaded_copy = frozenset()
|
52
53
|
grid_post = actions.CreateRow()
|
53
54
|
submit_insert = actions.SubmitInsert()
|
54
55
|
allow_merge_action = False
|
@@ -479,14 +480,20 @@ class Model(models.Model, fields.TableRow):
|
|
479
480
|
elem.after_ui_save(ar, None)
|
480
481
|
|
481
482
|
def save_watched_instance(elem, ar, watcher):
|
483
|
+
# raise Exception("20250726")
|
482
484
|
if watcher.is_dirty():
|
483
485
|
# pre_ui_save.send(sender=elem.__class__, instance=elem, ar=ar)
|
484
486
|
# elem.before_ui_save(ar, watcher)
|
485
487
|
elem.save(force_update=True)
|
486
488
|
watcher.send_update(ar)
|
487
489
|
ar.success(_("%s has been updated.") % obj2unicode(elem))
|
488
|
-
else:
|
489
|
-
|
490
|
+
# else:
|
491
|
+
# ar.success(_("%s : nothing to save.") % obj2unicode(elem))
|
492
|
+
# 20250726 The "nothing to save" message is confusing e.g. in
|
493
|
+
# ratings.ResponsesByExam when setting score1 or score2. These virtual
|
494
|
+
# fields store the value in their respective ChallengeRating object but
|
495
|
+
# the examResponse remains unchanged.
|
496
|
+
|
490
497
|
elem.after_ui_save(ar, watcher)
|
491
498
|
|
492
499
|
def delete_instance(self, ar):
|
@@ -948,6 +955,7 @@ LINO_MODEL_ATTRIBS = (
|
|
948
955
|
"before_ui_save",
|
949
956
|
"allow_cascaded_delete",
|
950
957
|
"allow_cascaded_copy",
|
958
|
+
# "suppress_cascaded_copy",
|
951
959
|
"workflow_state_field",
|
952
960
|
"workflow_owner_field",
|
953
961
|
"disabled_fields",
|
lino/core/store.py
CHANGED
@@ -203,7 +203,6 @@ class StoreField(object):
|
|
203
203
|
|
204
204
|
def set_value_in_object(self, ar, instance, v):
|
205
205
|
# logger.info("20180712 super set_value_in_object() %s", v)
|
206
|
-
|
207
206
|
old_value = self.value_from_object(instance, ar.request)
|
208
207
|
# old_value = getattr(instance,self.field.attname)
|
209
208
|
if old_value != v:
|
@@ -865,8 +864,8 @@ class FileFieldStoreField(StoreField):
|
|
865
864
|
|
866
865
|
|
867
866
|
class MethodStoreField(StoreField):
|
868
|
-
"""
|
869
|
-
Still used for DISPLAY_MODE_HTML.
|
867
|
+
"""
|
868
|
+
Still used for DISPLAY_MODE_HTML and writable virtual fields.
|
870
869
|
"""
|
871
870
|
|
872
871
|
def full_value_from_object(self, obj, ar=None):
|
@@ -898,6 +897,7 @@ class MethodStoreField(StoreField):
|
|
898
897
|
# pass
|
899
898
|
|
900
899
|
def form2obj(self, request, instance, post_data, is_new):
|
900
|
+
# print("20250726", self, post_data)
|
901
901
|
pass
|
902
902
|
# return instance
|
903
903
|
# raise Exception("Cannot update a virtual field")
|
lino/core/utils.py
CHANGED
@@ -810,29 +810,30 @@ def error2str(self, e):
|
|
810
810
|
|
811
811
|
|
812
812
|
def resolve_fields_list(model, k, collection_type=tuple, default=None):
|
813
|
-
|
814
|
-
if
|
813
|
+
value = getattr(model, k)
|
814
|
+
if value is None:
|
815
815
|
setattr(model, k, default)
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
816
|
+
return
|
817
|
+
elif value == default:
|
818
|
+
return
|
819
|
+
elif isinstance(value, collection_type):
|
820
|
+
return
|
821
|
+
if isinstance(value, str):
|
822
|
+
value = value.split()
|
823
|
+
if isinstance(value, (list, tuple)):
|
821
824
|
lst = []
|
822
|
-
for n in
|
825
|
+
for n in value:
|
823
826
|
f = model.get_data_elem(n)
|
824
827
|
if f is None:
|
825
|
-
msg = "Invalid field {} in {} of {}"
|
826
|
-
msg = msg.format(n, k, model)
|
828
|
+
msg = f"Invalid field {n} in {k} of {model}"
|
827
829
|
raise Exception(msg)
|
828
830
|
lst.append(f)
|
829
831
|
setattr(model, k, collection_type(lst))
|
830
832
|
# fields.fields_list(model, model.quick_search_fields))
|
831
833
|
else:
|
832
834
|
raise ChangedAPI(
|
833
|
-
"{
|
834
|
-
"of space-separated field names (not {
|
835
|
-
)
|
835
|
+
f"{model}.{k} must be None or a string "
|
836
|
+
f"of space-separated field names (not {value})")
|
836
837
|
|
837
838
|
|
838
839
|
def class_dict_items(cl, exclude=None):
|
lino/help_texts.py
CHANGED
@@ -17,6 +17,8 @@ help_texts = {
|
|
17
17
|
'lino.mixins.ProjectRelated' : _("""Mixin for models that are related to a “project”, i.e. to an object of the type given by your lino.core.site.Site.project_model."""),
|
18
18
|
'lino.mixins.ProjectRelated.project' : _("""Pointer to the project to which this object is related."""),
|
19
19
|
'lino.mixins.ProjectRelated.update_owned_instance' : _("""When a project-related object controls another project-related object, then the controlled automatically inherits the project of its controller."""),
|
20
|
+
'lino.mixins.clonable.CloneRow' : _("""See /dev/duplicate."""),
|
21
|
+
'lino.mixins.clonable.Clonable' : _("""See /dev/duplicate."""),
|
20
22
|
'lino.mixins.dupable.CheckedSubmitInsert' : _("""Like the standard lino.core.actions.SubmitInsert, but adds a confirmation if there is a possible duplicate record."""),
|
21
23
|
'lino.mixins.dupable.PhoneticWordBase' : _("""Base class for the table of phonetic words of a given dupable model. For every (non-abstract) dupable model there must be a subclass of PhoneticWordBase. The subclass must define a field owner which points to the Dupable, and the Dupable’s dupable_word_model must point to its subclass of PhoneticWordBase."""),
|
22
24
|
'lino.mixins.dupable.Dupable' : _("""Base class for models that can be “dupable”."""),
|
@@ -30,9 +32,6 @@ help_texts = {
|
|
30
32
|
'lino.mixins.dupable.DupableChecker' : _("""Checks for the following repairable problem:"""),
|
31
33
|
'lino.mixins.dupable.DupableChecker.model' : _("""alias of Dupable"""),
|
32
34
|
'lino.mixins.dupable.SimilarObjects' : _("""Shows the other objects that are similar to this one."""),
|
33
|
-
'lino.mixins.duplicable.Duplicate' : _("""Duplicate the selected row."""),
|
34
|
-
'lino.mixins.duplicable.Duplicate.run_from_ui' : _("""This actually runs the action."""),
|
35
|
-
'lino.mixins.duplicable.Duplicable' : _("""Adds a row action “Duplicate”, which duplicates (creates a clone of) the object it was called on."""),
|
36
35
|
'lino.mixins.human.Human' : _("""Base class for models that represent a human."""),
|
37
36
|
'lino.mixins.human.Human.title' : _("""Used to specify a professional position or academic qualification like “Dr.” or “PhD”."""),
|
38
37
|
'lino.mixins.human.Human.first_name' : _("""The first name, also known as given name."""),
|
@@ -87,10 +86,9 @@ help_texts = {
|
|
87
86
|
'lino.mixins.sequenced.MoveByN' : _("""Move this row N rows upwards or downwards."""),
|
88
87
|
'lino.mixins.sequenced.MoveUp' : _("""Move this row one row upwards."""),
|
89
88
|
'lino.mixins.sequenced.MoveDown' : _("""Move this row one row downwards."""),
|
90
|
-
'lino.mixins.sequenced.DuplicateSequenced' : _("""Duplicate this row."""),
|
91
89
|
'lino.mixins.sequenced.Sequenced' : _("""Mixin for models that have a field seqno containing a “sequence number”."""),
|
92
90
|
'lino.mixins.sequenced.Sequenced.seqno' : _("""The sequence number of this item with its parent."""),
|
93
|
-
'lino.mixins.sequenced.Sequenced.
|
91
|
+
'lino.mixins.sequenced.Sequenced.clone_row' : _("""Create a duplicate of this row and insert the new row below this one."""),
|
94
92
|
'lino.mixins.sequenced.Sequenced.move_up' : _("""Exchange the seqno of this item and the previous item."""),
|
95
93
|
'lino.mixins.sequenced.Sequenced.move_down' : _("""Exchange the seqno of this item and the next item."""),
|
96
94
|
'lino.mixins.sequenced.Sequenced.move_buttons' : _("""Displays buttons for certain actions on this row:"""),
|
@@ -311,7 +309,6 @@ help_texts = {
|
|
311
309
|
'lino.core.model.Model.submit_insert' : _("""The SubmitInsert action to be executed when the when the users submits an insert window."""),
|
312
310
|
'lino.core.model.Model.create_from_choice' : _("""Called when a learning combo has been submitted. Create a persistent database object if the given text contains enough information."""),
|
313
311
|
'lino.core.model.Model.choice_text_to_dict' : _("""Return a dict of the fields to fill when the given text contains enough information for creating a new database object."""),
|
314
|
-
'lino.core.model.Model.allow_cascaded_delete' : _("""A set of names of ForeignKey or GenericForeignKey fields of this model that allow for cascaded delete."""),
|
315
312
|
'lino.core.model.Model.__str__' : _("""Return a translatable text that describes this database row."""),
|
316
313
|
'lino.core.model.Model.as_str' : _("""Return a translatable text that describes this database row. Unlike __str__() this method gets an action request when it is called, so it knows the context."""),
|
317
314
|
'lino.core.model.Model.get_str_words' : _("""Yield a series of words that describe this database row in plain text."""),
|
@@ -717,4 +714,9 @@ help_texts = {
|
|
717
714
|
'lino.core.model.Model.get_choices_text' : _("""Return the text to be displayed when an instance of this model is being used as a choice in a combobox of a ForeignKey field pointing to this model. request is the web request, actor is the requesting actor."""),
|
718
715
|
'lino.core.model.Model.disable_delete' : _("""Decide whether this database object may be deleted. Return None when there is no veto against deleting this database row, otherwise a translatable message that explains to the user why they can’t delete this row."""),
|
719
716
|
'lino.core.model.Model.update_field' : _("""Shortcut to call lino.core.inject.update_field() for usage during lino.core.site.Site.do_site_startup() in a settings.py or similar place."""),
|
717
|
+
'lino.core.model.Model.on_duplicate' : _("""Called after duplicating a row."""),
|
718
|
+
'lino.core.model.Model.after_duplicate' : _("""Called by lino.mixins.clonable.Duplicate on the new copied row instance, after the row and its related fields have been saved."""),
|
719
|
+
'lino.core.model.Model.delete_veto_message' : _("""Return the message Cannot delete X because N Ys refer to it."""),
|
720
|
+
'lino.core.model.Model.allow_cascaded_delete' : _("""A set of foreign key fields that link this model to a master in a “possessive” way, i.e. objects of this model should get deleted together with their master."""),
|
721
|
+
'lino.core.model.Model.allow_cascaded_copy' : _("""A set of foreign key fields that that cause database rows to be automatically cloned when their master gets cloned."""),
|
720
722
|
}
|
lino/mixins/__init__.py
CHANGED
@@ -8,8 +8,9 @@ by applications and the :ref:`xl`. But none of them is mandatory.
|
|
8
8
|
.. autosummary::
|
9
9
|
:toctree:
|
10
10
|
|
11
|
-
|
11
|
+
|
12
12
|
dupable
|
13
|
+
clonable
|
13
14
|
sequenced
|
14
15
|
human
|
15
16
|
periods
|
@@ -50,7 +51,7 @@ from .polymorphic import Polymorphic
|
|
50
51
|
from .periods import ObservedDateRange, Yearly, Monthly, Today
|
51
52
|
from .periods import DateRange
|
52
53
|
from .sequenced import Sequenced, Hierarchical
|
53
|
-
from .
|
54
|
+
from .clonable import Clonable, CloneRow
|
54
55
|
from .registrable import Registrable, RegistrableState
|
55
56
|
from .ref import Referrable, StructuredReferrable
|
56
57
|
|
@@ -1,13 +1,10 @@
|
|
1
1
|
# -*- coding: UTF-8 -*-
|
2
2
|
# Copyright 2012-2025 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
|
-
"
|
5
|
-
[du'plikəblə] means "able to produce a duplicate
|
6
|
-
['duplikət], ['du:plikeit]".
|
7
|
-
|
8
|
-
"""
|
4
|
+
"See :doc:`/dev/duplicate`."
|
9
5
|
|
10
6
|
from django.utils.translation import gettext_lazy as _
|
7
|
+
from django.utils.text import format_lazy
|
11
8
|
|
12
9
|
from lino import logger
|
13
10
|
from lino.core import actions
|
@@ -16,16 +13,12 @@ from lino.core.diff import ChangeWatcher
|
|
16
13
|
# from lino.core.roles import Expert
|
17
14
|
|
18
15
|
|
19
|
-
class
|
20
|
-
""
|
21
|
-
|
22
|
-
This will call :meth:`lino.core.model.Model.on_duplicate` on the
|
23
|
-
new object and on related objects.
|
16
|
+
class CloneRow(actions.Action):
|
17
|
+
"See :doc:`/dev/duplicate`."
|
24
18
|
|
25
|
-
"""
|
26
|
-
|
27
|
-
label = "
|
28
|
-
# label = _("Duplicate")
|
19
|
+
# button_text = "⚇" # \u2687 "white circle with two dots"
|
20
|
+
button_text = "🗗" # OVERLAP (U+1F5D7)
|
21
|
+
label = _("Duplicate")
|
29
22
|
# icon_name = 'arrow_divide'
|
30
23
|
sort_index = 11
|
31
24
|
show_in_workflow = False
|
@@ -34,6 +27,11 @@ class Duplicate(actions.Action):
|
|
34
27
|
|
35
28
|
# required_roles = set([Expert])
|
36
29
|
|
30
|
+
def get_help_text(self, ba):
|
31
|
+
return format_lazy(
|
32
|
+
_("Insert a new {} as a copy of this."),
|
33
|
+
ba.actor.model._meta.verbose_name)
|
34
|
+
|
37
35
|
def get_action_view_permission(self, actor, user_type):
|
38
36
|
# the action is readonly because it doesn't write to the
|
39
37
|
# current object, but since it does modify the database we
|
@@ -48,30 +46,9 @@ class Duplicate(actions.Action):
|
|
48
46
|
return super().get_action_view_permission(actor, user_type)
|
49
47
|
|
50
48
|
def run_from_code(self, ar, **known_values):
|
49
|
+
# CloneSequenced uses known_values to set seqno to seqno + 1
|
51
50
|
obj = ar.selected_rows[0]
|
52
|
-
related =
|
53
|
-
for m, fk in obj._lino_ddh.fklist:
|
54
|
-
# print(fk.name, m.allow_cascaded_delete, m.allow_cascaded_copy, obj)
|
55
|
-
if fk.name in m.allow_cascaded_delete or fk.name in m.allow_cascaded_copy:
|
56
|
-
related.append((fk, m.objects.filter(**{fk.name: obj})))
|
57
|
-
|
58
|
-
fields_list = obj._meta.concrete_fields
|
59
|
-
if True:
|
60
|
-
for f in fields_list:
|
61
|
-
if not f.primary_key:
|
62
|
-
if f.name not in known_values:
|
63
|
-
known_values[f.name] = getattr(obj, f.name)
|
64
|
-
new = obj.__class__(**known_values)
|
65
|
-
# 20120704 create_instances causes fill_from_person() on a
|
66
|
-
# CBSS request.
|
67
|
-
else:
|
68
|
-
# doesn't seem to want to work
|
69
|
-
new = obj
|
70
|
-
for f in fields_list:
|
71
|
-
if f.primary_key:
|
72
|
-
# causes Django to consider this an unsaved instance
|
73
|
-
setattr(new, f.name, None)
|
74
|
-
|
51
|
+
new, related = obj.duplication_plan(**known_values)
|
75
52
|
new.on_duplicate(ar, None)
|
76
53
|
new.full_clean()
|
77
54
|
new.save(force_insert=True)
|
@@ -94,11 +71,9 @@ class Duplicate(actions.Action):
|
|
94
71
|
|
95
72
|
logger.info("%s has been duplicated to %s (%d related rows)",
|
96
73
|
obj, new, relcount)
|
97
|
-
|
98
74
|
return new
|
99
75
|
|
100
76
|
def run_from_ui(self, ar, **kw):
|
101
|
-
"""This actually runs the action."""
|
102
77
|
|
103
78
|
if (msg := ar.actor.model.disable_create(ar)) is not None:
|
104
79
|
ar.error(msg)
|
@@ -126,18 +101,38 @@ class Duplicate(actions.Action):
|
|
126
101
|
)
|
127
102
|
|
128
103
|
|
129
|
-
class
|
130
|
-
"
|
131
|
-
of) the object it was called on.
|
104
|
+
class Clonable(model.Model):
|
105
|
+
"See :doc:`/dev/duplicate`."
|
132
106
|
|
133
|
-
|
134
|
-
|
135
|
-
except the primary key and all related objects that are
|
136
|
-
duplicable.
|
107
|
+
class Meta:
|
108
|
+
abstract = True
|
137
109
|
|
138
|
-
|
110
|
+
clone_row = CloneRow()
|
139
111
|
|
140
|
-
|
141
|
-
|
112
|
+
def duplication_plan(obj, **known_values):
|
113
|
+
related = []
|
114
|
+
for m, fk in obj._lino_ddh.fklist:
|
115
|
+
# if fk.name in m.suppress_cascaded_copy:
|
116
|
+
# continue
|
117
|
+
# print(fk.name, m.allow_cascaded_delete, m.allow_cascaded_copy, obj)
|
118
|
+
# if fk.name in m.allow_cascaded_delete or fk.name in m.allow_cascaded_copy:
|
119
|
+
if fk.name in m.allow_cascaded_copy:
|
120
|
+
related.append((fk, m.objects.filter(**{fk.name: obj})))
|
142
121
|
|
143
|
-
|
122
|
+
fields_list = obj._meta.concrete_fields
|
123
|
+
if True:
|
124
|
+
for f in fields_list:
|
125
|
+
if not f.primary_key:
|
126
|
+
if f.name not in known_values:
|
127
|
+
known_values[f.name] = getattr(obj, f.name)
|
128
|
+
new = obj.__class__(**known_values)
|
129
|
+
# 20120704 create_instances causes fill_from_person() on a
|
130
|
+
# CBSS request.
|
131
|
+
else:
|
132
|
+
# doesn't seem to want to work
|
133
|
+
new = obj
|
134
|
+
for f in fields_list:
|
135
|
+
if f.primary_key:
|
136
|
+
# causes Django to consider this an unsaved instance
|
137
|
+
setattr(new, f.name, None)
|
138
|
+
return new, related
|
lino/mixins/dupable.py
CHANGED
@@ -5,8 +5,8 @@
|
|
5
5
|
Defines the :class:`Dupable` model mixin and related functionality
|
6
6
|
to assist users in finding unwanted duplicate database records.
|
7
7
|
|
8
|
-
Don't mix up this module with :mod:`lino.mixins
|
9
|
-
are "
|
8
|
+
Don't mix up this module with :mod:`lino.mixins.`. Models
|
9
|
+
are "" if users may *want* to duplicate some instance
|
10
10
|
thereof, while "dupable" implies that the duplicates are *unwanted*.
|
11
11
|
To dupe *somebody* means "to make a dupe of; deceive; delude; trick."
|
12
12
|
(`reference.com <https://dictionary.reference.com/browse/dupe>`_), and
|
lino/mixins/registrable.py
CHANGED
@@ -143,7 +143,7 @@ class Registrable(model.Model):
|
|
143
143
|
# if not ar.bound_action.action.readonly:
|
144
144
|
if not ba.action.readonly:
|
145
145
|
return False
|
146
|
-
return super(
|
146
|
+
return super().get_row_permission(ar, state, ba)
|
147
147
|
|
148
148
|
def register(self, ar):
|
149
149
|
"""
|
@@ -193,7 +193,7 @@ class Registrable(model.Model):
|
|
193
193
|
|
194
194
|
@classmethod
|
195
195
|
def get_simple_parameters(cls):
|
196
|
-
for p in super(
|
196
|
+
for p in super().get_simple_parameters():
|
197
197
|
yield p
|
198
198
|
# if isinstance(cls.workflow_state_field, str):
|
199
199
|
# raise Exception("Unresolved workflow state field in {}".format(cls))
|
@@ -203,4 +203,4 @@ class Registrable(model.Model):
|
|
203
203
|
|
204
204
|
def on_duplicate(self, ar, master):
|
205
205
|
self.state = self.workflow_state_field.choicelist.draft
|
206
|
-
super(
|
206
|
+
super().on_duplicate(ar, master)
|
lino/mixins/sequenced.py
CHANGED
@@ -24,7 +24,7 @@ from lino.utils.html import E
|
|
24
24
|
from lino.utils import AttrDict
|
25
25
|
from lino.utils import join_elems
|
26
26
|
|
27
|
-
from .
|
27
|
+
from lino.mixins.clonable import Clonable, CloneRow
|
28
28
|
|
29
29
|
|
30
30
|
class MoveByN(actions.Action):
|
@@ -167,8 +167,7 @@ class MoveDown(actions.Action):
|
|
167
167
|
ar.success(**kw)
|
168
168
|
|
169
169
|
|
170
|
-
class
|
171
|
-
"""Duplicate this row."""
|
170
|
+
class CloneSequenced(CloneRow):
|
172
171
|
|
173
172
|
def run_from_code(self, ar, **kw):
|
174
173
|
obj = ar.selected_rows[0]
|
@@ -184,7 +183,7 @@ class DuplicateSequenced(Duplicate):
|
|
184
183
|
return super().run_from_code(ar, **kw)
|
185
184
|
|
186
185
|
|
187
|
-
class Sequenced(
|
186
|
+
class Sequenced(Clonable):
|
188
187
|
"""Mixin for models that have a field :attr:`seqno` containing a
|
189
188
|
"sequence number".
|
190
189
|
|
@@ -192,12 +191,11 @@ class Sequenced(Duplicable):
|
|
192
191
|
|
193
192
|
The sequence number of this item with its parent.
|
194
193
|
|
195
|
-
.. method::
|
194
|
+
.. method:: clone_row
|
196
195
|
|
197
|
-
Create a duplicate of this
|
198
|
-
below this one.
|
196
|
+
Create a duplicate of this row and insert the new row below this one.
|
199
197
|
|
200
|
-
Implemented by :class:`
|
198
|
+
Implemented by :class:`CloneSequenced`
|
201
199
|
|
202
200
|
.. attribute:: move_up
|
203
201
|
|
@@ -212,28 +210,28 @@ class Sequenced(Duplicable):
|
|
212
210
|
Displays buttons for certain actions on this row:
|
213
211
|
|
214
212
|
- :attr:`move_up` and :attr:`move_down`
|
215
|
-
-
|
213
|
+
- clone_row
|
216
214
|
|
217
215
|
.. attribute:: move_by_n
|
218
216
|
|
219
217
|
"""
|
220
218
|
|
221
|
-
move_action_names = ("move_up", "move_down", "
|
219
|
+
move_action_names = ("move_up", "move_down", "clone_row")
|
222
220
|
"""The names of the actions to display in the `move_buttons`
|
223
221
|
column.
|
224
222
|
|
225
223
|
Overridden by :class:`lino.modlib.dashboard.Widget` where the
|
226
|
-
|
224
|
+
clone_row button would be irritating.
|
227
225
|
|
228
226
|
"""
|
229
227
|
|
230
|
-
class Meta
|
228
|
+
class Meta:
|
231
229
|
abstract = True
|
232
230
|
ordering = ["seqno"]
|
233
231
|
|
234
232
|
seqno = models.IntegerField(_("No."), blank=True, null=False)
|
235
233
|
|
236
|
-
|
234
|
+
clone_row = CloneSequenced()
|
237
235
|
|
238
236
|
move_up = MoveUp()
|
239
237
|
move_down = MoveDown()
|
@@ -352,7 +350,7 @@ Sequenced.set_widget_options("move_buttons", width=5)
|
|
352
350
|
Sequenced.set_widget_options("seqno", hide_sum=True)
|
353
351
|
|
354
352
|
|
355
|
-
class Hierarchical(
|
353
|
+
class Hierarchical(Clonable):
|
356
354
|
"""Model mixin for things that have a "parent" and "siblings".
|
357
355
|
|
358
356
|
Pronounciation: [hai'ra:kikl]
|
lino/modlib/dupable/models.py
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
"""Defines the :class:`Dupable` model mixin and related functionality
|
5
5
|
to assist users in finding unwanted duplicate database records.
|
6
6
|
|
7
|
-
Don't mix up this module with :mod:`lino.mixins
|
8
|
-
are "
|
7
|
+
Don't mix up this module with :mod:`lino.mixins.`. Models
|
8
|
+
are "" if users may *want* to duplicate some instance
|
9
9
|
thereof, while "dupable" implies that the duplicates are *unwanted*.
|
10
10
|
To dupe *somebody* means "to make a dupe of; deceive; delude; trick."
|
11
11
|
(`reference.com <https://dictionary.reference.com/browse/dupe>`_), and
|
lino/modlib/notify/api.py
CHANGED
@@ -8,6 +8,7 @@ from django.conf import settings
|
|
8
8
|
from django.utils.timezone import now
|
9
9
|
from lino.api import rt, dd
|
10
10
|
from lino.modlib.linod.utils import CHANNEL_NAME, BROADCAST_CHANNEL, get_channel_name
|
11
|
+
from lino_xl.lib.matrix.utils import send_notification_to_matrix_room, send_notification_direct
|
11
12
|
|
12
13
|
NOTIFICATION = "NOTIFICATION"
|
13
14
|
CHAT = "CHAT"
|
@@ -67,6 +68,10 @@ def send_notification(
|
|
67
68
|
if user is None or settings.SITE.loading_from_dump:
|
68
69
|
return
|
69
70
|
|
71
|
+
if dd.is_installed("matrix") and dd.plugins.matrix.credentials_file is not None:
|
72
|
+
# send_notification_to_matrix_room(f"{subject}\n\n{body}")
|
73
|
+
send_notification_direct(f"{subject}\n\n{body}", user)
|
74
|
+
|
70
75
|
if dd.get_plugin_setting("linod", "use_channels"):
|
71
76
|
# importing channels at module level would cause certain things to fail
|
72
77
|
# when channels isn't installed, e.g. `manage.py prep` in `lino_book.projects.workflows`.
|
lino/modlib/printing/mixins.py
CHANGED
@@ -16,7 +16,7 @@ from lino.modlib.checkdata.choicelists import Checker
|
|
16
16
|
|
17
17
|
from lino.utils.choosers import chooser
|
18
18
|
from lino.core.model import Model
|
19
|
-
from lino.mixins.
|
19
|
+
from lino.mixins.clonable import Clonable
|
20
20
|
|
21
21
|
from .choicelists import BuildMethods
|
22
22
|
from .actions import (
|
@@ -148,7 +148,7 @@ class Printable(Model):
|
|
148
148
|
return True
|
149
149
|
|
150
150
|
|
151
|
-
class CachedPrintable(
|
151
|
+
class CachedPrintable(Clonable, Printable):
|
152
152
|
class Meta(object):
|
153
153
|
abstract = True
|
154
154
|
|
lino/modlib/summaries/mixins.py
CHANGED
@@ -38,7 +38,8 @@ class UpdateSummariesByMaster(ComputeResults):
|
|
38
38
|
|
39
39
|
|
40
40
|
class Summarized(dd.Model):
|
41
|
-
|
41
|
+
|
42
|
+
class Meta:
|
42
43
|
abstract = True
|
43
44
|
|
44
45
|
compute_results = ComputeResults()
|
@@ -86,15 +87,17 @@ class Summarized(dd.Model):
|
|
86
87
|
|
87
88
|
def get_summary_collectors(self):
|
88
89
|
raise NotImplementedError(
|
89
|
-
"{} must define get_summary_collectors()"
|
90
|
+
f"{self.__class__} must define get_summary_collectors()"
|
90
91
|
)
|
91
92
|
|
92
93
|
|
93
94
|
class SlaveSummarized(Summarized):
|
94
|
-
|
95
|
+
|
96
|
+
class Meta:
|
95
97
|
abstract = True
|
96
98
|
|
97
99
|
allow_cascaded_delete = "master"
|
100
|
+
allow_cascaded_copy = set()
|
98
101
|
|
99
102
|
@classmethod
|
100
103
|
def check_all_summaries(cls):
|
@@ -181,7 +184,6 @@ class DateSummarized(Summarized):
|
|
181
184
|
flt.update(month=period)
|
182
185
|
if year is not None:
|
183
186
|
flt.update(year=year)
|
184
|
-
# obj = cls.get_for_period(**flt)
|
185
187
|
for obj in cls.get_for_filter(**flt):
|
186
188
|
obj.compute_summary_values()
|
187
189
|
|
lino/modlib/users/actions.py
CHANGED
@@ -495,6 +495,11 @@ def get_social_auth_links_func(content_header, flex_row, ar=None):
|
|
495
495
|
else:
|
496
496
|
el = E.span(anchor, style=style)
|
497
497
|
links.append(el)
|
498
|
+
anchor = E.a(E.span(gettext("Smart ID")), href="/auth/smart_id")
|
499
|
+
if flex_row:
|
500
|
+
links.append(E.div(anchor, style=style))
|
501
|
+
else:
|
502
|
+
links.append(E.span(anchor, style=style))
|
498
503
|
elems.append(E.div(*links, style="text-align: center;"))
|
499
504
|
return tostring(E.div(*elems))
|
500
505
|
|
lino/sphinxcontrib/__init__.py
CHANGED
@@ -102,7 +102,7 @@ def configure(globals_dict, django_settings_module=None):
|
|
102
102
|
rstgen.sphinxconf.configure()
|
103
103
|
|
104
104
|
You can specify an additional positional argument `django_settings_module`
|
105
|
-
(the name of a Django settings
|
105
|
+
(the name of a Django settings file). If this argument is specified, call
|
106
106
|
:meth:`lino.startup` with it.
|
107
107
|
|
108
108
|
"""
|
lino/sphinxcontrib/actordoc.py
CHANGED
@@ -11,7 +11,7 @@ for a Lino application.
|
|
11
11
|
source code. This is like :rst:dir:`py2rst` but with the following
|
12
12
|
names defined:
|
13
13
|
|
14
|
-
:settings: The Django settings
|
14
|
+
:settings: The Django settings file which is active while building
|
15
15
|
the docs.
|
16
16
|
|
17
17
|
:dd: The :mod:`lino.api.dd` module.
|
lino/utils/diag.py
CHANGED
@@ -341,9 +341,9 @@ class Analyzer(object):
|
|
341
341
|
return "{0}.{1}".format(fmn(mfk[0]), mfk[1].name)
|
342
342
|
|
343
343
|
items1 = []
|
344
|
-
for target, dp in
|
344
|
+
for target, dp in tdp.items():
|
345
345
|
items2 = []
|
346
|
-
for dh, pl in
|
346
|
+
for dh, pl in dp.items():
|
347
347
|
items2.append(
|
348
348
|
"{0} : {1}".format(
|
349
349
|
dh.__name__, ", ".join([fk2str(mfk) for mfk in pl])
|
lino/utils/instantiator.py
CHANGED
@@ -215,13 +215,33 @@ def create_and_get(model, **kw):
|
|
215
215
|
def make_if_needed(model, **values):
|
216
216
|
qs = model.objects.filter(**values)
|
217
217
|
if qs.count() == 1:
|
218
|
-
|
218
|
+
return qs.first()
|
219
|
+
# pass # ok, nothing to do
|
219
220
|
elif qs.count() == 0:
|
220
221
|
return model(**values)
|
221
222
|
else:
|
222
223
|
raise Exception(f"Multiple {model._meta.verbose_name_plural} for {values}")
|
223
224
|
|
224
225
|
|
226
|
+
def get_or_create(model, **kwargs):
|
227
|
+
# similar to Djanop's QuerySet.get_or_create() but calls full_clean
|
228
|
+
try:
|
229
|
+
obj = model.objects.get(**kwargs)
|
230
|
+
except model.DoesNotExist:
|
231
|
+
obj = model(**kwargs)
|
232
|
+
obj.full_clean()
|
233
|
+
obj.save()
|
234
|
+
return obj
|
235
|
+
|
236
|
+
|
237
|
+
def update_or_create(m, **kwargs):
|
238
|
+
if (obj := m.objects.filter(id=kwargs['id']).first()) is not None:
|
239
|
+
for k, v in kwargs.items():
|
240
|
+
setattr(obj, k, v)
|
241
|
+
return obj
|
242
|
+
return m(**kwargs)
|
243
|
+
|
244
|
+
|
225
245
|
def _test():
|
226
246
|
import doctest
|
227
247
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: lino
|
3
|
-
Version: 25.7.
|
3
|
+
Version: 25.7.3
|
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,14 +1,14 @@
|
|
1
1
|
lino/.cvsignore,sha256=1vrrWoP-WD8hPfCszHHIiJEi8KUMRCt5WvoKB9TSB1k,28
|
2
2
|
lino/SciTEDirectory.properties,sha256=rCYi_e-6h8Yx5DwXhAa6MBPlVINcl6Vv9BQDYZV2_go,28
|
3
|
-
lino/__init__.py,sha256=
|
3
|
+
lino/__init__.py,sha256=Z8-O-349Z6KOAuKypQdw30uEIz-6BXs2vR96MDswJSQ,6176
|
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=
|
7
|
+
lino/help_texts.py,sha256=vGF0OWysfFG0MYrTV9N1zqCQL-1T45aIS1iHR5Ypuxw,92484
|
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=w-5qIpWdXu5yXyCC4Qh4ApB3yZTn0AwdxAjEhH8PyVE,7510
|
11
|
-
lino/api/doctest.py,sha256=
|
11
|
+
lino/api/doctest.py,sha256=XPcuBVeBQyjsR789G9nIhgGzXKSNAq0MJIstPlhuQdU,26119
|
12
12
|
lino/api/rt.py,sha256=OCYWhrWnMcL988MdvBLBEP8qKQJEGXQhVoam_X0sotU,1376
|
13
13
|
lino/api/selenium.py,sha256=bOu8UaNz3Q7lGVvxjmvrtYtSWn1xfI1f5MN5sVcdYr8,9383
|
14
14
|
lino/api/shell.py,sha256=epyjwEZ396TiJ0AHqhVIvzX8TBIXU8xR4UHJlYOrRhc,536
|
@@ -28,11 +28,11 @@ lino/config/unused/403.html,sha256=ePwDIUXhz1iD8xXWWyt5xEvpcGIHU4LMnXma8x0ik1c,2
|
|
28
28
|
lino/config/unused/404.html,sha256=GOJrAyF6NcM69ETdSHgjff_-lvYs_-bOYhyZBem7x3I,220
|
29
29
|
lino/config/unused/500.html,sha256=aWmP37uPoMS-PJgPuBloxdx0nEreU7AvkXxsex3yVYs,544
|
30
30
|
lino/core/__init__.py,sha256=I4X69XK6Y1MZ8X6tC13Wmg13C3r5iTfYcFDiPJKpUdw,726
|
31
|
-
lino/core/actions.py,sha256=
|
31
|
+
lino/core/actions.py,sha256=opZ9_EyFaFxXk8prwzVnurFqmswFsKrf6ms38Rlc_wQ,32627
|
32
32
|
lino/core/actors.py,sha256=hbbzTpP7iBjQ2Eup4JhV5zx8w64arqPpkv4RnCptyKY,72585
|
33
|
-
lino/core/atomizer.py,sha256=
|
33
|
+
lino/core/atomizer.py,sha256=yK_l9-g8RZIjy2_iBB_efpyO1CrvegCBbjobD5mTTVc,13476
|
34
34
|
lino/core/boundaction.py,sha256=06NNPjCesEr-R1YQKkiuy8JKzDrMJJ948x9jczOkZqY,7850
|
35
|
-
lino/core/callbacks.py,sha256=
|
35
|
+
lino/core/callbacks.py,sha256=45lg153pzY7w94XLvh7QqHH7qOH5yTxLyRH7Vn_l1Ec,7549
|
36
36
|
lino/core/choicelists.py,sha256=5Xu3M5ZVOis2JoNSuNiJGBHdkqCwLofUxSd19iLIlKs,36503
|
37
37
|
lino/core/classproperty.py,sha256=_E95WPAs7BWbAuFpPvoYM2ZwW_mbq3rvF7o43WsMq_8,4316
|
38
38
|
lino/core/constants.py,sha256=GwSyViDk3wClZzgbrCo6N-JYOa3LCP46FSof-iZ5RRU,5085
|
@@ -43,17 +43,17 @@ lino/core/ddh.py,sha256=dYScxWKTOCDEgow7wJNJe812ESasmmITPK2ovraBQno,3172
|
|
43
43
|
lino/core/diff.py,sha256=XQ-oQQDS_v3kXd4eRP9Hwr5UCgp-TPZIPVav9ZblUno,5882
|
44
44
|
lino/core/elems.py,sha256=vGAqGwWkNUG9mtQkeu-EOlqPpOHyvnI6uhHn9ivsNdw,110631
|
45
45
|
lino/core/exceptions.py,sha256=QDxDo5cllSyXQ8VWet9hGXzNadxCOmwMVrFXc6V-vpE,665
|
46
|
-
lino/core/fields.py,sha256=
|
46
|
+
lino/core/fields.py,sha256=r8ZySAvyn2ZCkppPdgTVmqa0IPygM6xWU9GEgoCSQ-A,54775
|
47
47
|
lino/core/frames.py,sha256=ISxgq9zyZfqW3tDZMWdKi9Ij455lT_81qBH0xex0bfE,1161
|
48
48
|
lino/core/gfks.py,sha256=6VXn2FSIXOrwVq0stfbPevT37EWg1tg4Fn-HMNVnbmk,1970
|
49
49
|
lino/core/help.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
50
50
|
lino/core/inject.py,sha256=Qd_PGEn0yMXNYVPI0wCv1vvo2CNdlPkyoBmKZELOtGM,13422
|
51
|
-
lino/core/kernel.py,sha256=
|
51
|
+
lino/core/kernel.py,sha256=WbVyCANXcth5b-QGknJjidWc2mlmNjEUXiHStXzm8c0,48522
|
52
52
|
lino/core/keyboard.py,sha256=W3jA6qtB5HMppoNnd_6PgIM7ZlyHilJEhBvdeZTY7Xk,1283
|
53
53
|
lino/core/layouts.py,sha256=CWhKgCEBnjn39RMFRYUklPEvvCnZrDXhtigZpGuiR8o,28176
|
54
54
|
lino/core/menus.py,sha256=oZN93iwQU4vfUCuxQzaVz2xcccN5AG6NG2wGruL74sU,10713
|
55
55
|
lino/core/merge.py,sha256=sKtTeZtHdoDKerdHj4NXuXXNzpKDsfdPaiq-CY0NqQc,9094
|
56
|
-
lino/core/model.py,sha256=
|
56
|
+
lino/core/model.py,sha256=jcjCuB_Rg3JBvXUHT8f5kz-DlwZDBQla7kB19e1BQBs,37427
|
57
57
|
lino/core/permissions.py,sha256=sNReMhnjIpOZcJ79Z4k-Emp55evblExJZwH-PM-efcA,7579
|
58
58
|
lino/core/plugin.py,sha256=ZuA2d1oa3Mqx_jyPIwIV68cyzawLw_grthliIo83nuM,6835
|
59
59
|
lino/core/renderer.py,sha256=HhRC_gtrapNLw2Xl-cs67YdI_NdEdJ2ULsbvs5gb2wA,48252
|
@@ -61,12 +61,12 @@ lino/core/requests.py,sha256=_kwmx8VAwdaPssIdsZt_GzCst67BTR7WwVv4z_KCsNo,96389
|
|
61
61
|
lino/core/roles.py,sha256=PXwk436xUupxdbJcygRSYFu7ixfKjAJPQRUQ8sy0lB0,4425
|
62
62
|
lino/core/signals.py,sha256=ORY2s3Krlh9n24XyHetfwbeUhCqzib6YSqWeFTTY7ps,979
|
63
63
|
lino/core/site.py,sha256=HidiqVqXkTi-OKvNg8tvlR_FEKYEaowZ9h3ly0Zx-Fk,83583
|
64
|
-
lino/core/store.py,sha256=
|
64
|
+
lino/core/store.py,sha256=bbWrbsV-hPS1FF3e2ABiQHQ_Q61tD2XSRBDSwoTW6jQ,46093
|
65
65
|
lino/core/tables.py,sha256=sjmVu3A8gnamxwy16n76UJy2BXgiqeNeCEbI4oGd93Q,25431
|
66
66
|
lino/core/urls.py,sha256=06QlmN1vpxjmb5snO3SPpP6lX1pMdE60bTiBiC77_vQ,2677
|
67
67
|
lino/core/user_types.py,sha256=0iSYmzr2M9v2Mn2y6hzAZeqareUT-gD7l3MfIPyG9ZI,867
|
68
68
|
lino/core/userprefs.py,sha256=cmufIS9xJErKDrw05uoWtQTUR6WRWIGkU1KdAqzNr5M,2850
|
69
|
-
lino/core/utils.py,sha256=
|
69
|
+
lino/core/utils.py,sha256=DD3v75WK3sCmAaRQH3WTX3phbEsunPvepA0O5g1PBaw,40495
|
70
70
|
lino/core/views.py,sha256=qLjEN6GSXScbmAnKN7yDHySmsjL0h4sMKRIQCpOEdPU,7026
|
71
71
|
lino/core/widgets.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
72
72
|
lino/core/workflows.py,sha256=6DJ-sCcZ7kwUWYvArD2_j4NZBia0S3OgHySifC-NSuQ,10584
|
@@ -74,7 +74,7 @@ lino/core/auth/__init__.py,sha256=gbO35DCpyHQV9zjV1l349HQMME9-YgQ1h4amVOHywAc,98
|
|
74
74
|
lino/core/auth/apps.py,sha256=XCo18f23cEWZiZd4DUgL0JMTgxeERWFuQA8cQFQfUls,47
|
75
75
|
lino/core/auth/backends.py,sha256=IN3UHtfCb0AQqQL6MzIjhu-ESEphNDu1Q86qT48RsBI,8183
|
76
76
|
lino/core/auth/middleware.py,sha256=1c_z4lP_Rhbw7pdCapprGkjIXX40OJgIlFyQew4O-Nc,9708
|
77
|
-
lino/core/auth/utils.py,sha256=
|
77
|
+
lino/core/auth/utils.py,sha256=wPR0rxkuYuLv7_-eU-Qm5MsQ0nlM8GqlFZF2Iwzam8U,4401
|
78
78
|
lino/core/management/__init__.py,sha256=fp1cONBXgq1IftPk5c4b63gRlYOWpT5VzCIKrx0aGlE,61
|
79
79
|
lino/fake_migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
80
80
|
lino/locale/django.pot,sha256=iyeDILZFawKvi1w-4END2Xa9TDBw81ldWgbWegdGC9c,158276
|
@@ -116,16 +116,16 @@ lino/management/commands/run.py,sha256=MiK53KIACYKDTKF6knJGwU-uzEApGnDxByi-3_nrT
|
|
116
116
|
lino/management/commands/show.py,sha256=p59mer0ZDhNuasUzJpY0HbKr_st5_BMuwygInzp_yew,1371
|
117
117
|
lino/management/commands/syncscreenshots.py,sha256=XYZhqfm5_RwJzVFNGhHJKucl4j6T6mYo2GsDaUzvjAs,1561
|
118
118
|
lino/management/commands/update_conf.py,sha256=saAaQdPhn3mNOoHcBxOFSf_vBEgM-aopTHq1sJN20Bo,1026
|
119
|
-
lino/mixins/__init__.py,sha256=
|
120
|
-
lino/mixins/
|
121
|
-
lino/mixins/
|
119
|
+
lino/mixins/__init__.py,sha256=M5P13IaRIfz-73Lz1EKCArARXHd5Dz8jKoV5c0Z0bZc,8788
|
120
|
+
lino/mixins/clonable.py,sha256=6wJeUl_dHuVv60fFVZlCMcqsrFBbo5gGzXNWxQjOAoM,4631
|
121
|
+
lino/mixins/dupable.py,sha256=_uXPiD29dYzzzAIPuw0urBRApJ2Y4-kNDJg5ye-lGf4,10215
|
122
122
|
lino/mixins/human.py,sha256=YDIfIHHAaVmzd3uGsJp_vDvkaBWOp09I7i4AGNy9YsQ,13255
|
123
123
|
lino/mixins/periods.py,sha256=b2vucnjFXYalxiDlH_LsSfPwJU5tcluKfFAaLS3vTck,11519
|
124
124
|
lino/mixins/polymorphic.py,sha256=MLbfOeIYRoDZO4048X2oWhG5cxds2pLkwciXcw1xjVQ,9393
|
125
125
|
lino/mixins/printable.py,sha256=4U8M1lrTjUeuaPwrcWoanCBo53iAxiNpSTsVctI-gI0,199
|
126
126
|
lino/mixins/ref.py,sha256=qV8CprGCvwzzWTl6LQc9I1RwD8pziD0F7Ykoaznm8wM,5550
|
127
|
-
lino/mixins/registrable.py,sha256=
|
128
|
-
lino/mixins/sequenced.py,sha256=
|
127
|
+
lino/mixins/registrable.py,sha256=DYiwiIoYMO488ZGX7C5PRbKz9HBpzk1rG6q9-_WvymQ,7208
|
128
|
+
lino/mixins/sequenced.py,sha256=3DvjBEHLHacbBBq6iiVGftcvOPhBVpA9FN_tvNc6Bpo,16567
|
129
129
|
lino/modlib/__init__.py,sha256=cO31gNu2oRkp7o2v3D9gK2H7j4jF9rbVyPxPZhZQwrQ,940
|
130
130
|
lino/modlib/about/__init__.py,sha256=jhqGQIXU1o7KkmmQjfwPKJc3buibB09Fy55carAmi7U,342
|
131
131
|
lino/modlib/about/choicelists.py,sha256=2bxDb2u7cFacBOgLoEWrMmzQ4BJ3x1pmhdgqxzUp-Rw,1424
|
@@ -184,7 +184,7 @@ lino/modlib/dashboard/__init__.py,sha256=_PFbmakUn8DShXyJY3EfAcuZtX5ofWnS-8dk7s1
|
|
184
184
|
lino/modlib/dashboard/models.py,sha256=EgRNg88dmz-OlIdi1SyEuerWMsRqKIfqE2MgKL7kApw,3510
|
185
185
|
lino/modlib/dupable/__init__.py,sha256=fIQ8wj-T8ZbkjwQgW_-ankJsHLjPMepOTo32mJXNCvI,532
|
186
186
|
lino/modlib/dupable/mixins.py,sha256=SZ2Exe5q3ANYsP7gnEXQuQczwCDKdRfFvOavreu4mYI,6324
|
187
|
-
lino/modlib/dupable/models.py,sha256=
|
187
|
+
lino/modlib/dupable/models.py,sha256=fcPbWRLwAVOQ4y_E3kaeHUanxmZTS69dlg9TLNCeyZs,4575
|
188
188
|
lino/modlib/export_excel/__init__.py,sha256=HrsrhXjIMvMHRGu8whH3A_WijZWrH35p2cQsFXK60DY,356
|
189
189
|
lino/modlib/export_excel/models.py,sha256=u9COKVdVsPwGk5WjgVarjLSkxmS-KOdohXfH4CruF_c,5353
|
190
190
|
lino/modlib/extjs/__init__.py,sha256=6UBWAWSROwy3DfTXQmVUVJTF6eZ_e2k3BEfE4wtqVhU,10172
|
@@ -3550,7 +3550,7 @@ lino/modlib/memo/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeu
|
|
3550
3550
|
lino/modlib/memo/management/commands/removeurls.py,sha256=wZfy-u2ylCF-oKEgaMgvw9zvFIbgV3TZNUcJz4qvE2k,2133
|
3551
3551
|
lino/modlib/notify/__init__.py,sha256=suo7EMVdyTPTPFwuU2KZL25PwIEstTvvR4Turgdz7UE,6926
|
3552
3552
|
lino/modlib/notify/actions.py,sha256=ClRKDjmgx3m43IZ5cx0TdxXN_pU6hLIlo_jCwEW2LhY,2468
|
3553
|
-
lino/modlib/notify/api.py,sha256=
|
3553
|
+
lino/modlib/notify/api.py,sha256=oZemK9G8Ie6O8iEMDl5mv7BbpCpbfBHbk0xI9125RBY,4366
|
3554
3554
|
lino/modlib/notify/choicelists.py,sha256=7ZkYNMOXNDfyTvdx8Sn-Gsma9f31o-6G1CtivXmQDmA,1324
|
3555
3555
|
lino/modlib/notify/consumers.py,sha256=YaEAhAi_Oq5ovakuP5DI21YIAMvRqQcf4K8MBilcN2w,1529
|
3556
3556
|
lino/modlib/notify/mixins.py,sha256=rwsTgqpzvyiekOqHpxQRTPPdOhv2ZIPrW03YSATfdeE,3903
|
@@ -3582,7 +3582,7 @@ lino/modlib/periods/fixtures/std.py,sha256=aWzt-frGjzPDwQ2pCKU1nT3oE4xzm7AQ8uLTJ
|
|
3582
3582
|
lino/modlib/printing/__init__.py,sha256=u1fq44d073-IDH_t8hWs1sQdlAHdsCP85sfEOMSW5L4,689
|
3583
3583
|
lino/modlib/printing/actions.py,sha256=gn4XqIvToXUumymDA20sl7RRsPOejCMu8dKZ3NJJKcE,11669
|
3584
3584
|
lino/modlib/printing/choicelists.py,sha256=UeOVlkYsLV7gxmVWuKqgqrU5zRlYyUck_3ebKDYnqDA,9743
|
3585
|
-
lino/modlib/printing/mixins.py,sha256=
|
3585
|
+
lino/modlib/printing/mixins.py,sha256=meu4JvOJ_ErAOOR7qF9tEZZI-9NlRGa3z8f7KG9uHik,8335
|
3586
3586
|
lino/modlib/printing/models.py,sha256=fd-BEKSLpgxPnkh9U7fg2tjNy39exBi3xJC9VzJuXdU,185
|
3587
3587
|
lino/modlib/printing/utils.py,sha256=LUO9769wJvHCPZIqeVQ9XAS6UKJ6BfJbiwO8Dt1kHc4,737
|
3588
3588
|
lino/modlib/printing/config/report/Default.odt,sha256=4X8UD9H_5Th2CELP0C6DTe4g0ZNUPXAg1C00xP3Qluc,10930
|
@@ -3629,7 +3629,7 @@ lino/modlib/smtpd/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
3629
3629
|
lino/modlib/smtpd/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3630
3630
|
lino/modlib/smtpd/management/commands/recmail.py,sha256=_0co9uNx3Cq0zudrho-630yupuSCRM-Ilc5cIug3exE,1980
|
3631
3631
|
lino/modlib/summaries/__init__.py,sha256=IPoKcanVyKdWx2M1uSekQbsDUcdpw8yHmGKhiWtJIr0,538
|
3632
|
-
lino/modlib/summaries/mixins.py,sha256=
|
3632
|
+
lino/modlib/summaries/mixins.py,sha256=dUf8Lwo8ZSgXCAeUIXgB2G0PrW7415lBsSzPfZDXzQM,5844
|
3633
3633
|
lino/modlib/summaries/models.py,sha256=vx28VP6ApD9D9tgoemw6x2VTZZNLbMCfnRo75f4jjTw,2039
|
3634
3634
|
lino/modlib/summaries/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3635
3635
|
lino/modlib/summaries/fixtures/checksummaries.py,sha256=WOBdRAZkdje_2CGJof6BxhSNTQkCgBT0ri4E1heXl-8,382
|
@@ -4407,7 +4407,7 @@ lino/modlib/uploads/fixtures/demo.py,sha256=rhidbKN4vOyzqnRLMXu3gkx4zAtxGj3FoSz0
|
|
4407
4407
|
lino/modlib/uploads/fixtures/demo3.py,sha256=q0bwZrx5XtRsRlFpsa33fL0sCl7IdCYaP9E1rhCnJt4,547
|
4408
4408
|
lino/modlib/uploads/fixtures/std.py,sha256=nb5oRcX_WrkTLaGoch6PT7GA0FPKmqbN-BdlPq-hHSc,516
|
4409
4409
|
lino/modlib/users/__init__.py,sha256=P9am0pJURsgCmx9J55q8LFChF8Ga9mody1PtJRXWbvM,4578
|
4410
|
-
lino/modlib/users/actions.py,sha256=
|
4410
|
+
lino/modlib/users/actions.py,sha256=NcJVCfIhP3moN2MvhIonyCKzld7ruUtnCX4tFVMK7_c,18445
|
4411
4411
|
lino/modlib/users/choicelists.py,sha256=-X76C1NxIs5e7rFHp5Z0kjJkA1NlOP2vdLKGkI2wZRU,3876
|
4412
4412
|
lino/modlib/users/mixins.py,sha256=Ukib2jUnDR2MVJrASpmzoPS_eke-Z431U78JDPe8ysk,14275
|
4413
4413
|
lino/modlib/users/models.py,sha256=V5r_aY7M7gXfY1wAcIknacwsF8k9vtiMY898-y7GSjE,17842
|
@@ -4433,8 +4433,8 @@ lino/projects/__init__.py,sha256=clYlClMVuUD0O5h_0rtmolCoA_V4fn7f5bUb6iSJn6I,111
|
|
4433
4433
|
lino/projects/std/__init__.py,sha256=F1MQWdg7KpmHmKW-vWKRI0kwrkFd1nefWviKf4IIMD0,169
|
4434
4434
|
lino/projects/std/settings.py,sha256=wZBvXavMo3sTsSOj4vm4Kgd9Cw9EgoGYFJJcJ1JzxeA,2831
|
4435
4435
|
lino/projects/std/settings_test.py,sha256=qkxqAanlEvcuqOSuMtO8oGKnevftXflRmAxeyOicuSg,392
|
4436
|
-
lino/sphinxcontrib/__init__.py,sha256=
|
4437
|
-
lino/sphinxcontrib/actordoc.py,sha256=
|
4436
|
+
lino/sphinxcontrib/__init__.py,sha256=sg03m76tbuhgXW4JranBaVj0HvBPPSVMwFATG413KWA,3968
|
4437
|
+
lino/sphinxcontrib/actordoc.py,sha256=Q5tuu1gRN0WJ_m-x_72Tq6UiZXK2_EznB4OoEUnnFwM,20708
|
4438
4438
|
lino/sphinxcontrib/base.py,sha256=pq5u4bFSxMgPm9OMDo8xPVGhuS6MZAUd9bF6rQCCHJs,1193
|
4439
4439
|
lino/sphinxcontrib/help_texts_extractor.py,sha256=mlHyeiIdzbfzQXkT8j8skdcBQ-FV3zAPW2DXnY8Hs1I,10385
|
4440
4440
|
lino/sphinxcontrib/logo/__init__.py,sha256=dCHNLzhlMdSYVMui3vc2ybzPU6D4GikiRP-G9SCu1TA,2257
|
@@ -4592,7 +4592,7 @@ lino/utils/dates.py,sha256=eWF5WxA5uJf51Y9PKvDVBWD8yIf6yBF6oO6TeU3ujzw,1030
|
|
4592
4592
|
lino/utils/dbfreader.py,sha256=KrGsBAFV2tF9pAd9jsmBAFpZ-yw-CRymZHEn_q9IL90,13784
|
4593
4593
|
lino/utils/dbhash.py,sha256=tG1IHe6Bz9MaagTI-131gpcLcNw3g642QVvv7GsJH2g,3303
|
4594
4594
|
lino/utils/dblogger.py,sha256=kr0YxQY6veymvNg5A4tsvkqW8haRWdwqL0C-_9_QTg0,721
|
4595
|
-
lino/utils/diag.py,sha256=
|
4595
|
+
lino/utils/diag.py,sha256=quiGcv-e0pwn_yjjt7OUMo8kr1qKYmIFBjDnHxr_5X4,18754
|
4596
4596
|
lino/utils/djangotest.py,sha256=Phz1qNp0wDonZRja5dxbCk0Xl3a73gZNiKK8v9tAgZg,8334
|
4597
4597
|
lino/utils/dpy.py,sha256=8eL5SE6YfTFLvNjFJlFr2SpR_eubU0Rb3ckCbGgrsU8,20661
|
4598
4598
|
lino/utils/fieldutils.py,sha256=6GwPOfL-Jv-uh5-tZrTqC1hJccqHhdLbVSy4CAeegDA,2957
|
@@ -4600,7 +4600,7 @@ lino/utils/format_date.py,sha256=zJu8PO45hGsk6Znq8_93D3vUz9HcY7CjHduAFxoU0v8,312
|
|
4600
4600
|
lino/utils/html.py,sha256=nR2h6oa_47Baq5rdSln0aGbqzS6SFsWzl-uqjnGIUWU,3273
|
4601
4601
|
lino/utils/html2odf.py,sha256=Hxw4HiIHY1ZCjb4_JLykVHbr6yAMhhHrnrCnLNDYKAs,4826
|
4602
4602
|
lino/utils/html2xhtml.py,sha256=fvrIoLBFpiXtYO3UYaIgAIDjf6ATvrxolQX4etxS57Y,2119
|
4603
|
-
lino/utils/instantiator.py,sha256=
|
4603
|
+
lino/utils/instantiator.py,sha256=w_yt1ETFa4DruvF3clTUr1xQ-bVCRN4m5oi2zKljj5w,7553
|
4604
4604
|
lino/utils/jinja.py,sha256=1FZgWNKEP9wcokFuIfYysl_VD5mwVHxBHtpnmO17nRQ,1444
|
4605
4605
|
lino/utils/jscompressor.py,sha256=j9UTaaPCfRZLrWUh6PBp0KDDM0QshG7XAFzp-R_elOs,5225
|
4606
4606
|
lino/utils/jsgen.py,sha256=p5BSoCYs67AgD-Q9gmeJp_uQffskT3HXYdp7SrniDsI,15252
|
@@ -4635,8 +4635,8 @@ lino/utils/xml.py,sha256=EGDnO1UaREst9fS7KTESdbHnrrVCwKbRQdvut6B6GmQ,1612
|
|
4635
4635
|
lino/utils/mldbc/__init__.py,sha256=QqWRlzeXaOmFfbCk-vTY3SZMn1-FCf67XnpZdd_Nim0,1134
|
4636
4636
|
lino/utils/mldbc/fields.py,sha256=tAX8G5UKigr9c6g0F3ARIjZZtg406mdaZ--PWSbiH9E,2873
|
4637
4637
|
lino/utils/mldbc/mixins.py,sha256=CkYe5jDa7xp9fJq_V8zcZf8ocxgIjUgHc9KZccvA_Yw,1945
|
4638
|
-
lino-25.7.
|
4639
|
-
lino-25.7.
|
4640
|
-
lino-25.7.
|
4641
|
-
lino-25.7.
|
4642
|
-
lino-25.7.
|
4638
|
+
lino-25.7.3.dist-info/METADATA,sha256=V8-UPwVsw07yLV9_UI7YAxRmj6CntfLiivjBLfswdlo,42534
|
4639
|
+
lino-25.7.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
4640
|
+
lino-25.7.3.dist-info/licenses/AUTHORS.rst,sha256=8VEm_G4HOmYEa4oi1nVoKKsdo4JanekEJCefWd2E8vk,981
|
4641
|
+
lino-25.7.3.dist-info/licenses/COPYING,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
4642
|
+
lino-25.7.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|