Repository: HypothesisWorks/hypothesis

Issue:
Formally deprecate hypothesis.extra.fakefactory
As far as I know, `hypothesis.extra.fakefactory` exists mostly because Hypothesis didn't have an `emails()` strategy when the Django extra needed to infer a strategy for `EmailField`s.  Now we do - and `fakefactory()` is neither used internally nor recommended for users.

My view is that we should either deprecate this extra (my preference), or decide to support it properly (including newer versions and better shrinking).

Is there more background that I'm missing?  Would anyone object to removing it after a deprecation period?


Discussion:
I'm keen on formally deprecating it, yeah. It would in some way be nice to be able to take advantage of their generators, but I don't think we can do it via the official API - it's pretty unsuitable for the Hypothesis model.

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -44,7 +44,7 @@ def local_file(name):
 extras = {
     'datetime':  ['pytz'],
     'pytz':  ['pytz'],
-    'fakefactory': ['Faker>=0.7.0,<=0.7.1'],
+    'fakefactory': ['Faker>=0.7'],
     'django': ['pytz', 'django>=1.8,<2'],
     'numpy': ['numpy>=1.9.0'],
     'pytest': ['pytest>=2.8.0'],
diff --git a/src/hypothesis/extra/fakefactory.py b/src/hypothesis/extra/fakefactory.py
--- a/src/hypothesis/extra/fakefactory.py
+++ b/src/hypothesis/extra/fakefactory.py
@@ -23,12 +23,18 @@
 import faker
 from faker.factory import AVAILABLE_LOCALES
 
+from hypothesis._settings import note_deprecation
 from hypothesis.internal.compat import text_type
 from hypothesis.internal.reflection import check_valid_identifier
 from hypothesis.searchstrategy.strategies import SearchStrategy
 
 
 def fake_factory(source, locale=None, locales=None, providers=()):
+    note_deprecation(
+        'hypothesis.extra.fakefactory has been deprecated, because it does '
+        'not support example discovery or shrinking.  Consider using a lower-'
+        'level strategy (such as st.text()) instead.'
+    )
     check_valid_identifier(source)
     if source[0] == u'_':
         raise ValueError(u'Bad source name %s' % (source,))


Test patch:
diff --git a/tests/fakefactory/test_fake_factory.py b/tests/fakefactory/test_fake_factory.py
--- a/tests/fakefactory/test_fake_factory.py
+++ b/tests/fakefactory/test_fake_factory.py
@@ -22,6 +22,7 @@
 
 from hypothesis import given
 from tests.common.debug import minimal
+from tests.common.utils import checks_deprecated_behaviour
 from hypothesis.extra.fakefactory import fake_factory
 
 
@@ -31,21 +32,34 @@ def kittens(self):
         return u'meow %d' % (self.random_number(digits=10),)
 
 
-@given(fake_factory(u'kittens', providers=[KittenProvider]))
-def test_kittens_meow(kitten):
-    assert u'meow' in kitten
+@checks_deprecated_behaviour
+def test_kittens_meow():
+    @given(fake_factory(u'kittens', providers=[KittenProvider]))
+    def inner(kitten):
+        assert u'meow' in kitten
 
+    inner()
 
-@given(fake_factory(u'email'))
-def test_email(email):
-    assert u'@' in email
 
+@checks_deprecated_behaviour
+def test_email():
+    @given(fake_factory(u'email'))
+    def inner(email):
+        assert u'@' in email
 
-@given(fake_factory(u'name', locale=u'en_US'))
-def test_english_names_are_ascii(name):
-    name.encode(u'ascii')
+    inner()
 
 
+@checks_deprecated_behaviour
+def test_english_names_are_ascii():
+    @given(fake_factory(u'name', locale=u'en_US'))
+    def inner(name):
+        name.encode(u'ascii')
+
+    inner()
+
+
+@checks_deprecated_behaviour
 def test_french_names_may_have_an_accent():
     minimal(
         fake_factory(u'name', locale=u'fr_FR'),
@@ -53,6 +67,7 @@ def test_french_names_may_have_an_accent():
     )
 
 
+@checks_deprecated_behaviour
 def test_fake_factory_errors_with_both_locale_and_locales():
     with pytest.raises(ValueError):
         fake_factory(
@@ -60,6 +75,7 @@ def test_fake_factory_errors_with_both_locale_and_locales():
         )
 
 
+@checks_deprecated_behaviour
 def test_fake_factory_errors_with_unsupported_locale():
     with pytest.raises(ValueError):
         fake_factory(
@@ -67,11 +83,13 @@ def test_fake_factory_errors_with_unsupported_locale():
         )
 
 
+@checks_deprecated_behaviour
 def test_factory_errors_with_source_for_unsupported_locale():
     with pytest.raises(ValueError):
         fake_factory(u'state', locale=u'ja_JP')
 
 
+@checks_deprecated_behaviour
 def test_fake_factory_errors_if_any_locale_is_unsupported():
     with pytest.raises(ValueError):
         fake_factory(
@@ -79,11 +97,13 @@ def test_fake_factory_errors_if_any_locale_is_unsupported():
         )
 
 
+@checks_deprecated_behaviour
 def test_fake_factory_errors_if_unsupported_method():
     with pytest.raises(ValueError):
         fake_factory(u'spoon')
 
 
+@checks_deprecated_behaviour
 def test_fake_factory_errors_if_private_ish_method():
     with pytest.raises(ValueError):
         fake_factory(u'_Generator__config')