We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Update python_requires in setup.py
https://github.com/joke2k/faker/blob/146f205b942d15c95160df35d3e431624697d079/setup.py#L65
Finnish IBAN should be 18 characters of length
* Faker version: 4.1.1

Finnish IBAN should be 18 characters of length. Currently returned Finnish IBAN has 20 characters.

### Steps to reproduce

```
from faker import Faker
>>> fake = Faker('fi_FI')
>>> fin_iban = fake.iban()
>>> fin_iban
'FI807370583252728936'
>>> len(fin_iban)
20
```

### Expected behavior

```
>>> len(fin_iban)
18
```

### Actual behavior

```
>>> len(fin_iban)
20
```


--- 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/generator.py`
Content:
```
1 import random as random_module
2 import re
3 
4 _re_token = re.compile(r'\{\{(\s?)(\w+)(\s?)\}\}')
5 random = random_module.Random()
6 mod_random = random  # compat with name released in 0.8
7 
8 
9 class Generator:
10 
11     __config = {}
12 
13     def __init__(self, **config):
14         self.providers = []
15         self.__config = dict(
16             list(self.__config.items()) + list(config.items()))
17         self.__random = random
18 
19     def add_provider(self, provider):
20 
21         if isinstance(provider, type):
22             provider = provider(self)
23 
24         self.providers.insert(0, provider)
25 
26         for method_name in dir(provider):
27             # skip 'private' method
28             if method_name.startswith('_'):
29                 continue
30 
31             faker_function = getattr(provider, method_name)
32 
33             if callable(faker_function):
34                 # add all faker method to generator
35                 self.set_formatter(method_name, faker_function)
36 
37     def provider(self, name):
38         try:
39             lst = [p for p in self.get_providers()
40                    if p.__provider__ == name.lower()]
41             return lst[0]
42         except IndexError:
43             return None
44 
45     def get_providers(self):
46         """Returns added providers."""
47         return self.providers
48 
49     @property
50     def random(self):
51         return self.__random
52 
53     @random.setter
54     def random(self, value):
55         self.__random = value
56 
57     def seed_instance(self, seed=None):
58         """Calls random.seed"""
59         if self.__random == random:
60             # create per-instance random obj when first time seed_instance() is
61             # called
62             self.__random = random_module.Random()
63         self.__random.seed(seed)
64         return self
65 
66     @classmethod
67     def seed(cls, seed=None):
68         random.seed(seed)
69 
70     def format(self, formatter, *args, **kwargs):
71         """
72         This is a secure way to make a fake from another Provider.
73         """
74         # TODO: data export?
75         return self.get_formatter(formatter)(*args, **kwargs)
76 
77     def get_formatter(self, formatter):
78         try:
79             return getattr(self, formatter)
80         except AttributeError:
81             if 'locale' in self.__config:
82                 msg = 'Unknown formatter "{}" with locale "{}"'.format(
83                     formatter, self.__config['locale'],
84                 )
85             else:
86                 raise AttributeError('Unknown formatter "{}"'.format(
87                     formatter,
88                 ))
89             raise AttributeError(msg)
90 
91     def set_formatter(self, name, method):
92         """
93         This method adds a provider method to generator.
94         Override this method to add some decoration or logging stuff.
95         """
96         setattr(self, name, method)
97 
98     def parse(self, text):
99         """
100         Replaces tokens (like '{{ tokenName }}' or '{{tokenName}}')
101         with the result from the token method call.
102         """
103         return _re_token.sub(self.__format_token, text)
104 
105     def __format_token(self, matches):
106         formatter = list(matches.groups())
107         formatter[1] = str(self.format(formatter[1]))
108         return ''.join(formatter)
109
```
--- 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
@@ -1,14 +1,16 @@
 import random as random_module
 import re
 
-_re_token = re.compile(r'\{\{(\s?)(\w+)(\s?)\}\}')
+_re_token = re.compile(r'\{\{\s*(\w+)(:\s*\w+?)?\s*\}\}')
 random = random_module.Random()
 mod_random = random  # compat with name released in 0.8
 
 
 class Generator:
 
-    __config = {}
+    __config = {
+        'arguments': {},
+    }
 
     def __init__(self, **config):
         self.providers = []
@@ -71,7 +73,6 @@
         """
         This is a secure way to make a fake from another Provider.
         """
-        # TODO: data export?
         return self.get_formatter(formatter)(*args, **kwargs)
 
     def get_formatter(self, formatter):
@@ -95,14 +96,84 @@
         """
         setattr(self, name, method)
 
+    def set_arguments(self, group, argument, value=None):
+        """
+        Creates an argument group, with an individual argument or a dictionary
+        of arguments.  Used with the Generator.parse method.
+
+        generator.set_arguments('small', 'max_value', 10)
+        generator.set_arguments('small', {'min_value': 5, 'max_value': 10})
+        """
+        if group not in self.__config['arguments']:
+            self.__config['arguments'][group] = {}
+
+        if isinstance(argument, dict):
+            self.__config['arguments'][group] = argument
+        elif not isinstance(argument, str):
+            raise ValueError("Arguments must be either a string or dictionary")
+        else:
+            self.__config['arguments'][group][argument] = value
+
+    def get_arguments(self, group, argument=None):
+        """
+        Get the value of an argument configured within a argument group, or
+        the entire group as a dictionary.
+
+        generator.get_arguments('small', 'max_value')
+        generator.get_arguments('small')
+        """
+        if group in self.__config['arguments'] and argument:
+            result = self.__config['arguments'][group].get(argument)
+        else:
+            result = self.__config['arguments'].get(group)
+
+        return result
+
+    def del_arguments(self, group, argument=None):
+        """
+        Delete an argument from an argument group or the entire
+        argument group.
+
+        generator.del_arguments('small')
+        generator.del_arguments('small', 'max_value')
+        """
+        if group in self.__config['arguments']:
+            if argument:
+                result = self.__config['arguments'][group].pop(argument)
+            else:
+                result = self.__config['arguments'].pop(group)
+        else:
+            result = None
+
+        return result
+
     def parse(self, text):
         """
         Replaces tokens (like '{{ tokenName }}' or '{{tokenName}}')
-        with the result from the token method call.
+        with the result from the token method call. Arguments can be
+        parsed by using an argument group. '{{ tokenName:group }}'
+
+        Example:
+
+        generator.set_arguments('red_rgb', {'hue': 'red', 'color_format': 'rgb'})
+        generator.set_arguments('small', 'max_value', 10)
+
+        generator.parse('{{ color:red_rgb }} - {{ pyint:small }}')
         """
         return _re_token.sub(self.__format_token, text)
 
     def __format_token(self, matches):
-        formatter = list(matches.groups())
-        formatter[1] = str(self.format(formatter[1]))
-        return ''.join(formatter)
+        formatter, argument_group = list(matches.groups())
+        argument_group = argument_group.lstrip(":").strip() if argument_group else ''
+
+        if argument_group:
+            try:
+                arguments = self.__config['arguments'][argument_group]
+            except KeyError:
+                raise AttributeError('Unknown argument group "{}"'.format(argument_group))
+
+            formatted = str(self.format(formatter, **arguments))
+        else:
+            formatted = str(self.format(formatter))
+
+        return ''.join(formatted)

{"golden_diff": "diff --git a/faker/generator.py b/faker/generator.py\n--- a/faker/generator.py\n+++ b/faker/generator.py\n@@ -1,14 +1,16 @@\n import random as random_module\n import re\n \n-_re_token = re.compile(r'\\{\\{(\\s?)(\\w+)(\\s?)\\}\\}')\n+_re_token = re.compile(r'\\{\\{\\s*(\\w+)(:\\s*\\w+?)?\\s*\\}\\}')\n random = random_module.Random()\n mod_random = random  # compat with name released in 0.8\n \n \n class Generator:\n \n-    __config = {}\n+    __config = {\n+        'arguments': {},\n+    }\n \n     def __init__(self, **config):\n         self.providers = []\n@@ -71,7 +73,6 @@\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@@ -95,14 +96,84 @@\n         \"\"\"\n         setattr(self, name, method)\n \n+    def set_arguments(self, group, argument, value=None):\n+        \"\"\"\n+        Creates an argument group, with an individual argument or a dictionary\n+        of arguments.  Used with the Generator.parse method.\n+\n+        generator.set_arguments('small', 'max_value', 10)\n+        generator.set_arguments('small', {'min_value': 5, 'max_value': 10})\n+        \"\"\"\n+        if group not in self.__config['arguments']:\n+            self.__config['arguments'][group] = {}\n+\n+        if isinstance(argument, dict):\n+            self.__config['arguments'][group] = argument\n+        elif not isinstance(argument, str):\n+            raise ValueError(\"Arguments must be either a string or dictionary\")\n+        else:\n+            self.__config['arguments'][group][argument] = value\n+\n+    def get_arguments(self, group, argument=None):\n+        \"\"\"\n+        Get the value of an argument configured within a argument group, or\n+        the entire group as a dictionary.\n+\n+        generator.get_arguments('small', 'max_value')\n+        generator.get_arguments('small')\n+        \"\"\"\n+        if group in self.__config['arguments'] and argument:\n+            result = self.__config['arguments'][group].get(argument)\n+        else:\n+            result = self.__config['arguments'].get(group)\n+\n+        return result\n+\n+    def del_arguments(self, group, argument=None):\n+        \"\"\"\n+        Delete an argument from an argument group or the entire\n+        argument group.\n+\n+        generator.del_arguments('small')\n+        generator.del_arguments('small', 'max_value')\n+        \"\"\"\n+        if group in self.__config['arguments']:\n+            if argument:\n+                result = self.__config['arguments'][group].pop(argument)\n+            else:\n+                result = self.__config['arguments'].pop(group)\n+        else:\n+            result = None\n+\n+        return result\n+\n     def parse(self, text):\n         \"\"\"\n         Replaces tokens (like '{{ tokenName }}' or '{{tokenName}}')\n-        with the result from the token method call.\n+        with the result from the token method call. Arguments can be\n+        parsed by using an argument group. '{{ tokenName:group }}'\n+\n+        Example:\n+\n+        generator.set_arguments('red_rgb', {'hue': 'red', 'color_format': 'rgb'})\n+        generator.set_arguments('small', 'max_value', 10)\n+\n+        generator.parse('{{ color:red_rgb }} - {{ pyint:small }}')\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] = str(self.format(formatter[1]))\n-        return ''.join(formatter)\n+        formatter, argument_group = list(matches.groups())\n+        argument_group = argument_group.lstrip(\":\").strip() if argument_group else ''\n+\n+        if argument_group:\n+            try:\n+                arguments = self.__config['arguments'][argument_group]\n+            except KeyError:\n+                raise AttributeError('Unknown argument group \"{}\"'.format(argument_group))\n+\n+            formatted = str(self.format(formatter, **arguments))\n+        else:\n+            formatted = str(self.format(formatter))\n+\n+        return ''.join(formatted)\n", "issue": "Update python_requires in setup.py\nhttps://github.com/joke2k/faker/blob/146f205b942d15c95160df35d3e431624697d079/setup.py#L65\nFinnish IBAN should be 18 characters of length\n* Faker version: 4.1.1\r\n\r\nFinnish IBAN should be 18 characters of length. Currently returned Finnish IBAN has 20 characters.\r\n\r\n### Steps to reproduce\r\n\r\n```\r\nfrom faker import Faker\r\n>>> fake = Faker('fi_FI')\r\n>>> fin_iban = fake.iban()\r\n>>> fin_iban\r\n'FI807370583252728936'\r\n>>> len(fin_iban)\r\n20\r\n```\r\n\r\n### Expected behavior\r\n\r\n```\r\n>>> len(fin_iban)\r\n18\r\n```\r\n\r\n### Actual behavior\r\n\r\n```\r\n>>> len(fin_iban)\r\n20\r\n```\r\n\n", "before_files": [{"content": "import 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:\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 \"{}\" with locale \"{}\"'.format(\n                    formatter, self.__config['locale'],\n                )\n            else:\n                raise AttributeError('Unknown formatter \"{}\"'.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] = str(self.format(formatter[1]))\n        return ''.join(formatter)\n", "path": "faker/generator.py"}], "after_files": [{"content": "import random as random_module\nimport re\n\n_re_token = re.compile(r'\\{\\{\\s*(\\w+)(:\\s*\\w+?)?\\s*\\}\\}')\nrandom = random_module.Random()\nmod_random = random  # compat with name released in 0.8\n\n\nclass Generator:\n\n    __config = {\n        'arguments': {},\n    }\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        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 \"{}\" with locale \"{}\"'.format(\n                    formatter, self.__config['locale'],\n                )\n            else:\n                raise AttributeError('Unknown formatter \"{}\"'.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 set_arguments(self, group, argument, value=None):\n        \"\"\"\n        Creates an argument group, with an individual argument or a dictionary\n        of arguments.  Used with the Generator.parse method.\n\n        generator.set_arguments('small', 'max_value', 10)\n        generator.set_arguments('small', {'min_value': 5, 'max_value': 10})\n        \"\"\"\n        if group not in self.__config['arguments']:\n            self.__config['arguments'][group] = {}\n\n        if isinstance(argument, dict):\n            self.__config['arguments'][group] = argument\n        elif not isinstance(argument, str):\n            raise ValueError(\"Arguments must be either a string or dictionary\")\n        else:\n            self.__config['arguments'][group][argument] = value\n\n    def get_arguments(self, group, argument=None):\n        \"\"\"\n        Get the value of an argument configured within a argument group, or\n        the entire group as a dictionary.\n\n        generator.get_arguments('small', 'max_value')\n        generator.get_arguments('small')\n        \"\"\"\n        if group in self.__config['arguments'] and argument:\n            result = self.__config['arguments'][group].get(argument)\n        else:\n            result = self.__config['arguments'].get(group)\n\n        return result\n\n    def del_arguments(self, group, argument=None):\n        \"\"\"\n        Delete an argument from an argument group or the entire\n        argument group.\n\n        generator.del_arguments('small')\n        generator.del_arguments('small', 'max_value')\n        \"\"\"\n        if group in self.__config['arguments']:\n            if argument:\n                result = self.__config['arguments'][group].pop(argument)\n            else:\n                result = self.__config['arguments'].pop(group)\n        else:\n            result = None\n\n        return result\n\n    def parse(self, text):\n        \"\"\"\n        Replaces tokens (like '{{ tokenName }}' or '{{tokenName}}')\n        with the result from the token method call. Arguments can be\n        parsed by using an argument group. '{{ tokenName:group }}'\n\n        Example:\n\n        generator.set_arguments('red_rgb', {'hue': 'red', 'color_format': 'rgb'})\n        generator.set_arguments('small', 'max_value', 10)\n\n        generator.parse('{{ color:red_rgb }} - {{ pyint:small }}')\n        \"\"\"\n        return _re_token.sub(self.__format_token, text)\n\n    def __format_token(self, matches):\n        formatter, argument_group = list(matches.groups())\n        argument_group = argument_group.lstrip(\":\").strip() if argument_group else ''\n\n        if argument_group:\n            try:\n                arguments = self.__config['arguments'][argument_group]\n            except KeyError:\n                raise AttributeError('Unknown argument group \"{}\"'.format(argument_group))\n\n            formatted = str(self.format(formatter, **arguments))\n        else:\n            formatted = str(self.format(formatter))\n\n        return ''.join(formatted)\n", "path": "faker/generator.py"}]}