Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/hypothesis/configuration.py: 67%

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

52 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 os 

12import sys 

13import warnings 

14from pathlib import Path 

15 

16import _hypothesis_globals 

17 

18from hypothesis.errors import HypothesisSideeffectWarning 

19 

20__hypothesis_home_directory_default = Path.cwd() / ".hypothesis" 

21__hypothesis_home_directory = None 

22 

23 

24def set_hypothesis_home_dir(directory: str | Path | None) -> None: 

25 global __hypothesis_home_directory 

26 __hypothesis_home_directory = None if directory is None else Path(directory) 

27 

28 

29_GITIGNORE_STRING = """\ 

30# This .gitignore file was automatically created by Hypothesis. Hypothesis gitignores 

31# .hypothesis by default, because we generally recommend that .hypothesis not be checked 

32# into version control. 

33# 

34# If you *would* like to check .hypothesis into version control, you should delete this 

35# file. Hypothesis will not re-create this .gitignore unless .hypothesis is deleted (and 

36# if it does, that's a bug - please report it!) 

37 

38* 

39""" 

40 

41 

42class StorageDirectory: 

43 def __init__(self, path: Path, *, home_directory: Path) -> None: 

44 self.path = path 

45 self.home_directory = home_directory 

46 

47 def create_if_missing(self) -> None: 

48 # create the appropriate directory and files, if necessary. 

49 

50 existed_before = self.home_directory.exists() 

51 self.path.mkdir(parents=True, exist_ok=True) 

52 if not existed_before: 

53 p = self.home_directory / ".gitignore" 

54 p.write_text(_GITIGNORE_STRING, encoding="utf-8") 

55 

56 

57def storage_directory(*names: str, intent_to_write: bool = True) -> StorageDirectory: 

58 if intent_to_write: 

59 check_sideeffect_during_initialization( 

60 "accessing storage for {}", "/".join(names) 

61 ) 

62 

63 global __hypothesis_home_directory 

64 if not __hypothesis_home_directory: 

65 if where := os.getenv("HYPOTHESIS_STORAGE_DIRECTORY"): 

66 __hypothesis_home_directory = Path(where) 

67 if not __hypothesis_home_directory: 

68 __hypothesis_home_directory = __hypothesis_home_directory_default 

69 return StorageDirectory( 

70 __hypothesis_home_directory.joinpath(*names), 

71 home_directory=__hypothesis_home_directory, 

72 ) 

73 

74 

75_first_postinit_what = None 

76 

77 

78def check_sideeffect_during_initialization( 

79 what: str, *fmt_args: object, is_restart: bool = False 

80) -> None: 

81 """Called from locations that should not be executed during initialization, for example 

82 touching disk or materializing lazy/deferred strategies from plugins. If initialization 

83 is in progress, a warning is emitted. 

84 

85 Note that computing the repr can take nontrivial time or memory, so we avoid doing so 

86 unless (and until) we're actually emitting the warning. 

87 """ 

88 global _first_postinit_what 

89 # This is not a particularly hot path, but neither is it doing productive work, so we want to 

90 # minimize the cost by returning immediately. The drawback is that we require 

91 # notice_initialization_restarted() to be called if in_initialization changes away from zero. 

92 if _first_postinit_what is not None: 

93 return 

94 elif _hypothesis_globals.in_initialization > 0: 

95 msg = what.format(*fmt_args) 

96 if is_restart: 

97 when = "between importing hypothesis and loading the hypothesis plugin" 

98 elif "_hypothesis_pytestplugin" in sys.modules or os.getenv( 

99 "HYPOTHESIS_EXTEND_INITIALIZATION" 

100 ): 

101 when = "during pytest plugin or conftest initialization" 

102 else: # pragma: no cover 

103 # This can be triggered by Hypothesis plugins, but is really annoying 

104 # to test automatically - drop st.text().example() in hypothesis.run() 

105 # to manually confirm that we get the warning. 

106 when = "at import time" 

107 # Note: -Werror is insufficient under pytest, as doesn't take effect until 

108 # test session start. 

109 text = ( 

110 f"Slow code in plugin: avoid {msg} {when}! Set PYTHONWARNINGS=error " 

111 "to get a traceback and show which plugin is responsible." 

112 ) 

113 if is_restart: 

114 text += " Additionally, set HYPOTHESIS_EXTEND_INITIALIZATION=1 to pinpoint the exact location." 

115 warnings.warn( 

116 text, 

117 HypothesisSideeffectWarning, 

118 stacklevel=3, 

119 ) 

120 else: 

121 _first_postinit_what = (what, fmt_args) 

122 

123 

124def notice_initialization_restarted(*, warn: bool = True) -> None: 

125 """Reset _first_postinit_what, so that we don't think we're in post-init. Additionally, if it 

126 was set that means that there has been a sideeffect that we haven't warned about, so do that 

127 now (the warning text will be correct, and we also hint that the stacktrace can be improved). 

128 """ 

129 global _first_postinit_what 

130 if _first_postinit_what is not None: 

131 what, *fmt_args = _first_postinit_what 

132 _first_postinit_what = None 

133 if warn: 

134 check_sideeffect_during_initialization( 

135 what, 

136 *fmt_args, 

137 is_restart=True, 

138 )