lino 25.3.4__py3-none-any.whl → 25.4.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.
- lino/__init__.py +7 -1
- lino/api/dd.py +1 -1
- lino/config/admin_main_base.html +4 -3
- lino/help_texts.py +12 -14
- lino/management/commands/buildcache.py +2 -2
- lino/modlib/__init__.py +0 -1
- lino/modlib/extjs/views.py +1 -2
- lino/modlib/linod/mixins.py +94 -41
- lino/modlib/linod/models.py +1 -1
- lino/modlib/memo/__init__.py +4 -0
- lino/modlib/memo/models.py +47 -1
- lino/modlib/weasyprint/config/weasyprint/base.weasy.html +3 -1
- lino/sphinxcontrib/logo/__init__.py +2 -1
- lino/utils/__init__.py +1 -0
- lino/utils/dbhash.py +5 -3
- lino/utils/format_date.py +9 -4
- {lino-25.3.4.dist-info → lino-25.4.0.dist-info}/METADATA +1 -1
- {lino-25.3.4.dist-info → lino-25.4.0.dist-info}/RECORD +21 -21
- {lino-25.3.4.dist-info → lino-25.4.0.dist-info}/WHEEL +0 -0
- {lino-25.3.4.dist-info → lino-25.4.0.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-25.3.4.dist-info → lino-25.4.0.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.
|
34
|
+
__version__ = '25.4.0'
|
35
35
|
|
36
36
|
# import setuptools # avoid UserWarning "Distutils was imported before Setuptools"?
|
37
37
|
|
@@ -96,6 +96,12 @@ warnings.filterwarnings(
|
|
96
96
|
# TODO: get everything to work even when ResourceWarning gives an error
|
97
97
|
# warnings.filterwarnings("error", category=ResourceWarning)
|
98
98
|
|
99
|
+
warnings.filterwarnings("error", category=SyntaxWarning)
|
100
|
+
|
101
|
+
# 20250401 Activating the following line caused `doctest docs/plugins/linod.rst`
|
102
|
+
# to fail with "Fatal Python error: Segmentation fault":
|
103
|
+
# warnings.filterwarnings("error", category=DeprecationWarning)
|
104
|
+
|
99
105
|
|
100
106
|
# def setup_project(settings_module):
|
101
107
|
# os.environ['DJANGO_SETTINGS_MODULE'] = settings_module
|
lino/api/dd.py
CHANGED
@@ -155,7 +155,7 @@ from lino.utils import IncompleteDate, read_exception
|
|
155
155
|
|
156
156
|
from lino.utils.format_date import fdm, fdl, fdf, fdmy
|
157
157
|
from lino.utils.format_date import fds as fds_
|
158
|
-
from lino.utils.format_date import ftl
|
158
|
+
from lino.utils.format_date import ftl, ftf
|
159
159
|
|
160
160
|
|
161
161
|
def fds(d):
|
lino/config/admin_main_base.html
CHANGED
@@ -77,20 +77,21 @@
|
|
77
77
|
{{_("Or sign in using ")}}
|
78
78
|
{% for e in site.get_social_auth_links() %}
|
79
79
|
{{tostring(e)}}
|
80
|
-
{% endfor %}
|
80
|
+
{% endfor %}.
|
81
81
|
{% endif %}
|
82
82
|
</p>
|
83
83
|
{% if site.is_demo_site %}
|
84
84
|
<p>
|
85
85
|
{{_("This demo site has %d users:") %
|
86
|
-
site.models.users.UsersOverview.
|
86
|
+
site.models.users.UsersOverview.create_request().get_total_count()}}
|
87
87
|
</p>
|
88
88
|
{% if False %}
|
89
89
|
<p>{{ar.show(site.models.users.UsersOverview, display_mode="ul")}}</p>
|
90
90
|
{% else %}
|
91
91
|
{{as_ul('users.UsersOverview')}}
|
92
92
|
{% endif %}
|
93
|
-
<p>{{_("The password is the same for all of them:
|
93
|
+
<p>{{_("The password is the same for all of them:")}}
|
94
|
+
"{{site.plugins.users.demo_password}}".</p>
|
94
95
|
{% endif %}
|
95
96
|
{% endif %}
|
96
97
|
{% endblock %}
|
lino/help_texts.py
CHANGED
@@ -139,7 +139,7 @@ help_texts = {
|
|
139
139
|
'lino.modlib.extjs.ext_renderer.ExtRenderer.goto_instance' : _("""See JsRenderer.goto_instance(), but when this is called while the detail window is already open (only on another record), then we don’t want to redirect to another page because that would take more time."""),
|
140
140
|
'lino.modlib.extjs.views.AdminIndex' : _("""Similar to PlainIndex"""),
|
141
141
|
'lino.modlib.extjs.views.Restful' : _("""Used to collaborate with a restful Ext.data.Store."""),
|
142
|
-
'lino.modlib.extjs.views.ApiElement' : _("""The view that responds to
|
142
|
+
'lino.modlib.extjs.views.ApiElement' : _("""The view that responds to api/app_label/actor/pk."""),
|
143
143
|
'lino.modlib.gfks.Plugin' : _("""Base class for this plugin."""),
|
144
144
|
'lino.modlib.importfilters.Plugin' : _("""See /dev/plugins."""),
|
145
145
|
'lino.modlib.jinja.Plugin' : _("""See /dev/plugins."""),
|
@@ -153,13 +153,13 @@ help_texts = {
|
|
153
153
|
'lino.modlib.memo.Plugin' : _("""Base class for this plugin."""),
|
154
154
|
'lino.modlib.memo.Plugin.parser' : _("""An instance of lino.modlib.memo.parser.Parser."""),
|
155
155
|
'lino.modlib.memo.Plugin.front_end' : _("""The front end to use when writing previews."""),
|
156
|
-
'lino.modlib.memo.parser.Suggester' : _("""Holds the configuration for the behaviour of a given “trigger”."""),
|
157
156
|
'lino.modlib.memo.parser.Parser' : _("""The memo parser."""),
|
158
157
|
'lino.modlib.memo.parser.Parser.add_suggester' : _("""Add a Suggester (see there for args and kwargs)."""),
|
159
|
-
'lino.modlib.memo.parser.Parser.register_command' : _("""Register a memo command identified by the given text cmd."""),
|
160
|
-
'lino.modlib.memo.parser.Parser.register_django_model' : _("""Register the given string name as command for referring to database rows of the given Django database model model."""),
|
161
158
|
'lino.modlib.memo.parser.Parser.get_referred_objects' : _("""Yield all database objects referred in the given text using a suggester."""),
|
162
159
|
'lino.modlib.memo.parser.Parser.parse' : _("""Parse the given string src, replacing memo commands by their result."""),
|
160
|
+
'lino.modlib.memo.parser.Parser.register_command' : _("""Register a memo command identified by the given text cmd."""),
|
161
|
+
'lino.modlib.memo.parser.Parser.register_django_model' : _("""Register the given string name as command for referring to database rows of the given Django database model model."""),
|
162
|
+
'lino.modlib.memo.parser.Suggester' : _("""Holds the configuration for the behaviour of a given “trigger”."""),
|
163
163
|
'lino.modlib.restful.Plugin' : _("""See /dev/plugins."""),
|
164
164
|
'lino.modlib.smtpd.Plugin' : _("""See /dev/plugins."""),
|
165
165
|
'lino.modlib.system.Plugin' : _("""See /dev/plugins."""),
|
@@ -172,13 +172,6 @@ help_texts = {
|
|
172
172
|
'lino.modlib.tinymce.Plugin.window_buttons2' : _("""The second row of toolbar buttons when editing in own window."""),
|
173
173
|
'lino.modlib.tinymce.Plugin.window_buttons3' : _("""The third row of toolbar buttons when editing in own window."""),
|
174
174
|
'lino.modlib.tinymce.Plugin.media_name' : _("""Lino currently includes three versions of TinyMCE, but for production sites we still use the eldest version 3.4.8."""),
|
175
|
-
'lino.modlib.weasyprint.Plugin' : _("""See /dev/plugins."""),
|
176
|
-
'lino.modlib.weasyprint.Plugin.header_height' : _("""Height of header in mm. Set to None if you want no header."""),
|
177
|
-
'lino.modlib.weasyprint.Plugin.footer_height' : _("""Height of footer in mm. Set to None if you want no header."""),
|
178
|
-
'lino.modlib.weasyprint.Plugin.top_right_width' : _("""Width of top-right.jpg in mm. If not given, Lino computes it based on height."""),
|
179
|
-
'lino.modlib.weasyprint.Plugin.top_right_image' : _("""The first image file found in config named either top-right.jpg or top-right.png."""),
|
180
|
-
'lino.modlib.weasyprint.Plugin.header_image' : _("""The first image file found in config named either header.jpg or header.png."""),
|
181
|
-
'lino.modlib.weasyprint.Plugin.margin' : _("""Top and bottom page margin in mm."""),
|
182
175
|
'lino.modlib.wkhtmltopdf.Plugin' : _("""See /dev/plugins."""),
|
183
176
|
'lino.sphinxcontrib.actordoc.CurrentLanguage' : _("""Tell Sphinx to switch to the specified language until the end of this document."""),
|
184
177
|
'lino.sphinxcontrib.actordoc.CurrentProject' : _("""Tell Sphinx to switch to the specified project until the end of this document."""),
|
@@ -371,13 +364,18 @@ help_texts = {
|
|
371
364
|
'lino.modlib.linod.LogLevels' : _("""A choicelist of logging levels available in this application."""),
|
372
365
|
'lino.modlib.linod.SystemTask' : _("""Django model used to represent a background task."""),
|
373
366
|
'lino.modlib.linod.SystemTask.start_datetime' : _("""Tells at what time exactly this job started."""),
|
374
|
-
'lino.modlib.linod.SystemTask.message' : _("""Stores information about the job, mostly logs."""),
|
375
|
-
'lino.modlib.linod.SystemTask.disabled' : _("""Tells whether the task should be ignored."""),
|
376
|
-
'lino.modlib.linod.SystemTask.log_level' : _("""The logging level to apply when running this task."""),
|
377
367
|
'lino.modlib.linod.SystemTask.run' : _("""Performs a routine job."""),
|
378
368
|
'lino.modlib.linod.SystemTasks' : _("""The default table for the SystemTask model."""),
|
379
369
|
'lino.modlib.linod.Runnable' : _("""Model mixin used by SystemTask and other models."""),
|
370
|
+
'lino.modlib.linod.Runnable.run_now' : _("""Explicitly request to tun this task as soon as possible."""),
|
371
|
+
'lino.modlib.linod.Runnable.cancel_run' : _("""Cancel the explicit request to tun this task as soon as possible."""),
|
380
372
|
'lino.modlib.linod.Runnable.procedure' : _("""The background procedure to run in this task."""),
|
373
|
+
'lino.modlib.linod.Runnable.requested_at' : _("""The timestamp when a user has explicitly requested to run this task."""),
|
374
|
+
'lino.modlib.linod.Runnable.last_start_time' : _("""The timestamp when this task has started running in the task runner."""),
|
375
|
+
'lino.modlib.linod.Runnable.last_end_time' : _("""The timestamp when this task has finished running in the task runner."""),
|
376
|
+
'lino.modlib.linod.Runnable.message' : _("""Stores information about the job, mostly logs."""),
|
377
|
+
'lino.modlib.linod.Runnable.disabled' : _("""Tells whether the task should be ignored."""),
|
378
|
+
'lino.modlib.linod.Runnable.log_level' : _("""The logging level to apply when running this task."""),
|
381
379
|
'lino.modlib.periods.StoredYear' : _("""The Django model used to store a fiscal year."""),
|
382
380
|
'lino.modlib.periods.StoredPeriod' : _("""The Django model used to store an accounting period."""),
|
383
381
|
'lino.modlib.periods.StoredYears' : _("""The fiscal years defined in this database."""),
|
@@ -37,7 +37,7 @@ class Command(BaseCommand):
|
|
37
37
|
|
38
38
|
# the following log message was useful on Travis 20150104
|
39
39
|
if verbosity > 0:
|
40
|
-
logger.info("`
|
40
|
+
logger.info("`buildcache` started on %s.", project_dir)
|
41
41
|
|
42
42
|
# pth = project_dir / "settings.py"
|
43
43
|
# if pth.exists():
|
@@ -55,4 +55,4 @@ class Command(BaseCommand):
|
|
55
55
|
|
56
56
|
# settings.SITE.clear_site_config()
|
57
57
|
|
58
|
-
logger.info("`
|
58
|
+
logger.info("`buildcache` finished on %s.", project_dir)
|
lino/modlib/__init__.py
CHANGED
lino/modlib/extjs/views.py
CHANGED
@@ -321,8 +321,7 @@ NOT_FOUND = "%s has no row with primary key %r"
|
|
321
321
|
|
322
322
|
class ApiElement(View):
|
323
323
|
"""
|
324
|
-
The view that responds to
|
325
|
-
``r'api/(?P<app_label>\w+)/(?P<actor>\w+)/(?P<pk>[^/]+)$'``.
|
324
|
+
The view that responds to ``api/app_label/actor/pk``.
|
326
325
|
"""
|
327
326
|
|
328
327
|
@method_decorator(ensure_csrf_cookie)
|
lino/modlib/linod/mixins.py
CHANGED
@@ -38,6 +38,11 @@ class RunNow(dd.Action):
|
|
38
38
|
# icon_name = 'bell'
|
39
39
|
# icon_name = 'lightning'
|
40
40
|
|
41
|
+
# def get_action_permission(self, ar, obj, state):
|
42
|
+
# if obj.requested_at or obj.is_running():
|
43
|
+
# return False
|
44
|
+
# return super().get_action_permission(ar, obj, state)
|
45
|
+
|
41
46
|
def run_from_ui(self, ar, **kwargs):
|
42
47
|
# print("20231102 RunNow", ar.selected_rows)
|
43
48
|
for obj in ar.selected_rows:
|
@@ -45,10 +50,11 @@ class RunNow(dd.Action):
|
|
45
50
|
if True: # dd.plugins.linod.use_channels:
|
46
51
|
obj.last_start_time = None
|
47
52
|
obj.last_end_time = None
|
53
|
+
obj.requested_at = timezone.now()
|
48
54
|
obj.message = "{} requested to run this task at {}.".format(
|
49
55
|
ar.get_user(), dd.ftl(timezone.now())
|
50
56
|
)
|
51
|
-
obj.disabled = False
|
57
|
+
# obj.disabled = False
|
52
58
|
obj.full_clean()
|
53
59
|
obj.save()
|
54
60
|
else:
|
@@ -57,6 +63,30 @@ class RunNow(dd.Action):
|
|
57
63
|
ar.set_response(refresh=True)
|
58
64
|
|
59
65
|
|
66
|
+
class CancelRun(dd.Action):
|
67
|
+
label = _("Cancel request")
|
68
|
+
help_text = _("Cancel the request to run this task asap.")
|
69
|
+
select_rows = True
|
70
|
+
button_text = "🗙" # ⛒
|
71
|
+
# icon_name = 'bell'
|
72
|
+
# icon_name = 'lightning'
|
73
|
+
|
74
|
+
# def get_action_permission(self, ar, obj, state):
|
75
|
+
# if obj.requested_at is None:
|
76
|
+
# return False
|
77
|
+
# return super().get_action_permission(ar, obj, state)
|
78
|
+
|
79
|
+
def run_from_ui(self, ar, **kwargs):
|
80
|
+
for obj in ar.selected_rows:
|
81
|
+
assert issubclass(obj.__class__, Runnable)
|
82
|
+
obj.requested_at = None
|
83
|
+
obj.message = "{} cancelled the request to run this task.".format(
|
84
|
+
ar.get_user())
|
85
|
+
obj.full_clean()
|
86
|
+
obj.save()
|
87
|
+
ar.set_response(refresh=True)
|
88
|
+
|
89
|
+
|
60
90
|
class Runnable(Sequenced, RecurrenceSet):
|
61
91
|
class Meta:
|
62
92
|
abstract = True
|
@@ -66,6 +96,7 @@ class Runnable(Sequenced, RecurrenceSet):
|
|
66
96
|
last_start_time = dd.DateTimeField(
|
67
97
|
_("Started at"), null=True, editable=False)
|
68
98
|
last_end_time = dd.DateTimeField(_("Ended at"), null=True, editable=False)
|
99
|
+
requested_at = dd.DateTimeField(_("Requested at"), null=True, editable=False)
|
69
100
|
message = dd.RichTextField(
|
70
101
|
_("Logged messages"), format="plain", editable=False)
|
71
102
|
|
@@ -74,12 +105,23 @@ class Runnable(Sequenced, RecurrenceSet):
|
|
74
105
|
name = models.CharField(_("Name"), max_length=200, blank=True)
|
75
106
|
|
76
107
|
run_now = RunNow()
|
108
|
+
cancel_run = CancelRun()
|
77
109
|
|
78
110
|
def __str__(self):
|
111
|
+
# r = "{} ({} #{})".format(
|
112
|
+
# self.name, self._meta.verbose_name, self.seqno)
|
79
113
|
r = "{} #{} ({})".format(
|
80
114
|
self._meta.verbose_name, self.seqno, self.name)
|
81
115
|
return r
|
82
116
|
|
117
|
+
def disabled_fields(self, ar):
|
118
|
+
rv = super().disabled_fields(ar)
|
119
|
+
if self.requested_at is None:
|
120
|
+
rv.add('cancel_run')
|
121
|
+
else:
|
122
|
+
rv.add('run_now')
|
123
|
+
return rv
|
124
|
+
|
83
125
|
def full_clean(self, *args, **kwargs):
|
84
126
|
super().full_clean(*args, **kwargs)
|
85
127
|
# 20250213 The following caused 'Invalid procedure invoicing.Task for
|
@@ -114,6 +156,7 @@ class Runnable(Sequenced, RecurrenceSet):
|
|
114
156
|
# ar.info("Start %s with logging level %s", astr(self), self.log_level)
|
115
157
|
# forget about any previous run:
|
116
158
|
self.last_start_time = timezone.now()
|
159
|
+
self.requested_at = None
|
117
160
|
self.last_end_time = None
|
118
161
|
self.message = ""
|
119
162
|
# print("20231102 full_clean")
|
@@ -150,17 +193,20 @@ class Runnable(Sequenced, RecurrenceSet):
|
|
150
193
|
@dd.displayfield("Status")
|
151
194
|
def status(self, ar=None):
|
152
195
|
if self.is_running():
|
153
|
-
return _("Running since {}").format(dd.
|
196
|
+
return _("Running since {}").format(dd.ftf(self.last_start_time))
|
197
|
+
if self.requested_at is not None:
|
198
|
+
return _("Requested to run asap (since {})").format(
|
199
|
+
dd.ftf(self.requested_at))
|
154
200
|
if self.disabled:
|
155
201
|
return _("Disabled")
|
156
202
|
if self.last_start_time is None or self.last_end_time is None:
|
157
|
-
if self.every_unit in
|
203
|
+
if self.every_unit in {Recurrences.never, None}:
|
158
204
|
return _("Not scheduled")
|
159
205
|
return _("Scheduled to run asap")
|
160
206
|
next_time = self.get_next_suggested_date(self.last_end_time)
|
161
207
|
if next_time is None:
|
162
208
|
return _("Not scheduled")
|
163
|
-
return _("Scheduled to run at {}").format(dd.
|
209
|
+
return _("Scheduled to run at {}").format(dd.ftf(next_time))
|
164
210
|
|
165
211
|
|
166
212
|
async def start_task_runner(ar=None, max_count=None):
|
@@ -177,53 +223,60 @@ async def start_task_runner(ar=None, max_count=None):
|
|
177
223
|
next_time = now + \
|
178
224
|
timedelta(seconds=dd.plugins.linod.background_sleep_time)
|
179
225
|
|
226
|
+
tasks = []
|
180
227
|
for cls in Procedures.task_classes():
|
181
228
|
# asyncio.ensure_future(m.start_task_runner(ar.spawn_request()))
|
182
229
|
# print("20240424b")
|
183
|
-
|
230
|
+
async for obj in cls.objects.filter(
|
231
|
+
requested_at__isnull=False).order_by("requested_at"):
|
232
|
+
tasks.append(obj)
|
233
|
+
for cls in Procedures.task_classes():
|
234
|
+
async for obj in cls.objects.filter(
|
235
|
+
requested_at__isnull=True, disabled=False).order_by("seqno"):
|
236
|
+
tasks.append(obj)
|
184
237
|
# print("20240424c")
|
185
238
|
# async for self in tasks:
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
)
|
195
|
-
await ar.adebug(msg)
|
196
|
-
self.last_end_time = now
|
197
|
-
self.message = msg
|
198
|
-
await sync_to_async(self.full_clean)()
|
199
|
-
# self.full_clean()
|
200
|
-
await self.asave()
|
201
|
-
# self.disabled = True
|
202
|
-
else:
|
203
|
-
await ar.adebug("Skip running task %s", astr(self))
|
204
|
-
continue
|
205
|
-
|
206
|
-
if self.last_end_time is not None:
|
207
|
-
nst = await sync_to_async(self.get_next_suggested_date)(
|
208
|
-
self.last_end_time, ar.logger
|
239
|
+
for self in tasks:
|
240
|
+
# print("20240424d")
|
241
|
+
# raise Warning("20231230")
|
242
|
+
if self.last_end_time is None and self.last_start_time is not None:
|
243
|
+
run_duration = now - self.last_start_time
|
244
|
+
if run_duration > timedelta(hours=2):
|
245
|
+
msg = "Killed {} because running more than 2 hours".format(
|
246
|
+
astr(self)
|
209
247
|
)
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
248
|
+
await ar.adebug(msg)
|
249
|
+
self.last_end_time = now
|
250
|
+
self.message = msg
|
251
|
+
await sync_to_async(self.full_clean)()
|
252
|
+
# self.full_clean()
|
253
|
+
await self.asave()
|
254
|
+
# self.disabled = True
|
255
|
+
else:
|
256
|
+
await ar.adebug("Skip running task %s", astr(self))
|
257
|
+
continue
|
258
|
+
|
259
|
+
if self.requested_at is None and self.last_end_time is not None:
|
222
260
|
nst = await sync_to_async(self.get_next_suggested_date)(
|
223
261
|
self.last_end_time, ar.logger
|
224
262
|
)
|
225
|
-
if nst is
|
263
|
+
if nst is None:
|
264
|
+
await ar.adebug("No time suggested to start %s", astr(self))
|
265
|
+
continue
|
266
|
+
if nst > now:
|
267
|
+
await ar.adebug("Too early to start %s", astr(self))
|
226
268
|
next_time = min(next_time, nst)
|
269
|
+
continue
|
270
|
+
|
271
|
+
# await ar.adebug("Start %s", self)
|
272
|
+
# print("20231021 1 gonna start", self)
|
273
|
+
await self.start_task(ar)
|
274
|
+
assert self.last_end_time is not None
|
275
|
+
nst = await sync_to_async(self.get_next_suggested_date)(
|
276
|
+
self.last_end_time, ar.logger
|
277
|
+
)
|
278
|
+
if nst is not None:
|
279
|
+
next_time = min(next_time, nst)
|
227
280
|
|
228
281
|
count += 1
|
229
282
|
if max_count is not None and count >= max_count:
|
lino/modlib/linod/models.py
CHANGED
lino/modlib/memo/__init__.py
CHANGED
@@ -158,3 +158,7 @@ class Plugin(ad.Plugin):
|
|
158
158
|
mg = site.plugins.office
|
159
159
|
m = m.add_menu(mg.app_label, mg.verbose_name)
|
160
160
|
m.add_action("memo.Mentions")
|
161
|
+
# m.add_action("about.About.insert_reference")
|
162
|
+
|
163
|
+
# def get_quicklinks(self):
|
164
|
+
# yield "about.About.insert_reference"
|
lino/modlib/memo/models.py
CHANGED
@@ -14,8 +14,9 @@ from lino.core.roles import SiteStaff
|
|
14
14
|
from lino.core.gfks import gfk2lookup
|
15
15
|
from lino.modlib.gfks.mixins import Controllable
|
16
16
|
from lino.modlib.gfks.fields import GenericForeignKey, GenericForeignKeyIdField
|
17
|
+
from lino.modlib.about.models import About
|
17
18
|
from .parser import split_name_rest
|
18
|
-
|
19
|
+
from .mixins import MemoReferrable
|
19
20
|
|
20
21
|
# Translators: will also be concatenated with '(type)' and '(object)'
|
21
22
|
target_label = _("Target")
|
@@ -71,8 +72,10 @@ class Mention(Controllable):
|
|
71
72
|
obj = super()
|
72
73
|
return obj.as_summary_item(ar, text, **kwargs)
|
73
74
|
|
75
|
+
|
74
76
|
dd.update_field(Mention, 'owner', verbose_name=_("Referrer"))
|
75
77
|
|
78
|
+
|
76
79
|
class Mentions(dd.Table):
|
77
80
|
required_roles = dd.login_required(SiteStaff)
|
78
81
|
editable = False
|
@@ -89,8 +92,51 @@ class Mentions(dd.Table):
|
|
89
92
|
# column_names = "target *"
|
90
93
|
# default_display_modes = {None: constants.DISPLAY_MODE_SUMMARY}
|
91
94
|
|
95
|
+
|
92
96
|
class MentionsByTarget(Mentions):
|
93
97
|
label = _("Mentioned by")
|
94
98
|
master_key = "target"
|
95
99
|
column_names = "owner *"
|
96
100
|
default_display_modes = {None: constants.DISPLAY_MODE_SUMMARY}
|
101
|
+
|
102
|
+
|
103
|
+
CONTENT_TYPE_FIELD = dd.ForeignKey(ContentType, editable=True)
|
104
|
+
|
105
|
+
|
106
|
+
class InsertReference(dd.Action):
|
107
|
+
|
108
|
+
label = _("Insert reference")
|
109
|
+
select_rows = False
|
110
|
+
parameters = dict(
|
111
|
+
content_type=CONTENT_TYPE_FIELD,
|
112
|
+
primary_key=GenericForeignKeyIdField(CONTENT_TYPE_FIELD, editable=True)
|
113
|
+
)
|
114
|
+
params_layout = """
|
115
|
+
content_type
|
116
|
+
primary_key
|
117
|
+
"""
|
118
|
+
|
119
|
+
@dd.chooser()
|
120
|
+
def content_type_choices(self):
|
121
|
+
for obj in rt.models.gfks.ContentType.objects.all():
|
122
|
+
if issubclass(obj.model_class(), MemoReferrable):
|
123
|
+
yield obj
|
124
|
+
|
125
|
+
@dd.chooser(instance_values=True)
|
126
|
+
def primary_key_choices(cls, content_type):
|
127
|
+
if content_type is None:
|
128
|
+
# print("You must select a content type")
|
129
|
+
# return []
|
130
|
+
return [("", _("You must select a content type"))]
|
131
|
+
m = content_type.model_class()
|
132
|
+
return m.objects.all()
|
133
|
+
|
134
|
+
def run_from_ui(self, ar, **kwargs):
|
135
|
+
pv = ar.action_param_values
|
136
|
+
ct = pv.content_type.model_class()
|
137
|
+
obj = ct.objects.get(pk=pv.primary_key)
|
138
|
+
txt = obj.obj2memo()
|
139
|
+
ar.success(message=txt)
|
140
|
+
|
141
|
+
|
142
|
+
About.insert_reference = InsertReference()
|
@@ -56,7 +56,9 @@ div.recipient {
|
|
56
56
|
position:relative; left:{{100-dd.plugins.weasyprint.margin_left}}mm;
|
57
57
|
height:30mm;
|
58
58
|
width:80mm;
|
59
|
-
border: 1px solid
|
59
|
+
border: 1px solid lightgray;
|
60
|
+
border-radius: 2mm;
|
61
|
+
background-color: lightgray;
|
60
62
|
padding: 1em;
|
61
63
|
margin: 1em;
|
62
64
|
}
|
@@ -44,7 +44,8 @@ def config_inited(app, config):
|
|
44
44
|
|
45
45
|
def copy_custom_files(app, env, docnames):
|
46
46
|
if app.builder.format == "html":
|
47
|
-
|
47
|
+
# In older Sphinx version the builder.outdir was a simple string
|
48
|
+
staticdir = Path(app.builder.outdir) / "_static"
|
48
49
|
staticdir.mkdir(exist_ok=True)
|
49
50
|
(staticdir / "favicons").mkdir(exist_ok=True)
|
50
51
|
for fn in ("synodal-logo.png", "favicons/favicon.ico"):
|
lino/utils/__init__.py
CHANGED
lino/utils/dbhash.py
CHANGED
@@ -91,15 +91,17 @@ def check_virgin(restore=True, verbose=True):
|
|
91
91
|
if not can_restore:
|
92
92
|
raise Exception(
|
93
93
|
"Cannot restore database because some rows have been deleted")
|
94
|
-
# print(f"Tidy up {len(must_delete)} rows from database")
|
95
|
-
# It can happen that some rows refer to each other with a protected fk
|
96
|
-
# We call bulk delete() to avoid Lino deleting the items of an invoice
|
97
94
|
must_delete = list(must_delete.items())
|
95
|
+
if verbose:
|
96
|
+
print(f"Tidy up {len(must_delete)} rows from database: {must_delete}.")
|
98
97
|
while len(must_delete):
|
99
98
|
todo = []
|
100
99
|
hope = False
|
101
100
|
for m, added in must_delete:
|
102
101
|
try:
|
102
|
+
# It can happen that some rows refer to each other with a
|
103
|
+
# protected fk, so we call bulk delete() to avoid Lino deleting
|
104
|
+
# the items of an invoice.
|
103
105
|
m.objects.filter(pk__in=added).delete()
|
104
106
|
# obj.delete()
|
105
107
|
hope = True
|
lino/utils/format_date.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- coding: UTF-8 -*-
|
2
|
-
# Copyright 2009-
|
2
|
+
# Copyright 2009-2025 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
"""See :doc:`/topics/datetime`.
|
5
5
|
"""
|
@@ -111,6 +111,11 @@ def day_and_weekday(d):
|
|
111
111
|
|
112
112
|
def ftl(t):
|
113
113
|
# "format time long"
|
114
|
-
return "{}
|
115
|
-
t.strftime(settings.SITE.
|
116
|
-
|
114
|
+
return "{} {}".format(
|
115
|
+
t.strftime(settings.SITE.date_format_strftime),
|
116
|
+
t.strftime(settings.SITE.time_format_strftime))
|
117
|
+
|
118
|
+
|
119
|
+
def ftf(t):
|
120
|
+
# "format time full"
|
121
|
+
return "{} ({})".format(ftl(t), naturaltime(t))
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: lino
|
3
|
-
Version: 25.
|
3
|
+
Version: 25.4.0
|
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,20 +1,20 @@
|
|
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=hX67Z8YgYIUBNNmzsKRsa1ltkl1uwshB28hWTFIKLIU,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=fyiY0oSJ8iGNjKdw36QbrLu2y38SvIeddW3FH3y0Nbw,90988
|
8
8
|
lino/api/__init__.py,sha256=WmzHU-rHdZ68se_nI0SmepQTGE8-cd9tPpovHRH9aag,512
|
9
9
|
lino/api/ad.py,sha256=F6SrcKPRRalHKOZ7QLwsRWGq9hhykQIeo0b85cEk9NQ,314
|
10
|
-
lino/api/dd.py,sha256=
|
10
|
+
lino/api/dd.py,sha256=FSv9gDstKcKM1qFgSSJpJOGhvT0bDTIqwjcPA9pbMm8,7431
|
11
11
|
lino/api/doctest.py,sha256=87j1_xGpomQlEmUUh8CprBFbbqKuQe1OWr5iIXABWag,24028
|
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
|
15
15
|
lino/config/about.html.tmpl,sha256=Vt3drpxP5f26wb1meXq_Kc8ZUAl_TGfr1bcuWuz-7L4,705
|
16
16
|
lino/config/admin_main.html,sha256=uq179bSDST-ACy0iuOFqMfs501mdwnR7Zw9ICDFZfsc,37
|
17
|
-
lino/config/admin_main_base.html,sha256=
|
17
|
+
lino/config/admin_main_base.html,sha256=oTcu3ZNQi1R45WuwzY1OTP3X800m9LeUQCUcLxutV8s,4021
|
18
18
|
lino/config/apps.html.tmpl,sha256=UxRVdZq1BEVJWD77_mhxIB4ILenVO_Ml-w3LgumG22Y,696
|
19
19
|
lino/config/letter_margin_bottom.html,sha256=BzASupSu5l49EGrPFpUcrK4DDm_sijoOd28HC8kmpBg,66
|
20
20
|
lino/config/letter_margin_top.html,sha256=mTKb62bWXX0rH9FyIrwJUmptJmoC8_ZATxGUm0YW4RI,216
|
@@ -96,7 +96,7 @@ lino/locale/pt_BR/LC_MESSAGES/django.po,sha256=nDmkf5MQtIj9trPVTZcNNMghM4rH8nZet
|
|
96
96
|
lino/locale/zh_Hant/LC_MESSAGES/django.po,sha256=J9IELaIaZmBI2Vfu9HPIVA-g45QTYIxFzftWAB1U-s0,158557
|
97
97
|
lino/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
98
98
|
lino/management/commands/__init__.py,sha256=raVDRiXns3SegyXEhaLZMcxfEDs7ggy2nFUN5D0f5F0,47
|
99
|
-
lino/management/commands/buildcache.py,sha256=
|
99
|
+
lino/management/commands/buildcache.py,sha256=MrOio6uBtQNW5gnbRrPIjarwUe18R-irxC7dLBBCpR4,1949
|
100
100
|
lino/management/commands/demotest.py,sha256=yvxpl1G0Clt-iu7lY0DK9HVhaWyl_tQhYx0YUpddTWM,5041
|
101
101
|
lino/management/commands/diag.py,sha256=vt-NlZUx5gf7T4EpbM-gle3tAwMuwfPQY8lUgxjFaUw,478
|
102
102
|
lino/management/commands/dump2py.py,sha256=X2u6OVkSb4MVQucF6jOKDDwRc8TCBNakW3UX_9S-n-U,20344
|
@@ -126,7 +126,7 @@ lino/mixins/printable.py,sha256=4U8M1lrTjUeuaPwrcWoanCBo53iAxiNpSTsVctI-gI0,199
|
|
126
126
|
lino/mixins/ref.py,sha256=ZnyTcpHgcbYwDwgaBwLc5cGLQqz8MmjAypSEgPB7Ql4,5272
|
127
127
|
lino/mixins/registrable.py,sha256=0m68YGlipRhE83IsEvXATZtvyxtMsH-Dpd5TGZh_GzE,6936
|
128
128
|
lino/mixins/sequenced.py,sha256=6FiHJX2ZIraqUofdnb082b978PISNbpd2Vr87YA_1pg,16460
|
129
|
-
lino/modlib/__init__.py,sha256=
|
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
|
132
132
|
lino/modlib/about/models.py,sha256=X5yJJlyoQ58GN9RsdlUA1KsumvRtkureWnxLPPAXWlE,5131
|
@@ -189,7 +189,7 @@ lino/modlib/export_excel/__init__.py,sha256=k11dEbh1VgA7cMaUdMhiJvHNboX4BqN0Z5Wj
|
|
189
189
|
lino/modlib/export_excel/models.py,sha256=MoGj3RyAj8PBy75HFGBv9Y1QnsG-H_ajRK27UDpZPKo,5094
|
190
190
|
lino/modlib/extjs/__init__.py,sha256=6UBWAWSROwy3DfTXQmVUVJTF6eZ_e2k3BEfE4wtqVhU,10172
|
191
191
|
lino/modlib/extjs/ext_renderer.py,sha256=FAuqvEpmX8skaGXN6mXZuB7cq2pC38lxACxntiJ7RvU,60614
|
192
|
-
lino/modlib/extjs/views.py,sha256=
|
192
|
+
lino/modlib/extjs/views.py,sha256=M9282Qayd2z_cXIMs155ZTUeHt6HdwL2PwhwpeDaVDY,26297
|
193
193
|
lino/modlib/extjs/config/extjs/index.html,sha256=jO5hdNpFSkm9t0xhHD5hc8Hw1fSr6xb3zYq9aMyOI7Q,8603
|
194
194
|
lino/modlib/extjs/config/extjs/linoweb.js,sha256=I4VYGmkK4htqZvHM9g-6psJF3pp7SvgHEI0I02Sxpvo,175127
|
195
195
|
lino/modlib/extjs/config/extjs/service-worker.js,sha256=KEKWeehTlfBHk3r8NbsP9C5av_DukHORybxFOwbjYaQ,1767
|
@@ -3535,8 +3535,8 @@ lino/modlib/languages/fixtures/iso-639-3_20100707.tab,sha256=u8PwI2s8shy0_Val5-s
|
|
3535
3535
|
lino/modlib/linod/__init__.py,sha256=efmj_Kz3OO2zF1lvs7P459iufYGimH1-6Ge6Cbq85tQ,2665
|
3536
3536
|
lino/modlib/linod/choicelists.py,sha256=Cu82s1QpcGFmKUXJsg-7TSqpaESBCZKOEfxzFlJP06I,2626
|
3537
3537
|
lino/modlib/linod/consumers.py,sha256=XBjA1fflJ-e9yWRMKXyQAhrOklYzs5JRhEeGMOKWFqM,6730
|
3538
|
-
lino/modlib/linod/mixins.py,sha256=
|
3539
|
-
lino/modlib/linod/models.py,sha256=
|
3538
|
+
lino/modlib/linod/mixins.py,sha256=yE0J51bRA8u5YekrNnAlWoOBee3z5rqDE8yxHgiqGMM,12739
|
3539
|
+
lino/modlib/linod/models.py,sha256=tbPKNk3BLnnAPWvbNrWhz713b3IPM0z8UoctJcwVhhw,2357
|
3540
3540
|
lino/modlib/linod/routing.py,sha256=FiG0JVqp9TWWkNpl9Y_50UCAJ7ZEImDXkQUhlg4aGL4,2094
|
3541
3541
|
lino/modlib/linod/utils.py,sha256=dE973Xib6Be1DvNsZ0M5wzY_jpkk35R21WKs-jQPorM,339
|
3542
3542
|
lino/modlib/linod/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -3544,9 +3544,9 @@ lino/modlib/linod/fixtures/linod.py,sha256=qCFU2IktRVEdt1lChwu6kZLLnd4Ppfq_x9_2q
|
|
3544
3544
|
lino/modlib/linod/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3545
3545
|
lino/modlib/linod/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3546
3546
|
lino/modlib/linod/management/commands/linod.py,sha256=RsUgUBz-soF8wkfgUE8KJiLZltrhEeCm1m7AFNthUps,3826
|
3547
|
-
lino/modlib/memo/__init__.py,sha256=
|
3547
|
+
lino/modlib/memo/__init__.py,sha256=GdzNURo3v_o5PxTBZ_KNkzrjlcDzn4AO95pYBbHmk8Q,5389
|
3548
3548
|
lino/modlib/memo/mixins.py,sha256=Ij_bFcBY_ivo5t2HWArEeRkxIQhg61iP0sTNnhZpRac,11246
|
3549
|
-
lino/modlib/memo/models.py,sha256=
|
3549
|
+
lino/modlib/memo/models.py,sha256=zUEvWu0dK5QhkU3DeMqNqsrzSUzOl6DLZaJBNytfgrs,4388
|
3550
3550
|
lino/modlib/memo/parser.py,sha256=YbGf1EdJqTI4rqM05ZPTdufN_-aWeV_Z85Nh47HH8Pw,12996
|
3551
3551
|
lino/modlib/memo/views.py,sha256=H3g_nuiMzguptXLSWaWLJClU7BefXPFn9Rh8UIVVBeg,555
|
3552
3552
|
lino/modlib/notify/__init__.py,sha256=suo7EMVdyTPTPFwuU2KZL25PwIEstTvvR4Turgdz7UE,6926
|
@@ -4424,7 +4424,7 @@ lino/modlib/users/fixtures/std.py,sha256=Eo_TdqFC7NPryLeGRfp-nbOXw3hDqxTUpddFTxU
|
|
4424
4424
|
lino/modlib/weasyprint/__init__.py,sha256=81eULMBEUKB_2eKtWloEEh7ijOiSoxEgGigK6LJFrGo,2253
|
4425
4425
|
lino/modlib/weasyprint/choicelists.py,sha256=SaqDFfJLx9IFjhtOUtnBGZNpihUAzLvj0W49YHCZt0I,1396
|
4426
4426
|
lino/modlib/weasyprint/models.py,sha256=op6CRRBC8NatqGgGdQHU4zcVG4fu4mRS9Mz8STG3B3g,168
|
4427
|
-
lino/modlib/weasyprint/config/weasyprint/base.weasy.html,sha256=
|
4427
|
+
lino/modlib/weasyprint/config/weasyprint/base.weasy.html,sha256=SSDxOOKj_0o5JmUUDEoXHDb_eC5tT0dyjRa9l4ta3-o,4609
|
4428
4428
|
lino/modlib/wkhtmltopdf/__init__.py,sha256=1nqwVpOQH4YMhegnzrcfvXW_Xy9CIdHBHzrNvDGyVxg,773
|
4429
4429
|
lino/modlib/wkhtmltopdf/choicelists.py,sha256=Mq7LySs-HJIXnyUHN5PR55nQyg2cgPjEQuN9JUhBmUY,1818
|
4430
4430
|
lino/modlib/wkhtmltopdf/models.py,sha256=T7lHSSQKNcUWceNnNzq_bKEguXQ1THK5qyCDgeV6xfM,294
|
@@ -4436,7 +4436,7 @@ lino/sphinxcontrib/__init__.py,sha256=cz8sRK--NVr9thlToiuHRfJVelqdiYdRYmK2kyQKHq
|
|
4436
4436
|
lino/sphinxcontrib/actordoc.py,sha256=CrHbqW15V1w_6Rm1bZzRBZv1CduDRZKpCcJQtOJqOCM,20710
|
4437
4437
|
lino/sphinxcontrib/base.py,sha256=pq5u4bFSxMgPm9OMDo8xPVGhuS6MZAUd9bF6rQCCHJs,1193
|
4438
4438
|
lino/sphinxcontrib/help_texts_extractor.py,sha256=mlHyeiIdzbfzQXkT8j8skdcBQ-FV3zAPW2DXnY8Hs1I,10385
|
4439
|
-
lino/sphinxcontrib/logo/__init__.py,sha256=
|
4439
|
+
lino/sphinxcontrib/logo/__init__.py,sha256=dCHNLzhlMdSYVMui3vc2ybzPU6D4GikiRP-G9SCu1TA,2257
|
4440
4440
|
lino/sphinxcontrib/logo/make_favicons.py,sha256=cDFmh937qfYngnxajIOmuxPRyZ9X9iNWCiRlJjq6QKI,224
|
4441
4441
|
lino/sphinxcontrib/logo/src/lino-web-logo.xcf,sha256=AN4PbfN_HpdvW00PxkqbKmYQSOdmIXW5_zAmHxrC2Eo,68662
|
4442
4442
|
lino/sphinxcontrib/logo/src/logo_web.xcf,sha256=Tv9JaH1WXtPkgrx39Q_H_iIr2wlU7uFToNIkVQ2h57w,119207
|
@@ -4578,7 +4578,7 @@ lino/templates_old/404.html,sha256=9O5EJgULwLws0X1LjNig3xT4l9Hw04MBIGswD-EAlnw,2
|
|
4578
4578
|
lino/templates_old/500.html,sha256=inOR744w4FGJM_fCSQcnlk-OIYQpaBTxUQWgXQozon4,496
|
4579
4579
|
lino/templates_old/base.html,sha256=qYqj5-u1UPtpatrFkqBr3MnwS0oFUXCyQRcuNZczDfk,1641
|
4580
4580
|
lino/templates_old/base_site.html,sha256=NcLEk0kBT1b-SrhoGpDPUej7NExqJ9-dP1kbrvwBzrs,255
|
4581
|
-
lino/utils/__init__.py,sha256=
|
4581
|
+
lino/utils/__init__.py,sha256=r3PhUv44LoVlci5lARpqvq-8re6IwmfXxbTjDU-FVDs,18407
|
4582
4582
|
lino/utils/addressable.py,sha256=o7bmLbyvrmOoAT478s7XqjWKvnZ7zSXj4k7Xf0ccqf8,2213
|
4583
4583
|
lino/utils/ajax.py,sha256=npCS0WumhTQlBzXxQPKnp2sYCRcPsYcbFqzE2ykVc4Q,3254
|
4584
4584
|
lino/utils/choosers.py,sha256=9jjeLz-QcWVBfR8_GdY4PNYoqIYM63OI3OvOL2l1ZaU,17604
|
@@ -4589,13 +4589,13 @@ lino/utils/daemoncommand.py,sha256=NjGShiz09fddIV0WU0jK2nzO_CwPj1MfdmgwAOYZi4M,1
|
|
4589
4589
|
lino/utils/dataserializer.py,sha256=-_xHXaGwDSO6-sYEHEa2BtEmKS8bW6gsYx4dV-GbvDs,3779
|
4590
4590
|
lino/utils/dates.py,sha256=eWF5WxA5uJf51Y9PKvDVBWD8yIf6yBF6oO6TeU3ujzw,1030
|
4591
4591
|
lino/utils/dbfreader.py,sha256=4sXOGBKX6DFQCEPkCMfnJAVneHMyDzJQB5tsYAq90vQ,12205
|
4592
|
-
lino/utils/dbhash.py,sha256=
|
4592
|
+
lino/utils/dbhash.py,sha256=S2jCCYUItovF8Qkc2kVk5WS14U1c3RjijkUGqYs20_c,3450
|
4593
4593
|
lino/utils/dblogger.py,sha256=kr0YxQY6veymvNg5A4tsvkqW8haRWdwqL0C-_9_QTg0,721
|
4594
4594
|
lino/utils/diag.py,sha256=8BGsPrLd1_Fympy3PKiTpX1MdMWGApXr6IBoVOkWRxE,18314
|
4595
4595
|
lino/utils/djangotest.py,sha256=Phz1qNp0wDonZRja5dxbCk0Xl3a73gZNiKK8v9tAgZg,8334
|
4596
4596
|
lino/utils/dpy.py,sha256=Hw4ofFnhRPAE2PsPf9r5RpzcfVLQdIjtOe-XtMMLtuE,20661
|
4597
4597
|
lino/utils/fieldutils.py,sha256=IfwuTpSirKYEk5h1URxQ9CF6i0ZPcsuNQHyk-LQOdRE,2874
|
4598
|
-
lino/utils/format_date.py,sha256=
|
4598
|
+
lino/utils/format_date.py,sha256=esVElXGtmc_M5CAoFyomVr1hoi3ITn95e1ToZ09li-U,3008
|
4599
4599
|
lino/utils/html.py,sha256=pcE0UQmdQGxxmb-p0mBb47zNbRMXLP9cxxrXTLs4gbY,3143
|
4600
4600
|
lino/utils/html2odf.py,sha256=Hxw4HiIHY1ZCjb4_JLykVHbr6yAMhhHrnrCnLNDYKAs,4826
|
4601
4601
|
lino/utils/html2xhtml.py,sha256=fvrIoLBFpiXtYO3UYaIgAIDjf6ATvrxolQX4etxS57Y,2119
|
@@ -4633,8 +4633,8 @@ lino/utils/xml.py,sha256=EGDnO1UaREst9fS7KTESdbHnrrVCwKbRQdvut6B6GmQ,1612
|
|
4633
4633
|
lino/utils/mldbc/__init__.py,sha256=QqWRlzeXaOmFfbCk-vTY3SZMn1-FCf67XnpZdd_Nim0,1134
|
4634
4634
|
lino/utils/mldbc/fields.py,sha256=tAX8G5UKigr9c6g0F3ARIjZZtg406mdaZ--PWSbiH9E,2873
|
4635
4635
|
lino/utils/mldbc/mixins.py,sha256=CkYe5jDa7xp9fJq_V8zcZf8ocxgIjUgHc9KZccvA_Yw,1945
|
4636
|
-
lino-25.
|
4637
|
-
lino-25.
|
4638
|
-
lino-25.
|
4639
|
-
lino-25.
|
4640
|
-
lino-25.
|
4636
|
+
lino-25.4.0.dist-info/METADATA,sha256=ebewMi9c7NVn3fuBa28StXDO0GH1KOGbD70Js5S4a9s,42534
|
4637
|
+
lino-25.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
4638
|
+
lino-25.4.0.dist-info/licenses/AUTHORS.rst,sha256=8VEm_G4HOmYEa4oi1nVoKKsdo4JanekEJCefWd2E8vk,981
|
4639
|
+
lino-25.4.0.dist-info/licenses/COPYING,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
4640
|
+
lino-25.4.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|