lino 25.4.3__py3-none-any.whl → 25.4.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
lino/__init__.py CHANGED
@@ -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.4.3'
34
+ __version__ = '25.4.5'
35
35
 
36
36
  # import setuptools # avoid UserWarning "Distutils was imported before Setuptools"?
37
37
 
lino/core/fields.py CHANGED
@@ -163,7 +163,7 @@ class PriceField(models.DecimalField):
163
163
  """
164
164
  A thin wrapper around Django's `DecimalField
165
165
  <https://docs.djangoproject.com/en/5.0/ref/models/fields/#decimalfield>`_
166
- which adds default values for `decimal_places`, `max_length` and
166
+ with price-like default values for `decimal_places`, `max_length` and
167
167
  `max_digits`.
168
168
  """
169
169
 
@@ -656,8 +656,10 @@ class VirtualField(FakeField):
656
656
  self.model = model
657
657
  self.name = name
658
658
  self.attname = name
659
+ # if getattr(self.return_type, "model", False):
659
660
  if hasattr(self.return_type, "model"):
660
- # logger.info("20200425 return_type for virtual field %s has a model", self)
661
+ # logger.info("20200425 return_type for virtual "
662
+ # "field %s has a model %s (not %s)", self, self.return_type.model, model)
661
663
  return
662
664
  self.return_type.model = VirtualModel(model)
663
665
  self.return_type.column = None
lino/core/kernel.py CHANGED
@@ -37,6 +37,7 @@ from django.utils.translation import gettext_lazy as _
37
37
  from django.core.exceptions import PermissionDenied, ValidationError
38
38
  from django.db.utils import DatabaseError
39
39
  from django.db import IntegrityError
40
+ from django.utils.log import DEFAULT_LOGGING
40
41
 
41
42
  from django.db import models
42
43
 
@@ -162,7 +163,9 @@ class Kernel(object):
162
163
  # logger.info("20231016 kernel_startup (%s)", site._history_aware_logging)
163
164
  # print("20231019 kernel_startup()", site, site._history_aware_logging)
164
165
 
165
- if site._history_aware_logging:
166
+ # if site._history_aware_logging:
167
+ # if not is_devserver():
168
+ if "file" in DEFAULT_LOGGING['handlers']:
166
169
  if len(sys.argv) == 0:
167
170
  process_name = "WSGI"
168
171
  else:
lino/core/requests.py CHANGED
@@ -2031,9 +2031,9 @@ class ActionRequest(BaseRequest):
2031
2031
  if w is None:
2032
2032
  WARNINGS_LOGGED[e] = True
2033
2033
  # raise
2034
- # logger.exception(e)
2035
2034
  logger.warning(f"Error while executing {repr(self)}: {e}\n"
2036
2035
  "(Subsequent warnings will be silenced.)")
2036
+ logger.exception(e)
2037
2037
 
2038
2038
  if self._data_iterator is None:
2039
2039
  raise Exception(f"No data iterator for {self}")
lino/core/site.py CHANGED
@@ -36,12 +36,13 @@ from lino.utils.html import E, tostring
36
36
  from lino.core.plugin import Plugin
37
37
  from lino.utils import AttrDict, date_offset, i2d, buildurl
38
38
 
39
+
39
40
  NO_REMOTE_AUTH = True
40
41
  # 20240518 We have only one production site still using remote http
41
42
  # authentication, and they will migrate to sessions-based auth with their next
42
43
  # upgrade.
43
44
 
44
- ASYNC_LOGGING = False
45
+ # ASYNC_LOGGING = False
45
46
  # This is to fix the issue that the "started" and "ended" messages are not logged.
46
47
  # But setting this to True causes #4986 (Unable to configure handler 'mail_admins')
47
48
  # because since 20230529 we called logging..config.dictConfig() during
@@ -368,14 +369,14 @@ class Site(object):
368
369
  csv_params = dict()
369
370
 
370
371
  # attributes documented in book/docs/opics/loggin.rst:
371
- _history_aware_logging = False
372
+ _history_aware_logging = True
372
373
  log_each_action_request = False
374
+ default_loglevel = "INFO"
373
375
  logger_filename = "lino.log"
374
376
  logger_format = (
375
377
  "%(asctime)s %(levelname)s [%(name)s %(process)d %(thread)d] : %(message)s"
376
378
  )
377
379
  auto_configure_logger_names = "atelier lino"
378
- log_sock_path = None
379
380
 
380
381
  # appy_params = dict(ooPort=8100)
381
382
  appy_params = dict(
@@ -559,21 +560,13 @@ class Site(object):
559
560
  break
560
561
 
561
562
  if self.master_site is None:
562
- # cache_root = os.environ.get("LINO_CACHE_ROOT", None)
563
- # if cache_root:
564
- # # TODO: deprecate
565
- # cr = Path(cache_root).absolute()
566
- # if not cr.exists():
567
- # msg = "LINO_CACHE_ROOT ({0}) does not exist!".format(cr)
568
- # raise Exception(msg)
569
- # self.site_dir = (cr / self.project_name).resolve()
570
- # self.setup_cache_directory()
571
- # else:
572
- # self.site_dir = self.project_dir
573
563
  self.site_dir = self.project_dir
574
- db = self.get_database_settings()
575
- if db is not None:
576
- self.django_settings.update(DATABASES=db)
564
+ self.django_settings.update(DATABASES={
565
+ "default": {
566
+ "ENGINE": "django.db.backends.sqlite3",
567
+ "NAME": str(self.site_dir / "default.db")
568
+ }
569
+ })
577
570
  else:
578
571
  self.site_dir = self.master_site.site_dir
579
572
  self._history_aware_logging = self.master_site._history_aware_logging
@@ -605,31 +598,36 @@ class Site(object):
605
598
  self.startup_time = datetime.datetime.now()
606
599
 
607
600
  def setup_logging(self):
608
- # documented in book/docs/opics/loggin.rst
601
+ # documented in book/docs/topics/logging.rst
609
602
 
610
- if not self.auto_configure_logger_names:
603
+ if self.auto_configure_logger_names is None:
611
604
  return
612
605
 
613
- if len(logging.root.handlers) > 0:
614
- # Logging has been configured by something else. This can happen
615
- # when Site is instantiated a second time. Or accidentaly (e.g. when you call logging.basicConfig() in the settings.py), Or when some testing
616
- # environment runs multiple doctests in a same process. We don't
617
- # care, we restart configuration from scratch.
618
-
619
- for handler in logging.root.handlers[:]:
620
- logging.root.removeHandler(handler)
606
+ # if len(logging.root.handlers) > 0:
607
+ #
608
+ # # Logging has been configured by something else. This can happen
609
+ # # when Site is instantiated a second time. Or accidentaly (e.g. when
610
+ # # you call logging.basicConfig() in the settings.py), Or when some
611
+ # # testing environment runs multiple doctests in a same process. We
612
+ # # don't care, we restart configuration from scratch.
613
+ #
614
+ # for handler in logging.root.handlers[:]:
615
+ # logging.root.removeHandler(handler)
621
616
 
622
617
  from django.utils.log import DEFAULT_LOGGING
623
618
 
624
619
  d = DEFAULT_LOGGING
625
620
 
626
- if d.get("logger_ok", False):
627
- # raise Exception("20231017")
628
- return
621
+ # if d.get("logger_ok", False):
622
+ # # raise Exception("20231017")
623
+ # return
629
624
 
630
- level = os.environ.get("LINO_LOGLEVEL", "INFO").upper()
625
+ level = os.environ.get("LINO_LOGLEVEL", self.default_loglevel).upper()
631
626
  file_level = os.environ.get("LINO_FILE_LOGLEVEL", level).upper()
632
- min_level = min(*[getattr(logging, k) for k in (level, file_level)])
627
+ sql_level = os.environ.get("LINO_SQL_LOGLEVEL", level).upper()
628
+
629
+ min_level = min(*[getattr(logging, k) for k in (
630
+ level, file_level, sql_level)])
633
631
 
634
632
  # print("20231017 level is", level)
635
633
 
@@ -650,22 +648,13 @@ class Site(object):
650
648
 
651
649
  # when Site is instantiated several times, we keep the existing file handler
652
650
  # print("20231016", self.logger_filename, handlers.keys())
653
- if self.logger_filename and "file" not in handlers:
651
+ if "file" not in handlers:
654
652
  logdir = self.site_dir / "log"
655
653
  if logdir.is_dir():
656
654
  self._history_aware_logging = True
657
655
  log_file_path = logdir / self.logger_filename
658
656
  # print("20231019 logging", file_level, "to", log_file_path)
659
- self.log_sock_path = logdir / (self.logger_filename + ".sock")
660
- if self.log_sock_path.exists():
661
- # print("20231019 log via socket server")
662
- handlers["file"] = {
663
- "class": "lino.core.site.LinoSocketHandler",
664
- "host": str(self.log_sock_path),
665
- "port": None,
666
- "level": file_level,
667
- }
668
- else:
657
+ if True:
669
658
  # print("20231019 log directly to file")
670
659
  formatters = d.setdefault("formatters", {})
671
660
  formatters.setdefault(
@@ -679,6 +668,15 @@ class Site(object):
679
668
  "encoding": "UTF-8",
680
669
  "formatter": "verbose",
681
670
  }
671
+ else:
672
+ try:
673
+ from systemd.journal import JournalHandler
674
+ handlers["file"] = {
675
+ "class": "systemd.journal.JournalHandler",
676
+ "SYSLOG_IDENTIFIER": str(self.project_name),
677
+ }
678
+ except ImportError:
679
+ pass
682
680
 
683
681
  # when a file handler exists, we have the loggers use it even if this
684
682
  # instance didn't create it:
@@ -689,9 +687,10 @@ class Site(object):
689
687
  # if name not in d['loggers']:
690
688
  d["loggers"][name] = loggercfg
691
689
 
692
- dblogger = d["loggers"].setdefault("django.db.backends", {})
693
- dblogger["level"] = os.environ.get("LINO_SQL_LOGLEVEL", "WARNING")
694
- dblogger["handlers"] = loggercfg["handlers"]
690
+ if sql_level != level:
691
+ dblogger = d["loggers"].setdefault("django.db.backends", {})
692
+ dblogger["level"] = sql_level
693
+ dblogger["handlers"] = loggercfg["handlers"]
695
694
 
696
695
  # # https://code.djangoproject.com/ticket/30554
697
696
  # logger = d['loggers'].setdefault('django.utils.autoreload', {})
@@ -702,34 +701,25 @@ class Site(object):
702
701
  # if item not in ['linod', 'root']:
703
702
  # d['loggers'][item]['propagate'] = True
704
703
 
705
- if ASYNC_LOGGING:
706
- config = d.copy()
707
-
708
- try:
709
- logging.config.dictConfig(config)
710
- # logging.config.dictConfig(d)
711
- finally:
712
- d.clear()
713
- d["logger_ok"] = True
714
- d["version"] = 1
715
- d["disable_existing_loggers"] = False
716
- else:
717
- d["logger_ok"] = True
704
+ # if ASYNC_LOGGING:
705
+ # config = d.copy()
706
+ #
707
+ # try:
708
+ # logging.config.dictConfig(config)
709
+ # # logging.config.dictConfig(d)
710
+ # finally:
711
+ # d.clear()
712
+ # # d["logger_ok"] = True
713
+ # d["version"] = 1
714
+ # d["disable_existing_loggers"] = False
715
+ # else:
716
+ # d["logger_ok"] = True
718
717
  # self.update_settings(LOGGING=d)
719
718
  # pprint(d)
720
719
  # print("20161126 Site %s " % d['loggers'].keys())
721
720
  # import yaml
722
721
  # print("20231019", yaml.dump(d))
723
722
 
724
- def get_database_settings(self):
725
- if self.site_dir is None:
726
- pass # raise Exception("20160516 No site_dir")
727
- else:
728
- dbname = self.site_dir / "default.db"
729
- return {
730
- "default": {"ENGINE": "django.db.backends.sqlite3", "NAME": str(dbname)}
731
- }
732
-
733
723
  def get_anonymous_user(self):
734
724
  # The code below works even when users is not installed
735
725
  from lino.modlib.users.choicelists import UserTypes
lino/core/utils.py CHANGED
@@ -37,6 +37,9 @@ get_models = apps.get_models
37
37
 
38
38
  validate_url = URLValidator()
39
39
 
40
+ DEVSERVER_COMMANDS = {
41
+ "runserver", "testserver", "test", "demotest", "makescreenshots", "shell"}
42
+
40
43
 
41
44
  def djangoname(o):
42
45
  return o.__module__.split(".")[-2] + "." + o.__name__
@@ -144,6 +147,8 @@ def is_devserver():
144
147
 
145
148
  """
146
149
  # ~ print 20130315, sys.argv[1]
150
+ if settings.DEBUG:
151
+ return True # doctest under pytest
147
152
  if sys.argv[0].startswith("-"):
148
153
  return True # doctest under pytest
149
154
  if len(sys.argv) <= 1:
@@ -153,9 +158,9 @@ def is_devserver():
153
158
  # if sys.argv[0].endswith("doctest.py") or sys.argv[0].endswith("doctest_utf8.py"):
154
159
  if sys.argv[0].endswith("doctest.py") or sys.argv[0].endswith("pytest"):
155
160
  return True
156
- if sys.argv[1] in ("runserver", "testserver", "test", "makescreenshots", "shell"):
161
+ if sys.argv[1] in DEVSERVER_COMMANDS:
157
162
  return True
158
- # print(sys.argv[1])
163
+ # print(sys.argv)
159
164
  return False
160
165
 
161
166
 
lino/help_texts.py CHANGED
@@ -182,8 +182,6 @@ help_texts = {
182
182
  'lino.utils.IncompleteDate' : _("""Naive representation of a potentially incomplete gregorian date."""),
183
183
  'lino.utils.IncompleteDate.parse' : _("""Parse the given string and return an IncompleteDate object."""),
184
184
  'lino.utils.IncompleteDate.get_age' : _("""Return age in years as integer."""),
185
- 'lino.utils.SumCollector' : _("""A dictionary of sums to be collected using an arbitrary key."""),
186
- 'lino.utils.SumCollector.collect' : _("""Add the given value to the sum at the given key k."""),
187
185
  'lino.utils.MissingRow' : _("""Represents a database row that is expected to exist but doesn’t."""),
188
186
  'lino.utils.addressable.Addressable' : _("""General mixin (not only for Django models) to encapsulate the generating of “traditional” (“snail”) mail addresses."""),
189
187
  'lino.utils.addressable.Addressable.address_person_lines' : _("""Yield one or more text lines, one for each line of the person part."""),
@@ -1,18 +1,18 @@
1
1
  # -*- coding: UTF-8 -*-
2
- # Copyright 2010-2020 Rumma & Ko Ltd
2
+ # Copyright 2010-2025 Rumma & Ko Ltd
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
  """
5
5
  This defines the :class:`Registable` model mixin.
6
6
  """
7
7
 
8
8
  from django.db import models
9
- from django.utils.translation import gettext_lazy as _
9
+ # from django.utils.translation import gettext_lazy as _
10
10
 
11
+ from lino import logger
11
12
  from lino.core import model
12
- from lino.core.actions import Action
13
+ # from lino.core.actions import Action
13
14
  from lino.core.workflows import ChangeStateAction
14
15
  from lino.core.exceptions import ChangedAPI
15
-
16
16
  from lino.core.workflows import State
17
17
 
18
18
 
@@ -180,6 +180,7 @@ class Registrable(model.Model):
180
180
  state_field = self.workflow_state_field
181
181
  target_state = state_field.choicelist.draft
182
182
  self.set_workflow_state(ar, state_field, target_state)
183
+ logger.warning("%s deregisters %s", ar.get_user(), self)
183
184
 
184
185
  # no longer needed after 20170826
185
186
  # @classmethod
@@ -21,6 +21,9 @@ from lino.api import dd, rt, _
21
21
  from .choicelists import Checker, Checkers
22
22
  from .roles import CheckdataUser
23
23
 
24
+ MAX_LENGTH = 250
25
+ MORE = " (...)"
26
+
24
27
 
25
28
  class CheckerAction(dd.Action):
26
29
  fix_them = False
@@ -150,7 +153,7 @@ class Message(Controllable, UserAuthored):
150
153
  checker = Checkers.field(verbose_name=_("Checker"))
151
154
  # severity = Severities.field()
152
155
  # feedback = Feedbacks.field(blank=True)
153
- message = models.CharField(_("Message text"), max_length=250)
156
+ message = models.CharField(_("Message text"), max_length=MAX_LENGTH)
154
157
  # fixable = models.BooleanField(_("Fixable"), default=False)
155
158
 
156
159
  update_problem = UpdateMessage()
@@ -166,6 +169,11 @@ class Message(Controllable, UserAuthored):
166
169
  def __str__(self):
167
170
  return self.message
168
171
 
172
+ def full_clean(self):
173
+ if len(self.message) > MAX_LENGTH:
174
+ self.message = self.message[:MAX_LENGTH - len(MORE)] + MORE
175
+ super().full_clean()
176
+
169
177
  @classmethod
170
178
  def get_simple_parameters(cls):
171
179
  for p in super(Message, cls).get_simple_parameters():
@@ -11,6 +11,7 @@ from django.conf import settings
11
11
  from django.utils.html import mark_safe, escape
12
12
 
13
13
  from lino.api import dd, _
14
+ from lino.utils.sums import myround
14
15
  from lino.utils.xml import validate_xml
15
16
  from lino.utils.media import MediaFile
16
17
 
@@ -51,6 +52,7 @@ class XMLMaker(dd.Model):
51
52
  context = self.get_printable_context(ar)
52
53
  context.update(xml_element=xml_element)
53
54
  context.update(base64=base64)
55
+ context.update(myround=myround)
54
56
  xml = tpl.render(**context)
55
57
  # parts = [
56
58
  # dd.plugins.accounting.xml_media_dir,
@@ -3,13 +3,11 @@
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
 
5
5
  # import time
6
- import os
7
6
  import asyncio
8
-
9
7
  from django.conf import settings
10
8
  from django.core.management import BaseCommand, call_command
11
- from lino.api import dd, rt
12
- from lino.modlib.linod.mixins import start_log_server, start_task_runner
9
+ from lino.api import dd
10
+ from lino.modlib.linod.mixins import start_task_runner
13
11
  from lino.core.requests import BaseRequest
14
12
 
15
13
  if dd.plugins.linod.use_channels:
@@ -33,19 +31,6 @@ class Command(BaseCommand):
33
31
  # default=False)
34
32
 
35
33
  def handle(self, *args, **options):
36
- log_sock_path = settings.SITE.log_sock_path
37
-
38
- if log_sock_path and log_sock_path.exists():
39
- if options.get("force"):
40
- log_sock_path.unlink()
41
- else:
42
- raise Exception(
43
- f"log socket already exists: {log_sock_path}\n"
44
- "It's probable that a worker process is already running. "
45
- "Try: 'ps awx | grep linod' OR 'sudo supervisorctl status | grep worker'\n"
46
- "Or the last instance of the worker process did not finish properly. "
47
- "In that case remove the file and run this command again."
48
- )
49
34
 
50
35
  if not dd.plugins.linod.use_channels:
51
36
  # print("20240424 Run Lino daemon without channels")
@@ -57,8 +42,8 @@ class Command(BaseCommand):
57
42
  except settings.SITE.user_model.DoesNotExist:
58
43
  u = None
59
44
  ar = BaseRequest(user=u)
60
- # ar = rt.login(dd.plugins.linod.daemon_user)
61
- await asyncio.gather(start_log_server(), start_task_runner(ar))
45
+ # await asyncio.gather(start_log_server(), start_task_runner(ar))
46
+ await start_task_runner(ar)
62
47
  # t1 = asyncio.create_task(settings.SITE.start_log_server())
63
48
  # t2 = asyncio.create_task(start_task_runner(ar))
64
49
  # await t1
@@ -84,7 +69,7 @@ class Command(BaseCommand):
84
69
  async def initiate_linod():
85
70
  layer = get_channel_layer()
86
71
  # if log_sock_path is not None:
87
- await layer.send(CHANNEL_NAME, {"type": "log.server"})
72
+ # await layer.send(CHANNEL_NAME, {"type": "log.server"})
88
73
  # await asyncio.sleep(1)
89
74
  await layer.send(CHANNEL_NAME, {"type": "run.background.tasks"})
90
75
 
@@ -291,42 +291,3 @@ async def start_task_runner(ar=None, max_count=None):
291
291
  continue
292
292
  await ar.adebug("Let task runner sleep for %s seconds.", to_sleep)
293
293
  await asyncio.sleep(to_sleep)
294
-
295
-
296
- class LogReceiver(asyncio.Protocol):
297
- # def connection_made(self, transport):
298
- # print("20231019 connection_made", transport)
299
-
300
- def data_received(self, data: bytes):
301
- data = pickle.loads(
302
- data[4:]
303
- ) # first four bytes gives the size of the rest of the data
304
- record = logging.makeLogRecord(data)
305
- # print("20231019 data_received", record)
306
- # 20231019 server_logger.handle(record)
307
- logger.handle(record)
308
-
309
-
310
- async def start_log_server():
311
- # 'log.server' in linod.py
312
- site = settings.SITE
313
- log_sock_path = site.log_sock_path
314
- if log_sock_path is None:
315
- logger.info(
316
- "No log server because there is no directory %s.", site.site_dir / "log"
317
- )
318
- return
319
- if log_sock_path.exists():
320
- raise Exception("Cannot start log server when socket file exists.")
321
- logger.info("Log server starts listening on %s", log_sock_path)
322
-
323
- def remove_sock_file():
324
- logger.info("Remove socket file %s", site.log_sock_path)
325
- site.log_sock_path.unlink(missing_ok=True)
326
-
327
- site.register_shutdown_task(remove_sock_file)
328
- loop = asyncio.get_running_loop()
329
- server = await loop.create_unix_server(LogReceiver, log_sock_path)
330
- # await server.serve_forever()
331
- async with server:
332
- await server.serve_forever()
@@ -1,67 +1,70 @@
1
1
  # -*- coding: UTF-8 -*-
2
- # Copyright 2022 Rumma & Ko Ltd
2
+ # Copyright 2022-2025 Rumma & Ko Ltd
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
 
5
- from django.urls import re_path
5
+ from django.conf import settings
6
6
  from django.core.asgi import get_asgi_application
7
- from django.utils.functional import LazyObject
8
7
 
9
- from channels.middleware import BaseMiddleware
10
- from channels.db import database_sync_to_async
11
- from channels.sessions import SessionMiddlewareStack
12
- from channels.routing import ProtocolTypeRouter, URLRouter, ChannelNameRouter
8
+ if settings.SITE.plugins.linod.use_channels:
13
9
 
14
- from lino.core.auth import get_user
15
- from lino.modlib.notify.consumers import ClientConsumer
10
+ from django.urls import re_path
11
+ from django.utils.functional import LazyObject
12
+ from channels.middleware import BaseMiddleware
13
+ from channels.db import database_sync_to_async
14
+ from channels.sessions import SessionMiddlewareStack
15
+ from channels.routing import ProtocolTypeRouter, URLRouter, ChannelNameRouter
16
16
 
17
- from .utils import CHANNEL_NAME
18
- from .consumers import LinodConsumer
17
+ from lino.core.auth import get_user
18
+ from lino.modlib.notify.consumers import ClientConsumer
19
19
 
20
+ from .utils import CHANNEL_NAME
21
+ from .consumers import LinodConsumer
20
22
 
21
- class UserLazyObject(LazyObject):
22
- """
23
- Throw a more useful error message when scope['user'] is accessed before it's resolved
24
- """
23
+ class UserLazyObject(LazyObject):
24
+ """
25
+ Throw a more useful error message when scope['user'] is accessed before it's resolved
26
+ """
25
27
 
26
- def _setup(self):
27
- raise ValueError("Accessing scope user before it is ready.")
28
+ def _setup(self):
29
+ raise ValueError("Accessing scope user before it is ready.")
28
30
 
31
+ async def _get_user(scope):
32
+ class Wrapper:
33
+ def __init__(self, session):
34
+ self.session = session
29
35
 
30
- async def _get_user(scope):
31
- class Wrapper:
32
- def __init__(self, session):
33
- self.session = session
36
+ r = Wrapper(scope["session"])
37
+ return await database_sync_to_async(get_user)(r)
34
38
 
35
- r = Wrapper(scope["session"])
36
- return await database_sync_to_async(get_user)(r)
39
+ class AuthMiddleware(BaseMiddleware):
40
+ def populate_scope(self, scope):
41
+ # Make sure we have a session
42
+ if "session" not in scope:
43
+ raise ValueError("AuthMiddleware cannot find session in scope.")
44
+ # Add it to the scope if it's not there already
45
+ if "user" not in scope:
46
+ scope["user"] = UserLazyObject()
37
47
 
48
+ async def resolve_scope(self, scope):
49
+ scope["user"]._wrapped = await _get_user(scope)
38
50
 
39
- class AuthMiddleware(BaseMiddleware):
40
- def populate_scope(self, scope):
41
- # Make sure we have a session
42
- if "session" not in scope:
43
- raise ValueError("AuthMiddleware cannot find session in scope.")
44
- # Add it to the scope if it's not there already
45
- if "user" not in scope:
46
- scope["user"] = UserLazyObject()
51
+ async def __call__(self, scope, receive=None, send=None):
52
+ self.populate_scope(scope)
53
+ await self.resolve_scope(scope)
54
+ return await self.inner(scope, receive, send)
47
55
 
48
- async def resolve_scope(self, scope):
49
- scope["user"]._wrapped = await _get_user(scope)
56
+ routes = [re_path(r"^WS/$", ClientConsumer.as_asgi())]
50
57
 
51
- async def __call__(self, scope, receive=None, send=None):
52
- self.populate_scope(scope)
53
- await self.resolve_scope(scope)
54
- return await self.inner(scope, receive, send)
58
+ protocol_mapping = dict(
59
+ websocket=SessionMiddlewareStack(AuthMiddleware(URLRouter(routes))),
60
+ channel=ChannelNameRouter({CHANNEL_NAME: LinodConsumer.as_asgi()}),
61
+ http=get_asgi_application(),
62
+ )
55
63
 
64
+ application = ProtocolTypeRouter(protocol_mapping)
56
65
 
57
- routes = [re_path(r"^WS/$", ClientConsumer.as_asgi())]
66
+ # raise Exception("20240424")
58
67
 
59
- protocol_mapping = dict(
60
- websocket=SessionMiddlewareStack(AuthMiddleware(URLRouter(routes))),
61
- channel=ChannelNameRouter({CHANNEL_NAME: LinodConsumer.as_asgi()}),
62
- http=get_asgi_application(),
63
- )
68
+ else:
64
69
 
65
- application = ProtocolTypeRouter(protocol_mapping)
66
-
67
- # raise Exception("20240424")
70
+ application = get_asgi_application()