Package flumotion :: Package common :: Module messages
[hide private]

Source Code for Module flumotion.common.messages

  1  # -*- Mode: Python; test-case-name: flumotion.test.test_common_messages -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3  # 
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007 Fluendo, S.L. (www.fluendo.com). 
  6  # All rights reserved. 
  7   
  8  # This file may be distributed and/or modified under the terms of 
  9  # the GNU General Public License version 2 as published by 
 10  # the Free Software Foundation. 
 11  # This file is distributed without any warranty; without even the implied 
 12  # warranty of merchantability or fitness for a particular purpose. 
 13  # See "LICENSE.GPL" in the source distribution for more information. 
 14   
 15  # Licensees having purchased or holding a valid Flumotion Advanced 
 16  # Streaming Server license may use this file in accordance with the 
 17  # Flumotion Advanced Streaming Server Commercial License Agreement. 
 18  # See "LICENSE.Flumotion" in the source distribution for more information. 
 19   
 20  # Headers in this file shall remain intact. 
 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  # NOTE: same caveats apply for FancyEqMixin as above 
 43  # this might be a little heavy; we could consider only comparing 
 44  # on id, once we verify that all id's are unique 
 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 # these properties allow linking to the documentation 65 section = None 66 anchor = None 67 description = None 68 69 compareAttributes = ["level", "translatables", "debug", "mid", "priority", 70 "timestamp"] 71 72 # F0.8: remove id= in favor of mid= 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 # FIXME: untranslated is a really poor choice of id 118 self.id = mid or translatable.untranslated() 119 self.priority = priority 120 self.timestamp = timestamp or time.time() 121 # -1 is in __init__, -2 is in the subclass __init__, 122 # -3 is in the caller 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
129 - def __repr__(self):
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
140 - def getTimeStamp(self):
141 """Get the timestamp for the message 142 @returns: the timestamp or None 143 @rtype: int 144 """ 145 # F0.4: timestamp was added in 0.4.2 146 return getattr(self, 'timestamp', None)
147
148 - def getDescription(self):
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 # these are implemented as factory functions instead of classes because 158 # properly proxying to the correct subclass is hard with Copyable/RemoteCopy 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 # FIXME: figure out a way to not be shadowing the Warning builtin without 169 # breaking all other code 170 __pychecker__ = 'no-shadowbuiltin' 171 172
173 -def Warning(*args, **kwargs):
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
199 - def __init__(self):
200 self.messages = [] 201 self.value = None 202 self.failed = False
203
204 - def succeed(self, value):
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 # F0.8: remove; only here to be able to receive platform-3 translatables 224 # in trunk code, because they need to be in exactly the same module 225 # this is a straight copy from flumotion.common.i18n for these two classes 226 227
228 -class TranslatableSingular(Translatable, FancyEqMixin):
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
245 - def untranslated(self):
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
254 -class TranslatablePlural(Translatable, FancyEqMixin):
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
274 - def untranslated(self):
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