Hide keyboard shortcuts

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 

3 

4from collections import OrderedDict 

5 

6from faker.utils.distribution import choices_distribution, choices_distribution_unique 

7 

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'\^') 

14 

15 

16class BaseProvider: 

17 

18 __provider__ = 'base' 

19 __lang__ = None 

20 

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 } 

82 

83 def __init__(self, generator): 

84 self.generator = generator 

85 

86 def locale(self): 

87 """Generate a random underscored i18n locale code (e.g. en_US). 

88 

89 :sample: 

90 """ 

91 language_code = self.language_code() 

92 return language_code + '_' + self.random_element( 

93 BaseProvider.language_locale_codes[language_code], 

94 ) 

95 

96 def language_code(self): 

97 """Generate a random i18n language code (e.g. en). 

98 

99 :sample: 

100 """ 

101 return self.random_element(BaseProvider.language_locale_codes.keys()) 

102 

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. 

106 

107 This method is functionally equivalent to randomly sampling an integer 

108 from the sequence ``range(min, max + 1, step)``. 

109 

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) 

115 

116 def random_digit(self): 

117 """Generate a random digit (0 to 9). 

118 

119 :sample: 

120 """ 

121 return self.generator.random.randint(0, 9) 

122 

123 def random_digit_not_null(self): 

124 """Generate a random non-zero digit (1 to 9). 

125 

126 :sample: 

127 """ 

128 return self.generator.random.randint(1, 9) 

129 

130 def random_digit_or_empty(self): 

131 """Generate a random digit (0 to 9) or an empty string. 

132 

133 This method will return an empty string 50% of the time, 

134 and each digit has a 1/20 chance of being generated. 

135 

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 '' 

142 

143 def random_digit_not_null_or_empty(self): 

144 """Generate a random non-zero digit (1 to 9) or an empty string. 

145 

146 This method will return an empty string 50% of the time, 

147 and each digit has a 1/18 chance of being generated. 

148 

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 '' 

155 

156 def random_number(self, digits=None, fix_len=False): 

157 """Generate a random integer according to the following rules: 

158 

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. 

165 

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) 

184 

185 def random_letter(self): 

186 """Generate a random ASCII letter (a-z and A-Z). 

187 

188 :sample: 

189 """ 

190 return self.generator.random.choice( 

191 getattr(string, 'letters', string.ascii_letters)) 

192 

193 def random_letters(self, length=16): 

194 """Generate a list of random ASCII letters (a-z and A-Z) of the specified ``length``. 

195 

196 :sample: 

197 :sample: length=10 

198 """ 

199 return self.random_choices( 

200 getattr(string, 'letters', string.ascii_letters), 

201 length=length, 

202 ) 

203 

204 def random_lowercase_letter(self): 

205 """Generate a random lowercase ASCII letter (a-z). 

206 

207 :sample: 

208 """ 

209 return self.generator.random.choice(string.ascii_lowercase) 

210 

211 def random_uppercase_letter(self): 

212 """Generate a random uppercase ASCII letter (A-Z). 

213 

214 :sample: 

215 """ 

216 return self.generator.random.choice(string.ascii_uppercase) 

217 

218 def random_elements(self, elements=('a', 'b', 'c'), length=None, unique=False): 

219 """Generate a list of randomly sampled objects from ``elements``. 

220 

221 Set ``unique`` to ``False`` for random sampling with replacement, and set ``unique`` to 

222 ``True`` for random sampling without replacement. 

223 

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``. 

226 

227 The value of ``length`` cannot be greater than the number of objects 

228 in ``elements`` if ``unique`` is set to ``True``. 

229 

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: 

234 

235 .. code-block:: python 

236 

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 ) 

246 

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 ) 

256 

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).") 

276 

277 fn = choices_distribution_unique if unique else choices_distribution 

278 

279 if length is None: 

280 length = self.generator.random.randint(1, len(elements)) 

281 

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.") 

285 

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))] 

295 

296 return fn( 

297 list(choices), 

298 list(probabilities), 

299 self.generator.random, 

300 length=length, 

301 ) 

302 

303 def random_choices(self, elements=('a', 'b', 'c'), length=None): 

304 """Generate a list of objects randomly sampled from ``elements`` with replacement. 

305 

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``. 

309 

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) 

326 

327 def random_element(self, elements=('a', 'b', 'c')): 

328 """Generate a randomly sampled object from ``elements``. 

329 

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``. 

334 

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 """ 

343 

344 return self.random_elements(elements, length=1)[0] 

345 

346 def random_sample(self, elements=('a', 'b', 'c'), length=None): 

347 """Generate a list of objects randomly sampled from ``elements`` without replacement. 

348 

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``. 

352 

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) 

357 

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: 

366 

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``. 

377 

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 

395 

396 def numerify(self, text='###'): 

397 """Generate a string with each placeholder in ``text`` replaced according 

398 to the following rules: 

399 

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. 

404 

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. 

410 

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 

427 

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``. 

431 

432 By default, ``letters`` contains all ASCII letters, uppercase and lowercase. 

433 

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) 

438 

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: 

442 

443 - Number signs ('#') are replaced with a random digit (0 to 9). 

444 - Question marks ('?') are replaced with a random character from ``letters``. 

445 

446 By default, ``letters`` contains all ASCII letters, uppercase and lowercase. 

447 

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. 

451 

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) 

457 

458 def hexify(self, text='^^^^', upper=False): 

459 """Generate a string with each circumflex ('^') in ``text`` 

460 replaced with a random hexadecimal character. 

461 

462 By default, ``upper`` is set to False. If set to ``True``, output 

463 will be formatted using uppercase hexadecimal characters. 

464 

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)