We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
pydecimal left_digits ignored if min_value or max_value is specified
`max_value` should be set to `10 ** (left_digits -1) - epsilon` before this:

https://github.com/joke2k/faker/blob/d9f4b00b9134e6dfbb09cc1caa81c912b79c3c7c/faker/providers/python/__init__.py#L92-L102

Use cases for using both include:

- `min_value=0`, since `positive=True` disallows `0` (a bug in itself IMO, but that's an age old debate!)
- `min_value` at all actually? As in, 4 left digits, but no less than 42 in value, for example.
- a `max_value` that has a semantically different reason for existing, so it's convenient to specify in addition to `left_digits` [^]

Work around is to specify a `max_value` (per above) instead of `left_digits` if `min_value` or `max_value` are needed too.

(I will have a PR for this shortly.)

[^] - e.g. `left_digits` could be a database requirement (`NUMERIC(left + right, right)`), but `max_value` something to do with the logic the fake is for.

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

{"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@@ -1,3 +1,4 @@\n+import math\n import string\n import sys\n import warnings\n@@ -69,10 +70,15 @@\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-            left_digits = self.random_int(1, sys.float_info.dig - 1)\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@@ -90,6 +96,13 @@\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@@ -107,6 +120,14 @@\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", "issue": "pydecimal left_digits ignored if min_value or max_value is specified\n`max_value` should be set to `10 ** (left_digits -1) - epsilon` before this:\r\n\r\nhttps://github.com/joke2k/faker/blob/d9f4b00b9134e6dfbb09cc1caa81c912b79c3c7c/faker/providers/python/__init__.py#L92-L102\r\n\r\nUse cases for using both include:\r\n\r\n- `min_value=0`, since `positive=True` disallows `0` (a bug in itself IMO, but that's an age old debate!)\r\n- `min_value` at all actually? As in, 4 left digits, but no less than 42 in value, for example.\r\n- a `max_value` that has a semantically different reason for existing, so it's convenient to specify in addition to `left_digits` [^]\r\n\r\nWork around is to specify a `max_value` (per above) instead of `left_digits` if `min_value` or `max_value` are needed too.\r\n\r\n(I will have a PR for this shortly.)\r\n\r\n[^] - e.g. `left_digits` could be a database requirement (`NUMERIC(left + right, right)`), but `max_value` something to do with the logic the fake is for.\n", "before_files": [{"content": "import 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\n        # Make sure at least either left or right is set\n        if left_digits is None and right_digits is None:\n            left_digits = self.random_int(1, sys.float_info.dig - 1)\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            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        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\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"}]}