Buckets:
| import datetime | |
| import decimal | |
| import functools | |
| import re | |
| import unicodedata | |
| from importlib import import_module | |
| from django.conf import settings | |
| from django.utils import dateformat, numberformat | |
| from django.utils.functional import lazy | |
| from django.utils.translation import check_for_language, get_language, to_locale | |
| # format_cache is a mapping from (format_type, lang) to the format string. | |
| # By using the cache, it is possible to avoid running get_format_modules | |
| # repeatedly. | |
| _format_cache = {} | |
| _format_modules_cache = {} | |
| ISO_INPUT_FORMATS = { | |
| "DATE_INPUT_FORMATS": ["%Y-%m-%d"], | |
| "TIME_INPUT_FORMATS": ["%H:%M:%S", "%H:%M:%S.%f", "%H:%M"], | |
| "DATETIME_INPUT_FORMATS": [ | |
| "%Y-%m-%d %H:%M:%S", | |
| "%Y-%m-%d %H:%M:%S.%f", | |
| "%Y-%m-%d %H:%M", | |
| "%Y-%m-%d", | |
| ], | |
| } | |
| FORMAT_SETTINGS = frozenset( | |
| [ | |
| "DECIMAL_SEPARATOR", | |
| "THOUSAND_SEPARATOR", | |
| "NUMBER_GROUPING", | |
| "FIRST_DAY_OF_WEEK", | |
| "MONTH_DAY_FORMAT", | |
| "TIME_FORMAT", | |
| "DATE_FORMAT", | |
| "DATETIME_FORMAT", | |
| "SHORT_DATE_FORMAT", | |
| "SHORT_DATETIME_FORMAT", | |
| "YEAR_MONTH_FORMAT", | |
| "DATE_INPUT_FORMATS", | |
| "TIME_INPUT_FORMATS", | |
| "DATETIME_INPUT_FORMATS", | |
| ] | |
| ) | |
| def reset_format_cache(): | |
| """Clear any cached formats. | |
| This method is provided primarily for testing purposes, | |
| so that the effects of cached formats can be removed. | |
| """ | |
| global _format_cache, _format_modules_cache | |
| _format_cache = {} | |
| _format_modules_cache = {} | |
| def iter_format_modules(lang, format_module_path=None): | |
| """Find format modules.""" | |
| if not check_for_language(lang): | |
| return | |
| if format_module_path is None: | |
| format_module_path = settings.FORMAT_MODULE_PATH | |
| format_locations = [] | |
| if format_module_path: | |
| if isinstance(format_module_path, str): | |
| format_module_path = [format_module_path] | |
| for path in format_module_path: | |
| format_locations.append(path + ".%s") | |
| format_locations.append("django.conf.locale.%s") | |
| locale = to_locale(lang) | |
| locales = [locale] | |
| if "_" in locale: | |
| locales.append(locale.split("_")[0]) | |
| for location in format_locations: | |
| for loc in locales: | |
| try: | |
| yield import_module("%s.formats" % (location % loc)) | |
| except ImportError: | |
| pass | |
| def get_format_modules(lang=None): | |
| """Return a list of the format modules found.""" | |
| if lang is None: | |
| lang = get_language() | |
| if lang not in _format_modules_cache: | |
| _format_modules_cache[lang] = list( | |
| iter_format_modules(lang, settings.FORMAT_MODULE_PATH) | |
| ) | |
| return _format_modules_cache[lang] | |
| def get_format(format_type, lang=None, use_l10n=None): | |
| """ | |
| For a specific format type, return the format for the current | |
| language (locale). Default to the format in the settings. | |
| format_type is the name of the format, e.g. 'DATE_FORMAT'. | |
| If use_l10n is provided and is not None, it forces the value to | |
| be localized (or not), otherwise it's always localized. | |
| """ | |
| if use_l10n is None: | |
| use_l10n = True | |
| if use_l10n and lang is None: | |
| lang = get_language() | |
| format_type = str(format_type) # format_type may be lazy. | |
| cache_key = (format_type, lang) | |
| try: | |
| return _format_cache[cache_key] | |
| except KeyError: | |
| pass | |
| # The requested format_type has not been cached yet. Try to find it in any | |
| # of the format_modules for the given lang if l10n is enabled. If it's not | |
| # there or if l10n is disabled, fall back to the project settings. | |
| val = None | |
| if use_l10n: | |
| for module in get_format_modules(lang): | |
| val = getattr(module, format_type, None) | |
| if val is not None: | |
| break | |
| if val is None: | |
| if format_type not in FORMAT_SETTINGS: | |
| return format_type | |
| val = getattr(settings, format_type) | |
| elif format_type in ISO_INPUT_FORMATS: | |
| # If a list of input formats from one of the format_modules was | |
| # retrieved, make sure the ISO_INPUT_FORMATS are in this list. | |
| val = list(val) | |
| for iso_input in ISO_INPUT_FORMATS.get(format_type, ()): | |
| if iso_input not in val: | |
| val.append(iso_input) | |
| _format_cache[cache_key] = val | |
| return val | |
| get_format_lazy = lazy(get_format, str, list, tuple) | |
| def date_format(value, format=None, use_l10n=None): | |
| """ | |
| Format a datetime.date or datetime.datetime object using a | |
| localizable format. | |
| If use_l10n is provided and is not None, that will force the value to | |
| be localized (or not), otherwise it's always localized. | |
| """ | |
| return dateformat.format( | |
| value, get_format(format or "DATE_FORMAT", use_l10n=use_l10n) | |
| ) | |
| def time_format(value, format=None, use_l10n=None): | |
| """ | |
| Format a datetime.time object using a localizable format. | |
| If use_l10n is provided and is not None, it forces the value to | |
| be localized (or not), otherwise it's always localized. | |
| """ | |
| return dateformat.time_format( | |
| value, get_format(format or "TIME_FORMAT", use_l10n=use_l10n) | |
| ) | |
| def number_format(value, decimal_pos=None, use_l10n=None, force_grouping=False): | |
| """ | |
| Format a numeric value using localization settings. | |
| If use_l10n is provided and is not None, it forces the value to | |
| be localized (or not), otherwise it's always localized. | |
| """ | |
| if use_l10n is None: | |
| use_l10n = True | |
| lang = get_language() if use_l10n else None | |
| return numberformat.format( | |
| value, | |
| get_format("DECIMAL_SEPARATOR", lang, use_l10n=use_l10n), | |
| decimal_pos, | |
| get_format("NUMBER_GROUPING", lang, use_l10n=use_l10n), | |
| get_format("THOUSAND_SEPARATOR", lang, use_l10n=use_l10n), | |
| force_grouping=force_grouping, | |
| use_l10n=use_l10n, | |
| ) | |
| def localize(value, use_l10n=None): | |
| """ | |
| Check if value is a localizable type (date, number...) and return it | |
| formatted as a string using current locale format. | |
| If use_l10n is provided and is not None, it forces the value to | |
| be localized (or not), otherwise it's always localized. | |
| """ | |
| if isinstance(value, str): # Handle strings first for performance reasons. | |
| return value | |
| elif isinstance(value, bool): # Make sure booleans don't get treated as numbers | |
| return str(value) | |
| elif isinstance(value, (decimal.Decimal, float, int)): | |
| if use_l10n is False: | |
| return str(value) | |
| return number_format(value, use_l10n=use_l10n) | |
| elif isinstance(value, datetime.datetime): | |
| return date_format(value, "DATETIME_FORMAT", use_l10n=use_l10n) | |
| elif isinstance(value, datetime.date): | |
| return date_format(value, use_l10n=use_l10n) | |
| elif isinstance(value, datetime.time): | |
| return time_format(value, use_l10n=use_l10n) | |
| return value | |
| def localize_input(value, default=None): | |
| """ | |
| Check if an input value is a localizable type and return it | |
| formatted with the appropriate formatting string of the current locale. | |
| """ | |
| if isinstance(value, str): # Handle strings first for performance reasons. | |
| return value | |
| elif isinstance(value, bool): # Don't treat booleans as numbers. | |
| return str(value) | |
| elif isinstance(value, (decimal.Decimal, float, int)): | |
| return number_format(value) | |
| elif isinstance(value, datetime.datetime): | |
| format = default or get_format("DATETIME_INPUT_FORMATS")[0] | |
| format = sanitize_strftime_format(format) | |
| return value.strftime(format) | |
| elif isinstance(value, datetime.date): | |
| format = default or get_format("DATE_INPUT_FORMATS")[0] | |
| format = sanitize_strftime_format(format) | |
| return value.strftime(format) | |
| elif isinstance(value, datetime.time): | |
| format = default or get_format("TIME_INPUT_FORMATS")[0] | |
| return value.strftime(format) | |
| return value | |
| def sanitize_strftime_format(fmt): | |
| """ | |
| Ensure that certain specifiers are correctly padded with leading zeros. | |
| For years < 1000 specifiers %C, %F, %G, and %Y don't work as expected for | |
| strftime provided by glibc on Linux as they don't pad the year or century | |
| with leading zeros. Support for specifying the padding explicitly is | |
| available, however, which can be used to fix this issue. | |
| FreeBSD, macOS, and Windows do not support explicitly specifying the | |
| padding, but return four digit years (with leading zeros) as expected. | |
| This function checks whether the %Y produces a correctly padded string and, | |
| if not, makes the following substitutions: | |
| - %C → %02C | |
| - %F → %010F | |
| - %G → %04G | |
| - %Y → %04Y | |
| See https://bugs.python.org/issue13305 for more details. | |
| """ | |
| if datetime.date(1, 1, 1).strftime("%Y") == "0001": | |
| return fmt | |
| mapping = {"C": 2, "F": 10, "G": 4, "Y": 4} | |
| return re.sub( | |
| r"((?:^|[^%])(?:%%)*)%([CFGY])", | |
| lambda m: r"%s%%0%s%s" % (m[1], mapping[m[2]], m[2]), | |
| fmt, | |
| ) | |
| def sanitize_separators(value): | |
| """ | |
| Sanitize a value according to the current decimal and | |
| thousand separator setting. Used with form field input. | |
| """ | |
| if isinstance(value, str): | |
| parts = [] | |
| decimal_separator = get_format("DECIMAL_SEPARATOR") | |
| if decimal_separator in value: | |
| value, decimals = value.split(decimal_separator, 1) | |
| parts.append(decimals) | |
| if settings.USE_THOUSAND_SEPARATOR: | |
| thousand_sep = get_format("THOUSAND_SEPARATOR") | |
| if ( | |
| thousand_sep == "." | |
| and value.count(".") == 1 | |
| and len(value.split(".")[-1]) != 3 | |
| ): | |
| # Special case where we suspect a dot meant decimal separator | |
| # (see #22171). | |
| pass | |
| else: | |
| for replacement in { | |
| thousand_sep, | |
| unicodedata.normalize("NFKD", thousand_sep), | |
| }: | |
| value = value.replace(replacement, "") | |
| parts.append(value) | |
| value = ".".join(reversed(parts)) | |
| return value | |
Xet Storage Details
- Size:
- 10.3 kB
- Xet hash:
- 7756f2e471104b7c5bb52feeb408d4232f11cd9858e8f77f4bfb01589b5f9e39
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.