/ptah/view/formatter.py

https://github.com/mcdonc/ptah · Python · 207 lines · 153 code · 49 blank · 5 comment · 24 complexity · 530260a67b14e021602552c00904313a MD5 · raw file

  1. """ formatters """
  2. import pytz
  3. import colander
  4. import translationstring
  5. from datetime import date, datetime, timedelta
  6. from pyramid.i18n import get_localizer
  7. from pyramid.threadlocal import get_current_request
  8. from ptah import config
  9. _ = translationstring.TranslationStringFactory('ptah.view')
  10. class FormatImpl(dict):
  11. def __setitem__(self, name, formatter):
  12. if name in self:
  13. raise ValueError('Formatter "%s" arelady registered.'%name)
  14. super(FormatImpl, self).__setitem__(name, formatter)
  15. def __getattr__(self, name):
  16. try:
  17. return self[name]
  18. except KeyError:
  19. raise AttributeError(name)
  20. format = FormatImpl()
  21. _tzs = dict((str(tz).lower(), str(tz)) for tz in pytz.all_timezones)
  22. class Timezone(colander.SchemaType):
  23. """ timezone schema type """
  24. def serialize(self, node, appstruct):
  25. if appstruct is colander.null:
  26. return colander.null
  27. return str(appstruct)
  28. def deserialize(self, node, cstruct):
  29. if cstruct is colander.null or not cstruct:
  30. return colander.null
  31. try:
  32. v = str(cstruct)
  33. if v.startswith('GMT'):
  34. v = 'Etc/%s'%v
  35. try:
  36. return pytz.timezone(v)
  37. except:
  38. return pytz.timezone(_tzs[v.lower()])
  39. except Exception, e:
  40. raise colander.Invalid(
  41. node, _('"${val}" is not a timezone', mapping={'val':cstruct}))
  42. FORMAT = config.register_settings(
  43. 'format',
  44. config.SchemaNode(
  45. Timezone(),
  46. name = 'timezone',
  47. default = pytz.timezone('US/Central'),
  48. title = _('Timezone'),
  49. description = _('Site wide timezone.')),
  50. config.SchemaNode(
  51. colander.Str(),
  52. name = 'date_short',
  53. default = u'%m/%d/%y',
  54. title = _(u'Date'),
  55. description = _(u'Date short format')),
  56. config.SchemaNode(
  57. colander.Str(),
  58. name = 'date_medium',
  59. default = u'%b %d, %Y',
  60. title = _(u'Date'),
  61. description = _(u'Date medium format')),
  62. config.SchemaNode(
  63. colander.Str(),
  64. name = 'date_long',
  65. default = u'%B %d, %Y',
  66. title = _(u'Date'),
  67. description = _(u'Date long format')),
  68. config.SchemaNode(
  69. colander.Str(),
  70. name = 'date_full',
  71. default = u'%A, %B %d, %Y',
  72. title = _(u'Date'),
  73. description = _(u'Date full format')),
  74. config.SchemaNode(
  75. colander.Str(),
  76. name = 'time_short',
  77. default = u'%I:%M %p',
  78. title = _(u'Time'),
  79. description = _(u'Time short format')),
  80. config.SchemaNode(
  81. colander.Str(),
  82. name = 'time_medium',
  83. default = u'%I:%M %p',
  84. title = _(u'Time'),
  85. description = _(u'Time medium format')),
  86. config.SchemaNode(
  87. colander.Str(),
  88. name = 'time_long',
  89. default = u'%I:%M %p %z',
  90. title = _(u'Time'),
  91. description = _(u'Time long format')),
  92. config.SchemaNode(
  93. colander.Str(),
  94. name = 'time_full',
  95. default = u'%I:%M:%S %p %Z',
  96. title = _(u'Time'),
  97. description = _(u'Time full format')),
  98. title = 'Site formats',
  99. )
  100. def datetimeFormatter(value, tp='medium', request=None):
  101. """ datetime format """
  102. if not isinstance(value, datetime):
  103. return value
  104. tz = FORMAT.timezone
  105. if value.tzinfo is None:
  106. value = datetime(value.year, value.month, value.day, value.hour,
  107. value.minute, value.second, value.microsecond,
  108. pytz.utc)
  109. value = value.astimezone(tz)
  110. format = '%s %s'%(FORMAT['date_%s'%tp], FORMAT['time_%s'%tp])
  111. return unicode(value.strftime(str(format)))
  112. def timedeltaFormatter(value, type='short', request=None):
  113. """ timedelta formatter """
  114. if not isinstance(value, timedelta):
  115. return value
  116. if request is None:
  117. request = get_current_request()
  118. if type == 'full':
  119. hours = value.seconds/3600
  120. hs = hours*3600
  121. mins = (value.seconds - hs)/60
  122. ms = mins*60
  123. secs = value.seconds - hs - ms
  124. frm = []
  125. translate = get_localizer(request).translate
  126. if hours:
  127. frm.append(translate(
  128. '${hours} hour(s)', 'ptah.view', {'hours': hours}))
  129. if mins:
  130. frm.append(translate(
  131. '${mins} min(s)', 'ptah.view', {'mins': mins}))
  132. if secs:
  133. frm.append(translate(
  134. '${secs} sec(s)', 'ptah.view', {'secs': secs}))
  135. return ' '.join(frm)
  136. elif type == 'medium':
  137. return str(value)
  138. elif type == 'seconds':
  139. s = value.seconds + value.microseconds/1000000.0
  140. return '%2.4f'%s
  141. else:
  142. return str(value).split('.')[0]
  143. _size_types = {
  144. 'b': (1.0, 'B'),
  145. 'k': (1024.0, 'Kb'),
  146. 'm': (1048576.0, 'Mb'),
  147. }
  148. def sizeFormatter(value, type='k', request=None):
  149. """ size formatter """
  150. if not isinstance(value, (int, float)):
  151. return value
  152. f,t = _size_types.get(type, (1024.0, 'Kb'))
  153. if t == 'B':
  154. return '%.0f %s'%(value/f, t)
  155. return '%.2f %s'%(value/f, t)
  156. format['datetime'] = datetimeFormatter
  157. format['timedelta'] = timedeltaFormatter
  158. format['size'] = sizeFormatter