Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/faker/providers/python/__init__.py: 23%
208 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1import math
2import string
3import sys
4import warnings
6from decimal import Decimal
7from enum import Enum
8from typing import Any, Dict, Iterable, Iterator, List, Optional, Set, Tuple, Type, TypeVar, Union, cast, no_type_check
10from ...exceptions import BaseFakerException
11from .. import BaseProvider, ElementsType
13TypesNames = List[str]
14TypesSpec = Union[List[Type], Tuple[Type, ...]]
15TEnum = TypeVar("TEnum", bound=Enum)
18class EmptyEnumException(BaseFakerException):
19 pass
22class Provider(BaseProvider):
23 default_value_types: ElementsType[str] = (
24 "str",
25 "str",
26 "str",
27 "str",
28 "float",
29 "int",
30 "int",
31 "decimal",
32 "date_time",
33 "uri",
34 "email",
35 )
37 def _check_signature(self, value_types: Optional[TypesSpec], allowed_types: Optional[TypesSpec]) -> TypesSpec:
38 if value_types is not None and not isinstance(value_types, (list, tuple)):
39 value_types = (value_types,)
40 warnings.warn(
41 "Passing `value_types` as positional arguments is going to be "
42 "deprecated. Pass them as a list or tuple instead.",
43 PendingDeprecationWarning,
44 )
45 if allowed_types is not None and not isinstance(allowed_types, (list, tuple)):
46 allowed_types = (allowed_types,)
47 warnings.warn(
48 "Passing `allowed_types` as positional arguments is going to be "
49 "deprecated. Pass them as a list or tuple instead.",
50 PendingDeprecationWarning,
51 )
52 if value_types is None:
53 value_types = ()
54 if allowed_types is None:
55 allowed_types = ()
56 return tuple(value_types) + tuple(allowed_types)
58 def pybool(self) -> bool:
59 return self.random_int(0, 1) == 1
61 def pystr(
62 self,
63 min_chars: Optional[int] = None,
64 max_chars: int = 20,
65 prefix: str = "",
66 suffix: str = "",
67 ) -> str:
68 """
69 Generates a random string of upper and lowercase letters.
70 :return: Random of random length between min and max characters.
71 """
72 if min_chars is None:
73 chars = "".join(self.random_letters(length=max_chars))
74 else:
75 assert max_chars >= min_chars, "Maximum length must be greater than or equal to minimum length"
76 chars = "".join(
77 self.random_letters(
78 length=self.generator.random.randint(min_chars, max_chars),
79 ),
80 )
82 return prefix + chars + suffix
84 def pystr_format(
85 self,
86 string_format: str = "?#-###{{random_int}}{{random_letter}}",
87 letters: str = string.ascii_letters,
88 ) -> str:
89 return self.bothify(self.generator.parse(string_format), letters=letters)
91 def pyfloat(
92 self,
93 left_digits=None,
94 right_digits=None,
95 positive=False,
96 min_value=None,
97 max_value=None,
98 ):
99 if left_digits is not None and left_digits < 0:
100 raise ValueError("A float number cannot have less than 0 digits in its " "integer part")
101 if right_digits is not None and right_digits < 0:
102 raise ValueError("A float number cannot have less than 0 digits in its " "fractional part")
103 if left_digits == 0 and right_digits == 0:
104 raise ValueError("A float number cannot have less than 0 digits in total")
105 if None not in (min_value, max_value) and min_value > max_value:
106 raise ValueError("Min value cannot be greater than max value")
107 if None not in (min_value, max_value) and min_value == max_value:
108 raise ValueError("Min and max value cannot be the same")
109 if positive and min_value is not None and min_value <= 0:
110 raise ValueError("Cannot combine positive=True with negative or zero min_value")
111 if left_digits is not None and max_value and math.ceil(math.log10(abs(max_value))) > left_digits:
112 raise ValueError("Max value must fit within left digits")
113 if left_digits is not None and min_value and math.ceil(math.log10(abs(min_value))) > left_digits:
114 raise ValueError("Min value must fit within left digits")
116 # Make sure at least either left or right is set
117 if left_digits is None and right_digits is None:
118 needed_left_digits = max(1, math.ceil(math.log10(max(abs(max_value or 1), abs(min_value or 1)))))
119 right_digits = self.random_int(1, sys.float_info.dig - needed_left_digits)
121 # If only one side is set, choose #digits for other side
122 if (left_digits is None) ^ (right_digits is None):
123 if left_digits is None:
124 left_digits = max(1, sys.float_info.dig - right_digits)
125 else:
126 right_digits = max(1, sys.float_info.dig - left_digits)
128 # Make sure we don't ask for too many digits!
129 if left_digits + right_digits > sys.float_info.dig:
130 raise ValueError(
131 f"Asking for too many digits ({left_digits} + {right_digits} == {left_digits + right_digits} > "
132 f"{sys.float_info.dig})",
133 )
135 sign = ""
136 if (min_value is not None) or (max_value is not None):
137 # Make sure left_digits still respected
138 if left_digits is not None:
139 if max_value is None:
140 max_value = 10**left_digits # minus smallest representable, adjusted later
141 if min_value is None:
142 min_value = -(10**left_digits) # plus smallest representable, adjusted later
144 if max_value is not None and max_value < 0:
145 max_value += 1 # as the random_int will be generated up to max_value - 1
146 if min_value is not None and min_value < 0:
147 min_value += 1 # as we then append digits after the left_number
148 left_number = self._safe_random_int(
149 min_value,
150 max_value,
151 positive,
152 )
153 else:
154 sign = "+" if positive else self.random_element(("+", "-"))
155 left_number = self.random_number(left_digits)
157 result = float(f"{sign}{left_number}.{self.random_number(right_digits)}")
158 if positive and result == 0:
159 if right_digits:
160 result = float("0." + "0" * (right_digits - 1) + "1")
161 else:
162 result += sys.float_info.epsilon
164 if right_digits:
165 result = min(result, 10**left_digits - float(f'0.{"0" * (right_digits - 1)}1'))
166 result = max(result, -(10**left_digits + float(f'0.{"0" * (right_digits - 1)}1')))
167 else:
168 result = min(result, 10**left_digits - 1)
169 result = max(result, -(10**left_digits + 1))
171 # It's possible for the result to end up > than max_value
172 # This is a quick hack to ensure result is always smaller.
173 if max_value is not None:
174 if result > max_value:
175 result = result - (result - max_value)
176 return result
178 def _safe_random_int(self, min_value: float, max_value: float, positive: bool) -> int:
179 orig_min_value = min_value
180 orig_max_value = max_value
182 if min_value is None:
183 min_value = max_value - self.random_int()
184 if max_value is None:
185 max_value = min_value + self.random_int()
186 if positive:
187 min_value = max(min_value, 0)
189 if min_value == max_value:
190 return self._safe_random_int(orig_min_value, orig_max_value, positive)
191 else:
192 min_value = int(min_value)
193 max_value = int(max_value - 1)
194 if max_value < min_value:
195 max_value += 1
196 return self.random_int(min_value, max_value)
198 def pyint(self, min_value: int = 0, max_value: int = 9999, step: int = 1) -> int:
199 return self.generator.random_int(min_value, max_value, step=step)
201 def pydecimal(
202 self,
203 left_digits=None,
204 right_digits=None,
205 positive=False,
206 min_value=None,
207 max_value=None,
208 ):
209 if left_digits is not None and left_digits < 0: 209 ↛ 210line 209 didn't jump to line 210, because the condition on line 209 was never true
210 raise ValueError("A decimal number cannot have less than 0 digits in its " "integer part")
211 if right_digits is not None and right_digits < 0: 211 ↛ 212line 211 didn't jump to line 212, because the condition on line 211 was never true
212 raise ValueError("A decimal number cannot have less than 0 digits in its " "fractional part")
213 if (left_digits is not None and left_digits == 0) and (right_digits is not None and right_digits == 0): 213 ↛ 214line 213 didn't jump to line 214, because the condition on line 213 was never true
214 raise ValueError("A decimal number cannot have 0 digits in total")
215 if None not in (min_value, max_value) and min_value > max_value: 215 ↛ 216line 215 didn't jump to line 216, because the condition on line 215 was never true
216 raise ValueError("Min value cannot be greater than max value")
217 if None not in (min_value, max_value) and min_value == max_value: 217 ↛ 218line 217 didn't jump to line 218, because the condition on line 217 was never true
218 raise ValueError("Min and max value cannot be the same")
219 if positive and min_value is not None and min_value <= 0: 219 ↛ 220line 219 didn't jump to line 220, because the condition on line 219 was never true
220 raise ValueError("Cannot combine positive=True with negative or zero min_value")
221 if left_digits is not None and max_value and math.ceil(math.log10(abs(max_value))) > left_digits: 221 ↛ 222line 221 didn't jump to line 222, because the condition on line 221 was never true
222 raise ValueError("Max value must fit within left digits")
223 if left_digits is not None and min_value and math.ceil(math.log10(abs(min_value))) > left_digits: 223 ↛ 224line 223 didn't jump to line 224, because the condition on line 223 was never true
224 raise ValueError("Min value must fit within left digits")
226 # if either left or right digits are not specified we randomly choose a length
227 max_random_digits = 100
228 # Because if min_value is bigger than 10**100
229 max_digits_from_value = max(
230 math.ceil(math.log10(abs(min_value or 1))),
231 math.ceil(math.log10(abs(max_value or 1))),
232 )
233 max_left_random_digits = max(max_random_digits, max_digits_from_value + 10)
235 if min_value is not None and min_value >= 0: 235 ↛ 237line 235 didn't jump to line 237, because the condition on line 235 was never false
236 sign = "+"
237 elif max_value is not None and max_value <= 0:
238 sign = "-"
239 else:
240 sign = "+" if positive else self.random_element(("+", "-"))
242 if sign == "+": 242 ↛ 251line 242 didn't jump to line 251, because the condition on line 242 was never false
243 if max_value is not None: 243 ↛ 246line 243 didn't jump to line 246, because the condition on line 243 was never false
244 left_number = str(self.random_int(max(min_value or 0, 0), max_value))
245 else:
246 min_left_digits = math.ceil(math.log10(max(min_value or 1, 1)))
247 if left_digits is None:
248 left_digits = self.random_int(min_left_digits, max_left_random_digits)
249 left_number = "".join([str(self.random_digit()) for i in range(0, left_digits)]) or "0"
250 else:
251 if min_value is not None:
252 left_number = str(self.random_int(max(max_value or 0, 0), abs(min_value)))
253 else:
254 min_left_digits = math.ceil(math.log10(abs(min(max_value or 1, 1))))
255 if left_digits is None:
256 left_digits = self.random_int(min_left_digits, max_left_random_digits)
257 left_number = "".join([str(self.random_digit()) for i in range(0, left_digits)]) or "0"
259 if right_digits is None: 259 ↛ 262line 259 didn't jump to line 262, because the condition on line 259 was never false
260 right_digits = self.random_int(0, max_random_digits)
262 right_number = "".join([str(self.random_digit()) for i in range(0, right_digits)])
264 result = Decimal(f"{sign}{left_number}.{right_number}")
266 # Because the random result might have the same number of decimals as max_value the random number
267 # might be above max_value or below min_value
268 if max_value is not None and result > max_value: 268 ↛ 269line 268 didn't jump to line 269, because the condition on line 268 was never true
269 result = Decimal(max_value)
270 if min_value is not None and result < min_value: 270 ↛ 271line 270 didn't jump to line 271, because the condition on line 270 was never true
271 result = Decimal(min_value)
273 return result
275 def pytuple(
276 self,
277 nb_elements: int = 10,
278 variable_nb_elements: bool = True,
279 value_types: Optional[TypesSpec] = None,
280 allowed_types: Optional[TypesSpec] = None,
281 ) -> Tuple[Any, ...]:
282 return tuple(
283 self._pyiterable(
284 nb_elements=nb_elements,
285 variable_nb_elements=variable_nb_elements,
286 value_types=value_types,
287 allowed_types=allowed_types,
288 )
289 )
291 def pyset(
292 self,
293 nb_elements: int = 10,
294 variable_nb_elements: bool = True,
295 value_types: Optional[TypesSpec] = None,
296 allowed_types: Optional[TypesSpec] = None,
297 ) -> Set[Any]:
298 return set(
299 self._pyiterable(
300 nb_elements=nb_elements,
301 variable_nb_elements=variable_nb_elements,
302 value_types=value_types,
303 allowed_types=allowed_types,
304 )
305 )
307 def pylist(
308 self,
309 nb_elements: int = 10,
310 variable_nb_elements: bool = True,
311 value_types: Optional[TypesSpec] = None,
312 allowed_types: Optional[TypesSpec] = None,
313 ) -> List[Any]:
314 return list(
315 self._pyiterable(
316 nb_elements=nb_elements,
317 variable_nb_elements=variable_nb_elements,
318 value_types=value_types,
319 allowed_types=allowed_types,
320 )
321 )
323 @no_type_check
324 def pyiterable(
325 self,
326 nb_elements: int = 10,
327 variable_nb_elements: bool = True,
328 value_types: Optional[TypesSpec] = None,
329 allowed_types: Optional[TypesSpec] = None,
330 ) -> Iterable[Any]:
331 value_types: TypesSpec = self._check_signature(value_types, allowed_types)
332 return self.random_element([self.pylist, self.pytuple, self.pyset])(
333 nb_elements=nb_elements,
334 variable_nb_elements=variable_nb_elements,
335 value_types=value_types,
336 allowed_types=allowed_types,
337 )
339 def _random_type(self, type_list: List[str]) -> str:
340 value_type: str = self.random_element(type_list)
342 method_name = f"py{value_type}"
343 if hasattr(self, method_name):
344 value_type = method_name
346 return self.generator.format(value_type)
348 def _pyiterable(
349 self,
350 nb_elements: int = 10,
351 variable_nb_elements: bool = True,
352 value_types: Optional[TypesSpec] = None,
353 allowed_types: Optional[TypesSpec] = None,
354 ) -> Iterator:
356 value_types: TypesSpec = self._check_signature(value_types, allowed_types)
358 value_types: TypesNames = [
359 t if isinstance(t, str) else getattr(t, "__name__", type(t).__name__).lower()
360 for t in value_types
361 # avoid recursion
362 if t not in ["iterable", "list", "tuple", "dict", "set"]
363 ]
364 if not value_types:
365 value_types = self.default_value_types # type: ignore
367 if variable_nb_elements:
368 nb_elements = self.randomize_nb_elements(nb_elements, min=1)
370 for _ in range(nb_elements):
371 yield self._random_type(value_types)
373 def pydict(
374 self,
375 nb_elements: int = 10,
376 variable_nb_elements: bool = True,
377 value_types: Optional[TypesSpec] = None,
378 allowed_types: Optional[TypesSpec] = None,
379 ) -> Dict[Any, Any]:
380 """
381 Returns a dictionary.
383 :nb_elements: number of elements for dictionary
384 :variable_nb_elements: is use variable number of elements for dictionary
385 :value_types: type of dictionary values
386 """
387 if variable_nb_elements:
388 nb_elements = self.randomize_nb_elements(nb_elements, min=1)
390 return dict(
391 zip(
392 self.generator.words(nb_elements, unique=True),
393 self._pyiterable(
394 nb_elements=nb_elements,
395 variable_nb_elements=False,
396 value_types=value_types,
397 allowed_types=allowed_types,
398 ),
399 )
400 )
402 def pystruct(
403 self,
404 count: int = 10,
405 value_types: Optional[TypesSpec] = None,
406 allowed_types: Optional[TypesSpec] = None,
407 ) -> Tuple[List, Dict, Dict]:
408 value_types: TypesSpec = self._check_signature(value_types, allowed_types)
410 value_types: TypesNames = [
411 t if isinstance(t, str) else getattr(t, "__name__", type(t).__name__).lower()
412 for t in value_types
413 # avoid recursion
414 if t != "struct"
415 ]
416 if not value_types:
417 value_types = self.default_value_types # type: ignore
419 types = []
420 d = {}
421 nd = {}
422 for i in range(count):
423 d[self.generator.word()] = self._random_type(value_types)
424 types.append(self._random_type(value_types))
425 nd[self.generator.word()] = {
426 i: self._random_type(value_types),
427 i
428 + 1: [
429 self._random_type(value_types),
430 self._random_type(value_types),
431 self._random_type(value_types),
432 ],
433 i
434 + 2: {
435 i: self._random_type(value_types),
436 i + 1: self._random_type(value_types),
437 i
438 + 2: [
439 self._random_type(value_types),
440 self._random_type(value_types),
441 ],
442 },
443 }
444 return types, d, nd
446 def enum(self, enum_cls: Type[TEnum]) -> TEnum:
447 """
448 Returns a random enum of the provided input `Enum` type.
450 :param enum_cls: The `Enum` type to produce the value for.
451 :returns: A randomly selected enum value.
452 """
454 if enum_cls is None:
455 raise ValueError("'enum_cls' cannot be None")
457 if not issubclass(enum_cls, Enum):
458 raise TypeError("'enum_cls' must be an Enum type")
460 members: List[TEnum] = list(cast(Iterable[TEnum], enum_cls))
462 if len(members) < 1:
463 raise EmptyEnumException(f"The provided Enum: '{enum_cls.__name__}' has no members.")
465 return self.random_element(members)