1
1
from itertools import chain
2
- from typing import cast , Callable , Collection , Dict , List
2
+ from typing import cast , Callable , Collection , Dict , List , Union
3
3
4
4
from ..language import DirectiveLocation , parse_value
5
5
from ..pyutils import inspect , Undefined
31
31
is_output_type ,
32
32
specified_scalar_types ,
33
33
)
34
+ from .get_introspection_query import (
35
+ IntrospectionDirective ,
36
+ IntrospectionEnumType ,
37
+ IntrospectionField ,
38
+ IntrospectionInterfaceType ,
39
+ IntrospectionInputObjectType ,
40
+ IntrospectionInputValue ,
41
+ IntrospectionObjectType ,
42
+ IntrospectionQuery ,
43
+ IntrospectionScalarType ,
44
+ IntrospectionType ,
45
+ IntrospectionTypeRef ,
46
+ IntrospectionUnionType ,
47
+ )
34
48
from .value_from_ast import value_from_ast
35
49
36
50
__all__ = ["build_client_schema" ]
37
51
38
52
39
53
def build_client_schema (
40
- introspection : Dict , assume_valid : bool = False
54
+ introspection : IntrospectionQuery , assume_valid : bool = False
41
55
) -> GraphQLSchema :
42
56
"""Build a GraphQLSchema for use by client tools.
43
57
@@ -64,22 +78,25 @@ def build_client_schema(
64
78
65
79
# Given a type reference in introspection, return the GraphQLType instance,
66
80
# preferring cached instances before building new instances.
67
- def get_type (type_ref : Dict ) -> GraphQLType :
81
+ def get_type (type_ref : IntrospectionTypeRef ) -> GraphQLType :
68
82
kind = type_ref .get ("kind" )
69
83
if kind == TypeKind .LIST .name :
70
84
item_ref = type_ref .get ("ofType" )
71
85
if not item_ref :
72
86
raise TypeError ("Decorated type deeper than introspection query." )
87
+ item_ref = cast (IntrospectionTypeRef , item_ref )
73
88
return GraphQLList (get_type (item_ref ))
74
- elif kind == TypeKind .NON_NULL .name :
89
+ if kind == TypeKind .NON_NULL .name :
75
90
nullable_ref = type_ref .get ("ofType" )
76
91
if not nullable_ref :
77
92
raise TypeError ("Decorated type deeper than introspection query." )
93
+ nullable_ref = cast (IntrospectionTypeRef , nullable_ref )
78
94
nullable_type = get_type (nullable_ref )
79
95
return GraphQLNonNull (assert_nullable_type (nullable_type ))
96
+ type_ref = cast (IntrospectionType , type_ref )
80
97
return get_named_type (type_ref )
81
98
82
- def get_named_type (type_ref : Dict ) -> GraphQLNamedType :
99
+ def get_named_type (type_ref : IntrospectionType ) -> GraphQLNamedType :
83
100
type_name = type_ref .get ("name" )
84
101
if not type_name :
85
102
raise TypeError (f"Unknown type reference: { inspect (type_ref )} ." )
@@ -93,36 +110,42 @@ def get_named_type(type_ref: Dict) -> GraphQLNamedType:
93
110
)
94
111
return type_
95
112
96
- def get_object_type (type_ref : Dict ) -> GraphQLObjectType :
113
+ def get_object_type (type_ref : IntrospectionObjectType ) -> GraphQLObjectType :
97
114
return assert_object_type (get_type (type_ref ))
98
115
99
- def get_interface_type (type_ref : Dict ) -> GraphQLInterfaceType :
116
+ def get_interface_type (
117
+ type_ref : IntrospectionInterfaceType ,
118
+ ) -> GraphQLInterfaceType :
100
119
return assert_interface_type (get_type (type_ref ))
101
120
102
121
# Given a type's introspection result, construct the correct GraphQLType instance.
103
- def build_type (type_ : Dict ) -> GraphQLNamedType :
122
+ def build_type (type_ : IntrospectionType ) -> GraphQLNamedType :
104
123
if type_ and "name" in type_ and "kind" in type_ :
105
- builder = type_builders .get (cast ( str , type_ ["kind" ]) )
124
+ builder = type_builders .get (type_ ["kind" ])
106
125
if builder : # pragma: no cover else
107
- return cast ( GraphQLNamedType , builder (type_ ) )
126
+ return builder (type_ )
108
127
raise TypeError (
109
128
"Invalid or incomplete introspection result."
110
129
" Ensure that a full introspection query is used in order"
111
130
f" to build a client schema: { inspect (type_ )} ."
112
131
)
113
132
114
- def build_scalar_def (scalar_introspection : Dict ) -> GraphQLScalarType :
133
+ def build_scalar_def (
134
+ scalar_introspection : IntrospectionScalarType ,
135
+ ) -> GraphQLScalarType :
115
136
return GraphQLScalarType (
116
137
name = scalar_introspection ["name" ],
117
138
description = scalar_introspection .get ("description" ),
118
139
specified_by_url = scalar_introspection .get ("specifiedByURL" ),
119
140
)
120
141
121
142
def build_implementations_list (
122
- implementing_introspection : Dict ,
143
+ implementing_introspection : Union [
144
+ IntrospectionObjectType , IntrospectionInterfaceType
145
+ ],
123
146
) -> List [GraphQLInterfaceType ]:
124
- interfaces = implementing_introspection .get ("interfaces" )
125
- if interfaces is None :
147
+ maybe_interfaces = implementing_introspection .get ("interfaces" )
148
+ if maybe_interfaces is None :
126
149
# Temporary workaround until GraphQL ecosystem will fully support
127
150
# 'interfaces' on interface types
128
151
if implementing_introspection ["kind" ] == TypeKind .INTERFACE .name :
@@ -131,40 +154,46 @@ def build_implementations_list(
131
154
"Introspection result missing interfaces:"
132
155
f" { inspect (implementing_introspection )} ."
133
156
)
157
+ interfaces = cast (Collection [IntrospectionInterfaceType ], maybe_interfaces )
134
158
return [get_interface_type (interface ) for interface in interfaces ]
135
159
136
- def build_object_def (object_introspection : Dict ) -> GraphQLObjectType :
160
+ def build_object_def (
161
+ object_introspection : IntrospectionObjectType ,
162
+ ) -> GraphQLObjectType :
137
163
return GraphQLObjectType (
138
164
name = object_introspection ["name" ],
139
165
description = object_introspection .get ("description" ),
140
166
interfaces = lambda : build_implementations_list (object_introspection ),
141
167
fields = lambda : build_field_def_map (object_introspection ),
142
168
)
143
169
144
- def build_interface_def (interface_introspection : Dict ) -> GraphQLInterfaceType :
170
+ def build_interface_def (
171
+ interface_introspection : IntrospectionInterfaceType ,
172
+ ) -> GraphQLInterfaceType :
145
173
return GraphQLInterfaceType (
146
174
name = interface_introspection ["name" ],
147
175
description = interface_introspection .get ("description" ),
148
176
interfaces = lambda : build_implementations_list (interface_introspection ),
149
177
fields = lambda : build_field_def_map (interface_introspection ),
150
178
)
151
179
152
- def build_union_def (union_introspection : Dict ) -> GraphQLUnionType :
153
- possible_types = union_introspection .get ("possibleTypes" )
154
- if possible_types is None :
180
+ def build_union_def (
181
+ union_introspection : IntrospectionUnionType ,
182
+ ) -> GraphQLUnionType :
183
+ maybe_possible_types = union_introspection .get ("possibleTypes" )
184
+ if maybe_possible_types is None :
155
185
raise TypeError (
156
186
"Introspection result missing possibleTypes:"
157
187
f" { inspect (union_introspection )} ."
158
188
)
189
+ possible_types = cast (Collection [IntrospectionObjectType ], maybe_possible_types )
159
190
return GraphQLUnionType (
160
191
name = union_introspection ["name" ],
161
192
description = union_introspection .get ("description" ),
162
- types = lambda : [
163
- get_object_type (type_ ) for type_ in cast (List [Dict ], possible_types )
164
- ],
193
+ types = lambda : [get_object_type (type_ ) for type_ in possible_types ],
165
194
)
166
195
167
- def build_enum_def (enum_introspection : Dict ) -> GraphQLEnumType :
196
+ def build_enum_def (enum_introspection : IntrospectionEnumType ) -> GraphQLEnumType :
168
197
if enum_introspection .get ("enumValues" ) is None :
169
198
raise TypeError (
170
199
"Introspection result missing enumValues:"
@@ -184,7 +213,7 @@ def build_enum_def(enum_introspection: Dict) -> GraphQLEnumType:
184
213
)
185
214
186
215
def build_input_object_def (
187
- input_object_introspection : Dict ,
216
+ input_object_introspection : IntrospectionInputObjectType ,
188
217
) -> GraphQLInputObjectType :
189
218
if input_object_introspection .get ("inputFields" ) is None :
190
219
raise TypeError (
@@ -199,16 +228,18 @@ def build_input_object_def(
199
228
),
200
229
)
201
230
202
- type_builders : Dict [str , Callable [[Dict ], GraphQLType ]] = {
203
- TypeKind .SCALAR .name : build_scalar_def ,
204
- TypeKind .OBJECT .name : build_object_def ,
205
- TypeKind .INTERFACE .name : build_interface_def ,
206
- TypeKind .UNION .name : build_union_def ,
207
- TypeKind .ENUM .name : build_enum_def ,
208
- TypeKind .INPUT_OBJECT .name : build_input_object_def ,
231
+ type_builders : Dict [str , Callable [[IntrospectionType ], GraphQLNamedType ]] = {
232
+ TypeKind .SCALAR .name : build_scalar_def , # type: ignore
233
+ TypeKind .OBJECT .name : build_object_def , # type: ignore
234
+ TypeKind .INTERFACE .name : build_interface_def , # type: ignore
235
+ TypeKind .UNION .name : build_union_def , # type: ignore
236
+ TypeKind .ENUM .name : build_enum_def , # type: ignore
237
+ TypeKind .INPUT_OBJECT .name : build_input_object_def , # type: ignore
209
238
}
210
239
211
- def build_field_def_map (type_introspection : Dict ) -> Dict [str , GraphQLField ]:
240
+ def build_field_def_map (
241
+ type_introspection : Union [IntrospectionObjectType , IntrospectionInterfaceType ],
242
+ ) -> Dict [str , GraphQLField ]:
212
243
if type_introspection .get ("fields" ) is None :
213
244
raise TypeError (
214
245
f"Introspection result missing fields: { type_introspection } ."
@@ -218,8 +249,9 @@ def build_field_def_map(type_introspection: Dict) -> Dict[str, GraphQLField]:
218
249
for field_introspection in type_introspection ["fields" ]
219
250
}
220
251
221
- def build_field (field_introspection : Dict ) -> GraphQLField :
222
- type_ = get_type (field_introspection ["type" ])
252
+ def build_field (field_introspection : IntrospectionField ) -> GraphQLField :
253
+ type_introspection = cast (IntrospectionType , field_introspection ["type" ])
254
+ type_ = get_type (type_introspection )
223
255
if not is_output_type (type_ ):
224
256
raise TypeError (
225
257
"Introspection must provide output type for fields,"
@@ -242,27 +274,30 @@ def build_field(field_introspection: Dict) -> GraphQLField:
242
274
)
243
275
244
276
def build_argument_def_map (
245
- input_value_introspections : Dict ,
277
+ argument_value_introspections : Collection [ IntrospectionInputValue ] ,
246
278
) -> Dict [str , GraphQLArgument ]:
247
279
return {
248
280
argument_introspection ["name" ]: build_argument (argument_introspection )
249
- for argument_introspection in input_value_introspections
281
+ for argument_introspection in argument_value_introspections
250
282
}
251
283
252
- def build_argument (argument_introspection : Dict ) -> GraphQLArgument :
253
- type_ = get_type (argument_introspection ["type" ])
284
+ def build_argument (
285
+ argument_introspection : IntrospectionInputValue ,
286
+ ) -> GraphQLArgument :
287
+ type_introspection = cast (IntrospectionType , argument_introspection ["type" ])
288
+ type_ = get_type (type_introspection )
254
289
if not is_input_type (type_ ):
255
290
raise TypeError (
256
291
"Introspection must provide input type for arguments,"
257
292
f" but received: { inspect (type_ )} ."
258
293
)
259
294
type_ = cast (GraphQLInputType , type_ )
260
295
261
- default_value = argument_introspection .get ("defaultValue" )
296
+ default_value_introspection = argument_introspection .get ("defaultValue" )
262
297
default_value = (
263
298
Undefined
264
- if default_value is None
265
- else value_from_ast (parse_value (default_value ), type_ )
299
+ if default_value_introspection is None
300
+ else value_from_ast (parse_value (default_value_introspection ), type_ )
266
301
)
267
302
return GraphQLArgument (
268
303
type_ ,
@@ -272,7 +307,7 @@ def build_argument(argument_introspection: Dict) -> GraphQLArgument:
272
307
)
273
308
274
309
def build_input_value_def_map (
275
- input_value_introspections : Dict ,
310
+ input_value_introspections : Collection [ IntrospectionInputValue ] ,
276
311
) -> Dict [str , GraphQLInputField ]:
277
312
return {
278
313
input_value_introspection ["name" ]: build_input_value (
@@ -281,20 +316,23 @@ def build_input_value_def_map(
281
316
for input_value_introspection in input_value_introspections
282
317
}
283
318
284
- def build_input_value (input_value_introspection : Dict ) -> GraphQLInputField :
285
- type_ = get_type (input_value_introspection ["type" ])
319
+ def build_input_value (
320
+ input_value_introspection : IntrospectionInputValue ,
321
+ ) -> GraphQLInputField :
322
+ type_introspection = cast (IntrospectionType , input_value_introspection ["type" ])
323
+ type_ = get_type (type_introspection )
286
324
if not is_input_type (type_ ):
287
325
raise TypeError (
288
326
"Introspection must provide input type for input fields,"
289
327
f" but received: { inspect (type_ )} ."
290
328
)
291
329
type_ = cast (GraphQLInputType , type_ )
292
330
293
- default_value = input_value_introspection .get ("defaultValue" )
331
+ default_value_introspection = input_value_introspection .get ("defaultValue" )
294
332
default_value = (
295
333
Undefined
296
- if default_value is None
297
- else value_from_ast (parse_value (default_value ), type_ )
334
+ if default_value_introspection is None
335
+ else value_from_ast (parse_value (default_value_introspection ), type_ )
298
336
)
299
337
return GraphQLInputField (
300
338
type_ ,
@@ -303,7 +341,9 @@ def build_input_value(input_value_introspection: Dict) -> GraphQLInputField:
303
341
deprecation_reason = input_value_introspection .get ("deprecationReason" ),
304
342
)
305
343
306
- def build_directive (directive_introspection : Dict ) -> GraphQLDirective :
344
+ def build_directive (
345
+ directive_introspection : IntrospectionDirective ,
346
+ ) -> GraphQLDirective :
307
347
if directive_introspection .get ("args" ) is None :
308
348
raise TypeError (
309
349
"Introspection result missing directive args:"
0 commit comments