lino 25.3.4__py3-none-any.whl → 25.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lino/__init__.py +7 -1
- lino/api/dd.py +1 -1
- lino/config/admin_main_base.html +4 -3
- lino/core/kernel.py +19 -19
- lino/core/site.py +67 -52
- lino/help_texts.py +9 -11
- lino/management/commands/buildcache.py +2 -2
- lino/modlib/__init__.py +0 -1
- lino/modlib/about/models.py +1 -1
- lino/modlib/extjs/ext_renderer.py +1 -1
- lino/modlib/extjs/views.py +2 -3
- 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/memo/parser.py +4 -4
- 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.1.dist-info}/METADATA +1 -1
- {lino-25.3.4.dist-info → lino-25.4.1.dist-info}/RECORD +26 -26
- {lino-25.3.4.dist-info → lino-25.4.1.dist-info}/WHEEL +0 -0
- {lino-25.3.4.dist-info → lino-25.4.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-25.3.4.dist-info → lino-25.4.1.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.1'
|
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/core/kernel.py
CHANGED
@@ -41,7 +41,7 @@ from django.db import models
|
|
41
41
|
|
42
42
|
# import lino # for is_testing
|
43
43
|
from lino import logger
|
44
|
-
from lino.utils import codetime
|
44
|
+
# from lino.utils import codetime
|
45
45
|
from lino.utils.html import E
|
46
46
|
# from lino.core.utils import format_request
|
47
47
|
# from lino.utils import isiterable
|
@@ -111,22 +111,21 @@ class Kernel(object):
|
|
111
111
|
self.GFK_LIST = []
|
112
112
|
# logger.info("20140227 Kernel.__init__() done")
|
113
113
|
|
114
|
-
_code_mtime = None
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
return self._code_mtime
|
114
|
+
# _code_mtime = None
|
115
|
+
#
|
116
|
+
# @property
|
117
|
+
# def code_mtime(self):
|
118
|
+
# if self._code_mtime is None:
|
119
|
+
# # packages = [os.environ['DJANGO_SETTINGS_MODULE'], 'lino']
|
120
|
+
# # self._code_mtime = codetime(*packages)
|
121
|
+
# if self.site.developer_site_cache:
|
122
|
+
# self._code_mtime = codetime()
|
123
|
+
# else:
|
124
|
+
# # On a production server we test only the timestamp of
|
125
|
+
# # settings.py file because otherwise the result can differ
|
126
|
+
# # depending on which modules have already been imported.
|
127
|
+
# self._code_mtime = codetime(settings.SETTINGS_MODULE)
|
128
|
+
# return self._code_mtime
|
130
129
|
|
131
130
|
def kernel_startup(self, site):
|
132
131
|
"""This is a part of a Lino site startup. The Django Model
|
@@ -908,7 +907,7 @@ class Kernel(object):
|
|
908
907
|
self._must_build = True
|
909
908
|
|
910
909
|
def make_cache_file(self, fn, write, force=False, verbosity=1):
|
911
|
-
"""Make the specified cache file. This is used internally at
|
910
|
+
"""Make the specified cache file. This is used internally at site
|
912
911
|
startup.
|
913
912
|
|
914
913
|
"""
|
@@ -919,7 +918,8 @@ class Kernel(object):
|
|
919
918
|
fn = self.site.media_root / fn
|
920
919
|
if not force and not self._must_build and fn.exists():
|
921
920
|
mtime = os.stat(fn).st_mtime
|
922
|
-
if mtime > self.code_mtime:
|
921
|
+
# if mtime > self.code_mtime:
|
922
|
+
if mtime > self.site.lino_version:
|
923
923
|
# logger.debug("%s (%s) is up to date.", fn, time.ctime(mtime))
|
924
924
|
return 0
|
925
925
|
|
lino/core/site.py
CHANGED
@@ -558,17 +558,18 @@ class Site(object):
|
|
558
558
|
break
|
559
559
|
|
560
560
|
if self.master_site is None:
|
561
|
-
cache_root = os.environ.get("LINO_CACHE_ROOT", None)
|
562
|
-
if cache_root:
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
else:
|
571
|
-
|
561
|
+
# cache_root = os.environ.get("LINO_CACHE_ROOT", None)
|
562
|
+
# if cache_root:
|
563
|
+
# # TODO: deprecate
|
564
|
+
# cr = Path(cache_root).absolute()
|
565
|
+
# if not cr.exists():
|
566
|
+
# msg = "LINO_CACHE_ROOT ({0}) does not exist!".format(cr)
|
567
|
+
# raise Exception(msg)
|
568
|
+
# self.site_dir = (cr / self.project_name).resolve()
|
569
|
+
# self.setup_cache_directory()
|
570
|
+
# else:
|
571
|
+
# self.site_dir = self.project_dir
|
572
|
+
self.site_dir = self.project_dir
|
572
573
|
db = self.get_database_settings()
|
573
574
|
if db is not None:
|
574
575
|
self.django_settings.update(DATABASES=db)
|
@@ -987,11 +988,12 @@ class Site(object):
|
|
987
988
|
self.update_settings(MEDIA_URL="/media/")
|
988
989
|
|
989
990
|
if not "STATIC_ROOT" in self.django_settings:
|
990
|
-
cache_root = os.environ.get("LINO_CACHE_ROOT", None)
|
991
|
-
if cache_root:
|
992
|
-
|
993
|
-
else:
|
994
|
-
|
991
|
+
# cache_root = os.environ.get("LINO_CACHE_ROOT", None)
|
992
|
+
# if cache_root:
|
993
|
+
# p = Path(cache_root)
|
994
|
+
# else:
|
995
|
+
# p = self.site_dir
|
996
|
+
p = self.site_dir
|
995
997
|
self.update_settings(STATIC_ROOT=str(p / "static_root"))
|
996
998
|
if not "STATIC_URL" in self.django_settings:
|
997
999
|
self.update_settings(STATIC_URL="/static/")
|
@@ -1142,40 +1144,40 @@ class Site(object):
|
|
1142
1144
|
|
1143
1145
|
# print(20150331, self.django_settings['FIXTURE_DIRS'])
|
1144
1146
|
|
1145
|
-
def setup_cache_directory(self):
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1147
|
+
# def setup_cache_directory(self):
|
1148
|
+
# stamp = self.site_dir / "lino_cache.txt"
|
1149
|
+
# this = class2str(self.__class__)
|
1150
|
+
# if stamp.exists():
|
1151
|
+
# other = stamp.read_file()
|
1152
|
+
# if other == this:
|
1153
|
+
# ok = True
|
1154
|
+
# else:
|
1155
|
+
# ok = False
|
1156
|
+
# for parent in self.__class__.__mro__:
|
1157
|
+
# if other == class2str(parent):
|
1158
|
+
# ok = True
|
1159
|
+
# break
|
1160
|
+
# if not ok:
|
1161
|
+
# # Can happen e.g. when `python -m lino.hello` is
|
1162
|
+
# # called. in certain conditions.
|
1163
|
+
# msg = (
|
1164
|
+
# "Cannot use {site_dir} for {this} "
|
1165
|
+
# "because it is used for {other}. (Settings {settings})"
|
1166
|
+
# )
|
1167
|
+
# msg = msg.format(
|
1168
|
+
# site_dir=self.site_dir,
|
1169
|
+
# this=this,
|
1170
|
+
# settings=self.django_settings.get("SETTINGS_MODULE"),
|
1171
|
+
# other=other,
|
1172
|
+
# )
|
1173
|
+
# if True:
|
1174
|
+
# raise Exception(msg)
|
1175
|
+
# else:
|
1176
|
+
# # print(msg)
|
1177
|
+
# self.site_dir = None
|
1178
|
+
# else:
|
1179
|
+
# self.makedirs_if_missing(self.site_dir)
|
1180
|
+
# stamp.write_file(this)
|
1179
1181
|
|
1180
1182
|
def set_user_model(self, spec):
|
1181
1183
|
# if self.user_model is not None:
|
@@ -2004,6 +2006,17 @@ class Site(object):
|
|
2004
2006
|
s = self.plugins.jinja.render_from_ar(ar, "admin_main.html", **context)
|
2005
2007
|
return mark_safe(s)
|
2006
2008
|
|
2009
|
+
_lino_version = None
|
2010
|
+
|
2011
|
+
@property
|
2012
|
+
def lino_version(self):
|
2013
|
+
p = self.site_dir / "lino_version.txt"
|
2014
|
+
if self._lino_version is None:
|
2015
|
+
if not p.exists():
|
2016
|
+
p.touch()
|
2017
|
+
self._lino_version = p.stat().st_mtime
|
2018
|
+
return self._lino_version
|
2019
|
+
|
2007
2020
|
def build_site_cache(self, force=False, later=False, verbosity=1):
|
2008
2021
|
from lino.modlib.users.utils import with_user_profile
|
2009
2022
|
from lino.modlib.users.choicelists import UserTypes
|
@@ -2011,10 +2024,12 @@ class Site(object):
|
|
2011
2024
|
# if not self.is_prepared:
|
2012
2025
|
# self.prepare_layouts()
|
2013
2026
|
# self.is_prepared = True
|
2027
|
+
# settings_file = self.django_settings.get("__file__")
|
2028
|
+
# Path(settings_file).touch()
|
2029
|
+
p = self.site_dir / "lino_version.txt"
|
2030
|
+
p.touch()
|
2014
2031
|
|
2015
2032
|
if later:
|
2016
|
-
settings_file = self.django_settings.get("__file__")
|
2017
|
-
Path(settings_file).touch()
|
2018
2033
|
# print("20230823 later")
|
2019
2034
|
return
|
2020
2035
|
|
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."""),
|
@@ -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/about/models.py
CHANGED
@@ -119,7 +119,7 @@ class About(EmptyTable):
|
|
119
119
|
packages = set(["django"])
|
120
120
|
|
121
121
|
items.append(
|
122
|
-
E.li(gettext("Server timestamp"), " : ", E.b(dtfmt(site.
|
122
|
+
E.li(gettext("Server timestamp"), " : ", E.b(dtfmt(site.lino_version)))
|
123
123
|
)
|
124
124
|
|
125
125
|
for p in site.installed_plugins:
|
@@ -1481,7 +1481,7 @@ class ExtRenderer(JsCacheRenderer):
|
|
1481
1481
|
# if settings.SITE.never_build_site_cache:
|
1482
1482
|
# yield "GEN_TIMESTAMP = '%s';" % settings.SITE.kernel.lino_version
|
1483
1483
|
# else:
|
1484
|
-
yield "GEN_TIMESTAMP = %s;" % py2js(settings.SITE.
|
1484
|
+
yield "GEN_TIMESTAMP = %s;" % py2js(settings.SITE.lino_version)
|
1485
1485
|
|
1486
1486
|
return "\n".join(fn())
|
1487
1487
|
|
lino/modlib/extjs/views.py
CHANGED
@@ -138,7 +138,7 @@ def test_version_mismatch(request):
|
|
138
138
|
if os.environ.get("PYCHARM_HOSTED", False):
|
139
139
|
return {}
|
140
140
|
lv = request.GET.get(constants.URL_PARAM_LINO_VERSION)
|
141
|
-
if lv is None or float(lv) == settings.SITE.
|
141
|
+
if lv is None or float(lv) == settings.SITE.lino_version:
|
142
142
|
return {}
|
143
143
|
# print("20201217", lv, settings.SITE.kernel.code_mtime)
|
144
144
|
cache.clear()
|
@@ -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()
|
lino/modlib/memo/parser.py
CHANGED
@@ -13,6 +13,9 @@ TODO:
|
|
13
13
|
which would be empty for # and @ but "]" for memo commands.
|
14
14
|
|
15
15
|
"""
|
16
|
+
from etgen import etree
|
17
|
+
from django.db.models import Model
|
18
|
+
from django.conf import settings
|
16
19
|
from lino import logger
|
17
20
|
|
18
21
|
import re
|
@@ -24,9 +27,6 @@ import warnings
|
|
24
27
|
|
25
28
|
warnings.filterwarnings("ignore", category=MarkupResemblesLocatorWarning)
|
26
29
|
|
27
|
-
from django.conf import settings
|
28
|
-
from django.db.models import Model
|
29
|
-
from etgen import etree
|
30
30
|
|
31
31
|
# COMMAND_REGEX = re.compile(r"\[(\w+)\s*((?:[^[\]]|\[.*?\])*?)\]")
|
32
32
|
# ===...... .......=
|
@@ -139,7 +139,7 @@ class Parser:
|
|
139
139
|
for key in self.suggesters.keys()
|
140
140
|
]
|
141
141
|
)
|
142
|
-
return re.compile(r"([^\w])?([" + triggers + "])(\w+)")
|
142
|
+
return re.compile(r"([^\w])?([" + triggers + r"])(\w+)")
|
143
143
|
|
144
144
|
def register_command(self, cmdname, func: Callable[[Any, str, str, dict], None]):
|
145
145
|
"""Register a memo command identified by the given text `cmd`.
|
@@ -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.1
|
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=CcmiXMf7kjvfR3armsMJoL2tdYjk5eeMI5a5XcwanPk,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=MGIQvx-xvYSyfgtSHkolpJ2aQlvChEFyR9_Xw1qt49w,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
|
@@ -47,7 +47,7 @@ lino/core/frames.py,sha256=ISxgq9zyZfqW3tDZMWdKi9Ij455lT_81qBH0xex0bfE,1161
|
|
47
47
|
lino/core/gfks.py,sha256=6VXn2FSIXOrwVq0stfbPevT37EWg1tg4Fn-HMNVnbmk,1970
|
48
48
|
lino/core/help.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
49
49
|
lino/core/inject.py,sha256=Qd_PGEn0yMXNYVPI0wCv1vvo2CNdlPkyoBmKZELOtGM,13422
|
50
|
-
lino/core/kernel.py,sha256=
|
50
|
+
lino/core/kernel.py,sha256=BY86dmUaU95zw22RlhZXbbBGpuOvsxfanMqzFr6Us0w,46939
|
51
51
|
lino/core/keyboard.py,sha256=W3jA6qtB5HMppoNnd_6PgIM7ZlyHilJEhBvdeZTY7Xk,1283
|
52
52
|
lino/core/layouts.py,sha256=Wojx5UUyhy7PsZE8FWmiXcmZDj4wz2y_1_wlz1G560Q,28663
|
53
53
|
lino/core/menus.py,sha256=W0Co9K-ayvfX5Zt5rgSxJrFRejtiYrwIR5EecdYXPNc,10857
|
@@ -59,7 +59,7 @@ lino/core/renderer.py,sha256=auQn2v9bBp6jLIH3hXRQXbrjFrTmsO1o0DwaoXBn1eE,47310
|
|
59
59
|
lino/core/requests.py,sha256=67335dTFqcwfF1PvWFmWwDKmVyJvDW9dMRQJF_X_Q9I,95093
|
60
60
|
lino/core/roles.py,sha256=PXwk436xUupxdbJcygRSYFu7ixfKjAJPQRUQ8sy0lB0,4425
|
61
61
|
lino/core/signals.py,sha256=0JT89mkjSbRm57QZcSI9DoThoKUGkyi-egNhuLUKEds,948
|
62
|
-
lino/core/site.py,sha256=
|
62
|
+
lino/core/site.py,sha256=RsvMMSaCHzGcVpvUWKhkW4ugP6Fj7EfQXx5NegzJ9PQ,83164
|
63
63
|
lino/core/store.py,sha256=6pd4J5Y-U7Muz4mKFSL6K9KEZpJUbpM-I7RQTWyCo-8,51483
|
64
64
|
lino/core/tables.py,sha256=rMMDmDKMcWJ39fD9Q_EFV7qdcXMktwO40G4ATyKuRGg,24427
|
65
65
|
lino/core/urls.py,sha256=06QlmN1vpxjmb5snO3SPpP6lX1pMdE60bTiBiC77_vQ,2677
|
@@ -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,10 +126,10 @@ 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
|
-
lino/modlib/about/models.py,sha256=
|
132
|
+
lino/modlib/about/models.py,sha256=7dbWnw5DXy0BWsvj9bW9ugRQIxD8B_My3yA_ReLUP5o,5126
|
133
133
|
lino/modlib/awesomeuploader/__init__.py,sha256=pUUnpdglJ0IDMBgW-ZQwnTOPHDRjItEiIWbSwv4qvBM,1825
|
134
134
|
lino/modlib/awesomeuploader/models.py,sha256=LaK6IzLoCX4qMkVhsgdPfgawyFPe5rcHUgBFY0PbzWg,801
|
135
135
|
lino/modlib/awesomeuploader/config/awesomeuploader/snippet.js,sha256=cZCGi0e9lDW96vCg3KVJ5DUtg2KHLNdnPo5KPRrQxv8,1792
|
@@ -188,8 +188,8 @@ lino/modlib/dupable/models.py,sha256=0watviKwTiVwlArC54V3IxVVfcB1Yg5kO6ed2xCM9a0
|
|
188
188
|
lino/modlib/export_excel/__init__.py,sha256=k11dEbh1VgA7cMaUdMhiJvHNboX4BqN0Z5Wj9fV7rWw,469
|
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
|
-
lino/modlib/extjs/ext_renderer.py,sha256=
|
192
|
-
lino/modlib/extjs/views.py,sha256=
|
191
|
+
lino/modlib/extjs/ext_renderer.py,sha256=DVUoCmy-knDO_i6s8yVGy8xI2qsWBA8GByiv29Lm8ts,60609
|
192
|
+
lino/modlib/extjs/views.py,sha256=7IlzseAwtGPZtpsbow103mEV8VuKIH9uhfZmv9StneA,26292
|
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,10 +3544,10 @@ 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=
|
3550
|
-
lino/modlib/memo/parser.py,sha256=
|
3549
|
+
lino/modlib/memo/models.py,sha256=zUEvWu0dK5QhkU3DeMqNqsrzSUzOl6DLZaJBNytfgrs,4388
|
3550
|
+
lino/modlib/memo/parser.py,sha256=AKMfdbNFl9ehxl8TTFWwQ-ngfx7CD7hUjVA6bUNBY1c,12997
|
3551
3551
|
lino/modlib/memo/views.py,sha256=H3g_nuiMzguptXLSWaWLJClU7BefXPFn9Rh8UIVVBeg,555
|
3552
3552
|
lino/modlib/notify/__init__.py,sha256=suo7EMVdyTPTPFwuU2KZL25PwIEstTvvR4Turgdz7UE,6926
|
3553
3553
|
lino/modlib/notify/actions.py,sha256=ClRKDjmgx3m43IZ5cx0TdxXN_pU6hLIlo_jCwEW2LhY,2468
|
@@ -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.1.dist-info/METADATA,sha256=tByKXlu49CnGrkvvWX-WVmYBSYIQyjUr3rhA5AIKys4,42534
|
4637
|
+
lino-25.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
4638
|
+
lino-25.4.1.dist-info/licenses/AUTHORS.rst,sha256=8VEm_G4HOmYEa4oi1nVoKKsdo4JanekEJCefWd2E8vk,981
|
4639
|
+
lino-25.4.1.dist-info/licenses/COPYING,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
4640
|
+
lino-25.4.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|