Repository: HypothesisWorks/hypothesis

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`.

Resolving patch:
diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/misc.py b/hypothesis-python/src/hypothesis/strategies/_internal/misc.py
--- 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
--- 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