PageRenderTime 33ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/Windows/Python3.8/WPy64-3830/WPy64-3830/python-3.8.3.amd64/Lib/site-packages/babel/localedata.py

https://gitlab.com/abhi1tb/build
Python | 238 lines | 184 code | 12 blank | 42 comment | 14 complexity | 10eba5fc3cce716ab97d5182227457da MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. """
  3. babel.localedata
  4. ~~~~~~~~~~~~~~~~
  5. Low-level locale data access.
  6. :note: The `Locale` class, which uses this module under the hood, provides a
  7. more convenient interface for accessing the locale data.
  8. :copyright: (c) 2013-2019 by the Babel Team.
  9. :license: BSD, see LICENSE for more details.
  10. """
  11. import os
  12. import threading
  13. from itertools import chain
  14. from babel._compat import pickle, string_types, abc
  15. _cache = {}
  16. _cache_lock = threading.RLock()
  17. _dirname = os.path.join(os.path.dirname(__file__), 'locale-data')
  18. def normalize_locale(name):
  19. """Normalize a locale ID by stripping spaces and apply proper casing.
  20. Returns the normalized locale ID string or `None` if the ID is not
  21. recognized.
  22. """
  23. if not name or not isinstance(name, string_types):
  24. return None
  25. name = name.strip().lower()
  26. for locale_id in chain.from_iterable([_cache, locale_identifiers()]):
  27. if name == locale_id.lower():
  28. return locale_id
  29. def exists(name):
  30. """Check whether locale data is available for the given locale.
  31. Returns `True` if it exists, `False` otherwise.
  32. :param name: the locale identifier string
  33. """
  34. if not name or not isinstance(name, string_types):
  35. return False
  36. if name in _cache:
  37. return True
  38. file_found = os.path.exists(os.path.join(_dirname, '%s.dat' % name))
  39. return True if file_found else bool(normalize_locale(name))
  40. def locale_identifiers():
  41. """Return a list of all locale identifiers for which locale data is
  42. available.
  43. This data is cached after the first invocation in `locale_identifiers.cache`.
  44. Removing the `locale_identifiers.cache` attribute or setting it to `None`
  45. will cause this function to re-read the list from disk.
  46. .. versionadded:: 0.8.1
  47. :return: a list of locale identifiers (strings)
  48. """
  49. data = getattr(locale_identifiers, 'cache', None)
  50. if data is None:
  51. locale_identifiers.cache = data = [
  52. stem
  53. for stem, extension in
  54. (os.path.splitext(filename) for filename in os.listdir(_dirname))
  55. if extension == '.dat' and stem != 'root'
  56. ]
  57. return data
  58. def load(name, merge_inherited=True):
  59. """Load the locale data for the given locale.
  60. The locale data is a dictionary that contains much of the data defined by
  61. the Common Locale Data Repository (CLDR). This data is stored as a
  62. collection of pickle files inside the ``babel`` package.
  63. >>> d = load('en_US')
  64. >>> d['languages']['sv']
  65. u'Swedish'
  66. Note that the results are cached, and subsequent requests for the same
  67. locale return the same dictionary:
  68. >>> d1 = load('en_US')
  69. >>> d2 = load('en_US')
  70. >>> d1 is d2
  71. True
  72. :param name: the locale identifier string (or "root")
  73. :param merge_inherited: whether the inherited data should be merged into
  74. the data of the requested locale
  75. :raise `IOError`: if no locale data file is found for the given locale
  76. identifer, or one of the locales it inherits from
  77. """
  78. _cache_lock.acquire()
  79. try:
  80. data = _cache.get(name)
  81. if not data:
  82. # Load inherited data
  83. if name == 'root' or not merge_inherited:
  84. data = {}
  85. else:
  86. from babel.core import get_global
  87. parent = get_global('parent_exceptions').get(name)
  88. if not parent:
  89. parts = name.split('_')
  90. if len(parts) == 1:
  91. parent = 'root'
  92. else:
  93. parent = '_'.join(parts[:-1])
  94. data = load(parent).copy()
  95. filename = os.path.join(_dirname, '%s.dat' % name)
  96. with open(filename, 'rb') as fileobj:
  97. if name != 'root' and merge_inherited:
  98. merge(data, pickle.load(fileobj))
  99. else:
  100. data = pickle.load(fileobj)
  101. _cache[name] = data
  102. return data
  103. finally:
  104. _cache_lock.release()
  105. def merge(dict1, dict2):
  106. """Merge the data from `dict2` into the `dict1` dictionary, making copies
  107. of nested dictionaries.
  108. >>> d = {1: 'foo', 3: 'baz'}
  109. >>> merge(d, {1: 'Foo', 2: 'Bar'})
  110. >>> sorted(d.items())
  111. [(1, 'Foo'), (2, 'Bar'), (3, 'baz')]
  112. :param dict1: the dictionary to merge into
  113. :param dict2: the dictionary containing the data that should be merged
  114. """
  115. for key, val2 in dict2.items():
  116. if val2 is not None:
  117. val1 = dict1.get(key)
  118. if isinstance(val2, dict):
  119. if val1 is None:
  120. val1 = {}
  121. if isinstance(val1, Alias):
  122. val1 = (val1, val2)
  123. elif isinstance(val1, tuple):
  124. alias, others = val1
  125. others = others.copy()
  126. merge(others, val2)
  127. val1 = (alias, others)
  128. else:
  129. val1 = val1.copy()
  130. merge(val1, val2)
  131. else:
  132. val1 = val2
  133. dict1[key] = val1
  134. class Alias(object):
  135. """Representation of an alias in the locale data.
  136. An alias is a value that refers to some other part of the locale data,
  137. as specified by the `keys`.
  138. """
  139. def __init__(self, keys):
  140. self.keys = tuple(keys)
  141. def __repr__(self):
  142. return '<%s %r>' % (type(self).__name__, self.keys)
  143. def resolve(self, data):
  144. """Resolve the alias based on the given data.
  145. This is done recursively, so if one alias resolves to a second alias,
  146. that second alias will also be resolved.
  147. :param data: the locale data
  148. :type data: `dict`
  149. """
  150. base = data
  151. for key in self.keys:
  152. data = data[key]
  153. if isinstance(data, Alias):
  154. data = data.resolve(base)
  155. elif isinstance(data, tuple):
  156. alias, others = data
  157. data = alias.resolve(base)
  158. return data
  159. class LocaleDataDict(abc.MutableMapping):
  160. """Dictionary wrapper that automatically resolves aliases to the actual
  161. values.
  162. """
  163. def __init__(self, data, base=None):
  164. self._data = data
  165. if base is None:
  166. base = data
  167. self.base = base
  168. def __len__(self):
  169. return len(self._data)
  170. def __iter__(self):
  171. return iter(self._data)
  172. def __getitem__(self, key):
  173. orig = val = self._data[key]
  174. if isinstance(val, Alias): # resolve an alias
  175. val = val.resolve(self.base)
  176. if isinstance(val, tuple): # Merge a partial dict with an alias
  177. alias, others = val
  178. val = alias.resolve(self.base).copy()
  179. merge(val, others)
  180. if type(val) is dict: # Return a nested alias-resolving dict
  181. val = LocaleDataDict(val, base=self.base)
  182. if val is not orig:
  183. self._data[key] = val
  184. return val
  185. def __setitem__(self, key, value):
  186. self._data[key] = value
  187. def __delitem__(self, key):
  188. del self._data[key]
  189. def copy(self):
  190. return LocaleDataDict(self._data.copy(), base=self.base)