2
2
3
3
import keyword
4
4
import string
5
- from collections import OrderedDict
5
+ from collections . abc import Callable
6
6
from enum import Enum
7
7
from typing import (
8
8
Any ,
23
23
from attr ._make import _CountingAttr
24
24
from attrs import NOTHING , AttrsInstance , Factory , make_class
25
25
from hypothesis import strategies as st
26
- from hypothesis .strategies import SearchStrategy
26
+ from hypothesis .strategies import SearchStrategy , booleans
27
+ from typing_extensions import TypeAlias
28
+
29
+ from . import FeatureFlag
27
30
28
31
PosArg = Any
29
32
PosArgs = tuple [PosArg ]
30
33
KwArgs = dict [str , Any ]
34
+ AttrsAndArgs : TypeAlias = tuple [type [AttrsInstance ], PosArgs , KwArgs ]
31
35
32
36
primitive_strategies = st .sampled_from (
33
37
[
@@ -167,7 +171,7 @@ def gen_attr_names() -> Iterable[str]:
167
171
def _create_hyp_class (
168
172
attrs_and_strategy : list [tuple [_CountingAttr , st .SearchStrategy [PosArgs ]]],
169
173
frozen = None ,
170
- ) -> SearchStrategy [tuple ]:
174
+ ) -> SearchStrategy [AttrsAndArgs ]:
171
175
"""
172
176
A helper function for Hypothesis to generate attrs classes.
173
177
@@ -192,7 +196,7 @@ def key(t):
192
196
return st .tuples (
193
197
st .builds (
194
198
lambda f : make_class (
195
- "HypClass" , OrderedDict (zip (gen_attr_names (), attrs )), frozen = f
199
+ "HypClass" , dict (zip (gen_attr_names (), attrs )), frozen = f
196
200
),
197
201
st .booleans () if frozen is None else st .just (frozen ),
198
202
),
@@ -209,26 +213,28 @@ def just_class(tup):
209
213
return _create_hyp_class (combined_attrs )
210
214
211
215
212
- def just_class_with_type (tup ) :
216
+ def just_class_with_type (tup : tuple ) -> SearchStrategy [ AttrsAndArgs ] :
213
217
nested_cl = tup [1 ][0 ]
214
- default = attr .Factory (nested_cl )
215
- combined_attrs = list (tup [0 ])
216
- combined_attrs .append (
217
- (attr .ib (default = default , type = nested_cl ), st .just (nested_cl ()))
218
- )
219
- return _create_hyp_class (combined_attrs )
220
218
219
+ def make_with_default (takes_self : bool ) -> SearchStrategy [AttrsAndArgs ]:
220
+ combined_attrs = list (tup [0 ])
221
+ combined_attrs .append (
222
+ (
223
+ attr .ib (
224
+ default = (
225
+ Factory (
226
+ nested_cl if not takes_self else lambda _ : nested_cl (),
227
+ takes_self = takes_self ,
228
+ )
229
+ ),
230
+ type = nested_cl ,
231
+ ),
232
+ st .just (nested_cl ()),
233
+ )
234
+ )
235
+ return _create_hyp_class (combined_attrs )
221
236
222
- def just_class_with_type_takes_self (
223
- tup : tuple [list [tuple [_CountingAttr , SearchStrategy ]], tuple [type [AttrsInstance ]]]
224
- ) -> SearchStrategy [tuple [type [AttrsInstance ]]]:
225
- nested_cl = tup [1 ][0 ]
226
- default = Factory (lambda _ : nested_cl (), takes_self = True )
227
- combined_attrs = list (tup [0 ])
228
- combined_attrs .append (
229
- (attr .ib (default = default , type = nested_cl ), st .just (nested_cl ()))
230
- )
231
- return _create_hyp_class (combined_attrs )
237
+ return booleans ().flatmap (make_with_default )
232
238
233
239
234
240
def just_frozen_class_with_type (tup ):
@@ -240,22 +246,45 @@ def just_frozen_class_with_type(tup):
240
246
return _create_hyp_class (combined_attrs )
241
247
242
248
243
- def list_of_class (tup ) :
249
+ def list_of_class (tup : tuple ) -> SearchStrategy [ AttrsAndArgs ] :
244
250
nested_cl = tup [1 ][0 ]
245
- default = attr .Factory (lambda : [nested_cl ()])
246
- combined_attrs = list (tup [0 ])
247
- combined_attrs .append ((attr .ib (default = default ), st .just ([nested_cl ()])))
248
- return _create_hyp_class (combined_attrs )
249
251
252
+ def make_with_default (takes_self : bool ) -> SearchStrategy [AttrsAndArgs ]:
253
+ combined_attrs = list (tup [0 ])
254
+ combined_attrs .append (
255
+ (
256
+ attr .ib (
257
+ default = (
258
+ Factory (lambda : [nested_cl ()])
259
+ if not takes_self
260
+ else Factory (lambda _ : [nested_cl ()], takes_self = True )
261
+ ),
262
+ type = list [nested_cl ],
263
+ ),
264
+ st .just ([nested_cl ()]),
265
+ )
266
+ )
267
+ return _create_hyp_class (combined_attrs )
268
+
269
+ return booleans ().flatmap (make_with_default )
250
270
251
- def list_of_class_with_type (tup ):
271
+
272
+ def list_of_class_with_type (tup : tuple ) -> SearchStrategy [AttrsAndArgs ]:
252
273
nested_cl = tup [1 ][0 ]
253
- default = attr .Factory (lambda : [nested_cl ()])
254
- combined_attrs = list (tup [0 ])
255
- combined_attrs .append (
256
- (attr .ib (default = default , type = List [nested_cl ]), st .just ([nested_cl ()]))
257
- )
258
- return _create_hyp_class (combined_attrs )
274
+
275
+ def make_with_default (takes_self : bool ) -> SearchStrategy [AttrsAndArgs ]:
276
+ default = (
277
+ Factory (lambda : [nested_cl ()])
278
+ if not takes_self
279
+ else Factory (lambda _ : [nested_cl ()], takes_self = True )
280
+ )
281
+ combined_attrs = list (tup [0 ])
282
+ combined_attrs .append (
283
+ (attr .ib (default = default , type = List [nested_cl ]), st .just ([nested_cl ()]))
284
+ )
285
+ return _create_hyp_class (combined_attrs )
286
+
287
+ return booleans ().flatmap (make_with_default )
259
288
260
289
261
290
def dict_of_class (tup ):
@@ -266,7 +295,9 @@ def dict_of_class(tup):
266
295
return _create_hyp_class (combined_attrs )
267
296
268
297
269
- def _create_hyp_nested_strategy (simple_class_strategy ):
298
+ def _create_hyp_nested_strategy (
299
+ simple_class_strategy : SearchStrategy ,
300
+ ) -> SearchStrategy :
270
301
"""
271
302
Create a recursive attrs class.
272
303
Given a strategy for building (simpler) classes, create and return
@@ -275,6 +306,7 @@ def _create_hyp_nested_strategy(simple_class_strategy):
275
306
* a list of simpler classes
276
307
* a dict mapping the string "cls" to a simpler class.
277
308
"""
309
+
278
310
# A strategy producing tuples of the form ([list of attributes], <given
279
311
# class strategy>).
280
312
attrs_and_classes = st .tuples (lists_of_attrs (defaults = True ), simple_class_strategy )
@@ -286,7 +318,6 @@ def _create_hyp_nested_strategy(simple_class_strategy):
286
318
| attrs_and_classes .flatmap (list_of_class_with_type )
287
319
| attrs_and_classes .flatmap (dict_of_class )
288
320
| attrs_and_classes .flatmap (just_frozen_class_with_type )
289
- | attrs_and_classes .flatmap (just_class_with_type_takes_self )
290
321
)
291
322
292
323
@@ -430,9 +461,10 @@ def simple_classes(defaults=None, min_attrs=0, frozen=None, kw_only=None):
430
461
)
431
462
432
463
433
- # Ok, so st.recursive works by taking a base strategy (in this case,
434
- # simple_classes) and a special function. This function receives a strategy,
435
- # and returns another strategy (building on top of the base strategy).
436
- nested_classes = st .recursive (
437
- simple_classes (defaults = True ), _create_hyp_nested_strategy
438
- )
464
+ def nested_classes (
465
+ takes_self : FeatureFlag = "sometimes" ,
466
+ ) -> SearchStrategy [AttrsAndArgs ]:
467
+ # Ok, so st.recursive works by taking a base strategy (in this case,
468
+ # simple_classes) and a special function. This function receives a strategy,
469
+ # and returns another strategy (building on top of the base strategy).
470
+ return st .recursive (simple_classes (defaults = True ), _create_hyp_nested_strategy )
0 commit comments