No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

datas_base.py 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #
  2. # This file is part of Lodel 2 (https://github.com/OpenEdition)
  3. #
  4. # Copyright (C) 2015-2017 Cléo UMS-3287
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU Affero General Public License as published
  8. # by the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU Affero General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU Affero General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. #-*- coding: utf-8 -*-
  20. import warnings
  21. import datetime
  22. import time
  23. import os
  24. from lodel.context import LodelContext
  25. LodelContext.expose_modules(globals(), {
  26. 'lodel.leapi.datahandlers.base_classes': ['DataField'],
  27. 'lodel.exceptions': ['LodelException', 'LodelExceptions',
  28. 'LodelFatalError', 'DataNoneValid', 'FieldValidationError']})
  29. ##
  30. ## @brief Data field designed to handle boolean values
  31. class Boolean(DataField):
  32. help = 'A basic boolean field'
  33. base_type = 'bool'
  34. ## @brief A boolean field
  35. def __init__(self, **kwargs):
  36. ##
  37. # @remarks Commented out code left in the code base. Consider deletion.
  38. #if 'check_data_value' not in kwargs:
  39. # kwargs['check_data_value'] = self._check_data_value
  40. super().__init__(ftype='bool', **kwargs)
  41. ##
  42. # @brief Checks value.
  43. #
  44. # @param value mixed:
  45. # @throw FieldValidationError: if value is not valid
  46. # @return value
  47. def _check_data_value(self, value):
  48. value = super()._check_data_value(value)
  49. if not isinstance(value, bool):
  50. raise FieldValidationError("The value '%s' is not, and will never, be a boolean" % value)
  51. return value
  52. ##
  53. # @brief Data field designed to handle integer values.
  54. class Integer(DataField):
  55. help = 'Basic integer field'
  56. base_type = 'int'
  57. cast_type = int
  58. def __init__(self, **kwargs):
  59. super().__init__(**kwargs)
  60. ##
  61. # @brief Checks and casts value in appropriate type
  62. #
  63. # @param value *:
  64. # @param strict bool: Whether the value type should be treated strictly or cast.
  65. # @throw FieldValidationError: if value is inappropriate or can not be cast
  66. # @return value
  67. def _check_data_value(self, value, strict=False):
  68. value = super()._check_data_value(value)
  69. if (strict and not isinstance(value, int)):
  70. raise FieldValidationError("The value '%s' is not a python type integer" % value)
  71. try:
  72. if strict:
  73. value = int(value)
  74. else:
  75. value = int(float(value))
  76. except(ValueError, TypeError):
  77. raise FieldValidationError("The value '%s' is not an integer nor could be cast to." % value)
  78. return value
  79. ##
  80. # @brief Data field designed to handle string
  81. class Varchar(DataField):
  82. help = 'Basic string (varchar) field. Default size is 64 characters'
  83. base_type = 'char'
  84. ##
  85. # @brief A string field
  86. #
  87. # @brief max_length int: The maximum length of this field
  88. def __init__(self, max_length=64, **kwargs):
  89. self.max_length = int(max_length)
  90. super().__init__(**kwargs)
  91. ##
  92. # @brief checks if this class can override the given data handler
  93. #
  94. # @param data_handler DataHandler
  95. # @return bool
  96. def can_override(self, data_handler):
  97. if not super().can_override(data_handler):
  98. return False
  99. if data_handler.max_length != self.max_length:
  100. return False
  101. return True
  102. ##
  103. # @brief Check and cast value in appropriate type
  104. #
  105. # @param value *:
  106. # @throw FieldValidationError if value is inappropriate or can not be cast
  107. # @return value
  108. def _check_data_value(self, value):
  109. value = super()._check_data_value(value)
  110. if not isinstance(value, str):
  111. raise FieldValidationError("The value '%s' can't be a str" % value)
  112. if len(value) > self.max_length:
  113. raise FieldValidationError("The value '%s' is longer than the maximum length of this field (%s)" % (value, self.max_length))
  114. return value
  115. ##
  116. # @brief Data field designed to handle date & time
  117. class DateTime(DataField):
  118. help = 'A datetime field. Take two boolean options now_on_update and now_on_create'
  119. base_type = 'datetime'
  120. ##
  121. # @brief A datetime field
  122. #
  123. # @param now_on_update bool : If true, the date is set to NOW on update
  124. # @param now_on_create bool : If true, the date is set to NEW on creation
  125. # @param **kwargs
  126. #
  127. # @remarks Is it intended that DateTime objects can not be instantiated with
  128. # a provided arbitrary string value or something else?
  129. def __init__(self, now_on_update=False, now_on_create=False, **kwargs):
  130. self.now_on_update = now_on_update
  131. self.now_on_create = now_on_create
  132. self.datetime_format = '%Y-%m-%d' if 'format' not in kwargs else kwargs['format']
  133. super().__init__(**kwargs)
  134. ##
  135. # @brief Check and cast value in appropriate type
  136. #
  137. # @param value mixed:
  138. # @throw FieldValidationError: if value is inappropriate or can not be cast
  139. # @return value
  140. def _check_data_value(self, value):
  141. value = super()._check_data_value(value)
  142. if isinstance(value, str):
  143. try:
  144. value = datetime.datetime.fromtimestamp(time.mktime(time.strptime(value, self.datetime_format)))
  145. except ValueError:
  146. raise FieldValidationError("The value '%s' cannot be converted as a datetime" % value)
  147. if not isinstance(value, datetime.datetime):
  148. raise FieldValidationError("Tue value has to be a string or a datetime")
  149. return value
  150. def _construct_data(self, emcomponent, fname, datas, cur_value):
  151. if (self.now_on_create and cur_value is None) or self.now_on_update:
  152. return datetime.datetime.now()
  153. return cur_value
  154. ##
  155. # @brief Data field designed to handle long string
  156. class Text(DataField):
  157. help = 'A text field (big string)'
  158. base_type = 'text'
  159. def __init__(self, **kwargs):
  160. super(self.__class__, self).__init__(ftype='text', **kwargs)
  161. ##
  162. # @brief Check and cast value in appropriate type
  163. #
  164. # @param value *
  165. # @throw FieldValidationError if value is unappropriate or can not be cast
  166. # @return value
  167. def _check_data_value(self, value):
  168. value = super()._check_data_value(value)
  169. if not isinstance(value, str):
  170. raise FieldValidationError("The content passed to this Text field is not a convertible to a string")
  171. return value
  172. ##
  173. # @brief Data field designed to handle Files
  174. class File(DataField):
  175. base_type = 'file'
  176. ##
  177. # @brief a file field
  178. #
  179. # @param upload_path str : None by default
  180. # @param **kwargs
  181. def __init__(self, upload_path=None, **kwargs):
  182. self.upload_path = upload_path
  183. super().__init__(**kwargs)
  184. ##
  185. # @todo Add a check for the validity of the given value (should have a correct path syntax)
  186. def _check_data_value(self, value):
  187. return super()._check_data_value(value)