Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/faker/providers/__init__.py : 1%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import re
2import string
4from collections import OrderedDict
6from faker.utils.distribution import choices_distribution, choices_distribution_unique
8_re_hash = re.compile(r'#')
9_re_perc = re.compile(r'%')
10_re_excl = re.compile(r'!')
11_re_at = re.compile(r'@')
12_re_qm = re.compile(r'\?')
13_re_cir = re.compile(r'\^')
16class BaseProvider:
18 __provider__ = 'base'
19 __lang__ = None
21 # Locales supported by Linux Mint from `/usr/share/i18n/SUPPORTED`
22 language_locale_codes = {
23 'aa': ('DJ', 'ER', 'ET'), 'af': ('ZA',), 'ak': ('GH',), 'am': ('ET',),
24 'an': ('ES',), 'apn': ('IN',),
25 'ar': ('AE', 'BH', 'DJ', 'DZ', 'EG', 'EH', 'ER', 'IL', 'IN',
26 'IQ', 'JO', 'KM', 'KW', 'LB', 'LY', 'MA', 'MR', 'OM',
27 'PS', 'QA', 'SA', 'SD', 'SO', 'SS', 'SY', 'TD', 'TN',
28 'YE'),
29 'as': ('IN',), 'ast': ('ES',), 'ayc': ('PE',), 'az': ('AZ', 'IN'),
30 'be': ('BY',), 'bem': ('ZM',), 'ber': ('DZ', 'MA'), 'bg': ('BG',),
31 'bhb': ('IN',), 'bho': ('IN',), 'bn': ('BD', 'IN'), 'bo': ('CN', 'IN'),
32 'br': ('FR',), 'brx': ('IN',), 'bs': ('BA',), 'byn': ('ER',),
33 'ca': ('AD', 'ES', 'FR', 'IT'), 'ce': ('RU',), 'ckb': ('IQ',),
34 'cmn': ('TW',), 'crh': ('UA',), 'cs': ('CZ',), 'csb': ('PL',),
35 'cv': ('RU',), 'cy': ('GB',), 'da': ('DK',),
36 'de': ('AT', 'BE', 'CH', 'DE', 'LI', 'LU'), 'doi': ('IN',),
37 'dv': ('MV',), 'dz': ('BT',), 'el': ('GR', 'CY'),
38 'en': ('AG', 'AU', 'BW', 'CA', 'DK', 'GB', 'HK', 'IE', 'IN', 'NG',
39 'NZ', 'PH', 'SG', 'US', 'ZA', 'ZM', 'ZW'),
40 'eo': ('US',),
41 'es': ('AR', 'BO', 'CL', 'CO', 'CR', 'CU', 'DO', 'EC', 'ES', 'GT',
42 'HN', 'MX', 'NI', 'PA', 'PE', 'PR', 'PY', 'SV', 'US', 'UY', 'VE',
43 ), 'et': ('EE',), 'eu': ('ES', 'FR'), 'fa': ('IR',),
44 'ff': ('SN',), 'fi': ('FI',), 'fil': ('PH',), 'fo': ('FO',),
45 'fr': ('CA', 'CH', 'FR', 'LU'), 'fur': ('IT',), 'fy': ('NL', 'DE'),
46 'ga': ('IE',), 'gd': ('GB',), 'gez': ('ER', 'ET'), 'gl': ('ES',),
47 'gu': ('IN',), 'gv': ('GB',), 'ha': ('NG',), 'hak': ('TW',),
48 'he': ('IL',), 'hi': ('IN',), 'hne': ('IN',), 'hr': ('HR',),
49 'hsb': ('DE',), 'ht': ('HT',), 'hu': ('HU',), 'hy': ('AM',),
50 'ia': ('FR',), 'id': ('ID',), 'ig': ('NG',), 'ik': ('CA',),
51 'is': ('IS',), 'it': ('CH', 'IT'), 'iu': ('CA',), 'iw': ('IL',),
52 'ja': ('JP',), 'ka': ('GE',), 'kk': ('KZ',), 'kl': ('GL',),
53 'km': ('KH',), 'kn': ('IN',), 'ko': ('KR',), 'kok': ('IN',),
54 'ks': ('IN',), 'ku': ('TR',), 'kw': ('GB',), 'ky': ('KG',),
55 'lb': ('LU',), 'lg': ('UG',), 'li': ('BE', 'NL'), 'lij': ('IT',),
56 'ln': ('CD',), 'lo': ('LA',), 'lt': ('LT',), 'lv': ('LV',),
57 'lzh': ('TW',), 'mag': ('IN',), 'mai': ('IN',), 'mg': ('MG',),
58 'mhr': ('RU',), 'mi': ('NZ',), 'mk': ('MK',), 'ml': ('IN',),
59 'mn': ('MN',), 'mni': ('IN',), 'mr': ('IN',), 'ms': ('MY',),
60 'mt': ('MT',), 'my': ('MM',), 'nan': ('TW',), 'nb': ('NO',),
61 'nds': ('DE', 'NL'), 'ne': ('NP',), 'nhn': ('MX',),
62 'niu': ('NU', 'NZ'), 'nl': ('AW', 'BE', 'NL'), 'nn': ('NO',),
63 'nr': ('ZA',), 'nso': ('ZA',), 'oc': ('FR',), 'om': ('ET', 'KE'),
64 'or': ('IN',), 'os': ('RU',), 'pa': ('IN', 'PK'),
65 'pap': ('AN', 'AW', 'CW'), 'pl': ('PL',), 'ps': ('AF',),
66 'pt': ('BR', 'PT'), 'quz': ('PE',), 'raj': ('IN',), 'ro': ('RO',),
67 'ru': ('RU', 'UA'), 'rw': ('RW',), 'sa': ('IN',), 'sat': ('IN',),
68 'sc': ('IT',), 'sd': ('IN', 'PK'), 'se': ('NO',), 'shs': ('CA',),
69 'si': ('LK',), 'sid': ('ET',), 'sk': ('SK',), 'sl': ('SI',),
70 'so': ('DJ', 'ET', 'KE', 'SO'), 'sq': ('AL', 'ML'), 'sr': ('ME', 'RS'),
71 'ss': ('ZA',), 'st': ('ZA',), 'sv': ('FI', 'SE'), 'sw': ('KE', 'TZ'),
72 'szl': ('PL',), 'ta': ('IN', 'LK'), 'tcy': ('IN',), 'te': ('IN',),
73 'tg': ('TJ',), 'th': ('TH',), 'the': ('NP',), 'ti': ('ER', 'ET'),
74 'tig': ('ER',), 'tk': ('TM',), 'tl': ('PH',), 'tn': ('ZA',),
75 'tr': ('CY', 'TR'), 'ts': ('ZA',), 'tt': ('RU',), 'ug': ('CN',),
76 'uk': ('UA',), 'unm': ('US',), 'ur': ('IN', 'PK'), 'uz': ('UZ',),
77 've': ('ZA',), 'vi': ('VN',), 'wa': ('BE',), 'wae': ('CH',),
78 'wal': ('ET',), 'wo': ('SN',), 'xh': ('ZA',), 'yi': ('US',),
79 'yo': ('NG',), 'yue': ('HK',), 'zh': ('CN', 'HK', 'SG', 'TW'),
80 'zu': ('ZA',),
81 }
83 def __init__(self, generator):
84 self.generator = generator
86 def locale(self):
87 """Generate a random underscored i18n locale code (e.g. en_US).
89 :sample:
90 """
91 language_code = self.language_code()
92 return language_code + '_' + self.random_element(
93 BaseProvider.language_locale_codes[language_code],
94 )
96 def language_code(self):
97 """Generate a random i18n language code (e.g. en).
99 :sample:
100 """
101 return self.random_element(BaseProvider.language_locale_codes.keys())
103 def random_int(self, min=0, max=9999, step=1):
104 """Generate a random integer between two integers ``min`` and ``max`` inclusive
105 while observing the provided ``step`` value.
107 This method is functionally equivalent to randomly sampling an integer
108 from the sequence ``range(min, max + 1, step)``.
110 :sample:
111 :sample size=10: min=0, max=15
112 :sample size=10: min=0, max=15, step=3
113 """
114 return self.generator.random.randrange(min, max + 1, step)
116 def random_digit(self):
117 """Generate a random digit (0 to 9).
119 :sample:
120 """
121 return self.generator.random.randint(0, 9)
123 def random_digit_not_null(self):
124 """Generate a random non-zero digit (1 to 9).
126 :sample:
127 """
128 return self.generator.random.randint(1, 9)
130 def random_digit_or_empty(self):
131 """Generate a random digit (0 to 9) or an empty string.
133 This method will return an empty string 50% of the time,
134 and each digit has a 1/20 chance of being generated.
136 :sample size=10:
137 """
138 if self.generator.random.randint(0, 1):
139 return self.generator.random.randint(0, 9)
140 else:
141 return ''
143 def random_digit_not_null_or_empty(self):
144 """Generate a random non-zero digit (1 to 9) or an empty string.
146 This method will return an empty string 50% of the time,
147 and each digit has a 1/18 chance of being generated.
149 :sample size=10:
150 """
151 if self.generator.random.randint(0, 1):
152 return self.generator.random.randint(1, 9)
153 else:
154 return ''
156 def random_number(self, digits=None, fix_len=False):
157 """Generate a random integer according to the following rules:
159 - If ``digits`` is ``None`` (default), its value will be set to a random
160 integer from 1 to 9.
161 - If ``fix_len`` is ``False`` (default), all integers that do not exceed
162 the number of ``digits`` can be generated.
163 - If ``fix_len`` is ``True``, only integers with the exact number of
164 ``digits`` can be generated.
166 :sample: fix_len=False
167 :sample: fix_len=True
168 :sample: digits=3
169 :sample: digits=3, fix_len=False
170 :sample: digits=3, fix_len=True
171 """
172 if digits is None:
173 digits = self.random_digit_not_null()
174 if digits < 0:
175 raise ValueError("The digit parameter must be greater than or equal to 0.")
176 if fix_len:
177 if digits > 0:
178 return self.generator.random.randint(
179 pow(10, digits - 1), pow(10, digits) - 1)
180 else:
181 raise ValueError("A number of fixed length cannot have less than 1 digit in it.")
182 else:
183 return self.generator.random.randint(0, pow(10, digits) - 1)
185 def random_letter(self):
186 """Generate a random ASCII letter (a-z and A-Z).
188 :sample:
189 """
190 return self.generator.random.choice(
191 getattr(string, 'letters', string.ascii_letters))
193 def random_letters(self, length=16):
194 """Generate a list of random ASCII letters (a-z and A-Z) of the specified ``length``.
196 :sample:
197 :sample: length=10
198 """
199 return self.random_choices(
200 getattr(string, 'letters', string.ascii_letters),
201 length=length,
202 )
204 def random_lowercase_letter(self):
205 """Generate a random lowercase ASCII letter (a-z).
207 :sample:
208 """
209 return self.generator.random.choice(string.ascii_lowercase)
211 def random_uppercase_letter(self):
212 """Generate a random uppercase ASCII letter (A-Z).
214 :sample:
215 """
216 return self.generator.random.choice(string.ascii_uppercase)
218 def random_elements(self, elements=('a', 'b', 'c'), length=None, unique=False):
219 """Generate a list of randomly sampled objects from ``elements``.
221 Set ``unique`` to ``False`` for random sampling with replacement, and set ``unique`` to
222 ``True`` for random sampling without replacement.
224 If ``length`` is set to ``None`` or is omitted, ``length`` will be set to a random
225 integer from 1 to the size of ``elements``.
227 The value of ``length`` cannot be greater than the number of objects
228 in ``elements`` if ``unique`` is set to ``True``.
230 The value of ``elements`` can be any sequence type (``list``, ``tuple``, ``set``,
231 ``string``, etc) or an ``OrderedDict`` type. If it is the latter, the keys will be
232 used as the objects for sampling, and the values will be used as weighted probabilities
233 if ``unique`` is set to ``False``. For example:
235 .. code-block:: python
237 # Random sampling with replacement
238 fake.random_elements(
239 elements=OrderedDict([
240 ("variable_1", 0.5), # Generates "variable_1" 50% of the time
241 ("variable_2", 0.2), # Generates "variable_2" 20% of the time
242 ("variable_3", 0.2), # Generates "variable_3" 20% of the time
243 ("variable_4": 0.1), # Generates "variable_4" 10% of the time
244 ]), unique=False
245 )
247 # Random sampling without replacement (defaults to uniform distribution)
248 fake.random_elements(
249 elements=OrderedDict([
250 ("variable_1", 0.5),
251 ("variable_2", 0.2),
252 ("variable_3", 0.2),
253 ("variable_4": 0.1),
254 ]), unique=True
255 )
257 :sample: elements=('a', 'b', 'c', 'd'), unique=False
258 :sample: elements=('a', 'b', 'c', 'd'), unique=True
259 :sample: elements=('a', 'b', 'c', 'd'), length=10, unique=False
260 :sample: elements=('a', 'b', 'c', 'd'), length=4, unique=True
261 :sample: elements=OrderedDict([
262 ("a", 0.45),
263 ("b", 0.35),
264 ("c", 0.15),
265 ("d", 0.05),
266 ]), length=20, unique=False
267 :sample: elements=OrderedDict([
268 ("a", 0.45),
269 ("b", 0.35),
270 ("c", 0.15),
271 ("d", 0.05),
272 ]), unique=True
273 """
274 if isinstance(elements, dict) and not isinstance(elements, OrderedDict):
275 raise ValueError("Use OrderedDict only to avoid dependency on PYTHONHASHSEED (See #363).")
277 fn = choices_distribution_unique if unique else choices_distribution
279 if length is None:
280 length = self.generator.random.randint(1, len(elements))
282 if unique and length > len(elements):
283 raise ValueError(
284 "Sample length cannot be longer than the number of unique elements to pick from.")
286 if isinstance(elements, dict):
287 choices = elements.keys()
288 probabilities = elements.values()
289 else:
290 if unique:
291 # shortcut
292 return self.generator.random.sample(elements, length)
293 choices = elements
294 probabilities = [1.0 for _ in range(len(choices))]
296 return fn(
297 list(choices),
298 list(probabilities),
299 self.generator.random,
300 length=length,
301 )
303 def random_choices(self, elements=('a', 'b', 'c'), length=None):
304 """Generate a list of objects randomly sampled from ``elements`` with replacement.
306 For information on the ``elements`` and ``length`` arguments, please refer to
307 :meth:`random_elements() <faker.providers.BaseProvider.random_elements>` which
308 is used under the hood with the ``unique`` argument explicitly set to ``False``.
310 :sample: elements=('a', 'b', 'c', 'd')
311 :sample: elements=('a', 'b', 'c', 'd'), length=10
312 :sample: elements=OrderedDict([
313 ("a", 0.45),
314 ("b", 0.35),
315 ("c", 0.15),
316 ("d", 0.05),
317 ])
318 :sample: elements=OrderedDict([
319 ("a", 0.45),
320 ("b", 0.35),
321 ("c", 0.15),
322 ("d", 0.05),
323 ]), length=20
324 """
325 return self.random_elements(elements, length, unique=False)
327 def random_element(self, elements=('a', 'b', 'c')):
328 """Generate a randomly sampled object from ``elements``.
330 For information on the ``elements`` argument, please refer to
331 :meth:`random_elements() <faker.providers.BaseProvider.random_elements>` which
332 is used under the hood with the ``unique`` argument set to ``False`` and the
333 ``length`` argument set to ``1``.
335 :sample: elements=('a', 'b', 'c', 'd')
336 :sample size=10: elements=OrderedDict([
337 ("a", 0.45),
338 ("b", 0.35),
339 ("c", 0.15),
340 ("d", 0.05),
341 ])
342 """
344 return self.random_elements(elements, length=1)[0]
346 def random_sample(self, elements=('a', 'b', 'c'), length=None):
347 """Generate a list of objects randomly sampled from ``elements`` without replacement.
349 For information on the ``elements`` and ``length`` arguments, please refer to
350 :meth:`random_elements() <faker.providers.BaseProvider.random_elements>` which
351 is used under the hood with the ``unique`` argument explicitly set to ``True``.
353 :sample: elements=('a', 'b', 'c', 'd', 'e', 'f')
354 :sample: elements=('a', 'b', 'c', 'd', 'e', 'f'), length=3
355 """
356 return self.random_elements(elements, length, unique=True)
358 def randomize_nb_elements(
359 self,
360 number=10,
361 le=False,
362 ge=False,
363 min=None,
364 max=None):
365 """Generate a random integer near ``number`` according to the following rules:
367 - If ``le`` is ``False`` (default), allow generation up to 140% of ``number``.
368 If ``True``, upper bound generation is capped at 100%.
369 - If ``ge`` is ``False`` (default), allow generation down to 60% of ``number``.
370 If ``True``, lower bound generation is capped at 100%.
371 - If a numerical value for ``min`` is provided, generated values less than ``min``
372 will be clamped at ``min``.
373 - If a numerical value for ``max`` is provided, generated values greater than
374 ``max`` will be clamped at ``max``.
375 - If both ``le`` and ``ge`` are ``True``, the value of ``number`` will automatically
376 be returned, regardless of the values supplied for ``min`` and ``max``.
378 :sample: number=100
379 :sample: number=100, ge=True
380 :sample: number=100, ge=True, min=120
381 :sample: number=100, le=True
382 :sample: number=100, le=True, max=80
383 :sample: number=79, le=True, ge=True, min=80
384 """
385 if le and ge:
386 return number
387 _min = 100 if ge else 60
388 _max = 100 if le else 140
389 nb = int(number * self.generator.random.randint(_min, _max) / 100)
390 if min is not None and nb < min:
391 nb = min
392 if max is not None and nb > max:
393 nb = max
394 return nb
396 def numerify(self, text='###'):
397 """Generate a string with each placeholder in ``text`` replaced according
398 to the following rules:
400 - Number signs ('#') are replaced with a random digit (0 to 9).
401 - Percent signs ('%') are replaced with a random non-zero digit (1 to 9).
402 - Exclamation marks ('!') are replaced with a random digit or an empty string.
403 - At symbols ('@') are replaced with a random non-zero digit or an empty string.
405 Under the hood, this method uses :meth:`random_digit() <faker.providers.BaseProvider.random_digit>`,
406 :meth:`random_digit_not_null() <faker.providers.BaseProvider.random_digit_not_null>`,
407 :meth:`random_digit_or_empty() <faker.providers.BaseProvider.random_digit_or_empty>`,
408 and :meth:`random_digit_not_null_or_empty() <faker.providers.BaseProvider.random_digit_not_null_or_empty>`
409 to generate the random values.
411 :sample: text='Intel Core i%-%%##K vs AMD Ryzen % %%##X'
412 :sample: text='!!! !!@ !@! !@@ @!! @!@ @@! @@@'
413 """
414 text = _re_hash.sub(
415 lambda x: str(self.random_digit()),
416 text)
417 text = _re_perc.sub(
418 lambda x: str(self.random_digit_not_null()),
419 text)
420 text = _re_excl.sub(
421 lambda x: str(self.random_digit_or_empty()),
422 text)
423 text = _re_at.sub(
424 lambda x: str(self.random_digit_not_null_or_empty()),
425 text)
426 return text
428 def lexify(self, text='????', letters=string.ascii_letters):
429 """Generate a string with each question mark ('?') in ``text``
430 replaced with a random character from ``letters``.
432 By default, ``letters`` contains all ASCII letters, uppercase and lowercase.
434 :sample: text='Random Identifier: ??????????'
435 :sample: text='Random Identifier: ??????????', letters='ABCDE'
436 """
437 return _re_qm.sub(lambda x: self.random_element(letters), text)
439 def bothify(self, text='## ??', letters=string.ascii_letters):
440 """Generate a string with each placeholder in ``text`` replaced according
441 to the following rules:
443 - Number signs ('#') are replaced with a random digit (0 to 9).
444 - Question marks ('?') are replaced with a random character from ``letters``.
446 By default, ``letters`` contains all ASCII letters, uppercase and lowercase.
448 Under the hood, this method uses :meth:`numerify() <faker.providers.BaseProvider.numerify>` and
449 and :meth:`lexify() <faker.providers.BaseProvider.lexify>` to generate random values for number
450 signs and question marks respectively.
452 :sample: letters='ABCDE'
453 :sample: text='Product Number: ????-########'
454 :sample: text='Product Number: ????-########', letters='ABCDE'
455 """
456 return self.lexify(self.numerify(text), letters=letters)
458 def hexify(self, text='^^^^', upper=False):
459 """Generate a string with each circumflex ('^') in ``text``
460 replaced with a random hexadecimal character.
462 By default, ``upper`` is set to False. If set to ``True``, output
463 will be formatted using uppercase hexadecimal characters.
465 :sample: text='MAC Address: ^^:^^:^^:^^:^^:^^'
466 :sample: text='MAC Address: ^^:^^:^^:^^:^^:^^', upper=True
467 """
468 letters = string.hexdigits[:-6]
469 if upper:
470 letters = letters.upper()
471 return _re_cir.sub(lambda x: self.random_element(letters), text)