__init__.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. # coding=utf-8
  2. from collections import Counter
  3. import re
  4. import string
  5. from faker.utils.distribution import choices_distribution, choices_distribution_unique
  6. _re_hash = re.compile(r'#')
  7. _re_perc = re.compile(r'%')
  8. _re_excl = re.compile(r'!')
  9. _re_at = re.compile(r'@')
  10. _re_qm = re.compile(r'\?')
  11. _re_cir = re.compile(r'\^')
  12. class BaseProvider(object):
  13. __provider__ = 'base'
  14. __lang__ = None
  15. def __init__(self, generator):
  16. self.generator = generator
  17. def random_int(self, min=0, max=9999):
  18. """
  19. Returns a random integer between two values.
  20. :param min: lower bound value (inclusive; default=0)
  21. :param max: upper bound value (inclusive; default=9999)
  22. :returns: random integer between min and max
  23. """
  24. return self.generator.random.randint(min, max)
  25. def random_digit(self):
  26. """
  27. Returns a random digit/number
  28. between 0 and 9.
  29. """
  30. return self.generator.random.randint(0, 9)
  31. def random_digit_not_null(self):
  32. """
  33. Returns a random non-zero digit/number
  34. between 1 and 9.
  35. """
  36. return self.generator.random.randint(1, 9)
  37. def random_digit_or_empty(self):
  38. """
  39. Returns a random digit/number
  40. between 0 and 9 or an empty string.
  41. """
  42. if self.generator.random.randint(0, 1):
  43. return self.generator.random.randint(0, 9)
  44. else:
  45. return ''
  46. def random_digit_not_null_or_empty(self):
  47. """
  48. Returns a random non-zero digit/number
  49. between 1 and 9 or and empty string.
  50. """
  51. if self.generator.random.randint(0, 1):
  52. return self.generator.random.randint(1, 9)
  53. else:
  54. return ''
  55. def random_number(self, digits=None, fix_len=False):
  56. """
  57. Returns a random number with 1 digit (default, when digits==None),
  58. a random number with 0 to given number of digits, or a random number
  59. with given number to given number of digits (when ``fix_len==True``).
  60. :param digits: maximum number of digits
  61. :param fix_len: should the number have fixed length?
  62. :returns: random number with 0 to given number of digits or
  63. fixed length number
  64. """
  65. if digits is None:
  66. digits = self.random_digit()
  67. if fix_len:
  68. return self.generator.random.randint(
  69. pow(10, digits - 1), pow(10, digits) - 1)
  70. else:
  71. return self.generator.random.randint(0, pow(10, digits) - 1)
  72. def random_letter(self):
  73. """Returns a random letter (between a-z and A-Z)."""
  74. return self.generator.random.choice(
  75. getattr(string, 'letters', string.ascii_letters))
  76. def random_letters(self, length=16):
  77. """Returns a random letter (between a-z and A-Z)."""
  78. return self.random_choices(
  79. getattr(string, 'letters', string.ascii_letters),
  80. length=length,
  81. )
  82. def random_lowercase_letter(self):
  83. """Returns a random lowercase letter (between a-z)."""
  84. return self.generator.random.choice(string.ascii_lowercase)
  85. def random_uppercase_letter(self):
  86. """Returns a random letter (between A-Z)."""
  87. return self.generator.random.choice(string.ascii_uppercase)
  88. def random_elements(self, elements=('a', 'b', 'c'), length=None, unique=False):
  89. fn = choices_distribution_unique if unique else choices_distribution
  90. if length is None:
  91. length = self.generator.random.randint(1, len(elements))
  92. if unique and length > len(elements):
  93. raise ValueError(
  94. "Sample length cannot be longer than the number of unique elements to pick from.")
  95. if isinstance(elements, dict):
  96. choices = elements.keys()
  97. probabilities = elements.values()
  98. else:
  99. if unique:
  100. # shortcut
  101. return self.generator.random.sample(elements, length)
  102. choices = elements
  103. probabilities = [1.0 for _ in range(len(choices))]
  104. return fn(
  105. list(choices),
  106. list(probabilities),
  107. self.generator.random,
  108. length=length,
  109. )
  110. def random_choices(self, elements=('a', 'b', 'c'), length=None):
  111. """
  112. Returns a list of random, non-unique elements from a passed object.
  113. If `elements` is a dictionary, the value will be used as
  114. a weighting element. For example::
  115. random_element({"{{variable_1}}": 0.5, "{{variable_2}}": 0.2, "{{variable_3}}": 0.2, "{{variable_4}}": 0.1})
  116. will have the following distribution:
  117. * `variable_1`: 50% probability
  118. * `variable_2`: 20% probability
  119. * `variable_3`: 20% probability
  120. * `variable_4`: 10% probability
  121. """
  122. return self.random_elements(elements, length, unique=False)
  123. def random_element(self, elements=('a', 'b', 'c')):
  124. """
  125. Returns a random element from a passed object.
  126. If `elements` is a dictionary, the value will be used as
  127. a weighting element. For example::
  128. random_element({"{{variable_1}}": 0.5, "{{variable_2}}": 0.2, "{{variable_3}}": 0.2, "{{variable_4}}": 0.1})
  129. will have the following distribution:
  130. * `variable_1`: 50% probability
  131. * `variable_2`: 20% probability
  132. * `variable_3`: 20% probability
  133. * `variable_4`: 10% probability
  134. """
  135. return self.random_elements(elements, length=1)[0]
  136. def random_sample(self, elements=('a', 'b', 'c'), length=None):
  137. """
  138. Returns a list of random unique elements for the specified length.
  139. Multiple occurrences of the same value increase its probability to be in the output.
  140. """
  141. return self.random_elements(elements, length, unique=True)
  142. def randomize_nb_elements(
  143. self,
  144. number=10,
  145. le=False,
  146. ge=False,
  147. min=None,
  148. max=None):
  149. """
  150. Returns a random value near number.
  151. :param number: value to which the result must be near
  152. :param le: result must be lower or equal to number
  153. :param ge: result must be greater or equal to number
  154. :returns: a random int near number
  155. """
  156. if le and ge:
  157. return number
  158. _min = 100 if ge else 60
  159. _max = 100 if le else 140
  160. nb = int(number * self.generator.random.randint(_min, _max) / 100)
  161. if min is not None and nb < min:
  162. nb = min
  163. if max is not None and nb > min:
  164. nb = max
  165. return nb
  166. def numerify(self, text='###'):
  167. """
  168. Replaces all placeholders in given text with randomized values,
  169. replacing: all hash sign ('#') occurrences with a random digit
  170. (from 0 to 9); all percentage sign ('%') occurrences with a
  171. random non-zero digit (from 1 to 9); all exclamation mark ('!')
  172. occurrences with a random digit (from 0 to 9) or an empty string;
  173. and all at symbol ('@') occurrences with a random non-zero digit
  174. (from 1 to 9) or an empty string.
  175. :param text: string to be parsed
  176. :returns: string with all numerical placeholders filled in
  177. """
  178. text = _re_hash.sub(
  179. lambda x: str(self.random_digit()),
  180. text)
  181. text = _re_perc.sub(
  182. lambda x: str(self.random_digit_not_null()),
  183. text)
  184. text = _re_excl.sub(
  185. lambda x: str(self.random_digit_or_empty()),
  186. text)
  187. text = _re_at.sub(
  188. lambda x: str(self.random_digit_not_null_or_empty()),
  189. text)
  190. return text
  191. def lexify(self, text='????', letters=string.ascii_letters):
  192. """
  193. Replaces all question mark ('?') occurrences with a random letter.
  194. :param text: string to be parsed
  195. :param letters: a set of letters to choose from.
  196. :returns: string with all letter placeholders filled in
  197. """
  198. return _re_qm.sub(lambda x: self.random_element(letters), text)
  199. def bothify(self, text='## ??', letters=string.ascii_letters):
  200. """
  201. Replaces all placeholders with random numbers and letters.
  202. :param text: string to be parsed
  203. :returns: string with all numerical and letter placeholders filled in
  204. """
  205. return self.lexify(self.numerify(text), letters=letters)
  206. def hexify(self, text='^^^^', upper=False):
  207. """
  208. Replaces all circumflex ('^') occurrences with a random
  209. hexadecimal character.
  210. :param text: string to be parsed
  211. :param upper: Format as uppercase hexadecimal
  212. :returns: string with all letter placeholders filled in
  213. """
  214. letters = string.hexdigits[:-6]
  215. if upper:
  216. letters = letters.upper()
  217. return _re_cir.sub(lambda x: self.random_element(letters), text)