lino 25.3.0__py3-none-any.whl → 25.3.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 +1 -1
- lino/api/doctest.py +34 -36
- lino/core/inject.py +7 -6
- lino/core/kernel.py +0 -46
- lino/core/model.py +17 -15
- lino/core/plugin.py +4 -4
- lino/core/site.py +84 -30
- lino/management/commands/prep.py +1 -1
- lino/modlib/help/management/commands/makehelp.py +5 -2
- lino/modlib/jinja/mixins.py +2 -2
- lino/modlib/linod/mixins.py +3 -0
- lino/modlib/printing/mixins.py +3 -0
- lino/modlib/uploads/models.py +7 -6
- {lino-25.3.0.dist-info → lino-25.3.1.dist-info}/METADATA +1 -1
- {lino-25.3.0.dist-info → lino-25.3.1.dist-info}/RECORD +18 -39
- lino/sandbox/bcss/PerformInvestigation.py +0 -2260
- lino/sandbox/bcss/SSDNReply.py +0 -3924
- lino/sandbox/bcss/SSDNRequest.py +0 -3723
- lino/sandbox/bcss/__init__.py +0 -0
- lino/sandbox/bcss/readme.txt +0 -1
- lino/sandbox/bcss/test.py +0 -92
- lino/sandbox/bcss/test2.py +0 -128
- lino/sandbox/bcss/test3.py +0 -161
- lino/sandbox/bcss/test4.py +0 -167
- lino/sandbox/contacts/__init__.py +0 -0
- lino/sandbox/contacts/fixtures/__init__.py +0 -0
- lino/sandbox/contacts/fixtures/demo.py +0 -365
- lino/sandbox/contacts/manage.py +0 -10
- lino/sandbox/contacts/models.py +0 -395
- lino/sandbox/contacts/settings.py +0 -67
- lino/sandbox/tx25/XSD/RetrieveTIGroupsV3.wsdl +0 -65
- lino/sandbox/tx25/XSD/RetrieveTIGroupsV3.xsd +0 -286
- lino/sandbox/tx25/XSD/rn25_Release201104.xsd +0 -2855
- lino/sandbox/tx25/xsd2py1.py +0 -68
- lino/sandbox/tx25/xsd2py2.py +0 -62
- lino/sandbox/tx25/xsd2py3.py +0 -56
- {lino-25.3.0.dist-info → lino-25.3.1.dist-info}/WHEEL +0 -0
- {lino-25.3.0.dist-info → lino-25.3.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-25.3.0.dist-info → lino-25.3.1.dist-info}/licenses/COPYING +0 -0
lino/__init__.py
CHANGED
lino/api/doctest.py
CHANGED
@@ -14,6 +14,38 @@ tested document. It includes
|
|
14
14
|
|
15
15
|
"""
|
16
16
|
|
17
|
+
from lino.core.boundaction import BoundAction
|
18
|
+
from lino.core.tables import AbstractTable
|
19
|
+
from lino.core.actions import Action
|
20
|
+
from django.db.models import Model
|
21
|
+
from lino.core.layouts import BaseLayout
|
22
|
+
from lino.core.actions import register_params
|
23
|
+
from lino.core.actions import ShowTable
|
24
|
+
from lino.core.menus import Menu
|
25
|
+
from lino.utils.html import html2text
|
26
|
+
from lino.core.utils import full_model_name, get_models
|
27
|
+
from lino.utils.diag import visible_for
|
28
|
+
from lino.sphinxcontrib.actordoc import menuselection_text
|
29
|
+
from lino import logger
|
30
|
+
from lino.core.menus import find_menu_item
|
31
|
+
from lino.core import constants
|
32
|
+
from lino.core import actors, kernel
|
33
|
+
from lino.utils.sql import sql_summary
|
34
|
+
from lino.utils import diag
|
35
|
+
from lino.utils.diag import analyzer
|
36
|
+
from lino.utils.html import E, tostring, to_rst
|
37
|
+
from lino.utils import i2d
|
38
|
+
from lino.utils import AttrDict
|
39
|
+
from rstgen.utils import unindent, rmu, sixprint
|
40
|
+
from rstgen import attrtable
|
41
|
+
import rstgen
|
42
|
+
import pytest
|
43
|
+
from django.db import connection, reset_queries as reset_sql_queries
|
44
|
+
from django.test import Client
|
45
|
+
from django.utils.encoding import force_str
|
46
|
+
from django.utils import translation
|
47
|
+
from lino.api.shell import *
|
48
|
+
from lino.core.constants import *
|
17
49
|
import os
|
18
50
|
import sys
|
19
51
|
import datetime
|
@@ -31,39 +63,11 @@ from urllib.parse import urlencode
|
|
31
63
|
import django
|
32
64
|
django.setup()
|
33
65
|
|
34
|
-
from lino.core.constants import *
|
35
|
-
from lino.api.shell import *
|
36
|
-
from django.utils import translation
|
37
|
-
from django.utils.encoding import force_str
|
38
|
-
from django.test import Client
|
39
|
-
from django.db import connection, reset_queries as reset_sql_queries
|
40
66
|
|
41
|
-
import pytest
|
42
67
|
# from rstgen import table, ul
|
43
|
-
import rstgen
|
44
|
-
from rstgen import attrtable
|
45
|
-
from rstgen.utils import unindent, rmu, sixprint
|
46
68
|
|
47
|
-
from lino.utils import AttrDict
|
48
|
-
from lino.utils import i2d
|
49
|
-
from lino.utils.html import E, tostring, to_rst
|
50
|
-
from lino.utils.diag import analyzer
|
51
|
-
from lino.utils import diag
|
52
|
-
from lino.utils.sql import sql_summary
|
53
|
-
from lino.core import actors, kernel
|
54
|
-
from lino.core import constants
|
55
|
-
from lino.core.menus import find_menu_item
|
56
|
-
from lino import logger
|
57
|
-
from lino.sphinxcontrib.actordoc import menuselection_text
|
58
|
-
from lino.utils.diag import visible_for
|
59
|
-
from lino.core.utils import full_model_name, get_models
|
60
69
|
|
61
70
|
# from lino.core.utils import PseudoRequest
|
62
|
-
from lino.utils.html import html2text
|
63
|
-
from lino.core.menus import Menu
|
64
|
-
from lino.core.actions import ShowTable
|
65
|
-
from lino.core.actions import register_params
|
66
|
-
from lino.core.layouts import BaseLayout
|
67
71
|
|
68
72
|
test_client = Client()
|
69
73
|
"""An instance of :class:`django.test.Client`.
|
@@ -275,12 +279,6 @@ def show_choices(username, url, show_count=False):
|
|
275
279
|
print("{} rows".format(result["count"]))
|
276
280
|
|
277
281
|
|
278
|
-
from django.db.models import Model
|
279
|
-
from lino.core.actions import Action
|
280
|
-
from lino.core.tables import AbstractTable
|
281
|
-
from lino.core.boundaction import BoundAction
|
282
|
-
|
283
|
-
|
284
282
|
def show_workflow(actions, all=False, language=None):
|
285
283
|
"""
|
286
284
|
Show the given actions as a table. Usage example in
|
@@ -768,7 +766,6 @@ def walk_store_fields(only_detail_fields=False):
|
|
768
766
|
yield a, sf
|
769
767
|
|
770
768
|
|
771
|
-
# settings.SITE.kernel.check_virgin()
|
772
769
|
def set_log_level(level):
|
773
770
|
logger.setLevel(level)
|
774
771
|
for handler in logger.handlers:
|
@@ -800,6 +797,7 @@ def show_change_watchers():
|
|
800
797
|
)
|
801
798
|
print(rstgen.table(headers, rows, max_width=40))
|
802
799
|
|
800
|
+
|
803
801
|
def show_display_modes():
|
804
802
|
"""
|
805
803
|
Show the availble display modes per actor.
|
@@ -813,7 +811,7 @@ def show_display_modes():
|
|
813
811
|
rows.append(
|
814
812
|
[str(a)] + [
|
815
813
|
("x" if dm in a.extra_display_modes else "")
|
816
|
-
|
814
|
+
for dm in dml]
|
817
815
|
)
|
818
816
|
print(rstgen.table(headers, rows))
|
819
817
|
|
lino/core/inject.py
CHANGED
@@ -132,9 +132,9 @@ def check_pending_injects(sender, models_list=None, **kw):
|
|
132
132
|
# ~ logger.info("20131110 no pending injects")
|
133
133
|
"""
|
134
134
|
20130106
|
135
|
-
now we loop a last time over each model and fill
|
136
|
-
otherwise if some
|
137
|
-
has subclasses,
|
135
|
+
now we loop a last time over each model and fill its _meta._field_cache
|
136
|
+
otherwise if some plugin used inject_field() on a model that
|
137
|
+
has subclasses, the new field would not be seen by subclasses
|
138
138
|
"""
|
139
139
|
for model in models_list:
|
140
140
|
model._meta._expire_cache()
|
@@ -225,7 +225,8 @@ def update_model(model_spec, **actions):
|
|
225
225
|
def todo(model):
|
226
226
|
for k, v in actions.items():
|
227
227
|
if not hasattr(model, k):
|
228
|
-
raise Exception(
|
228
|
+
raise Exception(
|
229
|
+
"%s has no attribute %s to update." % (model, k))
|
229
230
|
setattr(model, k, v)
|
230
231
|
|
231
232
|
if isinstance(model_spec, models.Model):
|
@@ -389,8 +390,8 @@ def inject_quick_add_buttons(model, name, target):
|
|
389
390
|
inject_field(
|
390
391
|
model,
|
391
392
|
name,
|
392
|
-
fields.VirtualField(fields.DisplayField(
|
393
|
-
|
393
|
+
fields.VirtualField(fields.DisplayField(
|
394
|
+
tm._meta.verbose_name_plural), fn))
|
394
395
|
|
395
396
|
|
396
397
|
# def django_patch():
|
lino/core/kernel.py
CHANGED
@@ -26,7 +26,6 @@ import atexit
|
|
26
26
|
import signal
|
27
27
|
import threading
|
28
28
|
from importlib import import_module
|
29
|
-
import json
|
30
29
|
|
31
30
|
# from django.apps import AppConfig
|
32
31
|
from django.apps import apps
|
@@ -953,51 +952,6 @@ class Kernel(object):
|
|
953
952
|
# def setup_static_link(self, urlpatterns, short_name,
|
954
953
|
# attr_name=None, source=None):
|
955
954
|
|
956
|
-
def mark_virgin(self):
|
957
|
-
dbhash = self.get_dbhash()
|
958
|
-
fn = self.site.site_dir / "dbhash.json"
|
959
|
-
with fn.open("w") as fp:
|
960
|
-
json.dump(dbhash, fp)
|
961
|
-
|
962
|
-
def check_virgin(self):
|
963
|
-
new = self.get_dbhash()
|
964
|
-
fn = self.site.site_dir / "dbhash.json"
|
965
|
-
if not fn.exists():
|
966
|
-
raise Exception(
|
967
|
-
"No `dbhash.json` in {} " "(did you run `django-admin prep`?)".format(
|
968
|
-
self.site.site_dir
|
969
|
-
)
|
970
|
-
)
|
971
|
-
with fn.open("r") as fp:
|
972
|
-
old = json.load(fp)
|
973
|
-
|
974
|
-
# noi1r has noi1e as master_site, but the react front end removes the
|
975
|
-
# tinymce plugin, i.e. noi1r doesn't care about
|
976
|
-
# tinymce.TextFieldTemplate model.
|
977
|
-
|
978
|
-
diffs = {}
|
979
|
-
for k, v in new.items():
|
980
|
-
oldv = old.get(k, None)
|
981
|
-
if oldv != v:
|
982
|
-
diffs[k] = (oldv, v)
|
983
|
-
# diff = set(old.items()) ^ set(new.items())
|
984
|
-
if diffs:
|
985
|
-
# db = self.site.django_settings.get('SETTINGS_MODULE')
|
986
|
-
db = self.site.site_dir
|
987
|
-
raise Exception("Database {} isn't virgin: {}".format(db, diffs))
|
988
|
-
|
989
|
-
# logger.info("Database certified as virgin")
|
990
|
-
|
991
|
-
def get_dbhash(self):
|
992
|
-
# TODO: we currently check only the number of rows per model. That's
|
993
|
-
# very naive.
|
994
|
-
rv = dict()
|
995
|
-
for m in get_models(include_auto_created=True):
|
996
|
-
k = fmn(m)
|
997
|
-
if k != "sessions.Session":
|
998
|
-
rv[k] = m.objects.count()
|
999
|
-
return rv
|
1000
|
-
|
1001
955
|
|
1002
956
|
def site_startup(self):
|
1003
957
|
"""This is being imported and called from
|
lino/core/model.py
CHANGED
@@ -534,6 +534,7 @@ class Model(models.Model, fields.TableRow):
|
|
534
534
|
"""
|
535
535
|
watcher = ChangeWatcher(row)
|
536
536
|
# assert hasattr(row, state_field.attname)
|
537
|
+
row.before_ui_save(ar, watcher) # added 20250312 for #5976
|
537
538
|
old = getattr(row, state_field.attname)
|
538
539
|
target_state.choicelist.before_state_change(row, ar, old, target_state)
|
539
540
|
row.before_state_change(ar, old, target_state)
|
@@ -680,21 +681,22 @@ class Model(models.Model, fields.TableRow):
|
|
680
681
|
|
681
682
|
df = actor.get_disabled_fields(obj, ar)
|
682
683
|
# print(20170909, df)
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
if
|
691
|
-
if
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
684
|
+
if 'workflow_buttons' not in df:
|
685
|
+
for ba in actor.get_actions():
|
686
|
+
assert ba.actor == actor # 20170102
|
687
|
+
if ba.action.show_in_workflow:
|
688
|
+
# if actor.model.__name__ == 'Vote':
|
689
|
+
# if ba.action.__class__.__name__ == 'MarkVoteAssigned':
|
690
|
+
# print(20170115, actor, ar.get_user())
|
691
|
+
if ba.action.action_name not in df:
|
692
|
+
if actor.get_row_permission(obj, ar, state, ba):
|
693
|
+
if show and isinstance(ba.action, ChangeStateAction):
|
694
|
+
show_state()
|
695
|
+
sep = " \u2192 " # "→"
|
696
|
+
show = False
|
697
|
+
l.append(sep)
|
698
|
+
l.append(ar.action_button(ba, obj))
|
699
|
+
sep = " "
|
698
700
|
if state and show:
|
699
701
|
show_state()
|
700
702
|
return E.span(*l)
|
lino/core/plugin.py
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
# -*- coding: UTF-8 -*-
|
2
|
-
# Copyright 2008-
|
2
|
+
# Copyright 2008-2025 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
|
5
|
-
import os
|
6
5
|
import inspect
|
7
|
-
from os.path import
|
6
|
+
from os.path import join, dirname, isdir, abspath
|
8
7
|
from collections.abc import Iterable
|
9
8
|
from urllib.parse import urlencode
|
10
9
|
from lino.core.exceptions import ChangedAPI
|
@@ -56,7 +55,8 @@ class Plugin:
|
|
56
55
|
|
57
56
|
def hide(self):
|
58
57
|
if self.site._startup_done:
|
59
|
-
raise Exception(
|
58
|
+
raise Exception(
|
59
|
+
"Tried to deactivate plugin {} after startup".format(self))
|
60
60
|
self.hidden = True
|
61
61
|
|
62
62
|
def configure(self, **kw):
|
lino/core/site.py
CHANGED
@@ -3,17 +3,37 @@
|
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
# doctest lino/core/site.py
|
5
5
|
|
6
|
+
import json
|
7
|
+
from lino.core.exceptions import ChangedAPI
|
8
|
+
from lino.core.utils import get_models, is_logserver
|
9
|
+
from lino.utils.html import E, tostring
|
10
|
+
from lino import assert_django_code, DJANGO_DEFAULT_LANGUAGE
|
11
|
+
# from lino.core import constants
|
12
|
+
from lino.core.plugin import Plugin
|
13
|
+
from lino.core.utils import full_model_name as fmn
|
14
|
+
from rstgen.confparser import ConfigParser
|
15
|
+
from django.utils import translation
|
16
|
+
from django.utils.html import mark_safe
|
17
|
+
from django.utils.translation import get_language
|
18
|
+
from django.utils.translation import gettext_lazy as _
|
19
|
+
from django.conf import settings
|
20
|
+
import rstgen
|
21
|
+
from lino.utils import AttrDict, date_offset, i2d, buildurl
|
22
|
+
from lino import logger, __version__
|
23
|
+
from importlib.util import find_spec
|
24
|
+
from importlib import import_module, reload
|
25
|
+
from pathlib import Path
|
6
26
|
import os
|
7
27
|
import re
|
8
28
|
import sys
|
9
|
-
from os.path import
|
29
|
+
from os.path import dirname, join, isdir, relpath, exists
|
10
30
|
import inspect
|
11
31
|
import datetime
|
12
32
|
import warnings
|
13
33
|
import collections
|
14
34
|
import locale
|
15
35
|
import logging
|
16
|
-
from pprint import pprint
|
36
|
+
# from pprint import pprint
|
17
37
|
from logging.handlers import SocketHandler
|
18
38
|
import time
|
19
39
|
|
@@ -30,34 +50,12 @@ ASYNC_LOGGING = False
|
|
30
50
|
# activated, accesses settings.DEFAULT_EXCEPTION_REPORTER, which fails at this
|
31
51
|
# moment because the settings aren't yet loaded.
|
32
52
|
|
33
|
-
from pathlib import Path
|
34
|
-
from importlib import import_module, reload
|
35
|
-
from importlib.util import find_spec
|
36
|
-
|
37
|
-
from lino import logger, __version__
|
38
|
-
from lino.utils import AttrDict, date_offset, i2d, buildurl
|
39
|
-
import rstgen
|
40
|
-
|
41
|
-
from django.conf import settings
|
42
|
-
from django.utils.translation import gettext_lazy as _
|
43
|
-
from django.utils.translation import get_language
|
44
|
-
from django.utils.html import mark_safe
|
45
|
-
from django.db.utils import DatabaseError
|
46
|
-
from django.utils import translation
|
47
53
|
|
48
54
|
has_socialauth = find_spec("social_django") is not None
|
49
55
|
has_elasticsearch = find_spec("elasticsearch_django") is not None
|
50
56
|
has_haystack = find_spec("haystack") is not None
|
51
57
|
|
52
|
-
from rstgen.confparser import ConfigParser
|
53
|
-
from lino.core.plugin import Plugin
|
54
|
-
from lino.core import constants
|
55
|
-
|
56
|
-
from lino import assert_django_code, DJANGO_DEFAULT_LANGUAGE
|
57
|
-
from lino.utils.html import E, join_elems, tostring
|
58
|
-
from lino.core.utils import get_models, is_logserver
|
59
58
|
|
60
|
-
from lino.core.exceptions import ChangedAPI
|
61
59
|
# from .roles import SiteUser
|
62
60
|
|
63
61
|
|
@@ -88,14 +86,14 @@ def to_locale(language):
|
|
88
86
|
p = language.find("-")
|
89
87
|
if p >= 0:
|
90
88
|
# Get correct locale for sr-latn
|
91
|
-
if len(language[p + 1
|
89
|
+
if len(language[p + 1:]) > 2:
|
92
90
|
return (
|
93
91
|
language[:p].lower()
|
94
92
|
+ "_"
|
95
93
|
+ language[p + 1].upper()
|
96
|
-
+ language[p + 2
|
94
|
+
+ language[p + 2:].lower()
|
97
95
|
)
|
98
|
-
return language[:p].lower() + "_" + language[p + 1
|
96
|
+
return language[:p].lower() + "_" + language[p + 1:].upper()
|
99
97
|
return language.lower()
|
100
98
|
|
101
99
|
|
@@ -103,7 +101,8 @@ def class2str(cl):
|
|
103
101
|
return cl.__module__ + "." + cl.__name__
|
104
102
|
|
105
103
|
|
106
|
-
gettext_noop
|
104
|
+
def gettext_noop(s): return s
|
105
|
+
|
107
106
|
|
108
107
|
PLUGIN_CONFIGS = {}
|
109
108
|
|
@@ -718,7 +717,6 @@ class Site(object):
|
|
718
717
|
else:
|
719
718
|
d["logger_ok"] = True
|
720
719
|
# self.update_settings(LOGGING=d)
|
721
|
-
# from pprint import pprint
|
722
720
|
# pprint(d)
|
723
721
|
# print("20161126 Site %s " % d['loggers'].keys())
|
724
722
|
# import yaml
|
@@ -1796,6 +1794,61 @@ class Site(object):
|
|
1796
1794
|
# ~ return v
|
1797
1795
|
# ~ return getattr(obj,attrname,*args)
|
1798
1796
|
|
1797
|
+
def mark_virgin(self):
|
1798
|
+
"""
|
1799
|
+
Mark the database as virgin. This is called by :manage:`prep`.
|
1800
|
+
"""
|
1801
|
+
dbhash = self.get_dbhash()
|
1802
|
+
fn = self.site_dir / "dbhash.json"
|
1803
|
+
with fn.open("w") as fp:
|
1804
|
+
json.dump(dbhash, fp)
|
1805
|
+
# self.site.logger.info("Wrote %s", fn)
|
1806
|
+
|
1807
|
+
def check_virgin(self):
|
1808
|
+
"""
|
1809
|
+
Verify whether the database is virgin. Print the differences if there
|
1810
|
+
are any.
|
1811
|
+
"""
|
1812
|
+
new = self.get_dbhash()
|
1813
|
+
db = self.site_dir
|
1814
|
+
fn = db / "dbhash.json"
|
1815
|
+
if not fn.exists():
|
1816
|
+
raise Exception(
|
1817
|
+
f"No `dbhash.json` in {db} (did you run `django-admin prep`?)")
|
1818
|
+
with fn.open("r") as fp:
|
1819
|
+
old = json.load(fp)
|
1820
|
+
|
1821
|
+
# noi1r has noi1e as master_site, but the react front end removes the
|
1822
|
+
# tinymce plugin, i.e. noi1r doesn't care about
|
1823
|
+
# tinymce.TextFieldTemplate model.
|
1824
|
+
|
1825
|
+
ok = True
|
1826
|
+
for k, v in new.items():
|
1827
|
+
v = set(v)
|
1828
|
+
oldv = set(old.get(k, None))
|
1829
|
+
if oldv != v:
|
1830
|
+
if ok:
|
1831
|
+
print(f"Database {db} isn't virgin:")
|
1832
|
+
ok = False
|
1833
|
+
diffs = []
|
1834
|
+
if (added := len(oldv-v)):
|
1835
|
+
diffs.append(f"{added} rows added")
|
1836
|
+
if (removed := len(v-oldv)):
|
1837
|
+
diffs.append(f"{removed} rows removed")
|
1838
|
+
print(f"- {k}: {', '.join(diffs)}")
|
1839
|
+
|
1840
|
+
def get_dbhash(self):
|
1841
|
+
"""
|
1842
|
+
Return a dictionary with a hash value of the current database content.
|
1843
|
+
"""
|
1844
|
+
rv = dict()
|
1845
|
+
for m in get_models(include_auto_created=True):
|
1846
|
+
k = fmn(m)
|
1847
|
+
if k != "sessions.Session":
|
1848
|
+
# rv[k] = m.objects.count()
|
1849
|
+
rv[k] = list(m.objects.values_list('pk', flat=True))
|
1850
|
+
return rv
|
1851
|
+
|
1799
1852
|
def diagnostic_report_rst(self, *args):
|
1800
1853
|
"""Returns a string with a diagnostic report about this
|
1801
1854
|
site. :manage:`diag` is a command-line shortcut to this.
|
@@ -1992,7 +2045,8 @@ class Site(object):
|
|
1992
2045
|
):
|
1993
2046
|
yield "social_django.middleware.SocialAuthExceptionMiddleware"
|
1994
2047
|
|
1995
|
-
|
2048
|
+
# removed 20240921, see #5755 (Should we remove AjaxExceptionResponse?)
|
2049
|
+
if False:
|
1996
2050
|
yield "lino.utils.ajax.AjaxExceptionResponse"
|
1997
2051
|
|
1998
2052
|
if self.use_security_features:
|
lino/management/commands/prep.py
CHANGED
@@ -42,7 +42,10 @@ from lino.core.utils import model_class_path
|
|
42
42
|
from lino.modlib.help.utils import HelpTextsLoader, simplify_name
|
43
43
|
from lino.modlib.gfks.fields import GenericForeignKey
|
44
44
|
from lino.api.dd import full_model_name
|
45
|
-
|
45
|
+
|
46
|
+
# removed import doctest because it caused "pytest not installed" during
|
47
|
+
# makehelp on LF:
|
48
|
+
# from lino.api import doctest
|
46
49
|
|
47
50
|
use_dirhtml = False
|
48
51
|
|
@@ -255,7 +258,7 @@ class Command(GeneratingCommand):
|
|
255
258
|
settings=settings,
|
256
259
|
actors=actors,
|
257
260
|
# actors_list=[a for a in actors.actors_list if not a.abstract],
|
258
|
-
doctest=doctest,
|
261
|
+
# doctest=doctest,
|
259
262
|
translation=translation,
|
260
263
|
use_dirhtml=use_dirhtml,
|
261
264
|
include_useless=include_useless,
|
lino/modlib/jinja/mixins.py
CHANGED
@@ -55,8 +55,8 @@ class XMLMaker(dd.Model):
|
|
55
55
|
if self.xml_validator_file:
|
56
56
|
# print("20250218 {xml[:100]}")
|
57
57
|
# doc = etree.fromstring(xml.encode("utf-8"))
|
58
|
-
ar.logger.info("Validate %s against %s ...",
|
59
|
-
|
58
|
+
# ar.logger.info("Validate %s against %s ...",
|
59
|
+
# xmlfile.path.name, self.xml_validator_file)
|
60
60
|
if True:
|
61
61
|
validate_xml(xmlfile.path, self.xml_validator_file)
|
62
62
|
else:
|
lino/modlib/linod/mixins.py
CHANGED
@@ -132,6 +132,9 @@ class Runnable(Sequenced, RecurrenceSet):
|
|
132
132
|
await ar.adebug("Successfully terminated %s", self)
|
133
133
|
# ar.info("Successfully terminated %s", astr(self))
|
134
134
|
self.message = out.getvalue()
|
135
|
+
except Warning as e:
|
136
|
+
await ar.adebug("Terminated %s with warning %s", self, str(e))
|
137
|
+
self.message = out.getvalue()
|
135
138
|
except Exception as e:
|
136
139
|
self.message = out.getvalue()
|
137
140
|
self.message += "\n" + "".join(traceback.format_exception(e))
|
lino/modlib/printing/mixins.py
CHANGED
@@ -183,6 +183,9 @@ class CachedPrintable(Duplicable, Printable):
|
|
183
183
|
def get_target_url(self):
|
184
184
|
return self.build_method.get_target_url(self.do_print, self)
|
185
185
|
|
186
|
+
def get_target_file(self):
|
187
|
+
return self.build_method.get_target_file(self.do_print, self)
|
188
|
+
|
186
189
|
def get_cache_mtime(self):
|
187
190
|
"""Return the modification time (a `datetime`) of the generated cache
|
188
191
|
file, or `None` if no such file exists.
|
lino/modlib/uploads/models.py
CHANGED
@@ -481,12 +481,13 @@ def on_sanitize(soup, save=False, ar=None):
|
|
481
481
|
# raise Exception(f"20250301")
|
482
482
|
for tag in soup.find_all():
|
483
483
|
tag_name = tag.name.lower()
|
484
|
-
if tag_name == "img" and
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
484
|
+
if tag_name == "img" and ar is not None and save:
|
485
|
+
if (src := tag.get('src')) and src.startswith("data:image"):
|
486
|
+
file = base64_to_image(src)
|
487
|
+
upload = rt.models.uploads.Upload(file=file, user=ar.get_user())
|
488
|
+
sar = upload.get_default_table().request(parent=ar)
|
489
|
+
upload.save_new_instance(sar)
|
490
|
+
tag.replace_with(f'[file {upload.pk}]')
|
490
491
|
|
491
492
|
|
492
493
|
register_sanitizer(on_sanitize)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: lino
|
3
|
-
Version: 25.3.
|
3
|
+
Version: 25.3.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
|