We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
pydecimal unnecessarily limited by float's max digits
* Faker version: master at time of writing https://github.com/joke2k/faker/commit/d9f4b00b9134e6dfbb09cc1caa81c912b79c3c7c
* OS: Linux

Python's `Decimal` can be arbitrarily many digits; with default precision 28. Faker's `pydecimal` uses `pyfloat`, and so gets limited to `sys.float_info.dig`, which is appropriate for `pyfloat` but not really relevant for `pydecimal`. (The Decimal context could even be less than that.)

### Steps to reproduce

1. `pydecimal(left_digits=16)`

### Expected behavior

Get a 16 digit Decimal

### Actual behavior

> ValueError: Asking for too many digits (16 + 0 == 16 > 15)

pydecimal unnecessarily limited by float's max digits
* Faker version: master at time of writing https://github.com/joke2k/faker/commit/d9f4b00b9134e6dfbb09cc1caa81c912b79c3c7c
* OS: Linux

Python's `Decimal` can be arbitrarily many digits; with default precision 28. Faker's `pydecimal` uses `pyfloat`, and so gets limited to `sys.float_info.dig`, which is appropriate for `pyfloat` but not really relevant for `pydecimal`. (The Decimal context could even be less than that.)

### Steps to reproduce

1. `pydecimal(left_digits=16)`

### Expected behavior

Get a 16 digit Decimal

### Actual behavior

> ValueError: Asking for too many digits (16 + 0 == 16 > 15)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `faker/providers/python/__init__.py`
Content:
```
1 import math
2 import string
3 import sys
4 import warnings
5 
6 from decimal import Decimal
7 
8 from .. import BaseProvider
9 
10 
11 class Provider(BaseProvider):
12     default_value_types = (
13         'str', 'str', 'str', 'str', 'float', 'int', 'int', 'decimal',
14         'date_time', 'uri', 'email',
15     )
16 
17     def _check_signature(self, value_types, allowed_types):
18         if value_types is not None and not isinstance(value_types, (list, tuple)):
19             value_types = [value_types]
20             warnings.warn(
21                 'Passing value types as positional arguments is going to be '
22                 'deprecated.  Pass them as a list or tuple instead.',
23                 PendingDeprecationWarning,
24             )
25         if value_types is None:
26             value_types = ()
27         return tuple(value_types) + allowed_types
28 
29     def pybool(self):
30         return self.random_int(0, 1) == 1
31 
32     def pystr(self, min_chars=None, max_chars=20):
33         """
34         Generates a random string of upper and lowercase letters.
35         :type min_chars: int
36         :type max_chars: int
37         :return: String. Random of random length between min and max characters.
38         """
39         if min_chars is None:
40             return "".join(self.random_letters(length=max_chars))
41         else:
42             assert (
43                 max_chars >= min_chars), "Maximum length must be greater than or equal to minimum length"
44             return "".join(
45                 self.random_letters(
46                     length=self.generator.random.randint(min_chars, max_chars),
47                 ),
48             )
49 
50     def pystr_format(self, string_format='?#-###{{random_int}}{{random_letter}}', letters=string.ascii_letters):
51         return self.bothify(self.generator.parse(string_format), letters=letters)
52 
53     def pyfloat(self, left_digits=None, right_digits=None, positive=False,
54                 min_value=None, max_value=None):
55         if left_digits is not None and left_digits < 0:
56             raise ValueError(
57                 'A float number cannot have less than 0 digits in its '
58                 'integer part')
59         if right_digits is not None and right_digits < 0:
60             raise ValueError(
61                 'A float number cannot have less than 0 digits in its '
62                 'fractional part')
63         if left_digits == 0 and right_digits == 0:
64             raise ValueError(
65                 'A float number cannot have less than 0 digits in total')
66         if None not in (min_value, max_value) and min_value > max_value:
67             raise ValueError('Min value cannot be greater than max value')
68         if None not in (min_value, max_value) and min_value == max_value:
69             raise ValueError('Min and max value cannot be the same')
70         if positive and min_value is not None and min_value <= 0:
71             raise ValueError(
72                 'Cannot combine positive=True with negative or zero min_value')
73         if left_digits is not None and max_value and math.ceil(math.log10(abs(max_value))) > left_digits:
74             raise ValueError('Max value must fit within left digits')
75         if left_digits is not None and min_value and math.ceil(math.log10(abs(min_value))) > left_digits:
76             raise ValueError('Min value must fit within left digits')
77 
78         # Make sure at least either left or right is set
79         if left_digits is None and right_digits is None:
80             needed_left_digits = max(1, math.ceil(math.log10(max(abs(max_value or 1), abs(min_value or 1)))))
81             right_digits = self.random_int(1, sys.float_info.dig - needed_left_digits)
82 
83         # If only one side is set, choose #digits for other side
84         if (left_digits is None) ^ (right_digits is None):
85             if left_digits is None:
86                 left_digits = max(1, sys.float_info.dig - right_digits)
87             else:
88                 right_digits = max(1, sys.float_info.dig - left_digits)
89 
90         # Make sure we don't ask for too many digits!
91         if left_digits + right_digits > sys.float_info.dig:
92             raise ValueError(
93                 f'Asking for too many digits ({left_digits} + {right_digits} == {left_digits + right_digits} > '
94                 f'{sys.float_info.dig})',
95             )
96 
97         sign = ''
98         if (min_value is not None) or (max_value is not None):
99             # Make sure left_digits still respected
100             if left_digits is not None:
101                 if max_value is None:
102                     max_value = 10 ** left_digits  # minus smallest representable, adjusted later
103                 if min_value is None:
104                     min_value = -(10 ** left_digits)  # plus smallest representable, adjusted later
105 
106             if max_value is not None and max_value < 0:
107                 max_value += 1  # as the random_int will be generated up to max_value - 1
108             if min_value is not None and min_value < 0:
109                 min_value += 1  # as we then append digits after the left_number
110             left_number = self._safe_random_int(
111                 min_value, max_value, positive,
112             )
113         else:
114             sign = '+' if positive else self.random_element(('+', '-'))
115             left_number = self.random_number(left_digits)
116 
117         result = float(f'{sign}{left_number}.{self.random_number(right_digits)}')
118         if positive and result == 0:
119             if right_digits:
120                 result = float('0.' + '0' * (right_digits - 1) + '1')
121             else:
122                 result += sys.float_info.epsilon
123 
124         if right_digits:
125             result = min(result, 10 ** left_digits - float(f'0.{"0" * (right_digits - 1)}1'))
126             result = max(result, -(10 ** left_digits + float(f'0.{"0" * (right_digits - 1)}1')))
127         else:
128             result = min(result, 10 ** left_digits - 1)
129             result = max(result, -(10 ** left_digits + 1))
130 
131         return result
132 
133     def _safe_random_int(self, min_value, max_value, positive):
134         orig_min_value = min_value
135         orig_max_value = max_value
136 
137         if min_value is None:
138             min_value = max_value - self.random_int()
139         if max_value is None:
140             max_value = min_value + self.random_int()
141         if positive:
142             min_value = max(min_value, 0)
143 
144         if min_value == max_value:
145             return self._safe_random_int(orig_min_value, orig_max_value, positive)
146         else:
147             return self.random_int(min_value, max_value - 1)
148 
149     def pyint(self, min_value=0, max_value=9999, step=1):
150         return self.generator.random_int(min_value, max_value, step=step)
151 
152     def pydecimal(self, left_digits=None, right_digits=None, positive=False,
153                   min_value=None, max_value=None):
154 
155         float_ = self.pyfloat(
156             left_digits, right_digits, positive, min_value, max_value)
157         return Decimal(str(float_))
158 
159     def pytuple(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):
160         return tuple(
161             self._pyiterable(
162                 nb_elements,
163                 variable_nb_elements,
164                 value_types,
165                 *allowed_types))
166 
167     def pyset(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):
168         return set(
169             self._pyiterable(
170                 nb_elements,
171                 variable_nb_elements,
172                 value_types,
173                 *allowed_types))
174 
175     def pylist(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):
176         return list(
177             self._pyiterable(
178                 nb_elements,
179                 variable_nb_elements,
180                 value_types,
181                 *allowed_types))
182 
183     def pyiterable(
184             self,
185             nb_elements=10,
186             variable_nb_elements=True,
187             value_types=None,
188             *allowed_types):
189         value_types = self._check_signature(value_types, allowed_types)
190         return self.random_element([self.pylist, self.pytuple, self.pyset])(
191             nb_elements, variable_nb_elements, value_types, *allowed_types)
192 
193     def _random_type(self, type_list):
194         value_type = self.random_element(type_list)
195 
196         method_name = f'py{value_type}'
197         if hasattr(self, method_name):
198             value_type = method_name
199 
200         return self.generator.format(value_type)
201 
202     def _pyiterable(
203             self,
204             nb_elements=10,
205             variable_nb_elements=True,
206             value_types=None,
207             *allowed_types):
208 
209         value_types = self._check_signature(value_types, allowed_types)
210 
211         value_types = [t if isinstance(t, str) else getattr(t, '__name__', type(t).__name__).lower()
212                        for t in value_types
213                        # avoid recursion
214                        if t not in ['iterable', 'list', 'tuple', 'dict', 'set']]
215         if not value_types:
216             value_types = self.default_value_types
217 
218         if variable_nb_elements:
219             nb_elements = self.randomize_nb_elements(nb_elements, min=1)
220 
221         for _ in range(nb_elements):
222             yield self._random_type(value_types)
223 
224     def pydict(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):
225         """
226         Returns a dictionary.
227 
228         :nb_elements: number of elements for dictionary
229         :variable_nb_elements: is use variable number of elements for dictionary
230         :value_types: type of dictionary values
231         """
232         if variable_nb_elements:
233             nb_elements = self.randomize_nb_elements(nb_elements, min=1)
234 
235         return dict(zip(
236             self.generator.words(nb_elements, unique=True),
237             self._pyiterable(nb_elements, False, value_types, *allowed_types),
238         ))
239 
240     def pystruct(self, count=10, value_types=None, *allowed_types):
241         value_types = self._check_signature(value_types, allowed_types)
242 
243         value_types = [t if isinstance(t, str) else getattr(t, '__name__', type(t).__name__).lower()
244                        for t in value_types
245                        # avoid recursion
246                        if t != 'struct']
247         if not value_types:
248             value_types = self.default_value_types
249 
250         types = []
251         d = {}
252         nd = {}
253         for i in range(count):
254             d[self.generator.word()] = self._random_type(value_types)
255             types.append(self._random_type(value_types))
256             nd[self.generator.word()] = {i: self._random_type(value_types),
257                                          i + 1: [self._random_type(value_types),
258                                                  self._random_type(value_types),
259                                                  self._random_type(value_types)],
260                                          i + 2: {i: self._random_type(value_types),
261                                                  i + 1: self._random_type(value_types),
262                                                  i + 2: [self._random_type(value_types),
263                                                          self._random_type(value_types)]}}
264         return types, d, nd
265
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/faker/providers/python/__init__.py b/faker/providers/python/__init__.py
--- a/faker/providers/python/__init__.py
+++ b/faker/providers/python/__init__.py
@@ -151,10 +151,58 @@
 
     def pydecimal(self, left_digits=None, right_digits=None, positive=False,
                   min_value=None, max_value=None):
+        if left_digits is not None and left_digits < 0:
+            raise ValueError(
+                'A decimal number cannot have less than 0 digits in its '
+                'integer part')
+        if right_digits is not None and right_digits < 0:
+            raise ValueError(
+                'A decimal number cannot have less than 0 digits in its '
+                'fractional part')
+        if (left_digits is not None and left_digits == 0) and (right_digits is not None and right_digits == 0):
+            raise ValueError(
+                'A decimal number cannot have 0 digits in total')
+        if None not in (min_value, max_value) and min_value > max_value:
+            raise ValueError('Min value cannot be greater than max value')
+        if None not in (min_value, max_value) and min_value == max_value:
+            raise ValueError('Min and max value cannot be the same')
+        if positive and min_value is not None and min_value <= 0:
+            raise ValueError(
+                'Cannot combine positive=True with negative or zero min_value')
+        if left_digits is not None and max_value and math.ceil(math.log10(abs(max_value))) > left_digits:
+            raise ValueError('Max value must fit within left digits')
+        if left_digits is not None and min_value and math.ceil(math.log10(abs(min_value))) > left_digits:
+            raise ValueError('Min value must fit within left digits')
+
+        # if either left or right digits are not specified we randomly choose a length
+        max_random_digits = 100
+        minimum_left_digits = len(str(min_value)) if min_value is not None else 1
+        if left_digits is None and right_digits is None:
+            right_digits = self.random_int(1, max_random_digits)
+            left_digits = self.random_int(minimum_left_digits, max_random_digits)
+        if left_digits is not None and right_digits is None:
+            right_digits = self.random_int(1, max_random_digits)
+        if left_digits is None and right_digits is not None:
+            left_digits = self.random_int(minimum_left_digits, max_random_digits)
 
-        float_ = self.pyfloat(
-            left_digits, right_digits, positive, min_value, max_value)
-        return Decimal(str(float_))
+        sign = ''
+        left_number = ''.join([str(self.random_digit()) for i in range(0, left_digits)]) or '0'
+        if right_digits is not None:
+            right_number = ''.join([str(self.random_digit()) for i in range(0, right_digits)])
+        else:
+            right_number = ''
+        sign = '+' if positive else self.random_element(('+', '-'))
+
+        result = Decimal(f'{sign}{left_number}.{right_number}')
+
+        # Because the random result might have the same number of decimals as max_value the random number
+        # might be above max_value or below min_value
+        if max_value is not None and result > max_value:
+            result = max_value
+        if min_value is not None and result < min_value:
+            result = min_value
+
+        return result
 
     def pytuple(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):
         return tuple(

{"golden_diff": "diff --git a/faker/providers/python/__init__.py b/faker/providers/python/__init__.py\n--- a/faker/providers/python/__init__.py\n+++ b/faker/providers/python/__init__.py\n@@ -151,10 +151,58 @@\n \n     def pydecimal(self, left_digits=None, right_digits=None, positive=False,\n                   min_value=None, max_value=None):\n+        if left_digits is not None and left_digits < 0:\n+            raise ValueError(\n+                'A decimal number cannot have less than 0 digits in its '\n+                'integer part')\n+        if right_digits is not None and right_digits < 0:\n+            raise ValueError(\n+                'A decimal number cannot have less than 0 digits in its '\n+                'fractional part')\n+        if (left_digits is not None and left_digits == 0) and (right_digits is not None and right_digits == 0):\n+            raise ValueError(\n+                'A decimal number cannot have 0 digits in total')\n+        if None not in (min_value, max_value) and min_value > max_value:\n+            raise ValueError('Min value cannot be greater than max value')\n+        if None not in (min_value, max_value) and min_value == max_value:\n+            raise ValueError('Min and max value cannot be the same')\n+        if positive and min_value is not None and min_value <= 0:\n+            raise ValueError(\n+                'Cannot combine positive=True with negative or zero min_value')\n+        if left_digits is not None and max_value and math.ceil(math.log10(abs(max_value))) > left_digits:\n+            raise ValueError('Max value must fit within left digits')\n+        if left_digits is not None and min_value and math.ceil(math.log10(abs(min_value))) > left_digits:\n+            raise ValueError('Min value must fit within left digits')\n+\n+        # if either left or right digits are not specified we randomly choose a length\n+        max_random_digits = 100\n+        minimum_left_digits = len(str(min_value)) if min_value is not None else 1\n+        if left_digits is None and right_digits is None:\n+            right_digits = self.random_int(1, max_random_digits)\n+            left_digits = self.random_int(minimum_left_digits, max_random_digits)\n+        if left_digits is not None and right_digits is None:\n+            right_digits = self.random_int(1, max_random_digits)\n+        if left_digits is None and right_digits is not None:\n+            left_digits = self.random_int(minimum_left_digits, max_random_digits)\n \n-        float_ = self.pyfloat(\n-            left_digits, right_digits, positive, min_value, max_value)\n-        return Decimal(str(float_))\n+        sign = ''\n+        left_number = ''.join([str(self.random_digit()) for i in range(0, left_digits)]) or '0'\n+        if right_digits is not None:\n+            right_number = ''.join([str(self.random_digit()) for i in range(0, right_digits)])\n+        else:\n+            right_number = ''\n+        sign = '+' if positive else self.random_element(('+', '-'))\n+\n+        result = Decimal(f'{sign}{left_number}.{right_number}')\n+\n+        # Because the random result might have the same number of decimals as max_value the random number\n+        # might be above max_value or below min_value\n+        if max_value is not None and result > max_value:\n+            result = max_value\n+        if min_value is not None and result < min_value:\n+            result = min_value\n+\n+        return result\n \n     def pytuple(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):\n         return tuple(\n", "issue": "pydecimal unnecessarily limited by float's max digits\n* Faker version: master at time of writing https://github.com/joke2k/faker/commit/d9f4b00b9134e6dfbb09cc1caa81c912b79c3c7c\r\n* OS: Linux\r\n\r\nPython's `Decimal` can be arbitrarily many digits; with default precision 28. Faker's `pydecimal` uses `pyfloat`, and so gets limited to `sys.float_info.dig`, which is appropriate for `pyfloat` but not really relevant for `pydecimal`. (The Decimal context could even be less than that.)\r\n\r\n### Steps to reproduce\r\n\r\n1. `pydecimal(left_digits=16)`\r\n\r\n### Expected behavior\r\n\r\nGet a 16 digit Decimal\r\n\r\n### Actual behavior\r\n\r\n> ValueError: Asking for too many digits (16 + 0 == 16 > 15)\r\n\npydecimal unnecessarily limited by float's max digits\n* Faker version: master at time of writing https://github.com/joke2k/faker/commit/d9f4b00b9134e6dfbb09cc1caa81c912b79c3c7c\r\n* OS: Linux\r\n\r\nPython's `Decimal` can be arbitrarily many digits; with default precision 28. Faker's `pydecimal` uses `pyfloat`, and so gets limited to `sys.float_info.dig`, which is appropriate for `pyfloat` but not really relevant for `pydecimal`. (The Decimal context could even be less than that.)\r\n\r\n### Steps to reproduce\r\n\r\n1. `pydecimal(left_digits=16)`\r\n\r\n### Expected behavior\r\n\r\nGet a 16 digit Decimal\r\n\r\n### Actual behavior\r\n\r\n> ValueError: Asking for too many digits (16 + 0 == 16 > 15)\r\n\n", "before_files": [{"content": "import math\nimport string\nimport sys\nimport warnings\n\nfrom decimal import Decimal\n\nfrom .. import BaseProvider\n\n\nclass Provider(BaseProvider):\n    default_value_types = (\n        'str', 'str', 'str', 'str', 'float', 'int', 'int', 'decimal',\n        'date_time', 'uri', 'email',\n    )\n\n    def _check_signature(self, value_types, allowed_types):\n        if value_types is not None and not isinstance(value_types, (list, tuple)):\n            value_types = [value_types]\n            warnings.warn(\n                'Passing value types as positional arguments is going to be '\n                'deprecated.  Pass them as a list or tuple instead.',\n                PendingDeprecationWarning,\n            )\n        if value_types is None:\n            value_types = ()\n        return tuple(value_types) + allowed_types\n\n    def pybool(self):\n        return self.random_int(0, 1) == 1\n\n    def pystr(self, min_chars=None, max_chars=20):\n        \"\"\"\n        Generates a random string of upper and lowercase letters.\n        :type min_chars: int\n        :type max_chars: int\n        :return: String. Random of random length between min and max characters.\n        \"\"\"\n        if min_chars is None:\n            return \"\".join(self.random_letters(length=max_chars))\n        else:\n            assert (\n                max_chars >= min_chars), \"Maximum length must be greater than or equal to minimum length\"\n            return \"\".join(\n                self.random_letters(\n                    length=self.generator.random.randint(min_chars, max_chars),\n                ),\n            )\n\n    def pystr_format(self, string_format='?#-###{{random_int}}{{random_letter}}', letters=string.ascii_letters):\n        return self.bothify(self.generator.parse(string_format), letters=letters)\n\n    def pyfloat(self, left_digits=None, right_digits=None, positive=False,\n                min_value=None, max_value=None):\n        if left_digits is not None and left_digits < 0:\n            raise ValueError(\n                'A float number cannot have less than 0 digits in its '\n                'integer part')\n        if right_digits is not None and right_digits < 0:\n            raise ValueError(\n                'A float number cannot have less than 0 digits in its '\n                'fractional part')\n        if left_digits == 0 and right_digits == 0:\n            raise ValueError(\n                'A float number cannot have less than 0 digits in total')\n        if None not in (min_value, max_value) and min_value > max_value:\n            raise ValueError('Min value cannot be greater than max value')\n        if None not in (min_value, max_value) and min_value == max_value:\n            raise ValueError('Min and max value cannot be the same')\n        if positive and min_value is not None and min_value <= 0:\n            raise ValueError(\n                'Cannot combine positive=True with negative or zero min_value')\n        if left_digits is not None and max_value and math.ceil(math.log10(abs(max_value))) > left_digits:\n            raise ValueError('Max value must fit within left digits')\n        if left_digits is not None and min_value and math.ceil(math.log10(abs(min_value))) > left_digits:\n            raise ValueError('Min value must fit within left digits')\n\n        # Make sure at least either left or right is set\n        if left_digits is None and right_digits is None:\n            needed_left_digits = max(1, math.ceil(math.log10(max(abs(max_value or 1), abs(min_value or 1)))))\n            right_digits = self.random_int(1, sys.float_info.dig - needed_left_digits)\n\n        # If only one side is set, choose #digits for other side\n        if (left_digits is None) ^ (right_digits is None):\n            if left_digits is None:\n                left_digits = max(1, sys.float_info.dig - right_digits)\n            else:\n                right_digits = max(1, sys.float_info.dig - left_digits)\n\n        # Make sure we don't ask for too many digits!\n        if left_digits + right_digits > sys.float_info.dig:\n            raise ValueError(\n                f'Asking for too many digits ({left_digits} + {right_digits} == {left_digits + right_digits} > '\n                f'{sys.float_info.dig})',\n            )\n\n        sign = ''\n        if (min_value is not None) or (max_value is not None):\n            # Make sure left_digits still respected\n            if left_digits is not None:\n                if max_value is None:\n                    max_value = 10 ** left_digits  # minus smallest representable, adjusted later\n                if min_value is None:\n                    min_value = -(10 ** left_digits)  # plus smallest representable, adjusted later\n\n            if max_value is not None and max_value < 0:\n                max_value += 1  # as the random_int will be generated up to max_value - 1\n            if min_value is not None and min_value < 0:\n                min_value += 1  # as we then append digits after the left_number\n            left_number = self._safe_random_int(\n                min_value, max_value, positive,\n            )\n        else:\n            sign = '+' if positive else self.random_element(('+', '-'))\n            left_number = self.random_number(left_digits)\n\n        result = float(f'{sign}{left_number}.{self.random_number(right_digits)}')\n        if positive and result == 0:\n            if right_digits:\n                result = float('0.' + '0' * (right_digits - 1) + '1')\n            else:\n                result += sys.float_info.epsilon\n\n        if right_digits:\n            result = min(result, 10 ** left_digits - float(f'0.{\"0\" * (right_digits - 1)}1'))\n            result = max(result, -(10 ** left_digits + float(f'0.{\"0\" * (right_digits - 1)}1')))\n        else:\n            result = min(result, 10 ** left_digits - 1)\n            result = max(result, -(10 ** left_digits + 1))\n\n        return result\n\n    def _safe_random_int(self, min_value, max_value, positive):\n        orig_min_value = min_value\n        orig_max_value = max_value\n\n        if min_value is None:\n            min_value = max_value - self.random_int()\n        if max_value is None:\n            max_value = min_value + self.random_int()\n        if positive:\n            min_value = max(min_value, 0)\n\n        if min_value == max_value:\n            return self._safe_random_int(orig_min_value, orig_max_value, positive)\n        else:\n            return self.random_int(min_value, max_value - 1)\n\n    def pyint(self, min_value=0, max_value=9999, step=1):\n        return self.generator.random_int(min_value, max_value, step=step)\n\n    def pydecimal(self, left_digits=None, right_digits=None, positive=False,\n                  min_value=None, max_value=None):\n\n        float_ = self.pyfloat(\n            left_digits, right_digits, positive, min_value, max_value)\n        return Decimal(str(float_))\n\n    def pytuple(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):\n        return tuple(\n            self._pyiterable(\n                nb_elements,\n                variable_nb_elements,\n                value_types,\n                *allowed_types))\n\n    def pyset(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):\n        return set(\n            self._pyiterable(\n                nb_elements,\n                variable_nb_elements,\n                value_types,\n                *allowed_types))\n\n    def pylist(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):\n        return list(\n            self._pyiterable(\n                nb_elements,\n                variable_nb_elements,\n                value_types,\n                *allowed_types))\n\n    def pyiterable(\n            self,\n            nb_elements=10,\n            variable_nb_elements=True,\n            value_types=None,\n            *allowed_types):\n        value_types = self._check_signature(value_types, allowed_types)\n        return self.random_element([self.pylist, self.pytuple, self.pyset])(\n            nb_elements, variable_nb_elements, value_types, *allowed_types)\n\n    def _random_type(self, type_list):\n        value_type = self.random_element(type_list)\n\n        method_name = f'py{value_type}'\n        if hasattr(self, method_name):\n            value_type = method_name\n\n        return self.generator.format(value_type)\n\n    def _pyiterable(\n            self,\n            nb_elements=10,\n            variable_nb_elements=True,\n            value_types=None,\n            *allowed_types):\n\n        value_types = self._check_signature(value_types, allowed_types)\n\n        value_types = [t if isinstance(t, str) else getattr(t, '__name__', type(t).__name__).lower()\n                       for t in value_types\n                       # avoid recursion\n                       if t not in ['iterable', 'list', 'tuple', 'dict', 'set']]\n        if not value_types:\n            value_types = self.default_value_types\n\n        if variable_nb_elements:\n            nb_elements = self.randomize_nb_elements(nb_elements, min=1)\n\n        for _ in range(nb_elements):\n            yield self._random_type(value_types)\n\n    def pydict(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):\n        \"\"\"\n        Returns a dictionary.\n\n        :nb_elements: number of elements for dictionary\n        :variable_nb_elements: is use variable number of elements for dictionary\n        :value_types: type of dictionary values\n        \"\"\"\n        if variable_nb_elements:\n            nb_elements = self.randomize_nb_elements(nb_elements, min=1)\n\n        return dict(zip(\n            self.generator.words(nb_elements, unique=True),\n            self._pyiterable(nb_elements, False, value_types, *allowed_types),\n        ))\n\n    def pystruct(self, count=10, value_types=None, *allowed_types):\n        value_types = self._check_signature(value_types, allowed_types)\n\n        value_types = [t if isinstance(t, str) else getattr(t, '__name__', type(t).__name__).lower()\n                       for t in value_types\n                       # avoid recursion\n                       if t != 'struct']\n        if not value_types:\n            value_types = self.default_value_types\n\n        types = []\n        d = {}\n        nd = {}\n        for i in range(count):\n            d[self.generator.word()] = self._random_type(value_types)\n            types.append(self._random_type(value_types))\n            nd[self.generator.word()] = {i: self._random_type(value_types),\n                                         i + 1: [self._random_type(value_types),\n                                                 self._random_type(value_types),\n                                                 self._random_type(value_types)],\n                                         i + 2: {i: self._random_type(value_types),\n                                                 i + 1: self._random_type(value_types),\n                                                 i + 2: [self._random_type(value_types),\n                                                         self._random_type(value_types)]}}\n        return types, d, nd\n", "path": "faker/providers/python/__init__.py"}], "after_files": [{"content": "import math\nimport string\nimport sys\nimport warnings\n\nfrom decimal import Decimal\n\nfrom .. import BaseProvider\n\n\nclass Provider(BaseProvider):\n    default_value_types = (\n        'str', 'str', 'str', 'str', 'float', 'int', 'int', 'decimal',\n        'date_time', 'uri', 'email',\n    )\n\n    def _check_signature(self, value_types, allowed_types):\n        if value_types is not None and not isinstance(value_types, (list, tuple)):\n            value_types = [value_types]\n            warnings.warn(\n                'Passing value types as positional arguments is going to be '\n                'deprecated.  Pass them as a list or tuple instead.',\n                PendingDeprecationWarning,\n            )\n        if value_types is None:\n            value_types = ()\n        return tuple(value_types) + allowed_types\n\n    def pybool(self):\n        return self.random_int(0, 1) == 1\n\n    def pystr(self, min_chars=None, max_chars=20):\n        \"\"\"\n        Generates a random string of upper and lowercase letters.\n        :type min_chars: int\n        :type max_chars: int\n        :return: String. Random of random length between min and max characters.\n        \"\"\"\n        if min_chars is None:\n            return \"\".join(self.random_letters(length=max_chars))\n        else:\n            assert (\n                max_chars >= min_chars), \"Maximum length must be greater than or equal to minimum length\"\n            return \"\".join(\n                self.random_letters(\n                    length=self.generator.random.randint(min_chars, max_chars),\n                ),\n            )\n\n    def pystr_format(self, string_format='?#-###{{random_int}}{{random_letter}}', letters=string.ascii_letters):\n        return self.bothify(self.generator.parse(string_format), letters=letters)\n\n    def pyfloat(self, left_digits=None, right_digits=None, positive=False,\n                min_value=None, max_value=None):\n        if left_digits is not None and left_digits < 0:\n            raise ValueError(\n                'A float number cannot have less than 0 digits in its '\n                'integer part')\n        if right_digits is not None and right_digits < 0:\n            raise ValueError(\n                'A float number cannot have less than 0 digits in its '\n                'fractional part')\n        if left_digits == 0 and right_digits == 0:\n            raise ValueError(\n                'A float number cannot have less than 0 digits in total')\n        if None not in (min_value, max_value) and min_value > max_value:\n            raise ValueError('Min value cannot be greater than max value')\n        if None not in (min_value, max_value) and min_value == max_value:\n            raise ValueError('Min and max value cannot be the same')\n        if positive and min_value is not None and min_value <= 0:\n            raise ValueError(\n                'Cannot combine positive=True with negative or zero min_value')\n        if left_digits is not None and max_value and math.ceil(math.log10(abs(max_value))) > left_digits:\n            raise ValueError('Max value must fit within left digits')\n        if left_digits is not None and min_value and math.ceil(math.log10(abs(min_value))) > left_digits:\n            raise ValueError('Min value must fit within left digits')\n\n        # Make sure at least either left or right is set\n        if left_digits is None and right_digits is None:\n            needed_left_digits = max(1, math.ceil(math.log10(max(abs(max_value or 1), abs(min_value or 1)))))\n            right_digits = self.random_int(1, sys.float_info.dig - needed_left_digits)\n\n        # If only one side is set, choose #digits for other side\n        if (left_digits is None) ^ (right_digits is None):\n            if left_digits is None:\n                left_digits = max(1, sys.float_info.dig - right_digits)\n            else:\n                right_digits = max(1, sys.float_info.dig - left_digits)\n\n        # Make sure we don't ask for too many digits!\n        if left_digits + right_digits > sys.float_info.dig:\n            raise ValueError(\n                f'Asking for too many digits ({left_digits} + {right_digits} == {left_digits + right_digits} > '\n                f'{sys.float_info.dig})',\n            )\n\n        sign = ''\n        if (min_value is not None) or (max_value is not None):\n            # Make sure left_digits still respected\n            if left_digits is not None:\n                if max_value is None:\n                    max_value = 10 ** left_digits  # minus smallest representable, adjusted later\n                if min_value is None:\n                    min_value = -(10 ** left_digits)  # plus smallest representable, adjusted later\n\n            if max_value is not None and max_value < 0:\n                max_value += 1  # as the random_int will be generated up to max_value - 1\n            if min_value is not None and min_value < 0:\n                min_value += 1  # as we then append digits after the left_number\n            left_number = self._safe_random_int(\n                min_value, max_value, positive,\n            )\n        else:\n            sign = '+' if positive else self.random_element(('+', '-'))\n            left_number = self.random_number(left_digits)\n\n        result = float(f'{sign}{left_number}.{self.random_number(right_digits)}')\n        if positive and result == 0:\n            if right_digits:\n                result = float('0.' + '0' * (right_digits - 1) + '1')\n            else:\n                result += sys.float_info.epsilon\n\n        if right_digits:\n            result = min(result, 10 ** left_digits - float(f'0.{\"0\" * (right_digits - 1)}1'))\n            result = max(result, -(10 ** left_digits + float(f'0.{\"0\" * (right_digits - 1)}1')))\n        else:\n            result = min(result, 10 ** left_digits - 1)\n            result = max(result, -(10 ** left_digits + 1))\n\n        return result\n\n    def _safe_random_int(self, min_value, max_value, positive):\n        orig_min_value = min_value\n        orig_max_value = max_value\n\n        if min_value is None:\n            min_value = max_value - self.random_int()\n        if max_value is None:\n            max_value = min_value + self.random_int()\n        if positive:\n            min_value = max(min_value, 0)\n\n        if min_value == max_value:\n            return self._safe_random_int(orig_min_value, orig_max_value, positive)\n        else:\n            return self.random_int(min_value, max_value - 1)\n\n    def pyint(self, min_value=0, max_value=9999, step=1):\n        return self.generator.random_int(min_value, max_value, step=step)\n\n    def pydecimal(self, left_digits=None, right_digits=None, positive=False,\n                  min_value=None, max_value=None):\n        if left_digits is not None and left_digits < 0:\n            raise ValueError(\n                'A decimal number cannot have less than 0 digits in its '\n                'integer part')\n        if right_digits is not None and right_digits < 0:\n            raise ValueError(\n                'A decimal number cannot have less than 0 digits in its '\n                'fractional part')\n        if (left_digits is not None and left_digits == 0) and (right_digits is not None and right_digits == 0):\n            raise ValueError(\n                'A decimal number cannot have 0 digits in total')\n        if None not in (min_value, max_value) and min_value > max_value:\n            raise ValueError('Min value cannot be greater than max value')\n        if None not in (min_value, max_value) and min_value == max_value:\n            raise ValueError('Min and max value cannot be the same')\n        if positive and min_value is not None and min_value <= 0:\n            raise ValueError(\n                'Cannot combine positive=True with negative or zero min_value')\n        if left_digits is not None and max_value and math.ceil(math.log10(abs(max_value))) > left_digits:\n            raise ValueError('Max value must fit within left digits')\n        if left_digits is not None and min_value and math.ceil(math.log10(abs(min_value))) > left_digits:\n            raise ValueError('Min value must fit within left digits')\n\n        # if either left or right digits are not specified we randomly choose a length\n        max_random_digits = 100\n        minimum_left_digits = len(str(min_value)) if min_value is not None else 1\n        if left_digits is None and right_digits is None:\n            right_digits = self.random_int(1, max_random_digits)\n            left_digits = self.random_int(minimum_left_digits, max_random_digits)\n        if left_digits is not None and right_digits is None:\n            right_digits = self.random_int(1, max_random_digits)\n        if left_digits is None and right_digits is not None:\n            left_digits = self.random_int(minimum_left_digits, max_random_digits)\n\n        sign = ''\n        left_number = ''.join([str(self.random_digit()) for i in range(0, left_digits)]) or '0'\n        if right_digits is not None:\n            right_number = ''.join([str(self.random_digit()) for i in range(0, right_digits)])\n        else:\n            right_number = ''\n        sign = '+' if positive else self.random_element(('+', '-'))\n\n        result = Decimal(f'{sign}{left_number}.{right_number}')\n\n        # Because the random result might have the same number of decimals as max_value the random number\n        # might be above max_value or below min_value\n        if max_value is not None and result > max_value:\n            result = max_value\n        if min_value is not None and result < min_value:\n            result = min_value\n\n        return result\n\n    def pytuple(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):\n        return tuple(\n            self._pyiterable(\n                nb_elements,\n                variable_nb_elements,\n                value_types,\n                *allowed_types))\n\n    def pyset(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):\n        return set(\n            self._pyiterable(\n                nb_elements,\n                variable_nb_elements,\n                value_types,\n                *allowed_types))\n\n    def pylist(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):\n        return list(\n            self._pyiterable(\n                nb_elements,\n                variable_nb_elements,\n                value_types,\n                *allowed_types))\n\n    def pyiterable(\n            self,\n            nb_elements=10,\n            variable_nb_elements=True,\n            value_types=None,\n            *allowed_types):\n        value_types = self._check_signature(value_types, allowed_types)\n        return self.random_element([self.pylist, self.pytuple, self.pyset])(\n            nb_elements, variable_nb_elements, value_types, *allowed_types)\n\n    def _random_type(self, type_list):\n        value_type = self.random_element(type_list)\n\n        method_name = f'py{value_type}'\n        if hasattr(self, method_name):\n            value_type = method_name\n\n        return self.generator.format(value_type)\n\n    def _pyiterable(\n            self,\n            nb_elements=10,\n            variable_nb_elements=True,\n            value_types=None,\n            *allowed_types):\n\n        value_types = self._check_signature(value_types, allowed_types)\n\n        value_types = [t if isinstance(t, str) else getattr(t, '__name__', type(t).__name__).lower()\n                       for t in value_types\n                       # avoid recursion\n                       if t not in ['iterable', 'list', 'tuple', 'dict', 'set']]\n        if not value_types:\n            value_types = self.default_value_types\n\n        if variable_nb_elements:\n            nb_elements = self.randomize_nb_elements(nb_elements, min=1)\n\n        for _ in range(nb_elements):\n            yield self._random_type(value_types)\n\n    def pydict(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):\n        \"\"\"\n        Returns a dictionary.\n\n        :nb_elements: number of elements for dictionary\n        :variable_nb_elements: is use variable number of elements for dictionary\n        :value_types: type of dictionary values\n        \"\"\"\n        if variable_nb_elements:\n            nb_elements = self.randomize_nb_elements(nb_elements, min=1)\n\n        return dict(zip(\n            self.generator.words(nb_elements, unique=True),\n            self._pyiterable(nb_elements, False, value_types, *allowed_types),\n        ))\n\n    def pystruct(self, count=10, value_types=None, *allowed_types):\n        value_types = self._check_signature(value_types, allowed_types)\n\n        value_types = [t if isinstance(t, str) else getattr(t, '__name__', type(t).__name__).lower()\n                       for t in value_types\n                       # avoid recursion\n                       if t != 'struct']\n        if not value_types:\n            value_types = self.default_value_types\n\n        types = []\n        d = {}\n        nd = {}\n        for i in range(count):\n            d[self.generator.word()] = self._random_type(value_types)\n            types.append(self._random_type(value_types))\n            nd[self.generator.word()] = {i: self._random_type(value_types),\n                                         i + 1: [self._random_type(value_types),\n                                                 self._random_type(value_types),\n                                                 self._random_type(value_types)],\n                                         i + 2: {i: self._random_type(value_types),\n                                                 i + 1: self._random_type(value_types),\n                                                 i + 2: [self._random_type(value_types),\n                                                         self._random_type(value_types)]}}\n        return types, d, nd\n", "path": "faker/providers/python/__init__.py"}]}