/DjamboServerWithProcessing/django/django/utils/formats.py

https://gitlab.com/benji-bou/urotechchallenge-Serenity
Python | 258 lines | 213 code | 19 blank | 26 comment | 35 complexity | af4d927870a04306430f031980634cba MD5 | raw file
  1. import datetime
  2. import decimal
  3. import unicodedata
  4. from importlib import import_module
  5. from django.conf import settings
  6. from django.utils import dateformat, datetime_safe, numberformat, six
  7. from django.utils.encoding import force_str
  8. from django.utils.functional import lazy
  9. from django.utils.safestring import mark_safe
  10. from django.utils.translation import (
  11. check_for_language, get_language, to_locale,
  12. )
  13. # format_cache is a mapping from (format_type, lang) to the format string.
  14. # By using the cache, it is possible to avoid running get_format_modules
  15. # repeatedly.
  16. _format_cache = {}
  17. _format_modules_cache = {}
  18. ISO_INPUT_FORMATS = {
  19. 'DATE_INPUT_FORMATS': ['%Y-%m-%d'],
  20. 'TIME_INPUT_FORMATS': ['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'],
  21. 'DATETIME_INPUT_FORMATS': [
  22. '%Y-%m-%d %H:%M:%S',
  23. '%Y-%m-%d %H:%M:%S.%f',
  24. '%Y-%m-%d %H:%M',
  25. '%Y-%m-%d'
  26. ],
  27. }
  28. FORMAT_SETTINGS = frozenset([
  29. 'DECIMAL_SEPARATOR',
  30. 'THOUSAND_SEPARATOR',
  31. 'NUMBER_GROUPING',
  32. 'FIRST_DAY_OF_WEEK',
  33. 'MONTH_DAY_FORMAT',
  34. 'TIME_FORMAT',
  35. 'DATE_FORMAT',
  36. 'DATETIME_FORMAT',
  37. 'SHORT_DATE_FORMAT',
  38. 'SHORT_DATETIME_FORMAT',
  39. 'YEAR_MONTH_FORMAT',
  40. 'DATE_INPUT_FORMATS',
  41. 'TIME_INPUT_FORMATS',
  42. 'DATETIME_INPUT_FORMATS',
  43. ])
  44. def reset_format_cache():
  45. """Clear any cached formats.
  46. This method is provided primarily for testing purposes,
  47. so that the effects of cached formats can be removed.
  48. """
  49. global _format_cache, _format_modules_cache
  50. _format_cache = {}
  51. _format_modules_cache = {}
  52. def iter_format_modules(lang, format_module_path=None):
  53. """
  54. Does the heavy lifting of finding format modules.
  55. """
  56. if not check_for_language(lang):
  57. return
  58. if format_module_path is None:
  59. format_module_path = settings.FORMAT_MODULE_PATH
  60. format_locations = []
  61. if format_module_path:
  62. if isinstance(format_module_path, six.string_types):
  63. format_module_path = [format_module_path]
  64. for path in format_module_path:
  65. format_locations.append(path + '.%s')
  66. format_locations.append('django.conf.locale.%s')
  67. locale = to_locale(lang)
  68. locales = [locale]
  69. if '_' in locale:
  70. locales.append(locale.split('_')[0])
  71. for location in format_locations:
  72. for loc in locales:
  73. try:
  74. yield import_module('%s.formats' % (location % loc))
  75. except ImportError:
  76. pass
  77. def get_format_modules(lang=None, reverse=False):
  78. """
  79. Returns a list of the format modules found
  80. """
  81. if lang is None:
  82. lang = get_language()
  83. if lang not in _format_modules_cache:
  84. _format_modules_cache[lang] = list(iter_format_modules(lang, settings.FORMAT_MODULE_PATH))
  85. modules = _format_modules_cache[lang]
  86. if reverse:
  87. return list(reversed(modules))
  88. return modules
  89. def get_format(format_type, lang=None, use_l10n=None):
  90. """
  91. For a specific format type, returns the format for the current
  92. language (locale), defaults to the format in the settings.
  93. format_type is the name of the format, e.g. 'DATE_FORMAT'
  94. If use_l10n is provided and is not None, that will force the value to
  95. be localized (or not), overriding the value of settings.USE_L10N.
  96. """
  97. format_type = force_str(format_type)
  98. if use_l10n or (use_l10n is None and settings.USE_L10N):
  99. if lang is None:
  100. lang = get_language()
  101. cache_key = (format_type, lang)
  102. try:
  103. cached = _format_cache[cache_key]
  104. if cached is not None:
  105. return cached
  106. except KeyError:
  107. for module in get_format_modules(lang):
  108. try:
  109. val = getattr(module, format_type)
  110. for iso_input in ISO_INPUT_FORMATS.get(format_type, ()):
  111. if iso_input not in val:
  112. if isinstance(val, tuple):
  113. val = list(val)
  114. val.append(iso_input)
  115. _format_cache[cache_key] = val
  116. return val
  117. except AttributeError:
  118. pass
  119. _format_cache[cache_key] = None
  120. if format_type not in FORMAT_SETTINGS:
  121. return format_type
  122. # Return the general setting by default
  123. return getattr(settings, format_type)
  124. get_format_lazy = lazy(get_format, six.text_type, list, tuple)
  125. def date_format(value, format=None, use_l10n=None):
  126. """
  127. Formats a datetime.date or datetime.datetime object using a
  128. localizable format
  129. If use_l10n is provided and is not None, that will force the value to
  130. be localized (or not), overriding the value of settings.USE_L10N.
  131. """
  132. return dateformat.format(value, get_format(format or 'DATE_FORMAT', use_l10n=use_l10n))
  133. def time_format(value, format=None, use_l10n=None):
  134. """
  135. Formats a datetime.time object using a localizable format
  136. If use_l10n is provided and is not None, that will force the value to
  137. be localized (or not), overriding the value of settings.USE_L10N.
  138. """
  139. return dateformat.time_format(value, get_format(format or 'TIME_FORMAT', use_l10n=use_l10n))
  140. def number_format(value, decimal_pos=None, use_l10n=None, force_grouping=False):
  141. """
  142. Formats a numeric value using localization settings
  143. If use_l10n is provided and is not None, that will force the value to
  144. be localized (or not), overriding the value of settings.USE_L10N.
  145. """
  146. if use_l10n or (use_l10n is None and settings.USE_L10N):
  147. lang = get_language()
  148. else:
  149. lang = None
  150. return numberformat.format(
  151. value,
  152. get_format('DECIMAL_SEPARATOR', lang, use_l10n=use_l10n),
  153. decimal_pos,
  154. get_format('NUMBER_GROUPING', lang, use_l10n=use_l10n),
  155. get_format('THOUSAND_SEPARATOR', lang, use_l10n=use_l10n),
  156. force_grouping=force_grouping
  157. )
  158. def localize(value, use_l10n=None):
  159. """
  160. Checks if value is a localizable type (date, number...) and returns it
  161. formatted as a string using current locale format.
  162. If use_l10n is provided and is not None, that will force the value to
  163. be localized (or not), overriding the value of settings.USE_L10N.
  164. """
  165. if isinstance(value, six.string_types): # Handle strings first for performance reasons.
  166. return value
  167. elif isinstance(value, bool): # Make sure booleans don't get treated as numbers
  168. return mark_safe(six.text_type(value))
  169. elif isinstance(value, (decimal.Decimal, float) + six.integer_types):
  170. return number_format(value, use_l10n=use_l10n)
  171. elif isinstance(value, datetime.datetime):
  172. return date_format(value, 'DATETIME_FORMAT', use_l10n=use_l10n)
  173. elif isinstance(value, datetime.date):
  174. return date_format(value, use_l10n=use_l10n)
  175. elif isinstance(value, datetime.time):
  176. return time_format(value, 'TIME_FORMAT', use_l10n=use_l10n)
  177. return value
  178. def localize_input(value, default=None):
  179. """
  180. Checks if an input value is a localizable type and returns it
  181. formatted with the appropriate formatting string of the current locale.
  182. """
  183. if isinstance(value, six.string_types): # Handle strings first for performance reasons.
  184. return value
  185. elif isinstance(value, bool): # Don't treat booleans as numbers.
  186. return six.text_type(value)
  187. elif isinstance(value, (decimal.Decimal, float) + six.integer_types):
  188. return number_format(value)
  189. elif isinstance(value, datetime.datetime):
  190. value = datetime_safe.new_datetime(value)
  191. format = force_str(default or get_format('DATETIME_INPUT_FORMATS')[0])
  192. return value.strftime(format)
  193. elif isinstance(value, datetime.date):
  194. value = datetime_safe.new_date(value)
  195. format = force_str(default or get_format('DATE_INPUT_FORMATS')[0])
  196. return value.strftime(format)
  197. elif isinstance(value, datetime.time):
  198. format = force_str(default or get_format('TIME_INPUT_FORMATS')[0])
  199. return value.strftime(format)
  200. return value
  201. def sanitize_separators(value):
  202. """
  203. Sanitizes a value according to the current decimal and
  204. thousand separator setting. Used with form field input.
  205. """
  206. if settings.USE_L10N and isinstance(value, six.string_types):
  207. parts = []
  208. decimal_separator = get_format('DECIMAL_SEPARATOR')
  209. if decimal_separator in value:
  210. value, decimals = value.split(decimal_separator, 1)
  211. parts.append(decimals)
  212. if settings.USE_THOUSAND_SEPARATOR:
  213. thousand_sep = get_format('THOUSAND_SEPARATOR')
  214. if thousand_sep == '.' and value.count('.') == 1 and len(value.split('.')[-1]) != 3:
  215. # Special case where we suspect a dot meant decimal separator (see #22171)
  216. pass
  217. else:
  218. for replacement in {
  219. thousand_sep, unicodedata.normalize('NFKD', thousand_sep)}:
  220. value = value.replace(replacement, '')
  221. parts.append(value)
  222. value = '.'.join(reversed(parts))
  223. return value