dataforge-py 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dataforge/__init__.py +20 -0
- dataforge/backend.py +147 -0
- dataforge/cli.py +166 -0
- dataforge/core.py +1169 -0
- dataforge/locales/__init__.py +1 -0
- dataforge/locales/ar_SA/__init__.py +1 -0
- dataforge/locales/ar_SA/address.py +128 -0
- dataforge/locales/ar_SA/company.py +183 -0
- dataforge/locales/ar_SA/internet.py +25 -0
- dataforge/locales/ar_SA/person.py +217 -0
- dataforge/locales/ar_SA/phone.py +15 -0
- dataforge/locales/de_DE/__init__.py +1 -0
- dataforge/locales/de_DE/address.py +148 -0
- dataforge/locales/de_DE/company.py +125 -0
- dataforge/locales/de_DE/internet.py +32 -0
- dataforge/locales/de_DE/person.py +212 -0
- dataforge/locales/de_DE/phone.py +17 -0
- dataforge/locales/en_AU/__init__.py +1 -0
- dataforge/locales/en_AU/address.py +231 -0
- dataforge/locales/en_AU/company.py +193 -0
- dataforge/locales/en_AU/internet.py +34 -0
- dataforge/locales/en_AU/person.py +370 -0
- dataforge/locales/en_AU/phone.py +16 -0
- dataforge/locales/en_CA/__init__.py +1 -0
- dataforge/locales/en_CA/address.py +276 -0
- dataforge/locales/en_CA/company.py +193 -0
- dataforge/locales/en_CA/internet.py +34 -0
- dataforge/locales/en_CA/person.py +377 -0
- dataforge/locales/en_CA/phone.py +15 -0
- dataforge/locales/en_GB/__init__.py +1 -0
- dataforge/locales/en_GB/address.py +312 -0
- dataforge/locales/en_GB/company.py +196 -0
- dataforge/locales/en_GB/internet.py +34 -0
- dataforge/locales/en_GB/person.py +372 -0
- dataforge/locales/en_GB/phone.py +15 -0
- dataforge/locales/en_US/__init__.py +1 -0
- dataforge/locales/en_US/address.py +268 -0
- dataforge/locales/en_US/company.py +191 -0
- dataforge/locales/en_US/internet.py +34 -0
- dataforge/locales/en_US/person.py +370 -0
- dataforge/locales/en_US/phone.py +15 -0
- dataforge/locales/es_ES/__init__.py +1 -0
- dataforge/locales/es_ES/address.py +151 -0
- dataforge/locales/es_ES/company.py +125 -0
- dataforge/locales/es_ES/internet.py +30 -0
- dataforge/locales/es_ES/person.py +207 -0
- dataforge/locales/es_ES/phone.py +15 -0
- dataforge/locales/fr_FR/__init__.py +1 -0
- dataforge/locales/fr_FR/address.py +145 -0
- dataforge/locales/fr_FR/company.py +125 -0
- dataforge/locales/fr_FR/internet.py +30 -0
- dataforge/locales/fr_FR/person.py +212 -0
- dataforge/locales/fr_FR/phone.py +15 -0
- dataforge/locales/hi_IN/__init__.py +1 -0
- dataforge/locales/hi_IN/address.py +177 -0
- dataforge/locales/hi_IN/company.py +191 -0
- dataforge/locales/hi_IN/internet.py +26 -0
- dataforge/locales/hi_IN/person.py +218 -0
- dataforge/locales/hi_IN/phone.py +21 -0
- dataforge/locales/it_IT/__init__.py +1 -0
- dataforge/locales/it_IT/address.py +218 -0
- dataforge/locales/it_IT/company.py +151 -0
- dataforge/locales/it_IT/internet.py +31 -0
- dataforge/locales/it_IT/person.py +187 -0
- dataforge/locales/it_IT/phone.py +15 -0
- dataforge/locales/ja_JP/__init__.py +1 -0
- dataforge/locales/ja_JP/address.py +174 -0
- dataforge/locales/ja_JP/company.py +121 -0
- dataforge/locales/ja_JP/internet.py +30 -0
- dataforge/locales/ja_JP/person.py +207 -0
- dataforge/locales/ja_JP/phone.py +18 -0
- dataforge/locales/ko_KR/__init__.py +1 -0
- dataforge/locales/ko_KR/address.py +121 -0
- dataforge/locales/ko_KR/company.py +151 -0
- dataforge/locales/ko_KR/internet.py +30 -0
- dataforge/locales/ko_KR/person.py +157 -0
- dataforge/locales/ko_KR/phone.py +26 -0
- dataforge/locales/nl_NL/__init__.py +1 -0
- dataforge/locales/nl_NL/address.py +152 -0
- dataforge/locales/nl_NL/company.py +182 -0
- dataforge/locales/nl_NL/internet.py +41 -0
- dataforge/locales/nl_NL/person.py +218 -0
- dataforge/locales/nl_NL/phone.py +19 -0
- dataforge/locales/pl_PL/__init__.py +1 -0
- dataforge/locales/pl_PL/address.py +140 -0
- dataforge/locales/pl_PL/company.py +183 -0
- dataforge/locales/pl_PL/internet.py +36 -0
- dataforge/locales/pl_PL/person.py +217 -0
- dataforge/locales/pl_PL/phone.py +15 -0
- dataforge/locales/pt_BR/__init__.py +1 -0
- dataforge/locales/pt_BR/address.py +127 -0
- dataforge/locales/pt_BR/company.py +151 -0
- dataforge/locales/pt_BR/internet.py +31 -0
- dataforge/locales/pt_BR/person.py +187 -0
- dataforge/locales/pt_BR/phone.py +15 -0
- dataforge/locales/ru_RU/__init__.py +1 -0
- dataforge/locales/ru_RU/address.py +156 -0
- dataforge/locales/ru_RU/company.py +168 -0
- dataforge/locales/ru_RU/internet.py +26 -0
- dataforge/locales/ru_RU/person.py +218 -0
- dataforge/locales/ru_RU/phone.py +16 -0
- dataforge/locales/zh_CN/__init__.py +1 -0
- dataforge/locales/zh_CN/address.py +141 -0
- dataforge/locales/zh_CN/company.py +151 -0
- dataforge/locales/zh_CN/internet.py +30 -0
- dataforge/locales/zh_CN/person.py +157 -0
- dataforge/locales/zh_CN/phone.py +25 -0
- dataforge/providers/__init__.py +1 -0
- dataforge/providers/address.py +460 -0
- dataforge/providers/ai_chat.py +170 -0
- dataforge/providers/ai_prompt.py +447 -0
- dataforge/providers/automotive.py +416 -0
- dataforge/providers/barcode.py +149 -0
- dataforge/providers/base.py +34 -0
- dataforge/providers/color.py +247 -0
- dataforge/providers/company.py +144 -0
- dataforge/providers/crypto.py +105 -0
- dataforge/providers/datetime.py +397 -0
- dataforge/providers/ecommerce.py +316 -0
- dataforge/providers/education.py +234 -0
- dataforge/providers/file.py +271 -0
- dataforge/providers/finance.py +545 -0
- dataforge/providers/geo.py +332 -0
- dataforge/providers/government.py +114 -0
- dataforge/providers/internet.py +351 -0
- dataforge/providers/llm.py +726 -0
- dataforge/providers/lorem.py +241 -0
- dataforge/providers/medical.py +364 -0
- dataforge/providers/misc.py +196 -0
- dataforge/providers/network.py +283 -0
- dataforge/providers/payment.py +300 -0
- dataforge/providers/person.py +195 -0
- dataforge/providers/phone.py +87 -0
- dataforge/providers/profile.py +265 -0
- dataforge/providers/science.py +365 -0
- dataforge/providers/text.py +365 -0
- dataforge/py.typed +0 -0
- dataforge/pytest_plugin.py +80 -0
- dataforge/registry.py +164 -0
- dataforge/schema.py +772 -0
- dataforge/unique.py +171 -0
- dataforge_py-0.2.0.dist-info/METADATA +964 -0
- dataforge_py-0.2.0.dist-info/RECORD +145 -0
- dataforge_py-0.2.0.dist-info/WHEEL +4 -0
- dataforge_py-0.2.0.dist-info/entry_points.txt +35 -0
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
"""Finance provider — generates fake credit card numbers, IBANs, currencies."""
|
|
2
|
+
|
|
3
|
+
from typing import Literal, overload
|
|
4
|
+
|
|
5
|
+
from dataforge.providers.base import BaseProvider
|
|
6
|
+
|
|
7
|
+
# Credit card prefixes by network (BIN ranges)
|
|
8
|
+
_CARD_TYPES: tuple[tuple[str, str, int], ...] = (
|
|
9
|
+
# (name, prefix, total_length)
|
|
10
|
+
("Visa", "4", 16),
|
|
11
|
+
("Visa", "4", 16),
|
|
12
|
+
("Visa", "4", 16),
|
|
13
|
+
("Mastercard", "51", 16),
|
|
14
|
+
("Mastercard", "52", 16),
|
|
15
|
+
("Mastercard", "53", 16),
|
|
16
|
+
("Mastercard", "54", 16),
|
|
17
|
+
("Mastercard", "55", 16),
|
|
18
|
+
("American Express", "34", 15),
|
|
19
|
+
("American Express", "37", 15),
|
|
20
|
+
("Discover", "6011", 16),
|
|
21
|
+
("Discover", "65", 16),
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
_CURRENCIES: tuple[tuple[str, str, str], ...] = (
|
|
25
|
+
# (code, name, symbol)
|
|
26
|
+
("USD", "US Dollar", "$"),
|
|
27
|
+
("EUR", "Euro", "\u20ac"),
|
|
28
|
+
("GBP", "British Pound", "\u00a3"),
|
|
29
|
+
("JPY", "Japanese Yen", "\u00a5"),
|
|
30
|
+
("CNY", "Chinese Yuan", "\u00a5"),
|
|
31
|
+
("KRW", "South Korean Won", "\u20a9"),
|
|
32
|
+
("BRL", "Brazilian Real", "R$"),
|
|
33
|
+
("CAD", "Canadian Dollar", "C$"),
|
|
34
|
+
("AUD", "Australian Dollar", "A$"),
|
|
35
|
+
("CHF", "Swiss Franc", "CHF"),
|
|
36
|
+
("INR", "Indian Rupee", "\u20b9"),
|
|
37
|
+
("MXN", "Mexican Peso", "$"),
|
|
38
|
+
("SEK", "Swedish Krona", "kr"),
|
|
39
|
+
("NOK", "Norwegian Krone", "kr"),
|
|
40
|
+
("DKK", "Danish Krone", "kr"),
|
|
41
|
+
("PLN", "Polish Zloty", "z\u0142"),
|
|
42
|
+
("TRY", "Turkish Lira", "\u20ba"),
|
|
43
|
+
("RUB", "Russian Ruble", "\u20bd"),
|
|
44
|
+
("ZAR", "South African Rand", "R"),
|
|
45
|
+
("NZD", "New Zealand Dollar", "NZ$"),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Pre-split parallel tuples for vectorized batch generation —
|
|
49
|
+
# avoids per-item tuple indexing overhead in batch paths.
|
|
50
|
+
_CURRENCY_CODES: tuple[str, ...] = tuple(c[0] for c in _CURRENCIES)
|
|
51
|
+
_CURRENCY_NAMES: tuple[str, ...] = tuple(c[1] for c in _CURRENCIES)
|
|
52
|
+
_CURRENCY_SYMBOLS: tuple[str, ...] = tuple(c[2] for c in _CURRENCIES)
|
|
53
|
+
|
|
54
|
+
# IBAN formats by country: (country_code, total_length)
|
|
55
|
+
_IBAN_FORMATS: tuple[tuple[str, int], ...] = (
|
|
56
|
+
("DE", 22),
|
|
57
|
+
("FR", 27),
|
|
58
|
+
("GB", 22),
|
|
59
|
+
("ES", 24),
|
|
60
|
+
("IT", 27),
|
|
61
|
+
("NL", 18),
|
|
62
|
+
("BE", 16),
|
|
63
|
+
("AT", 20),
|
|
64
|
+
("CH", 21),
|
|
65
|
+
("PT", 25),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# BIC/SWIFT code components — pre-computed 4-char bank codes at module level
|
|
69
|
+
# to avoid per-call ``[:4].ljust(4, "X")`` overhead.
|
|
70
|
+
_BIC_BANK_CODES: tuple[str, ...] = tuple(
|
|
71
|
+
b[:4].ljust(4, "X")
|
|
72
|
+
for b in (
|
|
73
|
+
"DEUTDEFF",
|
|
74
|
+
"BNPAFRPP",
|
|
75
|
+
"BARCGB22",
|
|
76
|
+
"CHASUS33",
|
|
77
|
+
"CITIUS33",
|
|
78
|
+
"COBADEFF",
|
|
79
|
+
"HSBC",
|
|
80
|
+
"INGB",
|
|
81
|
+
"SCBL",
|
|
82
|
+
"UBSW",
|
|
83
|
+
"ABNA",
|
|
84
|
+
"RABO",
|
|
85
|
+
"BOFAUS3N",
|
|
86
|
+
"WFBIUS6S",
|
|
87
|
+
"NWBKGB2L",
|
|
88
|
+
"LOYDGB21",
|
|
89
|
+
"BKENGB2L",
|
|
90
|
+
"SOGEFRPP",
|
|
91
|
+
"CRLYFRPP",
|
|
92
|
+
"AGRIFRPP",
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
_BIC_LOCATIONS: tuple[str, ...] = (
|
|
97
|
+
"FF",
|
|
98
|
+
"PP",
|
|
99
|
+
"22",
|
|
100
|
+
"33",
|
|
101
|
+
"2L",
|
|
102
|
+
"3N",
|
|
103
|
+
"6S",
|
|
104
|
+
"MM",
|
|
105
|
+
"XX",
|
|
106
|
+
"HH",
|
|
107
|
+
"LX",
|
|
108
|
+
"BB",
|
|
109
|
+
"CC",
|
|
110
|
+
"DD",
|
|
111
|
+
"EE",
|
|
112
|
+
"GG",
|
|
113
|
+
"KK",
|
|
114
|
+
"LL",
|
|
115
|
+
"SS",
|
|
116
|
+
"TT",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
_BIC_COUNTRIES: tuple[str, ...] = (
|
|
120
|
+
"DE",
|
|
121
|
+
"FR",
|
|
122
|
+
"GB",
|
|
123
|
+
"US",
|
|
124
|
+
"NL",
|
|
125
|
+
"CH",
|
|
126
|
+
"IT",
|
|
127
|
+
"ES",
|
|
128
|
+
"AT",
|
|
129
|
+
"BE",
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Base58 alphabet for Bitcoin addresses (as a string for O(1) indexing)
|
|
133
|
+
_BASE58_STR: str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
|
134
|
+
_BASE58_LEN: int = 58 # len(_BASE58_STR)
|
|
135
|
+
|
|
136
|
+
# 7h — Luhn doubling lookup table: eliminates per-digit ``if d > 9: d -= 9``
|
|
137
|
+
_LUHN_DOUBLE: tuple[int, ...] = (0, 2, 4, 6, 8, 1, 3, 5, 7, 9)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
_CARD_TYPE_NAMES: tuple[str, ...] = (
|
|
141
|
+
"Visa",
|
|
142
|
+
"Mastercard",
|
|
143
|
+
"American Express",
|
|
144
|
+
"Discover",
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _luhn_checksum(number: str) -> str:
|
|
149
|
+
"""Append a Luhn check digit to *number* and return the full card number.
|
|
150
|
+
|
|
151
|
+
Uses reverse index math to avoid creating a ``reversed()`` iterator,
|
|
152
|
+
and ``ord(ch) - 48`` with a pre-computed ``_LUHN_DOUBLE`` lookup
|
|
153
|
+
table to eliminate per-digit branching.
|
|
154
|
+
"""
|
|
155
|
+
total = 0
|
|
156
|
+
_double = _LUHN_DOUBLE
|
|
157
|
+
n_len = len(number)
|
|
158
|
+
for i in range(n_len):
|
|
159
|
+
d = ord(number[n_len - 1 - i]) - 48
|
|
160
|
+
if i % 2 == 0:
|
|
161
|
+
d = _double[d]
|
|
162
|
+
total += d
|
|
163
|
+
check = (10 - (total % 10)) % 10
|
|
164
|
+
return number + str(check)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class FinanceProvider(BaseProvider):
|
|
168
|
+
"""Generates fake financial data: credit cards, IBANs, currencies.
|
|
169
|
+
|
|
170
|
+
Parameters
|
|
171
|
+
----------
|
|
172
|
+
engine : RandomEngine
|
|
173
|
+
The shared random engine instance.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
__slots__ = ()
|
|
177
|
+
|
|
178
|
+
_provider_name = "finance"
|
|
179
|
+
_locale_modules = ()
|
|
180
|
+
_field_map = {
|
|
181
|
+
"credit_card_number": "credit_card_number",
|
|
182
|
+
"card_number": "credit_card_number",
|
|
183
|
+
"card_type": "card_type",
|
|
184
|
+
"iban": "iban",
|
|
185
|
+
"currency_code": "currency_code",
|
|
186
|
+
"currency": "currency_code",
|
|
187
|
+
"currency_name": "currency_name",
|
|
188
|
+
"currency_symbol": "currency_symbol",
|
|
189
|
+
"price": "price",
|
|
190
|
+
"bic": "bic",
|
|
191
|
+
"routing_number": "routing_number",
|
|
192
|
+
"bitcoin_address": "bitcoin_address",
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
# ------------------------------------------------------------------
|
|
196
|
+
# Scalar helpers
|
|
197
|
+
# ------------------------------------------------------------------
|
|
198
|
+
|
|
199
|
+
def _one_credit_card_number(self) -> str:
|
|
200
|
+
_, prefix, length = self._engine.choice(_CARD_TYPES)
|
|
201
|
+
# Generate remaining digits (minus prefix, minus check digit)
|
|
202
|
+
remaining = length - len(prefix) - 1
|
|
203
|
+
body = prefix + self._engine.random_digits_str(remaining)
|
|
204
|
+
return _luhn_checksum(body)
|
|
205
|
+
|
|
206
|
+
def _one_credit_card(self) -> dict[str, str]:
|
|
207
|
+
name, prefix, length = self._engine.choice(_CARD_TYPES)
|
|
208
|
+
remaining = length - len(prefix) - 1
|
|
209
|
+
body = prefix + self._engine.random_digits_str(remaining)
|
|
210
|
+
number = _luhn_checksum(body)
|
|
211
|
+
exp_month = str(self._engine.random_int(1, 12)).zfill(2)
|
|
212
|
+
exp_year = str(self._engine.random_int(25, 30))
|
|
213
|
+
cvv_len = 4 if name == "American Express" else 3
|
|
214
|
+
cvv = self._engine.random_digits_str(cvv_len)
|
|
215
|
+
return {
|
|
216
|
+
"type": name,
|
|
217
|
+
"number": number,
|
|
218
|
+
"exp": f"{exp_month}/{exp_year}",
|
|
219
|
+
"cvv": cvv,
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
def _one_iban(self) -> str:
|
|
223
|
+
country, length = self._engine.choice(_IBAN_FORMATS)
|
|
224
|
+
bban_len = length - 4 # 2 country + 2 check
|
|
225
|
+
check = str(self._engine.random_int(2, 98)).zfill(2)
|
|
226
|
+
bban = self._engine.random_digits_str(bban_len)
|
|
227
|
+
return f"{country}{check}{bban}"
|
|
228
|
+
|
|
229
|
+
def _one_price(self, min_cents: int, max_cents: int) -> str:
|
|
230
|
+
cents = self._engine.random_int(min_cents, max_cents)
|
|
231
|
+
return f"{cents / 100:.2f}"
|
|
232
|
+
|
|
233
|
+
def _one_bic(self) -> str:
|
|
234
|
+
bank_code = self._engine.choice(_BIC_BANK_CODES)
|
|
235
|
+
country = self._engine.choice(_BIC_COUNTRIES)
|
|
236
|
+
location = self._engine.choice(_BIC_LOCATIONS)
|
|
237
|
+
return f"{bank_code}{country}{location}XXX"
|
|
238
|
+
|
|
239
|
+
def _one_routing_number(self) -> str:
|
|
240
|
+
# First two digits: Federal Reserve district (01-12)
|
|
241
|
+
d1 = self._engine.random_int(0, 1)
|
|
242
|
+
d2 = self._engine.random_int(1, 2) if d1 == 1 else self._engine.random_int(1, 9)
|
|
243
|
+
# Generate 6 random digits in one call
|
|
244
|
+
mid = self._engine.random_digits_str(6)
|
|
245
|
+
d = [
|
|
246
|
+
d1,
|
|
247
|
+
d2,
|
|
248
|
+
ord(mid[0]) - 48,
|
|
249
|
+
ord(mid[1]) - 48,
|
|
250
|
+
ord(mid[2]) - 48,
|
|
251
|
+
ord(mid[3]) - 48,
|
|
252
|
+
ord(mid[4]) - 48,
|
|
253
|
+
ord(mid[5]) - 48,
|
|
254
|
+
]
|
|
255
|
+
# ABA checksum
|
|
256
|
+
total = (
|
|
257
|
+
3 * d[0]
|
|
258
|
+
+ 7 * d[1]
|
|
259
|
+
+ d[2]
|
|
260
|
+
+ 3 * d[3]
|
|
261
|
+
+ 7 * d[4]
|
|
262
|
+
+ d[5]
|
|
263
|
+
+ 3 * d[6]
|
|
264
|
+
+ 7 * d[7]
|
|
265
|
+
)
|
|
266
|
+
check = (10 - (total % 10)) % 10
|
|
267
|
+
return f"{d1}{d2}{mid}{check}"
|
|
268
|
+
|
|
269
|
+
def _one_bitcoin_address(self) -> str:
|
|
270
|
+
# P2PKH addresses: "1" + 25-33 Base58 characters
|
|
271
|
+
length = self._engine.random_int(25, 33)
|
|
272
|
+
# 7k — Use divmod(bits, 58) for unbiased Base58 encoding.
|
|
273
|
+
# Previous approach used ``bits % 58`` + ``bits >>= 6`` which
|
|
274
|
+
# was biased because 2^6 = 64 is not divisible by 58.
|
|
275
|
+
bits = self._engine.getrandbits(length * 6)
|
|
276
|
+
chars: list[str] = []
|
|
277
|
+
for _ in range(length):
|
|
278
|
+
bits, idx = divmod(bits, _BASE58_LEN)
|
|
279
|
+
chars.append(_BASE58_STR[idx])
|
|
280
|
+
return "1" + "".join(chars)
|
|
281
|
+
|
|
282
|
+
# ------------------------------------------------------------------
|
|
283
|
+
# Public API
|
|
284
|
+
# ------------------------------------------------------------------
|
|
285
|
+
|
|
286
|
+
@overload
|
|
287
|
+
def credit_card_number(self) -> str: ...
|
|
288
|
+
@overload
|
|
289
|
+
def credit_card_number(self, count: Literal[1]) -> str: ...
|
|
290
|
+
@overload
|
|
291
|
+
def credit_card_number(self, count: int) -> str | list[str]: ...
|
|
292
|
+
def credit_card_number(self, count: int = 1) -> str | list[str]:
|
|
293
|
+
"""Generate a random credit card number (Luhn-valid).
|
|
294
|
+
|
|
295
|
+
Parameters
|
|
296
|
+
----------
|
|
297
|
+
count : int
|
|
298
|
+
Number of card numbers to generate.
|
|
299
|
+
"""
|
|
300
|
+
if count == 1:
|
|
301
|
+
return self._one_credit_card_number()
|
|
302
|
+
return [self._one_credit_card_number() for _ in range(count)]
|
|
303
|
+
|
|
304
|
+
@overload
|
|
305
|
+
def credit_card(self) -> dict[str, str]: ...
|
|
306
|
+
@overload
|
|
307
|
+
def credit_card(self, count: Literal[1]) -> dict[str, str]: ...
|
|
308
|
+
@overload
|
|
309
|
+
def credit_card(self, count: int) -> dict[str, str] | list[dict[str, str]]: ...
|
|
310
|
+
def credit_card(self, count: int = 1) -> dict[str, str] | list[dict[str, str]]:
|
|
311
|
+
"""Generate a full credit card (number, type, expiry, CVV).
|
|
312
|
+
|
|
313
|
+
Parameters
|
|
314
|
+
----------
|
|
315
|
+
count : int
|
|
316
|
+
Number of cards to generate.
|
|
317
|
+
"""
|
|
318
|
+
if count == 1:
|
|
319
|
+
return self._one_credit_card()
|
|
320
|
+
return [self._one_credit_card() for _ in range(count)]
|
|
321
|
+
|
|
322
|
+
@overload
|
|
323
|
+
def card_type(self) -> str: ...
|
|
324
|
+
@overload
|
|
325
|
+
def card_type(self, count: Literal[1]) -> str: ...
|
|
326
|
+
@overload
|
|
327
|
+
def card_type(self, count: int) -> str | list[str]: ...
|
|
328
|
+
def card_type(self, count: int = 1) -> str | list[str]:
|
|
329
|
+
"""Generate a random credit card network name.
|
|
330
|
+
|
|
331
|
+
Parameters
|
|
332
|
+
----------
|
|
333
|
+
count : int
|
|
334
|
+
Number of card types to generate.
|
|
335
|
+
"""
|
|
336
|
+
types = _CARD_TYPE_NAMES
|
|
337
|
+
if count == 1:
|
|
338
|
+
return self._engine.choice(types)
|
|
339
|
+
return self._engine.choices(types, count)
|
|
340
|
+
|
|
341
|
+
@overload
|
|
342
|
+
def iban(self) -> str: ...
|
|
343
|
+
@overload
|
|
344
|
+
def iban(self, count: Literal[1]) -> str: ...
|
|
345
|
+
@overload
|
|
346
|
+
def iban(self, count: int) -> str | list[str]: ...
|
|
347
|
+
def iban(self, count: int = 1) -> str | list[str]:
|
|
348
|
+
"""Generate a random IBAN.
|
|
349
|
+
|
|
350
|
+
Parameters
|
|
351
|
+
----------
|
|
352
|
+
count : int
|
|
353
|
+
Number of IBANs to generate.
|
|
354
|
+
"""
|
|
355
|
+
if count == 1:
|
|
356
|
+
return self._one_iban()
|
|
357
|
+
return [self._one_iban() for _ in range(count)]
|
|
358
|
+
|
|
359
|
+
@overload
|
|
360
|
+
def currency_code(self) -> str: ...
|
|
361
|
+
@overload
|
|
362
|
+
def currency_code(self, count: Literal[1]) -> str: ...
|
|
363
|
+
@overload
|
|
364
|
+
def currency_code(self, count: int) -> str | list[str]: ...
|
|
365
|
+
def currency_code(self, count: int = 1) -> str | list[str]:
|
|
366
|
+
"""Generate a random ISO 4217 currency code (e.g. ``"USD"``).
|
|
367
|
+
|
|
368
|
+
Parameters
|
|
369
|
+
----------
|
|
370
|
+
count : int
|
|
371
|
+
Number of codes to generate.
|
|
372
|
+
"""
|
|
373
|
+
if count == 1:
|
|
374
|
+
return self._engine.choice(_CURRENCY_CODES)
|
|
375
|
+
return self._engine.choices(_CURRENCY_CODES, count)
|
|
376
|
+
|
|
377
|
+
@overload
|
|
378
|
+
def currency_name(self) -> str: ...
|
|
379
|
+
@overload
|
|
380
|
+
def currency_name(self, count: Literal[1]) -> str: ...
|
|
381
|
+
@overload
|
|
382
|
+
def currency_name(self, count: int) -> str | list[str]: ...
|
|
383
|
+
def currency_name(self, count: int = 1) -> str | list[str]:
|
|
384
|
+
"""Generate a random currency name (e.g. ``"US Dollar"``).
|
|
385
|
+
|
|
386
|
+
Parameters
|
|
387
|
+
----------
|
|
388
|
+
count : int
|
|
389
|
+
Number of names to generate.
|
|
390
|
+
"""
|
|
391
|
+
if count == 1:
|
|
392
|
+
return self._engine.choice(_CURRENCY_NAMES)
|
|
393
|
+
return self._engine.choices(_CURRENCY_NAMES, count)
|
|
394
|
+
|
|
395
|
+
@overload
|
|
396
|
+
def currency_symbol(self) -> str: ...
|
|
397
|
+
@overload
|
|
398
|
+
def currency_symbol(self, count: Literal[1]) -> str: ...
|
|
399
|
+
@overload
|
|
400
|
+
def currency_symbol(self, count: int) -> str | list[str]: ...
|
|
401
|
+
def currency_symbol(self, count: int = 1) -> str | list[str]:
|
|
402
|
+
"""Generate a random currency symbol (e.g. ``"$"``).
|
|
403
|
+
|
|
404
|
+
Parameters
|
|
405
|
+
----------
|
|
406
|
+
count : int
|
|
407
|
+
Number of symbols to generate.
|
|
408
|
+
"""
|
|
409
|
+
if count == 1:
|
|
410
|
+
return self._engine.choice(_CURRENCY_SYMBOLS)
|
|
411
|
+
return self._engine.choices(_CURRENCY_SYMBOLS, count)
|
|
412
|
+
|
|
413
|
+
@overload
|
|
414
|
+
def price(self) -> str: ...
|
|
415
|
+
@overload
|
|
416
|
+
def price(self, count: Literal[1]) -> str: ...
|
|
417
|
+
@overload
|
|
418
|
+
def price(self, count: int) -> str | list[str]: ...
|
|
419
|
+
def price(
|
|
420
|
+
self, count: int = 1, min_val: float = 0.99, max_val: float = 9999.99
|
|
421
|
+
) -> str | list[str]:
|
|
422
|
+
"""Generate a random price string (e.g. ``"49.99"``).
|
|
423
|
+
|
|
424
|
+
Parameters
|
|
425
|
+
----------
|
|
426
|
+
count : int
|
|
427
|
+
Number of prices to generate.
|
|
428
|
+
min_val : float
|
|
429
|
+
Minimum price value.
|
|
430
|
+
max_val : float
|
|
431
|
+
Maximum price value.
|
|
432
|
+
"""
|
|
433
|
+
min_cents = int(min_val * 100)
|
|
434
|
+
max_cents = int(max_val * 100)
|
|
435
|
+
if count == 1:
|
|
436
|
+
return self._one_price(min_cents, max_cents)
|
|
437
|
+
# Inlined batch loop with local-bound random_int
|
|
438
|
+
_ri = self._engine.random_int
|
|
439
|
+
return [f"{_ri(min_cents, max_cents) / 100:.2f}" for _ in range(count)]
|
|
440
|
+
|
|
441
|
+
@overload
|
|
442
|
+
def bic(self) -> str: ...
|
|
443
|
+
@overload
|
|
444
|
+
def bic(self, count: Literal[1]) -> str: ...
|
|
445
|
+
@overload
|
|
446
|
+
def bic(self, count: int) -> str | list[str]: ...
|
|
447
|
+
def bic(self, count: int = 1) -> str | list[str]:
|
|
448
|
+
"""Generate a random BIC/SWIFT code (e.g. ``"DEUTDEFFXXX"``).
|
|
449
|
+
|
|
450
|
+
Parameters
|
|
451
|
+
----------
|
|
452
|
+
count : int
|
|
453
|
+
Number of BIC codes to generate.
|
|
454
|
+
"""
|
|
455
|
+
if count == 1:
|
|
456
|
+
return self._one_bic()
|
|
457
|
+
# Inlined batch loop with local-bound choices
|
|
458
|
+
_choice = self._engine.choice
|
|
459
|
+
return [
|
|
460
|
+
f"{_choice(_BIC_BANK_CODES)}{_choice(_BIC_COUNTRIES)}{_choice(_BIC_LOCATIONS)}XXX"
|
|
461
|
+
for _ in range(count)
|
|
462
|
+
]
|
|
463
|
+
|
|
464
|
+
@overload
|
|
465
|
+
def routing_number(self) -> str: ...
|
|
466
|
+
@overload
|
|
467
|
+
def routing_number(self, count: Literal[1]) -> str: ...
|
|
468
|
+
@overload
|
|
469
|
+
def routing_number(self, count: int) -> str | list[str]: ...
|
|
470
|
+
def routing_number(self, count: int = 1) -> str | list[str]:
|
|
471
|
+
"""Generate a random US ABA routing number with valid checksum.
|
|
472
|
+
|
|
473
|
+
Parameters
|
|
474
|
+
----------
|
|
475
|
+
count : int
|
|
476
|
+
Number of routing numbers to generate.
|
|
477
|
+
"""
|
|
478
|
+
if count == 1:
|
|
479
|
+
return self._one_routing_number()
|
|
480
|
+
# Inlined batch with local-bound helpers
|
|
481
|
+
_ri = self._engine.random_int
|
|
482
|
+
_rds = self._engine.random_digits_str
|
|
483
|
+
_ord = ord
|
|
484
|
+
result: list[str] = []
|
|
485
|
+
for _ in range(count):
|
|
486
|
+
d1 = _ri(0, 1)
|
|
487
|
+
d2 = _ri(1, 2) if d1 == 1 else _ri(1, 9)
|
|
488
|
+
mid = _rds(6)
|
|
489
|
+
d = [
|
|
490
|
+
d1,
|
|
491
|
+
d2,
|
|
492
|
+
_ord(mid[0]) - 48,
|
|
493
|
+
_ord(mid[1]) - 48,
|
|
494
|
+
_ord(mid[2]) - 48,
|
|
495
|
+
_ord(mid[3]) - 48,
|
|
496
|
+
_ord(mid[4]) - 48,
|
|
497
|
+
_ord(mid[5]) - 48,
|
|
498
|
+
]
|
|
499
|
+
total = (
|
|
500
|
+
3 * d[0]
|
|
501
|
+
+ 7 * d[1]
|
|
502
|
+
+ d[2]
|
|
503
|
+
+ 3 * d[3]
|
|
504
|
+
+ 7 * d[4]
|
|
505
|
+
+ d[5]
|
|
506
|
+
+ 3 * d[6]
|
|
507
|
+
+ 7 * d[7]
|
|
508
|
+
)
|
|
509
|
+
check = (10 - (total % 10)) % 10
|
|
510
|
+
result.append(f"{d1}{d2}{mid}{check}")
|
|
511
|
+
return result
|
|
512
|
+
|
|
513
|
+
@overload
|
|
514
|
+
def bitcoin_address(self) -> str: ...
|
|
515
|
+
@overload
|
|
516
|
+
def bitcoin_address(self, count: Literal[1]) -> str: ...
|
|
517
|
+
@overload
|
|
518
|
+
def bitcoin_address(self, count: int) -> str | list[str]: ...
|
|
519
|
+
def bitcoin_address(self, count: int = 1) -> str | list[str]:
|
|
520
|
+
"""Generate a random Bitcoin address (P2PKH format, starts with ``1``).
|
|
521
|
+
|
|
522
|
+
Parameters
|
|
523
|
+
----------
|
|
524
|
+
count : int
|
|
525
|
+
Number of addresses to generate.
|
|
526
|
+
"""
|
|
527
|
+
if count == 1:
|
|
528
|
+
return self._one_bitcoin_address()
|
|
529
|
+
# Inlined batch loop — use modular indexing into BASE58 alphabet
|
|
530
|
+
_b58 = _BASE58_STR
|
|
531
|
+
_b58_len = _BASE58_LEN
|
|
532
|
+
_getrandbits = self._engine.getrandbits
|
|
533
|
+
_ri = self._engine.random_int
|
|
534
|
+
result: list[str] = []
|
|
535
|
+
for _i in range(count):
|
|
536
|
+
length = _ri(25, 33)
|
|
537
|
+
# Generate all random bits at once
|
|
538
|
+
bits = _getrandbits(length * 6)
|
|
539
|
+
# Build string using list comprehension with divmod unrolled
|
|
540
|
+
chars: list[str] = ["1"]
|
|
541
|
+
for _j in range(length):
|
|
542
|
+
chars.append(_b58[bits % _b58_len])
|
|
543
|
+
bits //= _b58_len
|
|
544
|
+
result.append("".join(chars))
|
|
545
|
+
return result
|