We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
pytuple can occassionally return fewer than expected elements
* Faker version: 6.1.1
* OS: Mac OSX 10.15.5

Sporadically using pytuple may result in the tuple having less than the requested elements (`nb_elements`) even when `variable_nb_elements` is set to False.

This happens because pytuple relies on pyset, returning `tuple(self.pyset(...))`. Because it delegates to a set rather than a list, any duplicate numbers generated will result in the set, and following that the tuple, having fewer numbers than expected.

Suggest that the appropriate fix might be to use `pylist` instead of `pyset`

### Steps to reproduce

1. Specify `nb_elements = 3` in a call to pytuple, `variable_nb_elements= False`
2. Repeat until the tuple 'randomly' contains less than 3 elements  

```python
import faker

fake = faker.Faker()

for x in range(10000):
    random_tuple = fake.pytuple(nb_elements=3, variable_nb_elements=False, value_types=[int])
    assert len(random_tuple) == 3, f"Tuple {random_tuple} not len 3 at iteration {x}"
```

### Expected behavior

When calling pytuple with `nb_elements = 3` and `variable_nb_elements = False` the tuple should always contain 3 elements, even if there are duplicate values.

### Actual behavior

Sporadically the tuple contains less than 3 elements.


--- 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         left_digits = left_digits if left_digits is not None else (
74             self.random_int(1, sys.float_info.dig))
75         right_digits = right_digits if right_digits is not None else (
76             self.random_int(0, sys.float_info.dig - left_digits))
77         sign = ''
78         if (min_value is not None) or (max_value is not None):
79             if max_value is not None and max_value < 0:
80                 max_value += 1  # as the random_int will be generated up to max_value - 1
81             if min_value is not None and min_value < 0:
82                 min_value += 1  # as we then append digits after the left_number
83             left_number = self._safe_random_int(
84                 min_value, max_value, positive,
85             )
86         else:
87             sign = '+' if positive else self.random_element(('+', '-'))
88             left_number = self.random_number(left_digits)
89 
90         result = float(f'{sign}{left_number}.{self.random_number(right_digits)}')
91         if positive and result == 0:
92             if right_digits:
93                 result = float('0.' + '0' * (right_digits - 1) + '1')
94             else:
95                 result += sys.float_info.epsilon
96         return result
97 
98     def _safe_random_int(self, min_value, max_value, positive):
99         orig_min_value = min_value
100         orig_max_value = max_value
101 
102         if min_value is None:
103             min_value = max_value - self.random_int()
104         if max_value is None:
105             max_value = min_value + self.random_int()
106         if positive:
107             min_value = max(min_value, 0)
108 
109         if min_value == max_value:
110             return self._safe_random_int(orig_min_value, orig_max_value, positive)
111         else:
112             return self.random_int(min_value, max_value - 1)
113 
114     def pyint(self, min_value=0, max_value=9999, step=1):
115         return self.generator.random_int(min_value, max_value, step=step)
116 
117     def pydecimal(self, left_digits=None, right_digits=None, positive=False,
118                   min_value=None, max_value=None):
119 
120         float_ = self.pyfloat(
121             left_digits, right_digits, positive, min_value, max_value)
122         return Decimal(str(float_))
123 
124     def pytuple(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):
125         return tuple(
126             self.pyset(
127                 nb_elements,
128                 variable_nb_elements,
129                 value_types,
130                 *allowed_types))
131 
132     def pyset(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):
133         return set(
134             self._pyiterable(
135                 nb_elements,
136                 variable_nb_elements,
137                 value_types,
138                 *allowed_types))
139 
140     def pylist(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):
141         return list(
142             self._pyiterable(
143                 nb_elements,
144                 variable_nb_elements,
145                 value_types,
146                 *allowed_types))
147 
148     def pyiterable(
149             self,
150             nb_elements=10,
151             variable_nb_elements=True,
152             value_types=None,
153             *allowed_types):
154         value_types = self._check_signature(value_types, allowed_types)
155         return self.random_element([self.pylist, self.pytuple, self.pyset])(
156             nb_elements, variable_nb_elements, value_types, *allowed_types)
157 
158     def _random_type(self, type_list):
159         value_type = self.random_element(type_list)
160 
161         method_name = f'py{value_type}'
162         if hasattr(self, method_name):
163             value_type = method_name
164 
165         return self.generator.format(value_type)
166 
167     def _pyiterable(
168             self,
169             nb_elements=10,
170             variable_nb_elements=True,
171             value_types=None,
172             *allowed_types):
173 
174         value_types = self._check_signature(value_types, allowed_types)
175 
176         value_types = [t if isinstance(t, str) else getattr(t, '__name__', type(t).__name__).lower()
177                        for t in value_types
178                        # avoid recursion
179                        if t not in ['iterable', 'list', 'tuple', 'dict', 'set']]
180         if not value_types:
181             value_types = self.default_value_types
182 
183         if variable_nb_elements:
184             nb_elements = self.randomize_nb_elements(nb_elements, min=1)
185 
186         for _ in range(nb_elements):
187             yield self._random_type(value_types)
188 
189     def pydict(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):
190         """
191         Returns a dictionary.
192 
193         :nb_elements: number of elements for dictionary
194         :variable_nb_elements: is use variable number of elements for dictionary
195         :value_types: type of dictionary values
196         """
197         if variable_nb_elements:
198             nb_elements = self.randomize_nb_elements(nb_elements, min=1)
199 
200         return dict(zip(
201             self.generator.words(nb_elements, unique=True),
202             self._pyiterable(nb_elements, False, value_types, *allowed_types),
203         ))
204 
205     def pystruct(self, count=10, value_types=None, *allowed_types):
206         value_types = self._check_signature(value_types, allowed_types)
207 
208         value_types = [t if isinstance(t, str) else getattr(t, '__name__', type(t).__name__).lower()
209                        for t in value_types
210                        # avoid recursion
211                        if t != 'struct']
212         if not value_types:
213             value_types = self.default_value_types
214 
215         types = []
216         d = {}
217         nd = {}
218         for i in range(count):
219             d[self.generator.word()] = self._random_type(value_types)
220             types.append(self._random_type(value_types))
221             nd[self.generator.word()] = {i: self._random_type(value_types),
222                                          i + 1: [self._random_type(value_types),
223                                                  self._random_type(value_types),
224                                                  self._random_type(value_types)],
225                                          i + 2: {i: self._random_type(value_types),
226                                                  i + 1: self._random_type(value_types),
227                                                  i + 2: [self._random_type(value_types),
228                                                          self._random_type(value_types)]}}
229         return types, d, nd
230
```
--- 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
@@ -123,7 +123,7 @@
 
     def pytuple(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):
         return tuple(
-            self.pyset(
+            self._pyiterable(
                 nb_elements,
                 variable_nb_elements,
                 value_types,

{"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@@ -123,7 +123,7 @@\n \n     def pytuple(self, nb_elements=10, variable_nb_elements=True, value_types=None, *allowed_types):\n         return tuple(\n-            self.pyset(\n+            self._pyiterable(\n                 nb_elements,\n                 variable_nb_elements,\n                 value_types,\n", "issue": "pytuple can occassionally return fewer than expected elements\n* Faker version: 6.1.1\r\n* OS: Mac OSX 10.15.5\r\n\r\nSporadically using pytuple may result in the tuple having less than the requested elements (`nb_elements`) even when `variable_nb_elements` is set to False.\r\n\r\nThis happens because pytuple relies on pyset, returning `tuple(self.pyset(...))`. Because it delegates to a set rather than a list, any duplicate numbers generated will result in the set, and following that the tuple, having fewer numbers than expected.\r\n\r\nSuggest that the appropriate fix might be to use `pylist` instead of `pyset`\r\n\r\n### Steps to reproduce\r\n\r\n1. Specify `nb_elements = 3` in a call to pytuple, `variable_nb_elements= False`\r\n2. Repeat until the tuple 'randomly' contains less than 3 elements  \r\n\r\n```python\r\nimport faker\r\n\r\nfake = faker.Faker()\r\n\r\nfor x in range(10000):\r\n    random_tuple = fake.pytuple(nb_elements=3, variable_nb_elements=False, value_types=[int])\r\n    assert len(random_tuple) == 3, f\"Tuple {random_tuple} not len 3 at iteration {x}\"\r\n```\r\n\r\n### Expected behavior\r\n\r\nWhen calling pytuple with `nb_elements = 3` and `variable_nb_elements = False` the tuple should always contain 3 elements, even if there are duplicate values.\r\n\r\n### Actual behavior\r\n\r\nSporadically the tuple contains less than 3 elements.\r\n\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        left_digits = left_digits if left_digits is not None else (\n            self.random_int(1, sys.float_info.dig))\n        right_digits = right_digits if right_digits is not None else (\n            self.random_int(0, sys.float_info.dig - left_digits))\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.pyset(\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 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        left_digits = left_digits if left_digits is not None else (\n            self.random_int(1, sys.float_info.dig))\n        right_digits = right_digits if right_digits is not None else (\n            self.random_int(0, sys.float_info.dig - left_digits))\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"}]}