Repository: joke2k/faker

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.


Discussion:
Any definite plans to include this?  
Hi @gamesbook ,

I'm still waiting on someone to submit a PR. Feel free to take this on :)
I'm not sure about `part_name` and `description`, since they could be already achieved with `words()`. I can see a common enough case for `part_number`, but I don't think there's enough of a common _format_ for it.

I'd rather see the `pystr()` method extended to accept a `format` parameter, so you could call `Faker.pystr(format='???-#####')`

see also #362 

Resolving patch:
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 parse(self, text):
 
     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(self, min_chars=None, max_chars=20):
                 ),
             )
 
+    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_python.py b/tests/providers/test_python.py
--- 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 @@ def test_max_value_should_be_greater_than_min_value(self):
 
         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')