Repository: HypothesisWorks/hypothesis

Issue:
Missing dependency on setuptools
When importing `hypothesis` in a container that only installs the declared dependencies (i.e. `sortedcontainers` and `attrs`) then we see the following error:
```
Traceback (most recent call last):
  File "/run/shm/bazel-sandbox.58afe50bce693a45c42be3530f1579c8f12116963ef7e303ad72c1a2b06ed6f2/processwrapper-sandbox/4962/execroot/__main__/bazel-out/k8-fastbuild/bin/perception/cloud/proto_format_test.runfiles/internal_pip_dependency_hypothesis/pypi__hypothesis/hypothesis/entry_points.py", line 27, in <module>
    from importlib import metadata as importlib_metadata
ImportError: cannot import name 'metadata'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/run/shm/bazel-sandbox.58afe50bce693a45c42be3530f1579c8f12116963ef7e303ad72c1a2b06ed6f2/processwrapper-sandbox/4962/execroot/__main__/bazel-out/k8-fastbuild/bin/perception/cloud/proto_format_test.runfiles/internal_pip_dependency_hypothesis/pypi__hypothesis/hypothesis/entry_points.py", line 29, in <module>
    import importlib_metadata  # type: ignore  # mypy thinks this is a redefinition
ModuleNotFoundError: No module named 'importlib_metadata'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "common/python/runtime/python3_wrapper.py", line 36, in <module>
    eval(compiled_code, module.__dict__)
  File "/run/shm/bazel-sandbox.58afe50bce693a45c42be3530f1579c8f12116963ef7e303ad72c1a2b06ed6f2/processwrapper-sandbox/4962/execroot/__main__/bazel-out/k8-fastbuild/bin/perception/cloud/proto_format_test.runfiles/__main__/perception/cloud/proto_format_test.py", line 7, in <module>
    import hypothesis as hyp
  File "/run/shm/bazel-sandbox.58afe50bce693a45c42be3530f1579c8f12116963ef7e303ad72c1a2b06ed6f2/processwrapper-sandbox/4962/execroot/__main__/bazel-out/k8-fastbuild/bin/perception/cloud/proto_format_test.runfiles/internal_pip_dependency_hypothesis/pypi__hypothesis/hypothesis/__init__.py", line 27, in <module>
    from hypothesis.entry_points import run
  File "/run/shm/bazel-sandbox.58afe50bce693a45c42be3530f1579c8f12116963ef7e303ad72c1a2b06ed6f2/processwrapper-sandbox/4962/execroot/__main__/bazel-out/k8-fastbuild/bin/perception/cloud/proto_format_test.runfiles/internal_pip_dependency_hypothesis/pypi__hypothesis/hypothesis/entry_points.py", line 38, in <module>
    import pkg_resources
ModuleNotFoundError: No module named 'pkg_resources'
```
The `pkg_resources` module is provided by `setuptools`.

I think tweaking `setup.py` should fix it.


Discussion:
Given that this only affects Python 3.6 and 3.7 (`importlib.metadata` is in the standard library from 3.8 onwards), and that depending on `setuptools` is usually a bad idea, I propose the following:

- We add a fourth (!) fallback case, which skips loading entry points on Python < 3.8 if neither `importlib_metadata` nor `setuptools` is available (and emits a warning to that effect)
- We also add a conditional dependency on the `importlib_metadata ; python_version<'3.8'` package for `hypothesis[all]`, so that dependency-insensitive users get the fast path

And as a workaround for your container, I recommend either updating Python to 3.8+, or installing `importlib_metadata`.
Ah, that makes sense. I didn't look closely enough. `importlib_metadata` should indeed work for our container. I'll try that, thanks!

Resolving patch:
diff --git a/hypothesis-python/setup.py b/hypothesis-python/setup.py
--- a/hypothesis-python/setup.py
+++ b/hypothesis-python/setup.py
@@ -63,7 +63,7 @@ def local_file(name):
     "dateutil": ["python-dateutil>=1.4"],
     "lark": ["lark-parser>=0.6.5"],
     "numpy": ["numpy>=1.9.0"],
-    "pandas": ["pandas>=0.19"],
+    "pandas": ["pandas>=0.25"],
     "pytest": ["pytest>=4.3"],
     "dpcontracts": ["dpcontracts>=0.4"],
     "redis": ["redis>=3.0.0"],
@@ -72,7 +72,9 @@ def local_file(name):
     "django": ["pytz>=2014.1", "django>=2.2"],
 }
 
-extras["all"] = sorted(set(sum(extras.values(), [])))
+extras["all"] = sorted(
+    set(sum(extras.values(), ["importlib_metadata ; python_version<'3.8'"]))
+)
 
 
 setuptools.setup(
diff --git a/hypothesis-python/src/hypothesis/entry_points.py b/hypothesis-python/src/hypothesis/entry_points.py
--- a/hypothesis-python/src/hypothesis/entry_points.py
+++ b/hypothesis-python/src/hypothesis/entry_points.py
@@ -35,10 +35,26 @@ def get_entry_points():
 except ImportError:
     # But if we're not on Python >= 3.8 and the importlib_metadata backport
     # is not installed, we fall back to pkg_resources anyway.
-    import pkg_resources
+    try:
+        import pkg_resources
+    except ImportError:
+        import warnings
 
-    def get_entry_points():
-        yield from pkg_resources.iter_entry_points("hypothesis")
+        from hypothesis.errors import HypothesisWarning
+
+        warnings.warn(
+            "Under Python <= 3.7, Hypothesis requires either the importlib_metadata "
+            "or setuptools package in order to load plugins via entrypoints.",
+            HypothesisWarning,
+        )
+
+        def get_entry_points():
+            yield from ()
+
+    else:
+
+        def get_entry_points():
+            yield from pkg_resources.iter_entry_points("hypothesis")
 
 
 def run():


Test patch: