-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidators.py
More file actions
144 lines (97 loc) · 3.75 KB
/
validators.py
File metadata and controls
144 lines (97 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import ast
import core_logic
def is_instance_of(ast_node_type):
def validate(cursor_trail, tree):
selected_node = core_logic.get_node_at_cursor(cursor_trail, tree)
# make sure the node is allowed to be placed here
return isinstance(selected_node, ast_node_type)
return validate
# TODO: Move the validators into their own module
def is_not_instance_of(ast_node_type):
def validate(cursor_trail, tree):
selected_node = core_logic.get_node_at_cursor(cursor_trail, tree)
return not isinstance(selected_node, ast_node_type)
return validate
def is_within(ast_node_type):
def validate(cursor_trail, tree):
return core_logic.core_is_within(cursor_trail, tree, ast_node_type)
return validate
def is_within_field(ast_node_type, fieldname):
def validate(cursor_trail, tree):
return core_logic.core_is_within_field(cursor_trail, tree, ast_node_type, fieldname)
return validate
def is_not_in_context(context):
def validate(cursor_trail, tree):
return core_logic.core_is_not_in_context(cursor_trail, tree, context)
return validate
def is_in_context(context):
def validate(cursor_trail, tree):
return core_logic.core_is_in_context(cursor_trail, tree, context)
return validate
def validate_both(first_validator, second_validator):
"""Make sure both validators pass"""
def validate(cursor_trail, tree):
return (first_validator(cursor_trail, tree)
and second_validator(cursor_trail, tree))
return validate
def validate_one_of(*validators):
"""Make sure at lest one of the validators passess"""
def validate(cursor_trail, tree):
for validator in validators:
if validator(cursor_trail, tree):
return True
return False
return validate
def validate_all_of(*list_of_validators):
def validate(cursor_trail, tree):
for validator in list_of_validators:
if not validator(cursor_trail, tree):
return False
return True
return validate
def validate_not(validator):
"""Negates the validator"""
def negated(*args, **kwargs):
return not validator(*args, **kwargs)
return negated
def is_in_loop():
# TODO: Maybe the async variants work too?
return validate_one_of(
is_within_field(ast.For, "body"),
is_within_field(ast.While, "body")
)
# Validates that it's a simple expression
# and that it's in a simple context (no assigning to it)
is_simple_expression = validate_all_of(
validate_one_of(
is_instance_of(ast.expr),
# Simple expressions are allowed as statements
# They will be wrapped in a Expr node
is_instance_of(ast.stmt)
),
is_not_in_context(ast.Store),
is_not_in_context(ast.Param),
is_not_in_context(ast.Del),
)
# TODO: Replace all of the validate_both with validate_all
# For assignable expressions, any context goes
# and they can't be assign
is_assignable_expression = validate_one_of(
is_instance_of(ast.expr),
is_instance_of(ast.stmt),
)
# Those assignable expressions can't appear as targets of an annotated
# assignment
is_non_annotatable_assignable_expression = validate_all_of(
is_assignable_expression,
validate_not(
is_within_field(ast.AnnAssign, "target"),
),
)
simple_expression_within_function = validate_all_of(
is_simple_expression,
validate_one_of(
is_within(ast.FunctionDef),
is_within(ast.AsyncFunctionDef)
),
)