1# This file is part of Hypothesis, which may be found at
2# https://github.com/HypothesisWorks/hypothesis/
3#
4# Copyright the Hypothesis Authors.
5# Individual contributors are listed in AUTHORS.rst and the git log.
6#
7# This Source Code Form is subject to the terms of the Mozilla Public License,
8# v. 2.0. If a copy of the MPL was not distributed with this file, You can
9# obtain one at https://mozilla.org/MPL/2.0/.
10
11from collections.abc import Hashable
12from typing import Any, Optional
13
14from hypothesis.internal.conjecture.data import ConjectureData
15from hypothesis.strategies._internal import SearchStrategy
16from hypothesis.strategies._internal.strategies import Ex
17
18
19class SharedStrategy(SearchStrategy[Ex]):
20 def __init__(self, base: SearchStrategy[Ex], key: Optional[Hashable] = None):
21 super().__init__()
22 self.key = key
23 self.base = base
24
25 @property
26 def supports_find(self) -> bool:
27 return self.base.supports_find
28
29 def __repr__(self) -> str:
30 if self.key is not None:
31 return f"shared({self.base!r}, key={self.key!r})"
32 else:
33 return f"shared({self.base!r})"
34
35 # Ideally would be -> Ex, but key collisions with different-typed values are
36 # possible. See https://github.com/HypothesisWorks/hypothesis/issues/4301.
37 def do_draw(self, data: ConjectureData) -> Any:
38 if self.key is None or getattr(self.base, "_is_singleton", False):
39 strat_label = id(self.base)
40 else:
41 # Assume that uncached strategies are distinguishable by their
42 # label. False negatives (even collisions w/id above) are ok as
43 # long as they are infrequent.
44 strat_label = self.base.label
45 key = self.key or self
46 if key not in data._shared_strategy_draws:
47 drawn = data.draw(self.base)
48 data._shared_strategy_draws[key] = (strat_label, drawn)
49 else:
50 drawn_strat_label, drawn = data._shared_strategy_draws[key]
51 # Check disabled pending resolution of #4301
52 if drawn_strat_label != strat_label: # pragma: no cover
53 pass
54 # warnings.warn(
55 # f"Different strategies are shared under {key=}. This"
56 # " risks drawing values that are not valid examples for the strategy,"
57 # " or that have a narrower range than expected.",
58 # HypothesisWarning,
59 # stacklevel=1,
60 # )
61 return drawn