Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/hypothesis/strategies/_internal/misc.py: 66%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

65 statements  

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 Callable 

12from typing import TYPE_CHECKING, Any, NoReturn 

13 

14from hypothesis.errors import CannotInvert 

15from hypothesis.internal.conjecture.choice import ChoiceT 

16from hypothesis.internal.conjecture.data import ConjectureData 

17from hypothesis.internal.conjecture.junkdrawer import equal_values 

18from hypothesis.internal.reflection import get_pretty_function_description 

19from hypothesis.strategies._internal.strategies import ( 

20 Ex, 

21 RecurT, 

22 SampledFromStrategy, 

23 SearchStrategy, 

24 T, 

25 is_hashable, 

26) 

27from hypothesis.strategies._internal.utils import cacheable, defines_strategy 

28from hypothesis.utils.conventions import UniqueIdentifier 

29 

30if TYPE_CHECKING: 

31 from typing_extensions import Never 

32 

33 

34class JustStrategy(SampledFromStrategy[Ex]): 

35 """A strategy which always returns a single fixed value. 

36 

37 It's implemented as a length-one SampledFromStrategy so that all our 

38 special-case logic for filtering and sets applies also to just(x). 

39 

40 The important difference from a SampledFromStrategy with only one 

41 element to choose is that JustStrategy *never* touches the underlying 

42 choice sequence, i.e. drawing neither reads from nor writes to `data`. 

43 This is a reasonably important optimisation (or semantic distinction!) 

44 for both JustStrategy and SampledFromStrategy. 

45 """ 

46 

47 @property 

48 def value(self) -> Ex: 

49 return self.elements[0] 

50 

51 def __repr__(self) -> str: 

52 suffix = "".join( 

53 f".{name}({get_pretty_function_description(f)})" 

54 for name, f, _ in self._transformations 

55 ) 

56 if self.value is None: 

57 return "none()" + suffix 

58 return f"just({get_pretty_function_description(self.value)}){suffix}" 

59 

60 def calc_is_cacheable(self, recur: RecurT) -> bool: 

61 return is_hashable(self.value) 

62 

63 def do_filtered_draw(self, data: ConjectureData) -> Ex | UniqueIdentifier: 

64 # The parent class's `do_draw` implementation delegates directly to 

65 # `do_filtered_draw`, which we can greatly simplify in this case since 

66 # we have exactly one value. (This also avoids drawing any data.) 

67 return self._transform(self.value, data=data) 

68 

69 def _invert(self, value: Any) -> tuple[ChoiceT, ...]: 

70 if not equal_values(self._transform(self.value, data=None), value): 

71 raise CannotInvert(f"{value!r} is not produced by {self!r}") 

72 return () 

73 

74 

75@defines_strategy(eager=True) 

76def just(value: T) -> SearchStrategy[T]: 

77 """Return a strategy which only generates ``value``. 

78 

79 Note: ``value`` is not copied. Be wary of using mutable values. 

80 

81 If ``value`` is the result of a callable, you can use 

82 :func:`builds(callable) <hypothesis.strategies.builds>` instead 

83 of ``just(callable())`` to get a fresh value each time. 

84 

85 Examples from this strategy do not shrink (because there is only one). 

86 """ 

87 return JustStrategy([value]) 

88 

89 

90@defines_strategy(force_reusable_values=True) 

91def none() -> SearchStrategy[None]: 

92 """Return a strategy which only generates None. 

93 

94 Examples from this strategy do not shrink (because there is only 

95 one). 

96 """ 

97 return just(None) 

98 

99 

100class Nothing(SearchStrategy["Never"]): 

101 def calc_is_empty(self, recur: RecurT) -> bool: 

102 return True 

103 

104 def do_draw(self, data: ConjectureData) -> NoReturn: 

105 # This method should never be called because draw() will mark the 

106 # data as invalid immediately because is_empty is True. 

107 raise NotImplementedError("This should never happen") 

108 

109 def calc_has_reusable_values(self, recur: RecurT) -> bool: 

110 return True 

111 

112 def __repr__(self) -> str: 

113 return "nothing()" 

114 

115 def map(self, pack: Callable[[Any], Any]) -> SearchStrategy["Never"]: 

116 return self 

117 

118 def filter(self, condition: Callable[[Any], Any]) -> "SearchStrategy[Never]": 

119 return self 

120 

121 def flatmap( 

122 self, expand: Callable[[Any], "SearchStrategy[Any]"] 

123 ) -> "SearchStrategy[Never]": 

124 return self 

125 

126 

127NOTHING = Nothing() 

128 

129 

130@cacheable 

131@defines_strategy(eager=True) 

132def nothing() -> SearchStrategy["Never"]: 

133 """This strategy never successfully draws a value and will always reject on 

134 an attempt to draw. 

135 

136 Examples from this strategy do not shrink (because there are none). 

137 """ 

138 return NOTHING 

139 

140 

141class BooleansStrategy(SearchStrategy[bool]): 

142 def do_draw(self, data: ConjectureData) -> bool: 

143 return data.draw_boolean() 

144 

145 def _invert(self, value: Any) -> tuple[ChoiceT, ...]: 

146 if not isinstance(value, bool): 

147 raise CannotInvert(f"{value!r} is not a bool") 

148 return (value,) 

149 

150 def __repr__(self) -> str: 

151 return "booleans()"