diff --git a/.readthedocs.yml b/.readthedocs.yml index 975c45312e..ef0cb381ef 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,7 +5,10 @@ version: 2 # Optionally build your docs in additional formats such as PDF and ePub -formats: all +formats: + - htmlzip + - epub + # - pdf # busted by latex crash on unicode U+030A combining ring above, in text() docs # Optionally set the version of Python and requirements required to build your docs build: diff --git a/AUTHORS.rst b/AUTHORS.rst index 0983532443..ae3d941db4 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -79,6 +79,7 @@ their individual contributions. * `James Lamb `_ * `Jenny Rouleau `_ * `Jens Heinrich `_ +* `Jens Tröger `_ * `Jeremy Thurgood `_ * `J.J. Green `_ * `JP Viljoen `_ (froztbyte@froztbyte.net) diff --git a/hypothesis-python/RELEASE.rst b/hypothesis-python/RELEASE.rst new file mode 100644 index 0000000000..ef8f0378f2 --- /dev/null +++ b/hypothesis-python/RELEASE.rst @@ -0,0 +1,8 @@ +RELEASE_TYPE: minor + +This release adds an optional ``domains=`` parameter to the +:func:`~hypothesis.strategies.emails` strategy, and excludes +the special-use :wikipedia:`.arpa` domain from the default +strategy (:issue:`3567`). + +Thanks to Jens Tröger for reporting and fixing this bug! diff --git a/hypothesis-python/src/hypothesis/provisional.py b/hypothesis-python/src/hypothesis/provisional.py index 62b81cf8e5..31c26da167 100644 --- a/hypothesis-python/src/hypothesis/provisional.py +++ b/hypothesis-python/src/hypothesis/provisional.py @@ -34,14 +34,16 @@ # The file contains additional information about the date that it was last updated. try: # pragma: no cover traversable = resources.files("hypothesis.vendor") / "tlds-alpha-by-domain.txt" - _tlds = traversable.read_text().splitlines() + _comment, *_tlds = traversable.read_text().splitlines() except (AttributeError, ValueError): # pragma: no cover # .files() was added in 3.9 - _tlds = resources.read_text( + _comment, *_tlds = resources.read_text( "hypothesis.vendor", "tlds-alpha-by-domain.txt" ).splitlines() +assert _comment.startswith("#") -assert _tlds[0].startswith("#") -TOP_LEVEL_DOMAINS = ["COM"] + sorted(_tlds[1:], key=len) +# Remove special-use domain names from the list. For more discussion +# see https://github.com/HypothesisWorks/hypothesis/pull/3572 +TOP_LEVEL_DOMAINS = ["COM"] + sorted((d for d in _tlds if d != "ARPA"), key=len) class DomainNameStrategy(st.SearchStrategy): diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/core.py b/hypothesis-python/src/hypothesis/strategies/_internal/core.py index 2b528e39ee..17ba1c7f0c 100644 --- a/hypothesis-python/src/hypothesis/strategies/_internal/core.py +++ b/hypothesis-python/src/hypothesis/strategies/_internal/core.py @@ -2012,21 +2012,30 @@ def deferred(definition: Callable[[], SearchStrategy[Ex]]) -> SearchStrategy[Ex] return DeferredStrategy(definition) +def domains(): + import hypothesis.provisional + + return hypothesis.provisional.domains() + + @defines_strategy(force_reusable_values=True) -def emails() -> SearchStrategy[str]: +def emails( + *, domains: SearchStrategy[str] = LazyStrategy(domains, (), {}) +) -> SearchStrategy[str]: """A strategy for generating email addresses as unicode strings. The address format is specified in :rfc:`5322#section-3.4.1`. Values shrink towards shorter local-parts and host domains. + If ``domains`` is given then it must be a strategy that generates domain + names for the emails, defaulting to :func:`~hypothesis.provisional.domains`. + This strategy is useful for generating "user data" for tests, as mishandling of email addresses is a common source of bugs. """ - from hypothesis.provisional import domains - local_chars = string.ascii_letters + string.digits + "!#$%&'*+-/=^_`{|}~" local_part = text(local_chars, min_size=1, max_size=64) # TODO: include dot-atoms, quoted strings, escaped chars, etc in local part - return builds("{}@{}".format, local_part, domains()).filter( + return builds("{}@{}".format, local_part, domains).filter( lambda addr: len(addr) <= 254 ) diff --git a/hypothesis-python/tests/nocover/test_emails.py b/hypothesis-python/tests/nocover/test_emails.py index 41b3818c38..78537502e3 100644 --- a/hypothesis-python/tests/nocover/test_emails.py +++ b/hypothesis-python/tests/nocover/test_emails.py @@ -9,13 +9,19 @@ # obtain one at https://mozilla.org/MPL/2.0/. from hypothesis import given -from hypothesis.strategies import emails +from hypothesis.strategies import emails, just @given(emails()) -def test_is_valid_email(address): +def test_is_valid_email(address: str): local, at_, domain = address.rpartition("@") assert len(address) <= 254 assert at_ == "@" assert local assert domain + assert not domain.lower().endswith(".arpa") + + +@given(emails(domains=just("mydomain.com"))) +def test_can_restrict_email_domains(address: str): + assert address.endswith("@mydomain.com")