Repository: joke2k/faker
Pull request #1245 (2020-08-13 16:08:30)

Upgrade pytest to version 6
### What does this changes

The unique change affected for 6 version is the mandatory use of keyword arguments in fixtures decorators, proposed in [this issue](https://github.com/pytest-dev/pytest/issues/1682).

### What was wrong

Running the test suite with pytest 6 raises next warning error:

```
Passing arguments to pytest.fixture() as positional arguments is deprecated - pass them as a keyword argument instead
```

### How this fixes it

Use `scope='class'` in `tests/providers/test_barcode.py` fixture.



Patch:
diff --git a/faker/generator.py b/faker/generator.py
index 0402659b..46f176d1 100644
--- 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 @@ class Generator:
         """
         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 @@ class Generator:
         """
         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)
diff --git a/tox.ini b/tox.ini
index 72cab4a1..0bf3dbcd 100644
--- a/tox.ini
+++ b/tox.ini
@@ -6,7 +6,7 @@ skip_missing_interpreters = true
 deps =
     coverage
     freezegun<0.4
-    pytest>=5.4.0,<5.5
+    pytest>=6.0.1
     random2
     ukpostcodeparser>=1.1.1
     validators>=0.13.0


Test patch:
diff --git a/tests/providers/test_barcode.py b/tests/providers/test_barcode.py
index 8fee0fc3..614e1a5d 100644
--- a/tests/providers/test_barcode.py
+++ b/tests/providers/test_barcode.py
@@ -66,7 +66,7 @@ class TestBarcodeProvider:
             assert (sum(ean13_digits) + 2 * sum(ean13_digits[1::2])) % 10 == 0
 
 
-@pytest.fixture('class')
+@pytest.fixture(scope='class')
 def provider_class(request):
     if hasattr(request.cls, 'get_provider_class') and callable(request.cls.get_provider_class):
         _provider_class = request.cls.get_provider_class()
diff --git a/tests/test_generator.py b/tests/test_generator.py
index b7e58a0d..c38cbd75 100644
--- a/tests/test_generator.py
+++ b/tests/test_generator.py
@@ -17,7 +17,7 @@ class FooProvider:
         return 'foobar'
 
     def foo_formatter_with_arguments(self, param='', append=''):
-        return 'baz' + param + append
+        return 'baz' + str(param) + str(append)
 
 
 @pytest.fixture(autouse=True)
@@ -61,7 +61,41 @@ class TestGenerator:
 
     def test_parse_with_valid_formatter_tokens(self, generator):
         result = generator.parse('This is {{foo_formatter}} a text with "{{ foo_formatter }}"')
-        assert result == 'This is foobar a text with " foobar "'
+        assert result == 'This is foobar a text with "foobar"'
+
+    def test_arguments_group_with_values(self, generator):
+        generator.set_arguments('group1', 'argument1', 1)
+        generator.set_arguments('group1', 'argument2', 2)
+        assert generator.get_arguments('group1', 'argument1') == 1
+        assert generator.del_arguments('group1', 'argument2') == 2
+        assert generator.get_arguments('group1', 'argument2') is None
+        assert generator.get_arguments('group1') == {'argument1': 1}
+
+    def test_arguments_group_with_dictionaries(self, generator):
+        generator.set_arguments('group2', {'argument1': 3, 'argument2': 4})
+        assert generator.get_arguments('group2') == {'argument1': 3, 'argument2': 4}
+        assert generator.del_arguments('group2') == {'argument1': 3, 'argument2': 4}
+        assert generator.get_arguments('group2') is None
+
+    def test_arguments_group_with_invalid_name(self, generator):
+        assert generator.get_arguments('group3') is None
+        assert generator.del_arguments('group3') is None
+
+    def test_arguments_group_with_invalid_argument_type(self, generator):
+        with pytest.raises(ValueError) as excinfo:
+            generator.set_arguments('group', ['foo', 'bar'])
+        assert str(excinfo.value) == "Arguments must be either a string or dictionary"
+
+    def test_parse_with_valid_formatter_arguments(self, generator):
+        generator.set_arguments('format_name', {"param": "foo", "append": "bar"})
+        result = generator.parse('This is "{{foo_formatter_with_arguments:format_name}}"')
+        generator.del_arguments('format_name')
+        assert result == 'This is "bazfoobar"'
+
+    def test_parse_with_unknown_arguments_group(self, generator):
+        with pytest.raises(AttributeError) as excinfo:
+            generator.parse('This is "{{foo_formatter_with_arguments:unknown}}"')
+        assert str(excinfo.value) == 'Unknown argument group "unknown"'
 
     def test_parse_with_unknown_formatter_token(self, generator):
         with pytest.raises(AttributeError) as excinfo: