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

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

50 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 

11import inspect 

12from collections.abc import Sequence 

13from typing import Callable, Optional 

14 

15from hypothesis.configuration import check_sideeffect_during_initialization 

16from hypothesis.errors import InvalidArgument 

17from hypothesis.internal.conjecture.data import ConjectureData 

18from hypothesis.internal.reflection import get_pretty_function_description 

19from hypothesis.strategies._internal.strategies import ( 

20 Ex, 

21 RecurT, 

22 SearchStrategy, 

23 check_strategy, 

24) 

25 

26 

27class DeferredStrategy(SearchStrategy[Ex]): 

28 """A strategy which may be used before it is fully defined.""" 

29 

30 def __init__(self, definition: Callable[[], SearchStrategy[Ex]]): 

31 super().__init__() 

32 self.__wrapped_strategy: Optional[SearchStrategy[Ex]] = None 

33 self.__in_repr: bool = False 

34 self.__definition: Optional[Callable[[], SearchStrategy[Ex]]] = definition 

35 

36 @property 

37 def wrapped_strategy(self) -> SearchStrategy[Ex]: 

38 # we assign this before entering the condition to avoid a race condition 

39 # under threading. See issue #4523. 

40 definition = self.__definition 

41 if self.__wrapped_strategy is None: 

42 check_sideeffect_during_initialization("deferred evaluation of {!r}", self) 

43 

44 if not inspect.isfunction(definition): 

45 raise InvalidArgument( 

46 f"Expected definition to be a function but got {definition!r} " 

47 f"of type {type(definition).__name__} instead." 

48 ) 

49 result = definition() 

50 if result is self: 

51 raise InvalidArgument("Cannot define a deferred strategy to be itself") 

52 check_strategy(result, "definition()") 

53 self.__wrapped_strategy = result 

54 self.__definition = None 

55 return self.__wrapped_strategy 

56 

57 @property 

58 def branches(self) -> Sequence[SearchStrategy[Ex]]: 

59 return self.wrapped_strategy.branches 

60 

61 def calc_label(self) -> int: 

62 """Deferred strategies don't have a calculated label, because we would 

63 end up having to calculate the fixed point of some hash function in 

64 order to calculate it when they recursively refer to themself! 

65 

66 The label for the wrapped strategy will still appear because it 

67 will be passed to draw. 

68 """ 

69 # This is actually the same as the parent class implementation, but we 

70 # include it explicitly here in order to document that this is a 

71 # deliberate decision. 

72 return self.class_label 

73 

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

75 return recur(self.wrapped_strategy) 

76 

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

78 return recur(self.wrapped_strategy) 

79 

80 def __repr__(self) -> str: 

81 if self.__wrapped_strategy is not None: 

82 if self.__in_repr: 

83 return f"(deferred@{id(self)!r})" 

84 try: 

85 self.__in_repr = True 

86 return repr(self.__wrapped_strategy) 

87 finally: 

88 self.__in_repr = False 

89 else: 

90 description = get_pretty_function_description(self.__definition) 

91 return f"deferred({description})" 

92 

93 def do_draw(self, data: ConjectureData) -> Ex: 

94 return data.draw(self.wrapped_strategy)