Repository: joke2k/faker

Issue:
Not possible to seed uuid4
It is not possible to seed the uuid4 property.

```
>>> f1 = Faker()
>>> f1.seed(4321)
>>> print(f1.uuid4())
4a6d35db-b61b-49ed-a225-e16bc164f7cc

>>> f2 = Faker()
>>> f2.seed(4321)
>>> print(f2.uuid4())
b5f05be8-2f57-4a52-9b6f-5bcd03125278

```

The solution is pretty much given in:
http://stackoverflow.com/questions/41186818/how-to-generate-a-random-uuid-which-is-reproducible-with-a-seed-in-python

Comments:

Patch:
diff --git a/build32bit.sh b/build32bit.sh
index c493d7f3..c9df66f0 100755
--- a/build32bit.sh
+++ b/build32bit.sh
@@ -10,6 +10,7 @@ docker run -v ${PWD}:/code -e INSTALL_REQUIREMENTS=${INSTALL_REQUIREMENTS} i386/
     && DEBIAN_FRONTEND=noninteractive apt-get install -yq python3 locales python3-pip debianutils \
     && pip3 install tox coveralls \
     && locale-gen en_US.UTF-8 \
+    && export LANG='en_US.UTF-8' \
     && cd /code \
     && coverage run --source=faker setup.py test \
     && coverage report"
diff --git a/faker/generator.py b/faker/generator.py
index 40135a1b..b66b89bb 100644
--- a/faker/generator.py
+++ b/faker/generator.py
@@ -4,6 +4,7 @@ from __future__ import unicode_literals
 
 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 @@ class Generator(object):
 
     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
index eb8a70a6..36317627 100644
--- 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 @@ class Provider(BaseProvider):
                 ),
             )
 
+    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):
 


Test patch:
diff --git a/tests/providers/test_misc.py b/tests/providers/test_misc.py
index 1ee2476e..be2806f0 100644
--- a/tests/providers/test_misc.py
+++ b/tests/providers/test_misc.py
@@ -24,3 +24,15 @@ class TestMisc(unittest.TestCase):
         uuid4 = self.factory.uuid4(cast_to=lambda x: x)
         assert uuid4
         assert isinstance(uuid4, uuid.UUID)
+
+    def test_uuid4_seedability(self):
+        for _ in range(10):
+            random_seed = self.factory.random_int()
+            baseline_fake = Faker()
+            baseline_fake.seed(random_seed)
+            expected_uuids = [baseline_fake.uuid4() for i in range(1000)]
+
+            new_fake = Faker()
+            new_fake.seed(random_seed)
+            new_uuids = [new_fake.uuid4() for i in range(1000)]
+            assert new_uuids == expected_uuids
diff --git a/tests/providers/test_python.py b/tests/providers/test_python.py
index 61f5ca02..ccb93c79 100644
--- a/tests/providers/test_python.py
+++ b/tests/providers/test_python.py
@@ -1,6 +1,10 @@
 #  -*- coding: utf-8 -*-
 
 import unittest
+try:
+    from unittest.mock import patch
+except ImportError:
+    from mock import patch
 
 from faker import Faker
 
@@ -87,3 +91,19 @@ class TestPyfloat(unittest.TestCase):
 
         message = str(raises.exception)
         self.assertEqual(message, expected_message)
+
+
+class TestPystrFormat(unittest.TestCase):
+
+    def setUp(self):
+        self.factory = Faker(includes=['tests.mymodule.en_US'])
+
+    def test_formatter_invocation(self):
+        with patch.object(self.factory, 'foo') as mock_foo:
+            with patch('faker.providers.BaseProvider.bothify',
+                       wraps=self.factory.bothify) as mock_bothify:
+                mock_foo.return_value = 'barbar'
+                value = self.factory.pystr_format('{{foo}}?#?{{foo}}?#?{{foo}}', letters='abcde')
+                assert value.count('barbar') == 3
+                assert mock_foo.call_count == 3
+                mock_bothify.assert_called_once_with('barbar?#?barbar?#?barbar', letters='abcde')