1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """serializable translatable messages.
23 support for serializable translatable messages from component/manager to admin
24 """
25
26 import time
27
28 from twisted.spread import pb
29
30 from flumotion.common import log
31 from flumotion.configure import configure
32 from flumotion.common.i18n import FancyEqMixin, Translatable
33 from flumotion.common.i18n import *
34
35 __version__ = "$Rev: 7991 $"
36
37 (ERROR,
38 WARNING,
39 INFO) = range(1, 4)
40
41
42
43
44
45
46
47 -class Message(pb.Copyable, pb.RemoteCopy, FancyEqMixin):
48 """
49 I am a message to be shown in a UI.
50
51 Projects should subclass this base class to provide default project
52 and version class attributes.
53
54 @ivar section: name of the section in which the message is described.
55 @type section: str
56 @ivar anchor: name of the anchor in which the message is described.
57 @type anchor: str
58 @ivar description: the link text to show
59 @type description: L{flumotion.common.messages.Translatable}
60 """
61 project = configure.PACKAGE
62 version = configure.version
63
64
65 section = None
66 anchor = None
67 description = None
68
69 compareAttributes = ["level", "translatables", "debug", "mid", "priority",
70 "timestamp"]
71
72
73
74 - def __init__(self, level, translatable, debug=None, id=None, priority=50,
75 timestamp=None, mid=None):
76 """
77 Create a new message.
78
79 The id identifies this kind of message, and serves two purposes.
80
81 The first purpose is to serve as a key by which a kind of
82 message might be removed from a set of messages. For example, a
83 firewire component detecting that a cable has been plugged in
84 will remove any message that the cable is unplugged.
85
86 Secondly it serves so that the message viewers that watch the
87 'current state' of some object only see the latest message of a
88 given type. For example when messages are stored in persistent
89 state objects that can be transferred over the network, it
90 becomes inefficient to store the whole history of status
91 messages. Message stores can keep only the latest message of a
92 given ID.
93
94 @param level: ERROR, WARNING or INFO
95 @param translatable: a translatable possibly with markup for
96 linking to documentation or running commands.
97 @param debug: further, untranslated, debug information, not
98 always shown
99 @param priority: priority compared to other messages of the same
100 level
101 @param timestamp: time since epoch at which the message was
102 generated, in seconds.
103 @param mid: A unique id for this kind of message, as
104 discussed above. If not given, will be
105 generated from the contents of the
106 translatable.
107 """
108 self.level = level
109 self.translatables = []
110 self.debug = debug
111 if id:
112 import warnings
113 warnings.warn('Please use the mid kwarg instead',
114 DeprecationWarning, stacklevel=3)
115 mid = id
116
117
118 self.id = mid or translatable.untranslated()
119 self.priority = priority
120 self.timestamp = timestamp or time.time()
121
122
123 log.doLog(log.DEBUG, None, 'messages',
124 'creating message %r', self, where=-3)
125 log.doLog(log.DEBUG, None, 'messages',
126 'message debug %s', debug)
127 self.add(translatable)
128
130 return '<Message %r at %r>' % (self.id, id(self))
131
132 - def add(self, translatable):
133 if not isinstance(translatable, Translatable):
134 raise ValueError('%r is not Translatable' % translatable)
135 self.translatables.append(translatable)
136 log.doLog(log.DEBUG, None, 'messages',
137 'message %r: adding %r', (id(self), translatable.untranslated()),
138 where=-2)
139
141 """Get the timestamp for the message
142 @returns: the timestamp or None
143 @rtype: int
144 """
145
146 return getattr(self, 'timestamp', None)
147
149 """Get the description for the message
150 @returns: the description or None
151 @rtype: str
152 """
153 return getattr(self, 'description', None)
154
155 pb.setUnjellyableForClass(Message, Message)
156
157
158
159
160
161 -def Error(*args, **kwargs):
162 """
163 Create a L{Message} at ERROR level, indicating a failure that needs
164 intervention to be resolved.
165 """
166 return Message(ERROR, *args, **kwargs)
167
168
169
170 __pychecker__ = 'no-shadowbuiltin'
171
172
174 """
175 Create a L{Message} at WARNING level, indicating a potential problem.
176 """
177 return Message(WARNING, *args, **kwargs)
178 __pychecker__ = ''
179
180
181 -def Info(*args, **kwargs):
182 """
183 Create a L{Message} at INFO level.
184 """
185 return Message(INFO, *args, **kwargs)
186
187
188 -class Result(pb.Copyable, pb.RemoteCopy):
189 """
190 I am used in worker checks to return a result.
191
192 @ivar value: the result value of the check
193 @ivar failed: whether or not the check failed. Typically triggered
194 by adding an ERROR message to the result.
195 @ivar messages: list of messages
196 @type messages: list of L{Message}
197 """
198
200 self.messages = []
201 self.value = None
202 self.failed = False
203
205 """
206 Make the result be successful, setting the given result value.
207 """
208 self.value = value
209
210 - def add(self, message):
211 """
212 Add a message to the result.
213
214 @type message: L{Message}
215 """
216 self.messages.append(message)
217 if message.level == ERROR:
218 self.failed = True
219 self.value = None
220 pb.setUnjellyableForClass(Result, Result)
221
222
223
224
225
226
227
229 """
230 I represent a translatable gettext msg in the singular form.
231 """
232
233 compareAttributes = ["domain", "format", "args"]
234
235 - def __init__(self, domain, format, *args):
236 """
237 @param domain: the text domain for translations of this message
238 @param format: a format string
239 @param args: any arguments to the format string
240 """
241 self.domain = domain
242 self.format = format
243 self.args = args
244
246 if self.args:
247 result = self.format % self.args
248 else:
249 result = self.format
250 return result
251 pb.setUnjellyableForClass(TranslatableSingular, TranslatableSingular)
252
253
255 """
256 I represent a translatable gettext msg in the plural form.
257 """
258
259 compareAttributes = ["domain", "singular", "plural", "count", "args"]
260
261 - def __init__(self, domain, format, *args):
262 """
263 @param domain: the text domain for translations of this message
264 @param format: a (singular, plural, count) tuple
265 @param args: any arguments to the format string
266 """
267 singular, plural, count = format
268 self.domain = domain
269 self.singular = singular
270 self.plural = plural
271 self.count = count
272 self.args = args
273
275 if self.args:
276 result = self.singular % self.args
277 else:
278 result = self.singular
279 return result
280 pb.setUnjellyableForClass(TranslatablePlural, TranslatablePlural)
281