We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Would a faker.format() method make sense?
It could enable the syntax:
`print(faker.format('{name} considers a {catch_phrase} in {country}'))`

A sample implementation show how simple it would be:

``` python
def fake_fmt(fmt="{first_name}'s favorite number: {random_int}", fake=None):
    fake = fake or Faker()
    fields = [fld.split('}')[0].split(':')[0] for fld in fmt.split('{')[1:]]
    return fmt.format(**{field: getattr(fake, field)() for field in fields})
```

More test cases at: https://github.com/cclauss/Ten-lines-or-less/blob/master/fake_format.py

Fake Part Numbers, Names & Descriptions
Is there any interest in adding fake part numbers, names and descriptions? I could see this used for seeding product tables. Examples:
 `fake.part_number()`
`# MHP-17854623`

`fake.part_name()`
`# MOSFET Oscillator`

`fake.part_description()`
`# Electrical Coil Sensor DC Block Type`

I recently had a project where I had to seed a product table, and I'd be happy to do a PR.

--- 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 # coding=utf-8
2 
3 from __future__ import unicode_literals
4 
5 from decimal import Decimal
6 import sys
7 
8 import six
9 
10 from .. import BaseProvider
11 
12 
13 class Provider(BaseProvider):
14     def pybool(self):
15         return self.random_int(0, 1) == 1
16 
17     def pystr(self, min_chars=None, max_chars=20):
18         """
19         Generates a random string of upper and lowercase letters.
20         :type min_chars: int
21         :type max_chars: int
22         :return: String. Random of random length between min and max characters.
23         """
24         if min_chars is None:
25             return "".join(self.random_letters(length=max_chars))
26         else:
27             assert (
28                 max_chars >= min_chars), "Maximum length must be greater than or equal to minium length"
29             return "".join(
30                 self.random_letters(
31                     length=self.generator.random.randint(min_chars, max_chars),
32                 ),
33             )
34 
35     def pyfloat(self, left_digits=None, right_digits=None, positive=False,
36                 min_value=None, max_value=None):
37 
38         if left_digits is not None and left_digits < 0:
39             raise ValueError(
40                 'A float number cannot have less than 0 digits in its '
41                 'integer part')
42         if right_digits is not None and right_digits < 0:
43             raise ValueError(
44                 'A float number cannot have less than 0 digits in its '
45                 'fractional part')
46         if left_digits == 0 and right_digits == 0:
47             raise ValueError(
48                 'A float number cannot have less than 0 digits in total')
49         if None not in (min_value, max_value) and min_value > max_value:
50             raise ValueError('Min value cannot be greater than max value')
51 
52         left_digits = left_digits if left_digits is not None else (
53             self.random_int(1, sys.float_info.dig))
54         right_digits = right_digits if right_digits is not None else (
55             self.random_int(0, sys.float_info.dig - left_digits))
56         sign = ''
57         if (min_value is not None) or (max_value is not None):
58             if min_value is None:
59                 min_value = max_value - self.random_int()
60             if max_value is None:
61                 max_value = min_value + self.random_int()
62 
63             left_number = self.random_int(min_value, max_value - 1)
64         else:
65             sign = '+' if positive else self.random_element(('+', '-'))
66             left_number = self.random_number(left_digits)
67 
68         return float("{0}{1}.{2}".format(
69             sign,
70             left_number,
71             self.random_number(right_digits),
72         ))
73 
74     def pyint(self, min_value=0, max_value=9999, step=1):
75         return self.generator.random_int(min_value, max_value, step=step)
76 
77     def pydecimal(self, left_digits=None, right_digits=None, positive=False,
78                   min_value=None, max_value=None):
79 
80         float_ = self.pyfloat(
81             left_digits, right_digits, positive, min_value, max_value)
82         return Decimal(str(float_))
83 
84     def pytuple(self, nb_elements=10, variable_nb_elements=True, *value_types):
85         return tuple(
86             self.pyset(
87                 nb_elements,
88                 variable_nb_elements,
89                 *value_types))
90 
91     def pyset(self, nb_elements=10, variable_nb_elements=True, *value_types):
92         return set(
93             self._pyiterable(
94                 nb_elements,
95                 variable_nb_elements,
96                 *value_types))
97 
98     def pylist(self, nb_elements=10, variable_nb_elements=True, *value_types):
99         return list(
100             self._pyiterable(
101                 nb_elements,
102                 variable_nb_elements,
103                 *value_types))
104 
105     def pyiterable(
106             self,
107             nb_elements=10,
108             variable_nb_elements=True,
109             *value_types):
110         return self.random_element([self.pylist, self.pytuple, self.pyset])(
111             nb_elements, variable_nb_elements, *value_types)
112 
113     def _random_type(self, type_list):
114         value_type = self.random_element(type_list)
115 
116         method_name = "py{0}".format(value_type)
117         if hasattr(self, method_name):
118             value_type = method_name
119 
120         return self.generator.format(value_type)
121 
122     def _pyiterable(
123             self,
124             nb_elements=10,
125             variable_nb_elements=True,
126             *value_types):
127 
128         value_types = [t if isinstance(t, six.string_types) else getattr(t, '__name__', type(t).__name__).lower()
129                        for t in value_types
130                        # avoid recursion
131                        if t not in ['iterable', 'list', 'tuple', 'dict', 'set']]
132         if not value_types:
133             value_types = ['str', 'str', 'str', 'str', 'float',
134                            'int', 'int', 'decimal', 'date_time', 'uri', 'email']
135 
136         if variable_nb_elements:
137             nb_elements = self.randomize_nb_elements(nb_elements, min=1)
138 
139         for _ in range(nb_elements):
140             yield self._random_type(value_types)
141 
142     def pydict(self, nb_elements=10, variable_nb_elements=True, *value_types):
143         """
144         Returns a dictionary.
145 
146         :nb_elements: number of elements for dictionary
147         :variable_nb_elements: is use variable number of elements for dictionary
148         :value_types: type of dictionary values
149         """
150         if variable_nb_elements:
151             nb_elements = self.randomize_nb_elements(nb_elements, min=1)
152 
153         return dict(zip(
154             self.generator.words(nb_elements),
155             self._pyiterable(nb_elements, False, *value_types),
156         ))
157 
158     def pystruct(self, count=10, *value_types):
159 
160         value_types = [t if isinstance(t, six.string_types) else getattr(t, '__name__', type(t).__name__).lower()
161                        for t in value_types
162                        # avoid recursion
163                        if t != 'struct']
164         if not value_types:
165             value_types = ['str', 'str', 'str', 'str', 'float',
166                            'int', 'int', 'decimal', 'date_time', 'uri', 'email']
167 
168         types = []
169         d = {}
170         nd = {}
171         for i in range(count):
172             d[self.generator.word()] = self._random_type(value_types)
173             types.append(self._random_type(value_types))
174             nd[self.generator.word()] = {i: self._random_type(value_types),
175                                          i + 1: [self._random_type(value_types),
176                                                  self._random_type(value_types),
177                                                  self._random_type(value_types)],
178                                          i + 2: {i: self._random_type(value_types),
179                                                  i + 1: self._random_type(value_types),
180                                                  i + 2: [self._random_type(value_types),
181                                                          self._random_type(value_types)]}}
182         return types, d, nd
183
```

Path: `faker/generator.py`
Content:
```
1 # coding=utf-8
2 
3 from __future__ import unicode_literals
4 
5 import random as random_module
6 import re
7 
8 _re_token = re.compile(r'\{\{(\s?)(\w+)(\s?)\}\}')
9 random = random_module.Random()
10 mod_random = random  # compat with name released in 0.8
11 
12 
13 class Generator(object):
14 
15     __config = {}
16 
17     def __init__(self, **config):
18         self.providers = []
19         self.__config = dict(
20             list(self.__config.items()) + list(config.items()))
21         self.__random = random
22 
23     def add_provider(self, provider):
24 
25         if isinstance(provider, type):
26             provider = provider(self)
27 
28         self.providers.insert(0, provider)
29 
30         for method_name in dir(provider):
31             # skip 'private' method
32             if method_name.startswith('_'):
33                 continue
34 
35             faker_function = getattr(provider, method_name)
36 
37             if callable(faker_function):
38                 # add all faker method to generator
39                 self.set_formatter(method_name, faker_function)
40 
41     def provider(self, name):
42         try:
43             lst = [p for p in self.get_providers()
44                    if p.__provider__ == name.lower()]
45             return lst[0]
46         except IndexError:
47             return None
48 
49     def get_providers(self):
50         """Returns added providers."""
51         return self.providers
52 
53     @property
54     def random(self):
55         return self.__random
56 
57     @random.setter
58     def random(self, value):
59         self.__random = value
60 
61     def seed_instance(self, seed=None):
62         """Calls random.seed"""
63         if self.__random == random:
64             # create per-instance random obj when first time seed_instance() is
65             # called
66             self.__random = random_module.Random()
67         self.__random.seed(seed)
68         return self
69 
70     @classmethod
71     def seed(cls, seed=None):
72         random.seed(seed)
73 
74     def format(self, formatter, *args, **kwargs):
75         """
76         This is a secure way to make a fake from another Provider.
77         """
78         # TODO: data export?
79         return self.get_formatter(formatter)(*args, **kwargs)
80 
81     def get_formatter(self, formatter):
82         try:
83             return getattr(self, formatter)
84         except AttributeError:
85             if 'locale' in self.__config:
86                 msg = 'Unknown formatter "{0}" with locale "{1}"'.format(
87                     formatter, self.__config['locale'],
88                 )
89             else:
90                 raise AttributeError('Unknown formatter "{0}"'.format(
91                     formatter,
92                 ))
93             raise AttributeError(msg)
94 
95     def set_formatter(self, name, method):
96         """
97         This method adds a provider method to generator.
98         Override this method to add some decoration or logging stuff.
99         """
100         setattr(self, name, method)
101 
102     def parse(self, text):
103         """
104         Replaces tokens (like '{{ tokenName }}' or '{{tokenName}}')
105         with the result from the token method call.
106         """
107         return _re_token.sub(self.__format_token, text)
108 
109     def __format_token(self, matches):
110         formatter = list(matches.groups())
111         formatter[1] = self.format(formatter[1])
112         return ''.join(formatter)
113
```
--- 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/generator.py b/faker/generator.py
--- a/faker/generator.py
+++ b/faker/generator.py
@@ -4,6 +4,7 @@
 
 import random as random_module
 import re
+import six
 
 _re_token = re.compile(r'\{\{(\s?)(\w+)(\s?)\}\}')
 random = random_module.Random()
@@ -108,5 +109,5 @@
 
     def __format_token(self, matches):
         formatter = list(matches.groups())
-        formatter[1] = self.format(formatter[1])
+        formatter[1] = six.text_type(self.format(formatter[1]))
         return ''.join(formatter)
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
@@ -3,6 +3,7 @@
 from __future__ import unicode_literals
 
 from decimal import Decimal
+import string
 import sys
 
 import six
@@ -32,6 +33,9 @@
                 ),
             )
 
+    def pystr_format(self, string_format='?#-###{{random_int}}{{random_letter}}', letters=string.ascii_letters):
+        return self.bothify(self.generator.parse(string_format), letters=letters)
+
     def pyfloat(self, left_digits=None, right_digits=None, positive=False,
                 min_value=None, max_value=None):

{"golden_diff": "diff --git a/faker/generator.py b/faker/generator.py\n--- a/faker/generator.py\n+++ b/faker/generator.py\n@@ -4,6 +4,7 @@\n \n import random as random_module\n import re\n+import six\n \n _re_token = re.compile(r'\\{\\{(\\s?)(\\w+)(\\s?)\\}\\}')\n random = random_module.Random()\n@@ -108,5 +109,5 @@\n \n     def __format_token(self, matches):\n         formatter = list(matches.groups())\n-        formatter[1] = self.format(formatter[1])\n+        formatter[1] = six.text_type(self.format(formatter[1]))\n         return ''.join(formatter)\ndiff --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@@ -3,6 +3,7 @@\n from __future__ import unicode_literals\n \n from decimal import Decimal\n+import string\n import sys\n \n import six\n@@ -32,6 +33,9 @@\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", "issue": "Would a faker.format() method make sense?\nIt could enable the syntax:\n`print(faker.format('{name} considers a {catch_phrase} in {country}'))`\n\nA sample implementation show how simple it would be:\n\n``` python\ndef fake_fmt(fmt=\"{first_name}'s favorite number: {random_int}\", fake=None):\n    fake = fake or Faker()\n    fields = [fld.split('}')[0].split(':')[0] for fld in fmt.split('{')[1:]]\n    return fmt.format(**{field: getattr(fake, field)() for field in fields})\n```\n\nMore test cases at: https://github.com/cclauss/Ten-lines-or-less/blob/master/fake_format.py\n\nFake Part Numbers, Names & Descriptions\nIs there any interest in adding fake part numbers, names and descriptions? I could see this used for seeding product tables. Examples:\r\n `fake.part_number()`\r\n`# MHP-17854623`\r\n\r\n`fake.part_name()`\r\n`# MOSFET Oscillator`\r\n\r\n`fake.part_description()`\r\n`# Electrical Coil Sensor DC Block Type`\r\n\r\nI recently had a project where I had to seed a product table, and I'd be happy to do a PR.\n", "before_files": [{"content": "# coding=utf-8\n\nfrom __future__ import unicode_literals\n\nfrom decimal import Decimal\nimport sys\n\nimport six\n\nfrom .. import BaseProvider\n\n\nclass Provider(BaseProvider):\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 minium length\"\n            return \"\".join(\n                self.random_letters(\n                    length=self.generator.random.randint(min_chars, max_chars),\n                ),\n            )\n\n    def pyfloat(self, left_digits=None, right_digits=None, positive=False,\n                min_value=None, max_value=None):\n\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\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 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\n            left_number = self.random_int(min_value, max_value - 1)\n        else:\n            sign = '+' if positive else self.random_element(('+', '-'))\n            left_number = self.random_number(left_digits)\n\n        return float(\"{0}{1}.{2}\".format(\n            sign,\n            left_number,\n            self.random_number(right_digits),\n        ))\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):\n        return tuple(\n            self.pyset(\n                nb_elements,\n                variable_nb_elements,\n                *value_types))\n\n    def pyset(self, nb_elements=10, variable_nb_elements=True, *value_types):\n        return set(\n            self._pyiterable(\n                nb_elements,\n                variable_nb_elements,\n                *value_types))\n\n    def pylist(self, nb_elements=10, variable_nb_elements=True, *value_types):\n        return list(\n            self._pyiterable(\n                nb_elements,\n                variable_nb_elements,\n                *value_types))\n\n    def pyiterable(\n            self,\n            nb_elements=10,\n            variable_nb_elements=True,\n            *value_types):\n        return self.random_element([self.pylist, self.pytuple, self.pyset])(\n            nb_elements, variable_nb_elements, *value_types)\n\n    def _random_type(self, type_list):\n        value_type = self.random_element(type_list)\n\n        method_name = \"py{0}\".format(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):\n\n        value_types = [t if isinstance(t, six.string_types) 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 = ['str', 'str', 'str', 'str', 'float',\n                           'int', 'int', 'decimal', 'date_time', 'uri', 'email']\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):\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),\n            self._pyiterable(nb_elements, False, *value_types),\n        ))\n\n    def pystruct(self, count=10, *value_types):\n\n        value_types = [t if isinstance(t, six.string_types) 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 = ['str', 'str', 'str', 'str', 'float',\n                           'int', 'int', 'decimal', 'date_time', 'uri', 'email']\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"}, {"content": "# coding=utf-8\n\nfrom __future__ import unicode_literals\n\nimport random as random_module\nimport re\n\n_re_token = re.compile(r'\\{\\{(\\s?)(\\w+)(\\s?)\\}\\}')\nrandom = random_module.Random()\nmod_random = random  # compat with name released in 0.8\n\n\nclass Generator(object):\n\n    __config = {}\n\n    def __init__(self, **config):\n        self.providers = []\n        self.__config = dict(\n            list(self.__config.items()) + list(config.items()))\n        self.__random = random\n\n    def add_provider(self, provider):\n\n        if isinstance(provider, type):\n            provider = provider(self)\n\n        self.providers.insert(0, provider)\n\n        for method_name in dir(provider):\n            # skip 'private' method\n            if method_name.startswith('_'):\n                continue\n\n            faker_function = getattr(provider, method_name)\n\n            if callable(faker_function):\n                # add all faker method to generator\n                self.set_formatter(method_name, faker_function)\n\n    def provider(self, name):\n        try:\n            lst = [p for p in self.get_providers()\n                   if p.__provider__ == name.lower()]\n            return lst[0]\n        except IndexError:\n            return None\n\n    def get_providers(self):\n        \"\"\"Returns added providers.\"\"\"\n        return self.providers\n\n    @property\n    def random(self):\n        return self.__random\n\n    @random.setter\n    def random(self, value):\n        self.__random = value\n\n    def seed_instance(self, seed=None):\n        \"\"\"Calls random.seed\"\"\"\n        if self.__random == random:\n            # create per-instance random obj when first time seed_instance() is\n            # called\n            self.__random = random_module.Random()\n        self.__random.seed(seed)\n        return self\n\n    @classmethod\n    def seed(cls, seed=None):\n        random.seed(seed)\n\n    def format(self, formatter, *args, **kwargs):\n        \"\"\"\n        This is a secure way to make a fake from another Provider.\n        \"\"\"\n        # TODO: data export?\n        return self.get_formatter(formatter)(*args, **kwargs)\n\n    def get_formatter(self, formatter):\n        try:\n            return getattr(self, formatter)\n        except AttributeError:\n            if 'locale' in self.__config:\n                msg = 'Unknown formatter \"{0}\" with locale \"{1}\"'.format(\n                    formatter, self.__config['locale'],\n                )\n            else:\n                raise AttributeError('Unknown formatter \"{0}\"'.format(\n                    formatter,\n                ))\n            raise AttributeError(msg)\n\n    def set_formatter(self, name, method):\n        \"\"\"\n        This method adds a provider method to generator.\n        Override this method to add some decoration or logging stuff.\n        \"\"\"\n        setattr(self, name, method)\n\n    def parse(self, text):\n        \"\"\"\n        Replaces tokens (like '{{ tokenName }}' or '{{tokenName}}')\n        with the result from the token method call.\n        \"\"\"\n        return _re_token.sub(self.__format_token, text)\n\n    def __format_token(self, matches):\n        formatter = list(matches.groups())\n        formatter[1] = self.format(formatter[1])\n        return ''.join(formatter)\n", "path": "faker/generator.py"}], "after_files": [{"content": "# coding=utf-8\n\nfrom __future__ import unicode_literals\n\nfrom decimal import Decimal\nimport string\nimport sys\n\nimport six\n\nfrom .. import BaseProvider\n\n\nclass Provider(BaseProvider):\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 minium 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\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\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 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\n            left_number = self.random_int(min_value, max_value - 1)\n        else:\n            sign = '+' if positive else self.random_element(('+', '-'))\n            left_number = self.random_number(left_digits)\n\n        return float(\"{0}{1}.{2}\".format(\n            sign,\n            left_number,\n            self.random_number(right_digits),\n        ))\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):\n        return tuple(\n            self.pyset(\n                nb_elements,\n                variable_nb_elements,\n                *value_types))\n\n    def pyset(self, nb_elements=10, variable_nb_elements=True, *value_types):\n        return set(\n            self._pyiterable(\n                nb_elements,\n                variable_nb_elements,\n                *value_types))\n\n    def pylist(self, nb_elements=10, variable_nb_elements=True, *value_types):\n        return list(\n            self._pyiterable(\n                nb_elements,\n                variable_nb_elements,\n                *value_types))\n\n    def pyiterable(\n            self,\n            nb_elements=10,\n            variable_nb_elements=True,\n            *value_types):\n        return self.random_element([self.pylist, self.pytuple, self.pyset])(\n            nb_elements, variable_nb_elements, *value_types)\n\n    def _random_type(self, type_list):\n        value_type = self.random_element(type_list)\n\n        method_name = \"py{0}\".format(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):\n\n        value_types = [t if isinstance(t, six.string_types) 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 = ['str', 'str', 'str', 'str', 'float',\n                           'int', 'int', 'decimal', 'date_time', 'uri', 'email']\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):\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),\n            self._pyiterable(nb_elements, False, *value_types),\n        ))\n\n    def pystruct(self, count=10, *value_types):\n\n        value_types = [t if isinstance(t, six.string_types) 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 = ['str', 'str', 'str', 'str', 'float',\n                           'int', 'int', 'decimal', 'date_time', 'uri', 'email']\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"}, {"content": "# coding=utf-8\n\nfrom __future__ import unicode_literals\n\nimport random as random_module\nimport re\nimport six\n\n_re_token = re.compile(r'\\{\\{(\\s?)(\\w+)(\\s?)\\}\\}')\nrandom = random_module.Random()\nmod_random = random  # compat with name released in 0.8\n\n\nclass Generator(object):\n\n    __config = {}\n\n    def __init__(self, **config):\n        self.providers = []\n        self.__config = dict(\n            list(self.__config.items()) + list(config.items()))\n        self.__random = random\n\n    def add_provider(self, provider):\n\n        if isinstance(provider, type):\n            provider = provider(self)\n\n        self.providers.insert(0, provider)\n\n        for method_name in dir(provider):\n            # skip 'private' method\n            if method_name.startswith('_'):\n                continue\n\n            faker_function = getattr(provider, method_name)\n\n            if callable(faker_function):\n                # add all faker method to generator\n                self.set_formatter(method_name, faker_function)\n\n    def provider(self, name):\n        try:\n            lst = [p for p in self.get_providers()\n                   if p.__provider__ == name.lower()]\n            return lst[0]\n        except IndexError:\n            return None\n\n    def get_providers(self):\n        \"\"\"Returns added providers.\"\"\"\n        return self.providers\n\n    @property\n    def random(self):\n        return self.__random\n\n    @random.setter\n    def random(self, value):\n        self.__random = value\n\n    def seed_instance(self, seed=None):\n        \"\"\"Calls random.seed\"\"\"\n        if self.__random == random:\n            # create per-instance random obj when first time seed_instance() is\n            # called\n            self.__random = random_module.Random()\n        self.__random.seed(seed)\n        return self\n\n    @classmethod\n    def seed(cls, seed=None):\n        random.seed(seed)\n\n    def format(self, formatter, *args, **kwargs):\n        \"\"\"\n        This is a secure way to make a fake from another Provider.\n        \"\"\"\n        # TODO: data export?\n        return self.get_formatter(formatter)(*args, **kwargs)\n\n    def get_formatter(self, formatter):\n        try:\n            return getattr(self, formatter)\n        except AttributeError:\n            if 'locale' in self.__config:\n                msg = 'Unknown formatter \"{0}\" with locale \"{1}\"'.format(\n                    formatter, self.__config['locale'],\n                )\n            else:\n                raise AttributeError('Unknown formatter \"{0}\"'.format(\n                    formatter,\n                ))\n            raise AttributeError(msg)\n\n    def set_formatter(self, name, method):\n        \"\"\"\n        This method adds a provider method to generator.\n        Override this method to add some decoration or logging stuff.\n        \"\"\"\n        setattr(self, name, method)\n\n    def parse(self, text):\n        \"\"\"\n        Replaces tokens (like '{{ tokenName }}' or '{{tokenName}}')\n        with the result from the token method call.\n        \"\"\"\n        return _re_token.sub(self.__format_token, text)\n\n    def __format_token(self, matches):\n        formatter = list(matches.groups())\n        formatter[1] = six.text_type(self.format(formatter[1]))\n        return ''.join(formatter)\n", "path": "faker/generator.py"}]}