@@ -96,65 +96,52 @@ def visit_Constant(self, node):
96
96
self .generic_visit (node )
97
97
98
98
99
- def _constants_from_source (source : str ) -> AbstractSet [ConstantT ]:
100
- try :
101
- tree = ast .parse (source )
102
- visitor = ConstantVisitor ()
103
- visitor .visit (tree )
104
- except Exception :
105
- # A bunch of things can go wrong here.
106
- # * ast.parse may fail on the source code
107
- # * NodeVisitor may hit a RecursionError (see many related issues on
108
- # e.g. libcst https://github.com/Instagram/LibCST/issues?q=recursion),
109
- # or a MemoryError (`"[1, " * 200 + "]" * 200`)
110
- return set ()
111
-
99
+ def _constants_from_source (source : Union [str , bytes ]) -> AbstractSet [ConstantT ]:
100
+ tree = ast .parse (source )
101
+ visitor = ConstantVisitor ()
102
+ visitor .visit (tree )
112
103
return visitor .constants
113
104
114
105
115
106
@lru_cache (4096 )
116
107
def constants_from_module (module : ModuleType ) -> AbstractSet [ConstantT ]:
117
108
try :
118
109
module_file = inspect .getsourcefile (module )
110
+ # use type: ignore because we know this might error
111
+ source_bytes = Path (module_file ).read_bytes () # type: ignore
119
112
except Exception :
120
113
return set ()
121
114
122
- if module_file is None :
123
- return set ()
124
-
115
+ source_hash = hashlib .sha1 (source_bytes ).hexdigest ()[:16 ]
116
+ cache_p = storage_directory ("constants" ) / source_hash
125
117
try :
126
- source_bytes = Path ( module_file ) .read_bytes ()
118
+ return _constants_from_source ( cache_p .read_bytes () )
127
119
except Exception :
128
- return set ()
129
-
130
- constants_p = (
131
- storage_directory ("constants" ) / hashlib .sha1 (source_bytes ).hexdigest ()[:16 ]
132
- )
133
- if constants_p .exists ():
134
- try :
135
- source = constants_p .read_text ()
136
- except Exception :
137
- # if there's a problem reading the cached constants, fall back to
138
- # standard computation
139
- pass
140
- else :
141
- return _constants_from_source (source )
120
+ # if the cached location doesn't exist, or it does exist but there was
121
+ # a problem reading it, fall back to standard computation of the constants
122
+ pass
142
123
143
124
try :
144
- source = inspect . getsource ( module )
125
+ constants = _constants_from_source ( source_bytes )
145
126
except Exception :
127
+ # A bunch of things can go wrong here.
128
+ # * ast.parse may fail on the source code
129
+ # * NodeVisitor may hit a RecursionError (see many related issues on
130
+ # e.g. libcst https://github.com/Instagram/LibCST/issues?q=recursion),
131
+ # or a MemoryError (`"[1, " * 200 + "]" * 200`)
146
132
return set ()
147
133
148
- constants = _constants_from_source (source )
149
134
try :
150
- constants_p .parent .mkdir (parents = True , exist_ok = True )
151
- constants_p .write_text (
135
+ cache_p .parent .mkdir (parents = True , exist_ok = True )
136
+ cache_p .write_text (
152
137
f"# file: { module_file } \n # hypothesis_version: { hypothesis .__version__ } \n \n "
153
- + str (constants ),
138
+ # somewhat arbitrary sort order. The cache file doesn't *have* to be
139
+ # stable... but it is aesthetically pleasing, and means we could rely
140
+ # on it in the future!
141
+ + str (sorted (constants , key = lambda v : (str (type (v )), v ))),
154
142
encoding = "utf-8" ,
155
143
)
156
- except Exception :
157
- # e.g. read-only filesystem
144
+ except Exception : # pragma: no cover
158
145
pass
159
146
160
147
return constants
0 commit comments