Repository: HypothesisWorks/hypothesis (Python)

Issue:
[Bug?] `.filter` ignored on `just` strategy
Hi,
I hope this has not been reported before. I checked the issues and read the [changelog] ~but could not find anything related~ and this seems to be related to issue https://github.com/HypothesisWorks/hypothesis/issues/2036.

[changelog]: https://hypothesis.readthedocs.io/en/latest/changes.html

I noticed an unexpected difference in the behavior when `.filter` is applied on `just` strategy between Hypothesis 5.43.3 and Hypothesis 6.12.0 (the former ran on my machine, while the remote CI machine had 6.12.0 installed).

With Hypothesis 5.43.3 (expected behavior):
```python
import hypothesis.strategies
import hypothesis.strategies._internal.strategies

strategy = hypothesis.strategies.just(1).filter(lambda x: x > 10)
assert str(strategy) == "just(1).filter(lambda x: x > 10)"
assert type(strategy) == hypothesis.strategies._internal.strategies.FilteredStrategy
```

With Hypothesis 6.12.0 (unexpected behavior):

```python
import hypothesis.strategies
import hypothesis.strategies._internal.misc

strategy = hypothesis.strategies.just(1).filter(lambda x: x > 10)
assert str(strategy) == "just(1)"
assert type(strategy) == hypothesis.strategies._internal.misc.JustStrategy
```

This bug (?) is relevant for [icontract-hypothesis] when we test instance methods automatically where pre-conditions need to be applied on `self`. I'd expect the health check to be raised rather than the pre-conditions to be silently ignored.

[icontract-hypothesis]: https://github.com/mristin/icontract-hypothesis


Discussion:
This changed in #2688, [version 5.43.7](https://hypothesis.readthedocs.io/en/latest/changes.html#v5-43-7).  The preconditions *aren't* silently ignored - so our bug is limited to an incorrect `__repr__` for `just()` strategies, which I'll fix momentarily.  The return type is not part of our public/stable API though - note the `_internal`! - and so to keep your check working you'll need to add a special case for `_transformations` on a `SampledFromStrategy`.
Thanks a lot, @Zac-HD!

Just to confirm: I tried this in my Python console with Hypothesis 6.12.0 and indeed, the filter is applied:

```
>>> import hypothesis.strategies as st
>>> st.just(1).filter(lambda x: x > 10)
just(1)
>>> st.just(1).filter(lambda x: x > 10).example()
Traceback (most recent call last):
  ...
hypothesis.errors.Unsatisfiable: Unable to satisfy assumptions of hypothesis example_generating_inner_function.
```



Patch:
diff --git a/hypothesis-python/RELEASE.rst b/hypothesis-python/RELEASE.rst
new file mode 100644
index 0000000000..f050115f1b
--- /dev/null
+++ b/hypothesis-python/RELEASE.rst
@@ -0,0 +1,6 @@
+RELEASE_TYPE: patch
+
+This patch fixes :issue:`2964`, where ``.map()`` and ``.filter()`` methods
+were omitted from the ``repr()`` of :func:`~hypothesis.strategies.just` and
+:func:`~hypothesis.strategies.sampled_from` strategies, since
+:ref:`version 5.43.7 <v5.43.7>`.
diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/misc.py b/hypothesis-python/src/hypothesis/strategies/_internal/misc.py
index f0f9924e31..ae32f4780a 100644
--- a/hypothesis-python/src/hypothesis/strategies/_internal/misc.py
+++ b/hypothesis-python/src/hypothesis/strategies/_internal/misc.py
@@ -43,9 +43,13 @@ def value(self):
         return self.elements[0]
 
     def __repr__(self):
+        suffix = "".join(
+            f".{name}({get_pretty_function_description(f)})"
+            for name, f in self._transformations
+        )
         if self.value is None:
-            return "none()"
-        return f"just({get_pretty_function_description(self.value)})"
+            return "none()" + suffix
+        return f"just({get_pretty_function_description(self.value)}){suffix}"
 
     def calc_has_reusable_values(self, recur):
         return True


Test patch:
diff --git a/hypothesis-python/tests/nocover/test_pretty_repr.py b/hypothesis-python/tests/nocover/test_pretty_repr.py
index 5f2ac6170d..c379fa5e2a 100644
--- a/hypothesis-python/tests/nocover/test_pretty_repr.py
+++ b/hypothesis-python/tests/nocover/test_pretty_repr.py
@@ -15,6 +15,8 @@
 
 from collections import OrderedDict
 
+import pytest
+
 from hypothesis import given, strategies as st
 from hypothesis.control import reject
 from hypothesis.errors import HypothesisDeprecationWarning, InvalidArgument
@@ -105,3 +107,15 @@ def test_repr_evals_to_thing_with_same_repr(strategy):
     via_eval = eval(r, strategy_globals)
     r2 = repr(via_eval)
     assert r == r2
+
+
+@pytest.mark.parametrize(
+    "r",
+    [
+        "none().filter(foo).map(bar)",
+        "just(1).filter(foo).map(bar)",
+        "sampled_from([1, 2, 3]).filter(foo).map(bar)",
+    ],
+)
+def test_sampled_transform_reprs(r):
+    assert repr(eval(r, strategy_globals)) == r