Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/contrib/messages/storage/base.py: 41%
78 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1from django.conf import settings
2from django.contrib.messages import constants, utils
4LEVEL_TAGS = utils.get_level_tags()
7class Message:
8 """
9 Represent an actual message that can be stored in any of the supported
10 storage classes (typically session- or cookie-based) and rendered in a view
11 or template.
12 """
14 def __init__(self, level, message, extra_tags=None):
15 self.level = int(level)
16 self.message = message
17 self.extra_tags = extra_tags
19 def _prepare(self):
20 """
21 Prepare the message for serialization by forcing the ``message``
22 and ``extra_tags`` to str in case they are lazy translations.
23 """
24 self.message = str(self.message)
25 self.extra_tags = str(self.extra_tags) if self.extra_tags is not None else None
27 def __eq__(self, other):
28 if not isinstance(other, Message):
29 return NotImplemented
30 return self.level == other.level and self.message == other.message
32 def __str__(self):
33 return str(self.message)
35 @property
36 def tags(self):
37 return " ".join(tag for tag in [self.extra_tags, self.level_tag] if tag)
39 @property
40 def level_tag(self):
41 return LEVEL_TAGS.get(self.level, "")
44class BaseStorage:
45 """
46 This is the base backend for temporary message storage.
48 This is not a complete class; to be a usable storage backend, it must be
49 subclassed and the two methods ``_get`` and ``_store`` overridden.
50 """
52 def __init__(self, request, *args, **kwargs):
53 self.request = request
54 self._queued_messages = []
55 self.used = False
56 self.added_new = False
57 super().__init__(*args, **kwargs)
59 def __len__(self):
60 return len(self._loaded_messages) + len(self._queued_messages)
62 def __iter__(self):
63 self.used = True
64 if self._queued_messages:
65 self._loaded_messages.extend(self._queued_messages)
66 self._queued_messages = []
67 return iter(self._loaded_messages)
69 def __contains__(self, item):
70 return item in self._loaded_messages or item in self._queued_messages
72 def __repr__(self):
73 return f"<{self.__class__.__qualname__}: request={self.request!r}>"
75 @property
76 def _loaded_messages(self):
77 """
78 Return a list of loaded messages, retrieving them first if they have
79 not been loaded yet.
80 """
81 if not hasattr(self, "_loaded_data"):
82 messages, all_retrieved = self._get()
83 self._loaded_data = messages or []
84 return self._loaded_data
86 def _get(self, *args, **kwargs):
87 """
88 Retrieve a list of stored messages. Return a tuple of the messages
89 and a flag indicating whether or not all the messages originally
90 intended to be stored in this storage were, in fact, stored and
91 retrieved; e.g., ``(messages, all_retrieved)``.
93 **This method must be implemented by a subclass.**
95 If it is possible to tell if the backend was not used (as opposed to
96 just containing no messages) then ``None`` should be returned in
97 place of ``messages``.
98 """
99 raise NotImplementedError(
100 "subclasses of BaseStorage must provide a _get() method"
101 )
103 def _store(self, messages, response, *args, **kwargs):
104 """
105 Store a list of messages and return a list of any messages which could
106 not be stored.
108 One type of object must be able to be stored, ``Message``.
110 **This method must be implemented by a subclass.**
111 """
112 raise NotImplementedError(
113 "subclasses of BaseStorage must provide a _store() method"
114 )
116 def _prepare_messages(self, messages):
117 """
118 Prepare a list of messages for storage.
119 """
120 for message in messages: 120 ↛ 121line 120 didn't jump to line 121, because the loop on line 120 never started
121 message._prepare()
123 def update(self, response):
124 """
125 Store all unread messages.
127 If the backend has yet to be iterated, store previously stored messages
128 again. Otherwise, only store messages added after the last iteration.
129 """
130 self._prepare_messages(self._queued_messages)
131 if self.used: 131 ↛ 132line 131 didn't jump to line 132, because the condition on line 131 was never true
132 return self._store(self._queued_messages, response)
133 elif self.added_new: 133 ↛ 134line 133 didn't jump to line 134, because the condition on line 133 was never true
134 messages = self._loaded_messages + self._queued_messages
135 return self._store(messages, response)
137 def add(self, level, message, extra_tags=""):
138 """
139 Queue a message to be stored.
141 The message is only queued if it contained something and its level is
142 not less than the recording level (``self.level``).
143 """
144 if not message:
145 return
146 # Check that the message level is not less than the recording level.
147 level = int(level)
148 if level < self.level:
149 return
150 # Add the message.
151 self.added_new = True
152 message = Message(level, message, extra_tags=extra_tags)
153 self._queued_messages.append(message)
155 def _get_level(self):
156 """
157 Return the minimum recorded level.
159 The default level is the ``MESSAGE_LEVEL`` setting. If this is
160 not found, the ``INFO`` level is used.
161 """
162 if not hasattr(self, "_level"):
163 self._level = getattr(settings, "MESSAGE_LEVEL", constants.INFO)
164 return self._level
166 def _set_level(self, value=None):
167 """
168 Set a custom minimum recorded level.
170 If set to ``None``, the default level will be used (see the
171 ``_get_level`` method).
172 """
173 if value is None and hasattr(self, "_level"):
174 del self._level
175 else:
176 self._level = int(value)
178 level = property(_get_level, _set_level, _set_level)