11from itertools import chain
2- from typing import cast , Callable , Collection , Dict , List
2+ from typing import cast , Callable , Collection , Dict , List , Union
33
44from ..language import DirectiveLocation , parse_value
55from ..pyutils import inspect , Undefined
3131 is_output_type ,
3232 specified_scalar_types ,
3333)
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+ )
3448from .value_from_ast import value_from_ast
3549
3650__all__ = ["build_client_schema" ]
3751
3852
3953def build_client_schema (
40- introspection : Dict , assume_valid : bool = False
54+ introspection : IntrospectionQuery , assume_valid : bool = False
4155) -> GraphQLSchema :
4256 """Build a GraphQLSchema for use by client tools.
4357
@@ -64,22 +78,25 @@ def build_client_schema(
6478
6579 # Given a type reference in introspection, return the GraphQLType instance,
6680 # preferring cached instances before building new instances.
67- def get_type (type_ref : Dict ) -> GraphQLType :
81+ def get_type (type_ref : IntrospectionTypeRef ) -> GraphQLType :
6882 kind = type_ref .get ("kind" )
6983 if kind == TypeKind .LIST .name :
7084 item_ref = type_ref .get ("ofType" )
7185 if not item_ref :
7286 raise TypeError ("Decorated type deeper than introspection query." )
87+ item_ref = cast (IntrospectionTypeRef , item_ref )
7388 return GraphQLList (get_type (item_ref ))
74- elif kind == TypeKind .NON_NULL .name :
89+ if kind == TypeKind .NON_NULL .name :
7590 nullable_ref = type_ref .get ("ofType" )
7691 if not nullable_ref :
7792 raise TypeError ("Decorated type deeper than introspection query." )
93+ nullable_ref = cast (IntrospectionTypeRef , nullable_ref )
7894 nullable_type = get_type (nullable_ref )
7995 return GraphQLNonNull (assert_nullable_type (nullable_type ))
96+ type_ref = cast (IntrospectionType , type_ref )
8097 return get_named_type (type_ref )
8198
82- def get_named_type (type_ref : Dict ) -> GraphQLNamedType :
99+ def get_named_type (type_ref : IntrospectionType ) -> GraphQLNamedType :
83100 type_name = type_ref .get ("name" )
84101 if not type_name :
85102 raise TypeError (f"Unknown type reference: { inspect (type_ref )} ." )
@@ -93,36 +110,42 @@ def get_named_type(type_ref: Dict) -> GraphQLNamedType:
93110 )
94111 return type_
95112
96- def get_object_type (type_ref : Dict ) -> GraphQLObjectType :
113+ def get_object_type (type_ref : IntrospectionObjectType ) -> GraphQLObjectType :
97114 return assert_object_type (get_type (type_ref ))
98115
99- def get_interface_type (type_ref : Dict ) -> GraphQLInterfaceType :
116+ def get_interface_type (
117+ type_ref : IntrospectionInterfaceType ,
118+ ) -> GraphQLInterfaceType :
100119 return assert_interface_type (get_type (type_ref ))
101120
102121 # 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 :
104123 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" ])
106125 if builder : # pragma: no cover else
107- return cast ( GraphQLNamedType , builder (type_ ) )
126+ return builder (type_ )
108127 raise TypeError (
109128 "Invalid or incomplete introspection result."
110129 " Ensure that a full introspection query is used in order"
111130 f" to build a client schema: { inspect (type_ )} ."
112131 )
113132
114- def build_scalar_def (scalar_introspection : Dict ) -> GraphQLScalarType :
133+ def build_scalar_def (
134+ scalar_introspection : IntrospectionScalarType ,
135+ ) -> GraphQLScalarType :
115136 return GraphQLScalarType (
116137 name = scalar_introspection ["name" ],
117138 description = scalar_introspection .get ("description" ),
118139 specified_by_url = scalar_introspection .get ("specifiedByURL" ),
119140 )
120141
121142 def build_implementations_list (
122- implementing_introspection : Dict ,
143+ implementing_introspection : Union [
144+ IntrospectionObjectType , IntrospectionInterfaceType
145+ ],
123146 ) -> 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 :
126149 # Temporary workaround until GraphQL ecosystem will fully support
127150 # 'interfaces' on interface types
128151 if implementing_introspection ["kind" ] == TypeKind .INTERFACE .name :
@@ -131,40 +154,46 @@ def build_implementations_list(
131154 "Introspection result missing interfaces:"
132155 f" { inspect (implementing_introspection )} ."
133156 )
157+ interfaces = cast (Collection [IntrospectionInterfaceType ], maybe_interfaces )
134158 return [get_interface_type (interface ) for interface in interfaces ]
135159
136- def build_object_def (object_introspection : Dict ) -> GraphQLObjectType :
160+ def build_object_def (
161+ object_introspection : IntrospectionObjectType ,
162+ ) -> GraphQLObjectType :
137163 return GraphQLObjectType (
138164 name = object_introspection ["name" ],
139165 description = object_introspection .get ("description" ),
140166 interfaces = lambda : build_implementations_list (object_introspection ),
141167 fields = lambda : build_field_def_map (object_introspection ),
142168 )
143169
144- def build_interface_def (interface_introspection : Dict ) -> GraphQLInterfaceType :
170+ def build_interface_def (
171+ interface_introspection : IntrospectionInterfaceType ,
172+ ) -> GraphQLInterfaceType :
145173 return GraphQLInterfaceType (
146174 name = interface_introspection ["name" ],
147175 description = interface_introspection .get ("description" ),
148176 interfaces = lambda : build_implementations_list (interface_introspection ),
149177 fields = lambda : build_field_def_map (interface_introspection ),
150178 )
151179
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 :
155185 raise TypeError (
156186 "Introspection result missing possibleTypes:"
157187 f" { inspect (union_introspection )} ."
158188 )
189+ possible_types = cast (Collection [IntrospectionObjectType ], maybe_possible_types )
159190 return GraphQLUnionType (
160191 name = union_introspection ["name" ],
161192 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 ],
165194 )
166195
167- def build_enum_def (enum_introspection : Dict ) -> GraphQLEnumType :
196+ def build_enum_def (enum_introspection : IntrospectionEnumType ) -> GraphQLEnumType :
168197 if enum_introspection .get ("enumValues" ) is None :
169198 raise TypeError (
170199 "Introspection result missing enumValues:"
@@ -184,7 +213,7 @@ def build_enum_def(enum_introspection: Dict) -> GraphQLEnumType:
184213 )
185214
186215 def build_input_object_def (
187- input_object_introspection : Dict ,
216+ input_object_introspection : IntrospectionInputObjectType ,
188217 ) -> GraphQLInputObjectType :
189218 if input_object_introspection .get ("inputFields" ) is None :
190219 raise TypeError (
@@ -199,16 +228,18 @@ def build_input_object_def(
199228 ),
200229 )
201230
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
209238 }
210239
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 ]:
212243 if type_introspection .get ("fields" ) is None :
213244 raise TypeError (
214245 f"Introspection result missing fields: { type_introspection } ."
@@ -218,8 +249,9 @@ def build_field_def_map(type_introspection: Dict) -> Dict[str, GraphQLField]:
218249 for field_introspection in type_introspection ["fields" ]
219250 }
220251
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 )
223255 if not is_output_type (type_ ):
224256 raise TypeError (
225257 "Introspection must provide output type for fields,"
@@ -242,27 +274,30 @@ def build_field(field_introspection: Dict) -> GraphQLField:
242274 )
243275
244276 def build_argument_def_map (
245- input_value_introspections : Dict ,
277+ argument_value_introspections : Collection [ IntrospectionInputValue ] ,
246278 ) -> Dict [str , GraphQLArgument ]:
247279 return {
248280 argument_introspection ["name" ]: build_argument (argument_introspection )
249- for argument_introspection in input_value_introspections
281+ for argument_introspection in argument_value_introspections
250282 }
251283
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 )
254289 if not is_input_type (type_ ):
255290 raise TypeError (
256291 "Introspection must provide input type for arguments,"
257292 f" but received: { inspect (type_ )} ."
258293 )
259294 type_ = cast (GraphQLInputType , type_ )
260295
261- default_value = argument_introspection .get ("defaultValue" )
296+ default_value_introspection = argument_introspection .get ("defaultValue" )
262297 default_value = (
263298 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_ )
266301 )
267302 return GraphQLArgument (
268303 type_ ,
@@ -272,7 +307,7 @@ def build_argument(argument_introspection: Dict) -> GraphQLArgument:
272307 )
273308
274309 def build_input_value_def_map (
275- input_value_introspections : Dict ,
310+ input_value_introspections : Collection [ IntrospectionInputValue ] ,
276311 ) -> Dict [str , GraphQLInputField ]:
277312 return {
278313 input_value_introspection ["name" ]: build_input_value (
@@ -281,20 +316,23 @@ def build_input_value_def_map(
281316 for input_value_introspection in input_value_introspections
282317 }
283318
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 )
286324 if not is_input_type (type_ ):
287325 raise TypeError (
288326 "Introspection must provide input type for input fields,"
289327 f" but received: { inspect (type_ )} ."
290328 )
291329 type_ = cast (GraphQLInputType , type_ )
292330
293- default_value = input_value_introspection .get ("defaultValue" )
331+ default_value_introspection = input_value_introspection .get ("defaultValue" )
294332 default_value = (
295333 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_ )
298336 )
299337 return GraphQLInputField (
300338 type_ ,
@@ -303,7 +341,9 @@ def build_input_value(input_value_introspection: Dict) -> GraphQLInputField:
303341 deprecation_reason = input_value_introspection .get ("deprecationReason" ),
304342 )
305343
306- def build_directive (directive_introspection : Dict ) -> GraphQLDirective :
344+ def build_directive (
345+ directive_introspection : IntrospectionDirective ,
346+ ) -> GraphQLDirective :
307347 if directive_introspection .get ("args" ) is None :
308348 raise TypeError (
309349 "Introspection result missing directive args:"
0 commit comments