Package Camelot :: Package camelot :: Package types
[frames] | no frames]

Source Code for Package Camelot.camelot.types

  1  #  ============================================================================
 
  2  #
 
  3  #  Copyright (C) 2007-2008 Conceptive Engineering bvba. All rights reserved.
 
  4  #  www.conceptive.be / project-camelot@conceptive.be
 
  5  #
 
  6  #  This file is part of the Camelot Library.
 
  7  #
 
  8  #  This file may be used under the terms of the GNU General Public
 
  9  #  License version 2.0 as published by the Free Software Foundation
 
 10  #  and appearing in the file LICENSE.GPL included in the packaging of
 
 11  #  this file.  Please review the following information to ensure GNU
 
 12  #  General Public Licensing requirements will be met:
 
 13  #  http://www.trolltech.com/products/qt/opensource.html
 
 14  #
 
 15  #  If you are unsure which license is appropriate for your use, please
 
 16  #  review the following information:
 
 17  #  http://www.trolltech.com/products/qt/licensing.html or contact
 
 18  #  project-camelot@conceptive.be.
 
 19  #
 
 20  #  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
 21  #  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
 22  #
 
 23  #  For use of this library in commercial applications, please contact
 
 24  #  project-camelot@conceptive.be
 
 25  #
 
 26  #  ============================================================================
 
 27  
 
 28  """
 
 29  Camelot extends the SQLAlchemy field types with a number of its own field
 
 30  types. Those field types are automatically mapped to a specific delegate taking
 
 31  care of the visualisation.
 
 32  
 
 33  Those fields are stored in the :mod:`camelot.types` module.
 
 34  """ 
 35  
 
 36  import logging 
 37  logger = logging.getLogger('camelot.types') 
 38  
 
 39  from sqlalchemy import types 
 40  
 
 41  from camelot.core.files.storage import StoredFile, StoredImage, Storage 
 42  
 
43 -class VirtualAddress(types.TypeDecorator):
44 """A single field that can be used to enter phone numbers, fax numbers, email 45 addresses, im addresses. The editor provides soft validation of the data 46 entered. The address or number is stored as a string in the database. 47 48 This column type accepts and returns tuples of strings, the first string is 49 the :attr:`virtual_address_type`, and the second the address itself. 50 51 eg: ``('email','project-camelot@conceptive.be')`` is stored as 52 ``mail://project-camelot@conceptive.be`` 53 54 .. image:: ../_static/virtualaddress_editor.png 55 """ 56 57 impl = types.Unicode 58 virtual_address_types = ['phone', 'fax', 'mobile', 'email', 'im', 'pager',] 59
60 - def bind_processor(self, dialect):
61 62 impl_processor = self.impl.bind_processor(dialect) 63 if not impl_processor: 64 impl_processor = lambda x:x 65 66 def processor(value): 67 if value is not None: 68 if value[1]: 69 value = u'://'.join(value) 70 else: 71 value = None 72 return impl_processor(value)
73 74 return processor
75
76 - def result_processor(self, dialect):
77 78 impl_processor = self.impl.result_processor(dialect) 79 if not impl_processor: 80 impl_processor = lambda x:x 81 82 def processor(value): 83 84 if value: 85 split = value.split('://') 86 if len(split)>1: 87 return tuple(split) 88 return (u'phone',u'')
89 90 return processor 91 92
93 -class Code(types.TypeDecorator):
94 """SQLAlchemy column type to store codes. Where a code is a list of strings 95 on which a regular expression can be enforced. 96 97 This column type accepts and returns a list of strings and stores them as a 98 string joined with points. 99 100 eg: ``['08', 'AB']`` is stored as ``08.AB`` 101 102 .. image:: ../_static/editors/CodeEditor_editable.png 103 """ 104 105 impl = types.Unicode 106
107 - def __init__(self, parts, separator=u'.', **kwargs):
108 """ 109 :param parts: a list of input masks specifying the mask for each part, 110 eg ``['99', 'AA']``. For valid input masks, see 111 `QLineEdit <http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qlineedit.html>`_ 112 """ 113 import string 114 translator = string.maketrans('', '') 115 self.parts = parts 116 self.separator = separator 117 max_length = sum(len(part.translate(translator, '<>!')) for part in parts) + len(parts)*len(self.separator) 118 types.TypeDecorator.__init__(self, length=max_length, **kwargs)
119
120 - def bind_processor(self, dialect):
121 122 impl_processor = self.impl.bind_processor(dialect) 123 if not impl_processor: 124 impl_processor = lambda x:x 125 126 def processor(value): 127 if value is not None: 128 value = self.separator.join(value) 129 return impl_processor(value)
130 131 return processor
132
133 - def result_processor(self, dialect):
134 135 impl_processor = self.impl.result_processor(dialect) 136 if not impl_processor: 137 impl_processor = lambda x:x 138 139 def processor(value): 140 141 if value: 142 return value.split(self.separator) 143 return ['' for _p in self.parts]
144 145 return processor 146
147 -class IPAddress(Code):
148 - def __init__(self, **kwargs):
149 super(IPAddress, self).__init__(parts=['900','900','900','900'])
150
151 -class Rating(types.TypeDecorator):
152 """The rating field is an integer field that is visualized as a number of stars that 153 can be selected:: 154 155 class Movie(Entity): 156 title = Field(Unicode(60), required=True) 157 rating = Field(camelot.types.Rating()) 158 159 .. image:: ../_static/editors/StarEditor_editable.png 160 """ 161 162 impl = types.Integer
163
164 -class RichText(types.TypeDecorator):
165 """RichText fields are unlimited text fields which contain html. The html will be 166 rendered in a rich text editor. 167 168 .. image:: ../_static/editors/RichTextEditor_editable.png 169 """ 170 171 impl = types.UnicodeText
172
173 -class Language(types.TypeDecorator):
174 """The languages are stored as ISO codes in the database 175 """ 176 177 impl = types.Unicode 178 choices = [] 179 180 _localedata_list = [] 181 182 try: 183 import babel 184 _localedata_list = babel.localedata.list() 185 except Exception, e: 186 logger.warn(u'Could not load list with languages from babel, list will be empty', exc_info=e) 187 for code in _localedata_list: 188 locale = babel.Locale(code) 189 display_name = locale.get_display_name() 190 if display_name: 191 choices.append((code, u'%s (%s)'%(code, display_name))) 192 else: 193 choices.append((code, code)) 194
195 - def __init__(self):
196 types.TypeDecorator.__init__(self, length=20)
197
198 -class Color(types.TypeDecorator):
199 """The Color field returns and accepts tuples of the form (r,g,b,a) where 200 r,g,b,a are integers between 0 and 255. The color is stored as an hexadecimal 201 string of the form AARRGGBB into the database, where AA is the transparency, 202 RR is red, GG is green BB is blue:: 203 204 class MovieType(Entity): 205 color = Field(camelot.types.Color()) 206 207 .. image:: ../_static/editors/ColorEditor_editable.png 208 209 The colors are stored in the database as strings 210 """ 211 212 impl = types.Unicode 213
214 - def __init__(self):
215 types.TypeDecorator.__init__(self, length=8)
216
217 - def bind_processor(self, dialect):
218 219 impl_processor = self.impl.bind_processor(dialect) 220 if not impl_processor: 221 impl_processor = lambda x:x 222 223 def processor(value): 224 if value is not None: 225 assert len(value) == 4 226 for i in range(4): 227 assert value[i] >= 0 228 assert value[i] <= 255 229 return '%02X%02X%02X%02X'%(value[3], value[0], value[1], value[2]) 230 return impl_processor(value)
231 232 return processor
233
234 - def result_processor(self, dialect):
235 236 impl_processor = self.impl.result_processor(dialect) 237 if not impl_processor: 238 impl_processor = lambda x:x 239 240 def processor(value): 241 242 if value: 243 return (int(value[2:4],16), int(value[4:6],16), int(value[6:8],16), int(value[0:2],16))
244 245 return processor 246
247 -class Enumeration(types.TypeDecorator):
248 """The enumeration field stores integers in the database, but represents them as 249 strings. This allows efficient storage and querying while preserving readable code. 250 251 Typical use of this field would be a status field. 252 253 Enumeration fields are visualized as a combo box, where the labels in the combo 254 box are the capitalized strings:: 255 256 class Movie(Entity): 257 title = Field(Unicode(60), required=True) 258 state = Field(camelot.types.Enumeration([(1,'planned'), (2,'recording'), (3,'finished'), (4,'canceled')]), 259 index=True, required=True, default='planning') 260 261 .. image:: ../_static/editors/ChoicesEditor_editable.png 262 """ 263 264 impl = types.Integer 265
266 - def __init__(self, choices=[], **kwargs):
267 """ 268 @param param: choices is a list of tuples. each tuple contains an integer and its 269 associated string. eg. : choices = [(1,'draft'), (2,'approved')] 270 """ 271 types.TypeDecorator.__init__(self, **kwargs) 272 self._int_to_string = dict(choices) 273 self._string_to_int = dict((v,k) for (k,v) in choices) 274 self.choices = [v for (k,v) in choices]
275
276 - def bind_processor(self, dialect):
277 278 impl_processor = self.impl.bind_processor(dialect) 279 if not impl_processor: 280 impl_processor = lambda x:x 281 282 def processor(value): 283 if value is not None: 284 try: 285 value = self._string_to_int[value] 286 return impl_processor(value) 287 except KeyError, e: 288 logger.error('could not process enumeration value %s, possible values are %s'%(value, u', '.join(list(self._string_to_int.keys()))), exc_info=e)
289 290 return processor
291
292 - def result_processor(self, dialect):
293 294 impl_processor = self.impl.result_processor(dialect) 295 if not impl_processor: 296 impl_processor = lambda x:x 297 298 def processor(value): 299 if value is not None: 300 value = impl_processor(value) 301 try: 302 return self._int_to_string[value] 303 except KeyError, e: 304 logger.error('could not process %s'%value, exc_info=e)
305 306 return processor 307
308 -class File(types.TypeDecorator):
309 """Sqlalchemy column type to store files. Only the location of the file is stored 310 311 This column type accepts and returns a StoredFile, and stores them in the directory 312 specified by settings.MEDIA_ROOT. The name of the file is stored as a string in 313 the database. A subdirectory upload_to can be specified:: 314 315 class Movie(Entity): 316 script = Field(camelot.types.File(upload_to='script')) 317 318 .. image:: ../_static/editors/FileEditor_editable.png 319 """ 320 321 impl = types.Unicode 322 stored_file_implementation = StoredFile 323
324 - def __init__(self, max_length=100, upload_to='', storage=Storage, **kwargs):
325 self.max_length = max_length 326 self.storage = storage(upload_to, self.stored_file_implementation) 327 types.TypeDecorator.__init__(self, length=max_length, **kwargs)
328
329 - def bind_processor(self, dialect):
330 331 impl_processor = self.impl.bind_processor(dialect) 332 if not impl_processor: 333 impl_processor = lambda x:x 334 335 def processor(value): 336 if value is not None: 337 assert isinstance(value, (self.stored_file_implementation)) 338 return impl_processor(value.name) 339 return impl_processor(value)
340 341 return processor
342
343 - def result_processor(self, dialect):
344 345 impl_processor = self.impl.result_processor(dialect) 346 if not impl_processor: 347 impl_processor = lambda x:x 348 349 def processor(value): 350 351 if value: 352 value = impl_processor(value) 353 return self.stored_file_implementation(self.storage, value)
354 355 return processor 356
357 -class Image(File):
358 """Sqlalchemy column type to store images 359 360 This column type accepts and returns a StoredImage, and stores them in the directory 361 specified by settings.MEDIA_ROOT. The name of the file is stored as a string in 362 the database. 363 364 The Image field type provides the same functionallity as the File field type, but 365 the files stored should be images. 366 367 .. image:: ../_static/editors/ImageEditor_editable.png 368 """ 369 370 stored_file_implementation = StoredImage
371