Skip to content

Commit a88c628

Browse files
committed
Move rules into individual files.
* Don't use *args, instead explicitly specify all args (I think there is less overhead here than having py create a tuple to pass).
1 parent fe3a31b commit a88c628

30 files changed

+1267
-1145
lines changed

graphql/core/validation/__init__.py

Lines changed: 4 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,9 @@
1-
from . import rules as Rules
2-
from ..error import GraphQLError
3-
from ..language.ast import FragmentDefinition, FragmentSpread
4-
from ..language.visitor import Visitor, visit
1+
from ..language.visitor import visit
52
from ..type import GraphQLSchema
63
from ..utils.type_info import TypeInfo
7-
8-
specified_rules = [
9-
Rules.UniqueOperationNames,
10-
Rules.LoneAnonymousOperation,
11-
Rules.KnownTypeNames,
12-
Rules.FragmentsOnCompositeTypes,
13-
Rules.VariablesAreInputTypes,
14-
Rules.ScalarLeafs,
15-
Rules.FieldsOnCorrectType,
16-
Rules.UniqueFragmentNames,
17-
Rules.KnownFragmentNames,
18-
Rules.NoUnusedFragments,
19-
Rules.PossibleFragmentSpreads,
20-
Rules.NoFragmentCycles,
21-
Rules.NoUndefinedVariables,
22-
Rules.NoUnusedVariables,
23-
Rules.KnownDirectives,
24-
Rules.KnownArgumentNames,
25-
Rules.UniqueArgumentNames,
26-
Rules.ArgumentsOfCorrectType,
27-
Rules.ProvidedNonNullArguments,
28-
Rules.DefaultValuesOfCorrectType,
29-
Rules.VariablesInAllowedPosition,
30-
Rules.OverlappingFieldsCanBeMerged,
31-
Rules.UniqueInputFieldNames
32-
]
4+
from .context import ValidationContext
5+
from .rules import specified_rules
6+
from .visitor import ValidationVisitor
337

348

359
def validate(schema, ast, rules=None):
@@ -48,140 +22,3 @@ def visit_using_rules(schema, ast, rules):
4822
rules = [rule(context) for rule in rules]
4923
visit(ast, ValidationVisitor(rules, context, type_info, errors))
5024
return errors
51-
52-
53-
class ValidationVisitor(Visitor):
54-
def __init__(self, rules, context, type_info, errors):
55-
self.context = context
56-
self.rules = rules
57-
self.total_rules = len(rules)
58-
self.type_info = type_info
59-
self.errors = errors
60-
self.ignore_children = {}
61-
62-
def enter(self, node, key, parent, path, ancestors):
63-
self.type_info.enter(node)
64-
to_ignore = None
65-
rules_wanting_to_visit_fragment = None
66-
67-
skipped = 0
68-
for rule in self.rules:
69-
if rule in self.ignore_children:
70-
skipped += 1
71-
continue
72-
73-
visit_spread_fragments = getattr(rule, 'visit_spread_fragments', False)
74-
75-
if isinstance(node, FragmentDefinition) and key and visit_spread_fragments:
76-
if to_ignore is None:
77-
to_ignore = []
78-
79-
to_ignore.append(rule)
80-
continue
81-
82-
result = rule.enter(node, key, parent, path, ancestors)
83-
84-
if result and is_error(result):
85-
append(self.errors, result)
86-
result = False
87-
88-
if result is None and visit_spread_fragments and isinstance(node, FragmentSpread):
89-
if rules_wanting_to_visit_fragment is None:
90-
rules_wanting_to_visit_fragment = []
91-
92-
rules_wanting_to_visit_fragment.append(rule)
93-
94-
if result is False:
95-
if to_ignore is None:
96-
to_ignore = []
97-
98-
to_ignore.append(rule)
99-
100-
if rules_wanting_to_visit_fragment:
101-
fragment = self.context.get_fragment(node.name.value)
102-
103-
if fragment:
104-
sub_visitor = ValidationVisitor(rules_wanting_to_visit_fragment, self.context, self.type_info,
105-
self.errors)
106-
visit(fragment, sub_visitor)
107-
108-
should_skip = (len(to_ignore) if to_ignore else 0 + skipped) == self.total_rules
109-
110-
if should_skip:
111-
self.type_info.leave(node)
112-
113-
elif to_ignore:
114-
for rule in to_ignore:
115-
self.ignore_children[rule] = node
116-
117-
if should_skip:
118-
return False
119-
120-
def leave(self, node, key, parent, path, ancestors):
121-
for rule in self.rules:
122-
if rule in self.ignore_children:
123-
if self.ignore_children[rule] is node:
124-
del self.ignore_children[rule]
125-
126-
continue
127-
128-
result = rule.leave(node, key, parent, path, ancestors)
129-
130-
if result and is_error(result):
131-
append(self.errors, result)
132-
133-
self.type_info.leave(node)
134-
135-
136-
def is_error(value):
137-
if isinstance(value, list):
138-
return all(isinstance(item, GraphQLError) for item in value)
139-
return isinstance(value, GraphQLError)
140-
141-
142-
def append(arr, items):
143-
if isinstance(items, list):
144-
arr.extend(items)
145-
else:
146-
arr.append(items)
147-
148-
149-
class ValidationContext(object):
150-
def __init__(self, schema, ast, type_info):
151-
self._schema = schema
152-
self._ast = ast
153-
self._type_info = type_info
154-
self._fragments = None
155-
156-
def get_schema(self):
157-
return self._schema
158-
159-
def get_ast(self):
160-
return self._ast
161-
162-
def get_fragment(self, name):
163-
fragments = self._fragments
164-
if fragments is None:
165-
self._fragments = fragments = {}
166-
for statement in self.get_ast().definitions:
167-
if isinstance(statement, FragmentDefinition):
168-
fragments[statement.name.value] = statement
169-
return fragments.get(name)
170-
171-
def get_type(self):
172-
return self._type_info.get_type()
173-
174-
def get_parent_type(self):
175-
return self._type_info.get_parent_type()
176-
177-
def get_input_type(self):
178-
return self._type_info.get_input_type()
179-
180-
def get_field_def(self):
181-
return self._type_info.get_field_def()
182-
183-
def get_directive(self):
184-
return self._type_info.get_directive()
185-
186-
def get_argument(self):
187-
return self._type_info.get_argument()

graphql/core/validation/context.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from ..language.ast import FragmentDefinition
2+
3+
4+
class ValidationContext(object):
5+
def __init__(self, schema, ast, type_info):
6+
self._schema = schema
7+
self._ast = ast
8+
self._type_info = type_info
9+
self._fragments = None
10+
11+
def get_schema(self):
12+
return self._schema
13+
14+
def get_ast(self):
15+
return self._ast
16+
17+
def get_fragment(self, name):
18+
fragments = self._fragments
19+
if fragments is None:
20+
self._fragments = fragments = {}
21+
for statement in self.get_ast().definitions:
22+
if isinstance(statement, FragmentDefinition):
23+
fragments[statement.name.value] = statement
24+
return fragments.get(name)
25+
26+
def get_type(self):
27+
return self._type_info.get_type()
28+
29+
def get_parent_type(self):
30+
return self._type_info.get_parent_type()
31+
32+
def get_input_type(self):
33+
return self._type_info.get_input_type()
34+
35+
def get_field_def(self):
36+
return self._type_info.get_field_def()
37+
38+
def get_directive(self):
39+
return self._type_info.get_directive()
40+
41+
def get_argument(self):
42+
return self._type_info.get_argument()

0 commit comments

Comments
 (0)