Repository: HypothesisWorks/hypothesis

Issue:
Python 3.11: `sre_constants` and `sre_parse` are deprecated
With Python 3.11.0a7 and hypothesis 6.45.0, running a file such as:

```python
from hypothesis import given
from hypothesis.strategies import from_regex

@given(from_regex("x"))
def test_regex(s):
    pass

test_regex()
```

with `-Wall` results in:

```
.../lib/python3.11/site-packages/hypothesis/strategies/_internal/regex.py:13: DeprecationWarning: module 'sre_constants' is deprecated
  import sre_constants as sre
.../lib/python3.11/site-packages/hypothesis/strategies/_internal/regex.py:14: DeprecationWarning: module 'sre_parse' is deprecated
  import sre_parse
```

Also see https://github.com/python/cpython/issues/91308.

Traceback with `-Werror`:

```pytb
Traceback (most recent call last):
  File ".../test.py", line 8, in <module>
    test_regex()
    ^^^^^^^^^^^^
  File ".../test.py", line 5, in test_regex
    def test_regex(s):
                   ^^^
  File ".../lib/python3.11/site-packages/hypothesis/core.py", line 1085, in wrapped_test
    processed_args = process_arguments_to_given(
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/core.py", line 482, in process_arguments_to_given
    search_strategy.validate()
    ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/strategies.py", line 406, in validate
    self.do_validate()
    ^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/collections.py", line 43, in do_validate
    s.validate()
    ^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/strategies.py", line 406, in validate
    self.do_validate()
    ^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/strategies.py", line 806, in do_validate
    self.mapped_strategy.validate()
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/strategies.py", line 406, in validate
    self.do_validate()
    ^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/lazy.py", line 131, in do_validate
    w.validate()
    ^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/strategies.py", line 406, in validate
    self.do_validate()
    ^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/strategies.py", line 806, in do_validate
    self.mapped_strategy.validate()
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/strategies.py", line 406, in validate
    self.do_validate()
    ^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/collections.py", line 43, in do_validate
    s.validate()
    ^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/strategies.py", line 406, in validate
    self.do_validate()
    ^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/lazy.py", line 129, in do_validate
    w = self.wrapped_strategy
        ^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/lazy.py", line 108, in wrapped_strategy
    base = self.function(*self.__args, **self.__kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/core.py", line 687, in from_regex
    from hypothesis.strategies._internal.regex import regex_strategy
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.11/site-packages/hypothesis/strategies/_internal/regex.py", line 13, in <module>
    import sre_constants as sre
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/sre_constants.py", line 2, in <module>
    warnings.warn(f"module {__name__!r} is deprecated",
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
DeprecationWarning: module 'sre_constants' is deprecated
```



Discussion:

Resolving patch:
diff --git a/hypothesis-python/src/hypothesis/provisional.py b/hypothesis-python/src/hypothesis/provisional.py
--- a/hypothesis-python/src/hypothesis/provisional.py
+++ b/hypothesis-python/src/hypothesis/provisional.py
@@ -19,7 +19,7 @@
 # https://tools.ietf.org/html/rfc3696
 
 import string
-from importlib.resources import read_text
+from importlib import resources
 
 from hypothesis import strategies as st
 from hypothesis.errors import InvalidArgument
@@ -32,7 +32,14 @@
 
 # This file is sourced from http://data.iana.org/TLD/tlds-alpha-by-domain.txt
 # The file contains additional information about the date that it was last updated.
-_tlds = read_text("hypothesis.vendor", "tlds-alpha-by-domain.txt").splitlines()
+try:  # pragma: no cover
+    traversable = resources.files("hypothesis.vendor") / "tlds-alpha-by-domain.txt"
+    _tlds = traversable.read_text().splitlines()
+except AttributeError:  # .files() was added in Python 3.9
+    _tlds = resources.read_text(
+        "hypothesis.vendor", "tlds-alpha-by-domain.txt"
+    ).splitlines()
+
 assert _tlds[0].startswith("#")
 TOP_LEVEL_DOMAINS = ["COM"] + sorted(_tlds[1:], key=len)
 
diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/datetime.py b/hypothesis-python/src/hypothesis/strategies/_internal/datetime.py
--- a/hypothesis-python/src/hypothesis/strategies/_internal/datetime.py
+++ b/hypothesis-python/src/hypothesis/strategies/_internal/datetime.py
@@ -12,7 +12,7 @@
 import os.path
 from calendar import monthrange
 from functools import lru_cache
-from importlib.resources import is_resource
+from importlib import resources
 from typing import Optional
 
 from hypothesis.errors import InvalidArgument
@@ -348,7 +348,12 @@ def _valid_key_cacheable(tzpath, key):
         *package_loc, resource_name = key.split("/")
         package = "tzdata.zoneinfo." + ".".join(package_loc)
         try:
-            return is_resource(package, resource_name)
+            try:
+                traversable = resources.files(package) / resource_name
+                return traversable.exists()
+            except AttributeError:
+                # .files() was added in Python 3.9
+                return resources.is_resource(package, resource_name)
         except ModuleNotFoundError:
             return False
 
diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/regex.py b/hypothesis-python/src/hypothesis/strategies/_internal/regex.py
--- a/hypothesis-python/src/hypothesis/strategies/_internal/regex.py
+++ b/hypothesis-python/src/hypothesis/strategies/_internal/regex.py
@@ -10,8 +10,13 @@
 
 import operator
 import re
-import sre_constants as sre
-import sre_parse
+
+try:  # pragma: no cover
+    import re._constants as sre
+    import re._parser as sre_parse
+except ImportError:  # Python < 3.11
+    import sre_constants as sre  # type: ignore
+    import sre_parse  # type: ignore
 
 from hypothesis import reject, strategies as st
 from hypothesis.internal.charmap import as_general_categories, categories


Test patch:
diff --git a/hypothesis-python/tests/cover/test_settings.py b/hypothesis-python/tests/cover/test_settings.py
--- a/hypothesis-python/tests/cover/test_settings.py
+++ b/hypothesis-python/tests/cover/test_settings.py
@@ -469,7 +469,7 @@ def test_show_changed():
 
 
 def test_note_deprecation_checks_date():
-    with pytest.warns(None) as rec:
+    with pytest.warns(HypothesisDeprecationWarning) as rec:
         note_deprecation("This is bad", since="RELEASEDAY", has_codemod=False)
     assert len(rec) == 1
     with pytest.raises(AssertionError):
diff --git a/hypothesis-python/tests/nocover/test_recursive.py b/hypothesis-python/tests/nocover/test_recursive.py
--- a/hypothesis-python/tests/nocover/test_recursive.py
+++ b/hypothesis-python/tests/nocover/test_recursive.py
@@ -10,7 +10,7 @@
 
 import threading
 
-from hypothesis import given, settings, strategies as st
+from hypothesis import HealthCheck, given, settings, strategies as st
 
 from tests.common.debug import find_any, minimal
 from tests.common.utils import flaky
@@ -128,11 +128,15 @@ def test_can_form_sets_of_recursive_data():
 
 
 def test_drawing_from_recursive_strategy_is_thread_safe():
-    shared_strategy = st.recursive(st.integers(), lambda s: st.lists(s, max_size=3))
+    shared_strategy = st.recursive(
+        st.integers(), lambda s: st.lists(s, max_size=2), max_leaves=20
+    )
 
     errors = []
 
-    @settings(database=None)
+    @settings(
+        database=None, deadline=None, suppress_health_check=[HealthCheck.too_slow]
+    )
     @given(data=st.data())
     def test(data):
         try:
diff --git a/whole-repo-tests/test_mypy.py b/whole-repo-tests/test_mypy.py
--- a/whole-repo-tests/test_mypy.py
+++ b/whole-repo-tests/test_mypy.py
@@ -8,7 +8,6 @@
 # v. 2.0. If a copy of the MPL was not distributed with this file, You can
 # obtain one at https://mozilla.org/MPL/2.0/.
 
-import os
 import subprocess
 import textwrap
 
@@ -31,15 +30,12 @@ def test_mypy_passes_on_hypothesis_strict():
 
 
 def get_mypy_output(fname, *extra_args):
-    return subprocess.Popen(
+    return subprocess.run(
         [tool_path("mypy"), *extra_args, fname],
-        stdout=subprocess.PIPE,
         encoding="utf-8",
-        universal_newlines=True,
-        # We set the MYPYPATH explicitly, because PEP561 discovery wasn't
-        # working in CI as of mypy==0.730 - hopefully a temporary workaround.
-        env=dict(os.environ, MYPYPATH=PYTHON_SRC),
-    ).stdout.read()
+        capture_output=True,
+        text=True,
+    ).stdout
 
 
 def get_mypy_analysed_type(fname, val):