fakefactory.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. # coding=utf-8
  2. #
  3. # This file is part of Hypothesis, which may be found at
  4. # https://github.com/HypothesisWorks/hypothesis-python
  5. #
  6. # Most of this work is copyright (C) 2013-2018 David R. MacIver
  7. # (david@drmaciver.com), but it contains contributions by others. See
  8. # CONTRIBUTING.rst for a full list of people who may hold copyright, and
  9. # consult the git log if you need to determine who owns an individual
  10. # contribution.
  11. #
  12. # This Source Code Form is subject to the terms of the Mozilla Public License,
  13. # v. 2.0. If a copy of the MPL was not distributed with this file, You can
  14. # obtain one at http://mozilla.org/MPL/2.0/.
  15. #
  16. # END HEADER
  17. from __future__ import division, print_function, absolute_import
  18. import random as globalrandom
  19. from random import Random
  20. import faker
  21. from faker.factory import AVAILABLE_LOCALES
  22. from hypothesis._settings import note_deprecation
  23. from hypothesis.internal.compat import text_type
  24. from hypothesis.internal.reflection import check_valid_identifier
  25. from hypothesis.searchstrategy.strategies import SearchStrategy
  26. def fake_factory(source, locale=None, locales=None, providers=()):
  27. note_deprecation(
  28. 'hypothesis.extra.fakefactory has been deprecated, because it does '
  29. 'not support example discovery or shrinking. Consider using a lower-'
  30. 'level strategy (such as st.text()) instead.'
  31. )
  32. check_valid_identifier(source)
  33. if source[0] == u'_':
  34. raise ValueError(u'Bad source name %s' % (source,))
  35. if locale is not None and locales is not None:
  36. raise ValueError(u'Cannot specify both single and multiple locales')
  37. if locale:
  38. locales = (locale,)
  39. elif locales:
  40. locales = tuple(locales)
  41. else:
  42. locales = None
  43. for l in (locales or ()):
  44. if l not in AVAILABLE_LOCALES:
  45. raise ValueError(u'Unsupported locale %r' % (l,))
  46. def supports_source(locale):
  47. test_faker = faker.Faker(locale)
  48. for provider in providers:
  49. test_faker.add_provider(provider)
  50. return hasattr(test_faker, source)
  51. if locales is None:
  52. locales = list(filter(supports_source, AVAILABLE_LOCALES))
  53. if not locales:
  54. raise ValueError(u'No such source %r' % (source,))
  55. else:
  56. for l in locales:
  57. if not supports_source(locale):
  58. raise ValueError(u'Unsupported source %s for locale %s' % (
  59. source, l
  60. ))
  61. return FakeFactoryStrategy(source, providers, locales)
  62. class FakeFactoryStrategy(SearchStrategy):
  63. def __init__(self, source, providers, locales):
  64. self.source = source
  65. self.providers = tuple(providers)
  66. self.locales = tuple(locales)
  67. self.factories = {}
  68. def do_draw(self, data):
  69. seed = data.draw_bytes(4)
  70. random = Random(bytes(seed))
  71. return self.gen_example(random)
  72. def factory_for(self, locale):
  73. try:
  74. return self.factories[locale]
  75. except KeyError:
  76. pass
  77. factory = faker.Faker(locale=locale)
  78. self.factories[locale] = factory
  79. for p in self.providers:
  80. factory.add_provider(p)
  81. return factory
  82. def gen_example(self, random):
  83. factory = self.factory_for(random.choice(self.locales))
  84. original = globalrandom.getstate()
  85. seed = random.getrandbits(128)
  86. try:
  87. factory.seed(seed)
  88. return text_type(getattr(factory, self.source)())
  89. finally:
  90. globalrandom.setstate(original)