Skip to content

Commit df0eef9

Browse files
committed
Update hypothesis tests
1 parent 02b616c commit df0eef9

File tree

6 files changed

+629
-132
lines changed

6 files changed

+629
-132
lines changed

hypo_test/expressions.py

Lines changed: 68 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -395,68 +395,87 @@ def DictComp(draw, expression) -> ast.DictComp:
395395
)
396396

397397

398-
leaves = NameConstant() | \
399-
Name() | \
400-
Num() | \
401-
Str() | \
402-
Bytes()
398+
leaves = one_of(
399+
NameConstant(),
400+
Name(),
401+
Num(),
402+
Str(),
403+
Bytes()
404+
)
405+
406+
407+
# Group related operations for better recursive structure
408+
def binary_operations(expr):
409+
"""Simple binary and comparison operations"""
410+
return one_of(
411+
BinOp(expr),
412+
Compare(expr),
413+
BoolOp(expr),
414+
UnaryOp(expr)
415+
)
416+
417+
def collections(expr):
418+
"""Collection types"""
419+
return one_of(
420+
List(expr),
421+
Tuple(expr),
422+
Set(expr),
423+
Dict(expr)
424+
)
425+
426+
def calls_and_access(expr):
427+
"""Function calls and member access"""
428+
return one_of(
429+
Call(expr),
430+
Attribute(expr),
431+
Subscript(expr)
432+
)
433+
434+
def control_flow(expr):
435+
"""Control flow expressions"""
436+
return one_of(
437+
IfExp(expr),
438+
Yield(expr),
439+
YieldFrom(expr)
440+
)
441+
442+
def comprehensions(expr):
443+
"""List/dict/generator comprehensions"""
444+
return one_of(
445+
ListComp(expr),
446+
DictComp(expr),
447+
GeneratorExp(expr)
448+
)
403449

404450

405451
def async_expression() -> SearchStrategy:
406452
return recursive(
407453
leaves,
408-
lambda expression:
409-
one_of(
410-
Yield(expression),
411-
YieldFrom(expression),
412-
Await(expression),
413-
IfExp(expression),
414-
Call(expression),
415-
BinOp(expression),
416-
Set(expression),
417-
List(expression),
418-
Tuple(expression),
419-
BoolOp(expression),
420-
UnaryOp(expression),
421-
Attribute(expression),
422-
Dict(expression),
423-
Compare(expression),
424-
Lambda(expression),
425-
ListComp(expression),
426-
GeneratorExp(expression),
427-
DictComp(expression),
428-
Subscript(expression)
454+
lambda expression: one_of(
455+
binary_operations(expression),
456+
collections(expression),
457+
calls_and_access(expression),
458+
control_flow(expression),
459+
comprehensions(expression),
460+
Await(expression), # Async-specific
461+
Lambda(expression) # Complex case
429462
),
430-
max_leaves=150
463+
max_leaves=50
431464
)
432465

433466

434467
def expression() -> SearchStrategy:
435468
return recursive(
436469
leaves,
437-
lambda expression:
438-
one_of(
439-
Yield(expression),
440-
YieldFrom(expression),
441-
# Await(expression),
442-
IfExp(expression),
443-
Call(expression),
444-
BinOp(expression),
445-
Set(expression),
446-
List(expression),
447-
Tuple(expression),
448-
BoolOp(expression),
449-
UnaryOp(expression),
450-
Attribute(expression),
451-
Dict(expression),
452-
Compare(expression),
453-
Lambda(expression),
454-
ListComp(expression),
455-
GeneratorExp(expression),
456-
DictComp(expression),
457-
Subscript(expression)
470+
lambda expression: one_of(
471+
binary_operations(expression),
472+
collections(expression),
473+
calls_and_access(expression),
474+
control_flow(expression),
475+
comprehensions(expression),
476+
Lambda(expression) # Complex case
458477
),
459-
max_leaves=150
478+
max_leaves=50
460479
)
461480

462481

hypo_test/folding.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
11
import python_minifier.ast_compat as ast
22

3-
from hypothesis.strategies import SearchStrategy, composite, lists, recursive, sampled_from
3+
from hypothesis.strategies import SearchStrategy, composite, lists, one_of, recursive, sampled_from
44

55
from .expressions import NameConstant, Num
66

7-
leaves = NameConstant() | Num()
7+
leaves = one_of(
8+
NameConstant(),
9+
Num()
10+
)
811

912

1013
@composite
1114
def BinOp(draw, expression) -> ast.BinOp:
1215
op = draw(
1316
sampled_from(
1417
[
15-
ast.Add(),
18+
ast.Add(), # Most common arithmetic
1619
ast.Sub(),
1720
ast.Mult(),
1821
ast.Div(),
22+
ast.Mod(), # Common operations
1923
ast.FloorDiv(),
20-
ast.Mod(),
21-
ast.Pow(),
22-
ast.LShift(),
23-
ast.RShift(),
24+
ast.Pow(), # Less common
25+
ast.BitAnd(), # Bitwise operations
2426
ast.BitOr(),
2527
ast.BitXor(),
26-
ast.BitAnd(),
27-
ast.MatMult()
28+
ast.LShift(),
29+
ast.RShift(),
30+
ast.MatMult() # Least common (matrix mult)
2831
]
2932
)
3033
)

hypo_test/module.py

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,19 @@ def AugAssign(draw):
2323
op = draw(
2424
sampled_from(
2525
[
26-
ast.Add(),
26+
ast.Add(), # Most common arithmetic
2727
ast.Sub(),
2828
ast.Mult(),
2929
ast.Div(),
30+
ast.Mod(), # Common operations
3031
ast.FloorDiv(),
31-
ast.Mod(),
32-
ast.Pow(),
33-
ast.LShift(),
34-
ast.RShift(),
32+
ast.Pow(), # Less common
33+
ast.BitAnd(), # Bitwise operations
3534
ast.BitOr(),
3635
ast.BitXor(),
37-
ast.BitOr(),
38-
ast.BitAnd(),
39-
ast.MatMult()
36+
ast.LShift(),
37+
ast.RShift(),
38+
ast.MatMult() # Least common (matrix mult)
4039
]
4140
)
4241
)
@@ -51,7 +50,7 @@ def Print(draw):
5150

5251
@composite
5352
def Raise(draw):
54-
return ast.Raise(draw(none() | expression()), cause=None)
53+
return ast.Raise(draw(one_of(none(), expression())), cause=None)
5554

5655

5756
@composite
@@ -81,14 +80,16 @@ def Continue(draw) -> ast.Continue:
8180

8281
@composite
8382
def With(draw, statements) -> ast.With:
84-
items = draw(lists(expression(), min_size=1, max_size=3))
83+
# Tuples cannot be context expressions - they parse as multiple withitems
84+
items = draw(lists(expression().filter(lambda e: not isinstance(e, ast.Tuple)), min_size=1, max_size=3))
8585
body = draw(lists(statements, min_size=1, max_size=3))
8686
return ast.With([ast.withitem(context_expr=i, optional_vars=None) for i in items], body)
8787

8888

8989
@composite
9090
def AsyncWith(draw, statements) -> ast.AsyncWith:
91-
items = draw(lists(expression(), min_size=1, max_size=3))
91+
# Tuples cannot be context expressions - they parse as multiple withitems
92+
items = draw(lists(expression().filter(lambda e: not isinstance(e, ast.Tuple)), min_size=1, max_size=3))
9293
body = draw(lists(statements, min_size=1, max_size=3))
9394
return ast.AsyncWith([ast.withitem(context_expr=i, optional_vars=None) for i in items], body)
9495

@@ -102,7 +103,7 @@ def If(draw, statements) -> ast.If:
102103

103104
@composite
104105
def ExceptHandler(draw, statements) -> ast.ExceptHandler:
105-
t = draw(none() | Name())
106+
t = draw(one_of(none(), Name()))
106107

107108
n = None
108109
if t is not None:
@@ -181,7 +182,7 @@ def Nonlocal(draw) -> ast.Nonlocal:
181182

182183
@composite
183184
def alias(draw) -> ast.alias:
184-
return ast.alias(name=draw(name()), asname=draw(none() | name()))
185+
return ast.alias(name=draw(name()), asname=draw(one_of(none(), name())))
185186

186187

187188
@composite
@@ -202,7 +203,7 @@ def ImportFrom(draw) -> ast.ImportFrom:
202203
def TypeVar(draw) -> ast.TypeVar:
203204
return ast.TypeVar(
204205
name=draw(name()),
205-
bound=draw(none() | expression())
206+
bound=draw(one_of(none(), expression()))
206207
)
207208

208209

@@ -232,7 +233,7 @@ def FunctionDef(draw, statements) -> ast.FunctionDef:
232233
body = draw(lists(statements, min_size=1, max_size=3))
233234
decorator_list = draw(lists(Name(), min_size=0, max_size=2))
234235
type_params = draw(lists(one_of(TypeVar(), TypeVarTuple(), ParamSpec()), min_size=0, max_size=3))
235-
returns = draw(none() | expression())
236+
returns = draw(one_of(none(), expression()))
236237
return ast.FunctionDef(n, args, body, decorator_list, returns, type_params=type_params)
237238

238239

@@ -243,7 +244,7 @@ def AsyncFunctionDef(draw, statements) -> ast.AsyncFunctionDef:
243244
body = draw(lists(statements, min_size=1, max_size=3))
244245
decorator_list = draw(lists(Name(), min_size=0, max_size=2))
245246
type_params = draw(lists(one_of(TypeVar(), TypeVarTuple(), ParamSpec()), min_size=0, max_size=3))
246-
returns = draw(none() | expression())
247+
returns = draw(one_of(none(), expression()))
247248
return ast.AsyncFunctionDef(n, args, body, decorator_list, returns, type_params=type_params)
248249

249250

@@ -261,7 +262,14 @@ def ClassDef(draw, statements) -> ast.ClassDef:
261262
bases = draw(lists(expression(), min_size=0, max_size=2))
262263
keywords = draw(lists(keyword(), min_size=0, max_size=2))
263264

264-
assume(len({kw.arg for kw in keywords}) == len(keywords))
265+
# Remove duplicate keyword names
266+
seen_args = set()
267+
unique_keywords = []
268+
for kw in keywords:
269+
if kw.arg not in seen_args:
270+
seen_args.add(kw.arg)
271+
unique_keywords.append(kw)
272+
keywords = unique_keywords
265273

266274
body = draw(lists(statements, min_size=1, max_size=3))
267275
decorator_list = draw(lists(Name(), min_size=0, max_size=2))
@@ -277,39 +285,38 @@ def ClassDef(draw, statements) -> ast.ClassDef:
277285

278286
if hasattr(ast, 'Print'):
279287
simple_statements = one_of(
280-
Pass(),
281-
Break(),
288+
Pass(), # Simplest - no operation
289+
Break(), # Simple control flow
282290
Continue(),
283-
Global(),
291+
Global(), # Simple declarations
284292
Nonlocal(),
285-
Expr(),
286-
Assert(),
287-
Print(),
288-
Raise(),
289-
# Delete() |
290-
Assign(),
291-
AnnAssign(),
293+
Expr(), # Expression statement
294+
Assign(), # Simple assignments
292295
AugAssign(),
293-
Import(),
296+
AnnAssign(), # Type annotations
297+
Print(), # Python 2 print statement
298+
Assert(), # More complex statements
299+
Raise(),
300+
Import(), # Import statements
294301
ImportFrom()
302+
# Delete() - commented out
295303
)
296304
else:
297305
simple_statements = one_of(
298-
Pass(),
299-
Break(),
306+
Pass(), # Simplest - no operation
307+
Break(), # Simple control flow
300308
Continue(),
301-
Global(),
309+
Global(), # Simple declarations
302310
Nonlocal(),
303-
Expr(),
304-
Assert(),
305-
Raise(),
306-
# Delete() |
307-
Assign(),
308-
AnnAssign(),
311+
Expr(), # Expression statement
312+
Assign(), # Simple assignments
309313
AugAssign(),
310-
Import(),
314+
AnnAssign(), # Type annotations
315+
Assert(), # More complex statements
316+
Raise(),
317+
Import(), # Import statements
311318
ImportFrom(),
312-
TypeAlias()
319+
TypeAlias() # Most complex
313320
)
314321

315322

@@ -318,22 +325,22 @@ def suite() -> SearchStrategy:
318325
simple_statements,
319326
lambda statements:
320327
one_of(
321-
With(statements),
328+
If(statements), # Simple conditional
329+
While(statements), # Simple loop
330+
For(statements), # Loop with iteration
331+
With(statements), # Context manager
332+
FunctionDef(statements), # Function definition
333+
AsyncFor(statements), # Async variants
322334
AsyncWith(statements),
323-
If(statements),
324-
For(statements),
325-
AsyncFor(statements),
326-
While(statements),
327-
FunctionDef(statements),
328335
AsyncFunctionDef(statements),
329-
ClassDef(statements),
330-
Try(statements)
336+
Try(statements), # Complex exception handling
337+
ClassDef(statements) # Most complex
331338
),
332339
max_leaves=100
333340
)
334341

335342

336343
@composite
337344
def Module(draw) -> ast.Module:
338-
b = draw(lists(suite(), min_size=1, max_size=10))
345+
b = draw(lists(suite(), min_size=1, max_size=3))
339346
return ast.Module(body=b, type_ignores=[])

0 commit comments

Comments
 (0)