execute.py 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251
  1. from asyncio import ensure_future, gather
  2. from collections.abc import Mapping
  3. from inspect import isawaitable
  4. from typing import (
  5. Any,
  6. AsyncIterable,
  7. Awaitable,
  8. Callable,
  9. Dict,
  10. Iterable,
  11. List,
  12. Optional,
  13. Union,
  14. Tuple,
  15. Type,
  16. cast,
  17. )
  18. try:
  19. from typing import TypedDict
  20. except ImportError: # Python < 3.8
  21. from typing_extensions import TypedDict
  22. from ..error import GraphQLError, GraphQLFormattedError, located_error
  23. from ..language import (
  24. DocumentNode,
  25. FieldNode,
  26. FragmentDefinitionNode,
  27. OperationDefinitionNode,
  28. OperationType,
  29. )
  30. from ..pyutils import (
  31. inspect,
  32. is_awaitable as default_is_awaitable,
  33. is_iterable,
  34. AwaitableOrValue,
  35. Path,
  36. Undefined,
  37. )
  38. from ..type import (
  39. GraphQLAbstractType,
  40. GraphQLField,
  41. GraphQLLeafType,
  42. GraphQLList,
  43. GraphQLNonNull,
  44. GraphQLObjectType,
  45. GraphQLOutputType,
  46. GraphQLSchema,
  47. GraphQLFieldResolver,
  48. GraphQLTypeResolver,
  49. GraphQLResolveInfo,
  50. SchemaMetaFieldDef,
  51. TypeMetaFieldDef,
  52. TypeNameMetaFieldDef,
  53. assert_valid_schema,
  54. is_abstract_type,
  55. is_leaf_type,
  56. is_list_type,
  57. is_non_null_type,
  58. is_object_type,
  59. )
  60. from .collect_fields import collect_fields, collect_sub_fields
  61. from .middleware import MiddlewareManager
  62. from .values import get_argument_values, get_variable_values
  63. __all__ = [
  64. "assert_valid_execution_arguments",
  65. "default_field_resolver",
  66. "default_type_resolver",
  67. "execute",
  68. "execute_sync",
  69. "get_field_def",
  70. "ExecutionResult",
  71. "ExecutionContext",
  72. "FormattedExecutionResult",
  73. "Middleware",
  74. ]
  75. # Terminology
  76. #
  77. # "Definitions" are the generic name for top-level statements in the document.
  78. # Examples of this include:
  79. # 1) Operations (such as a query)
  80. # 2) Fragments
  81. #
  82. # "Operations" are a generic name for requests in the document.
  83. # Examples of this include:
  84. # 1) query,
  85. # 2) mutation
  86. #
  87. # "Selections" are the definitions that can appear legally and at
  88. # single level of the query. These include:
  89. # 1) field references e.g "a"
  90. # 2) fragment "spreads" e.g. "...c"
  91. # 3) inline fragment "spreads" e.g. "...on Type { a }"
  92. class FormattedExecutionResult(TypedDict, total=False):
  93. """Formatted execution result"""
  94. errors: List[GraphQLFormattedError]
  95. data: Optional[Dict[str, Any]]
  96. extensions: Dict[str, Any]
  97. class ExecutionResult:
  98. """The result of GraphQL execution.
  99. - ``data`` is the result of a successful execution of the query.
  100. - ``errors`` is included when any errors occurred as a non-empty list.
  101. - ``extensions`` is reserved for adding non-standard properties.
  102. """
  103. __slots__ = "data", "errors", "extensions"
  104. data: Optional[Dict[str, Any]]
  105. errors: Optional[List[GraphQLError]]
  106. extensions: Optional[Dict[str, Any]]
  107. def __init__(
  108. self,
  109. data: Optional[Dict[str, Any]] = None,
  110. errors: Optional[List[GraphQLError]] = None,
  111. extensions: Optional[Dict[str, Any]] = None,
  112. ):
  113. self.data = data
  114. self.errors = errors
  115. self.extensions = extensions
  116. def __repr__(self) -> str:
  117. name = self.__class__.__name__
  118. ext = "" if self.extensions is None else f", extensions={self.extensions}"
  119. return f"{name}(data={self.data!r}, errors={self.errors!r}{ext})"
  120. def __iter__(self) -> Iterable[Any]:
  121. return iter((self.data, self.errors))
  122. @property
  123. def formatted(self) -> FormattedExecutionResult:
  124. """Get execution result formatted according to the specification."""
  125. formatted: FormattedExecutionResult = {"data": self.data}
  126. if self.errors is not None:
  127. formatted["errors"] = [error.formatted for error in self.errors]
  128. if self.extensions is not None:
  129. formatted["extensions"] = self.extensions
  130. return formatted
  131. def __eq__(self, other: Any) -> bool:
  132. if isinstance(other, dict):
  133. if "extensions" not in other:
  134. return other == dict(data=self.data, errors=self.errors)
  135. return other == dict(
  136. data=self.data, errors=self.errors, extensions=self.extensions
  137. )
  138. if isinstance(other, tuple):
  139. if len(other) == 2:
  140. return other == (self.data, self.errors)
  141. return other == (self.data, self.errors, self.extensions)
  142. return (
  143. isinstance(other, self.__class__)
  144. and other.data == self.data
  145. and other.errors == self.errors
  146. and other.extensions == self.extensions
  147. )
  148. def __ne__(self, other: Any) -> bool:
  149. return not self == other
  150. Middleware = Optional[Union[Tuple, List, MiddlewareManager]]
  151. class ExecutionContext:
  152. """Data that must be available at all points during query execution.
  153. Namely, schema of the type system that is currently executing, and the fragments
  154. defined in the query document.
  155. """
  156. schema: GraphQLSchema
  157. fragments: Dict[str, FragmentDefinitionNode]
  158. root_value: Any
  159. context_value: Any
  160. operation: OperationDefinitionNode
  161. variable_values: Dict[str, Any]
  162. field_resolver: GraphQLFieldResolver
  163. type_resolver: GraphQLTypeResolver
  164. subscribe_field_resolver: GraphQLFieldResolver
  165. errors: List[GraphQLError]
  166. middleware_manager: Optional[MiddlewareManager]
  167. is_awaitable = staticmethod(default_is_awaitable)
  168. def __init__(
  169. self,
  170. schema: GraphQLSchema,
  171. fragments: Dict[str, FragmentDefinitionNode],
  172. root_value: Any,
  173. context_value: Any,
  174. operation: OperationDefinitionNode,
  175. variable_values: Dict[str, Any],
  176. field_resolver: GraphQLFieldResolver,
  177. type_resolver: GraphQLTypeResolver,
  178. subscribe_field_resolver: GraphQLFieldResolver,
  179. errors: List[GraphQLError],
  180. middleware_manager: Optional[MiddlewareManager],
  181. is_awaitable: Optional[Callable[[Any], bool]],
  182. ) -> None:
  183. self.schema = schema
  184. self.fragments = fragments
  185. self.root_value = root_value
  186. self.context_value = context_value
  187. self.operation = operation
  188. self.variable_values = variable_values
  189. self.field_resolver = field_resolver # type: ignore
  190. self.type_resolver = type_resolver # type: ignore
  191. self.subscribe_field_resolver = subscribe_field_resolver # type: ignore
  192. self.errors = errors
  193. self.middleware_manager = middleware_manager
  194. if is_awaitable:
  195. self.is_awaitable = is_awaitable
  196. self._subfields_cache: Dict[Tuple, Dict[str, List[FieldNode]]] = {}
  197. @classmethod
  198. def build(
  199. cls,
  200. schema: GraphQLSchema,
  201. document: DocumentNode,
  202. root_value: Any = None,
  203. context_value: Any = None,
  204. raw_variable_values: Optional[Dict[str, Any]] = None,
  205. operation_name: Optional[str] = None,
  206. field_resolver: Optional[GraphQLFieldResolver] = None,
  207. type_resolver: Optional[GraphQLTypeResolver] = None,
  208. subscribe_field_resolver: Optional[GraphQLFieldResolver] = None,
  209. middleware: Optional[Middleware] = None,
  210. is_awaitable: Optional[Callable[[Any], bool]] = None,
  211. ) -> Union[List[GraphQLError], "ExecutionContext"]:
  212. """Build an execution context
  213. Constructs a ExecutionContext object from the arguments passed to execute, which
  214. we will pass throughout the other execution methods.
  215. Throws a GraphQLError if a valid execution context cannot be created.
  216. For internal use only.
  217. """
  218. operation: Optional[OperationDefinitionNode] = None
  219. fragments: Dict[str, FragmentDefinitionNode] = {}
  220. middleware_manager: Optional[MiddlewareManager] = None
  221. if middleware is not None:
  222. if isinstance(middleware, (list, tuple)):
  223. middleware_manager = MiddlewareManager(*middleware)
  224. elif isinstance(middleware, MiddlewareManager):
  225. middleware_manager = middleware
  226. else:
  227. raise TypeError(
  228. "Middleware must be passed as a list or tuple of functions"
  229. " or objects, or as a single MiddlewareManager object."
  230. f" Got {inspect(middleware)} instead."
  231. )
  232. for definition in document.definitions:
  233. if isinstance(definition, OperationDefinitionNode):
  234. if operation_name is None:
  235. if operation:
  236. return [
  237. GraphQLError(
  238. "Must provide operation name"
  239. " if query contains multiple operations."
  240. )
  241. ]
  242. operation = definition
  243. elif definition.name and definition.name.value == operation_name:
  244. operation = definition
  245. elif isinstance(definition, FragmentDefinitionNode):
  246. fragments[definition.name.value] = definition
  247. if not operation:
  248. if operation_name is not None:
  249. return [GraphQLError(f"Unknown operation named '{operation_name}'.")]
  250. return [GraphQLError("Must provide an operation.")]
  251. coerced_variable_values = get_variable_values(
  252. schema,
  253. operation.variable_definitions or (),
  254. raw_variable_values or {},
  255. max_errors=50,
  256. )
  257. if isinstance(coerced_variable_values, list):
  258. return coerced_variable_values # errors
  259. return cls(
  260. schema,
  261. fragments,
  262. root_value,
  263. context_value,
  264. operation,
  265. coerced_variable_values, # coerced values
  266. field_resolver or default_field_resolver,
  267. type_resolver or default_type_resolver,
  268. subscribe_field_resolver or default_field_resolver,
  269. [],
  270. middleware_manager,
  271. is_awaitable,
  272. )
  273. @staticmethod
  274. def build_response(
  275. data: Optional[Dict[str, Any]], errors: List[GraphQLError]
  276. ) -> ExecutionResult:
  277. """Build response.
  278. Given a completed execution context and data, build the (data, errors) response
  279. defined by the "Response" section of the GraphQL spec.
  280. """
  281. if not errors:
  282. return ExecutionResult(data, None)
  283. # Sort the error list in order to make it deterministic, since we might have
  284. # been using parallel execution.
  285. errors.sort(
  286. key=lambda error: (error.locations or [], error.path or [], error.message)
  287. )
  288. return ExecutionResult(data, errors)
  289. def execute_operation(
  290. self, operation: OperationDefinitionNode, root_value: Any
  291. ) -> Optional[AwaitableOrValue[Any]]:
  292. """Execute an operation.
  293. Implements the "Executing operations" section of the spec.
  294. """
  295. root_type = self.schema.get_root_type(operation.operation)
  296. if root_type is None:
  297. raise GraphQLError(
  298. "Schema is not configured to execute"
  299. f" {operation.operation.value} operation.",
  300. operation,
  301. )
  302. root_fields = collect_fields(
  303. self.schema,
  304. self.fragments,
  305. self.variable_values,
  306. root_type,
  307. operation.selection_set,
  308. )
  309. path = None
  310. return (
  311. self.execute_fields_serially
  312. if operation.operation == OperationType.MUTATION
  313. else self.execute_fields
  314. )(root_type, root_value, path, root_fields)
  315. def execute_fields_serially(
  316. self,
  317. parent_type: GraphQLObjectType,
  318. source_value: Any,
  319. path: Optional[Path],
  320. fields: Dict[str, List[FieldNode]],
  321. ) -> AwaitableOrValue[Dict[str, Any]]:
  322. """Execute the given fields serially.
  323. Implements the "Executing selection sets" section of the spec
  324. for fields that must be executed serially.
  325. """
  326. results: AwaitableOrValue[Dict[str, Any]] = {}
  327. is_awaitable = self.is_awaitable
  328. for response_name, field_nodes in fields.items():
  329. field_path = Path(path, response_name, parent_type.name)
  330. result = self.execute_field(
  331. parent_type, source_value, field_nodes, field_path
  332. )
  333. if result is Undefined:
  334. continue
  335. if is_awaitable(results):
  336. # noinspection PyShadowingNames
  337. async def await_and_set_result(
  338. results: Awaitable[Dict[str, Any]],
  339. response_name: str,
  340. result: AwaitableOrValue[Any],
  341. ) -> Dict[str, Any]:
  342. awaited_results = await results
  343. awaited_results[response_name] = (
  344. await result if is_awaitable(result) else result
  345. )
  346. return awaited_results
  347. results = await_and_set_result(
  348. cast(Awaitable, results), response_name, result
  349. )
  350. elif is_awaitable(result):
  351. # noinspection PyShadowingNames
  352. async def set_result(
  353. results: Dict[str, Any],
  354. response_name: str,
  355. result: Awaitable,
  356. ) -> Dict[str, Any]:
  357. results[response_name] = await result
  358. return results
  359. results = set_result(
  360. cast(Dict[str, Any], results), response_name, result
  361. )
  362. else:
  363. cast(Dict[str, Any], results)[response_name] = result
  364. return results
  365. def execute_fields(
  366. self,
  367. parent_type: GraphQLObjectType,
  368. source_value: Any,
  369. path: Optional[Path],
  370. fields: Dict[str, List[FieldNode]],
  371. ) -> AwaitableOrValue[Dict[str, Any]]:
  372. """Execute the given fields concurrently.
  373. Implements the "Executing selection sets" section of the spec
  374. for fields that may be executed in parallel.
  375. """
  376. results = {}
  377. is_awaitable = self.is_awaitable
  378. awaitable_fields: List[str] = []
  379. append_awaitable = awaitable_fields.append
  380. for response_name, field_nodes in fields.items():
  381. field_path = Path(path, response_name, parent_type.name)
  382. result = self.execute_field(
  383. parent_type, source_value, field_nodes, field_path
  384. )
  385. if result is not Undefined:
  386. results[response_name] = result
  387. if is_awaitable(result):
  388. append_awaitable(response_name)
  389. # If there are no coroutines, we can just return the object
  390. if not awaitable_fields:
  391. return results
  392. # Otherwise, results is a map from field name to the result of resolving that
  393. # field, which is possibly a coroutine object. Return a coroutine object that
  394. # will yield this same map, but with any coroutines awaited in parallel and
  395. # replaced with the values they yielded.
  396. async def get_results() -> Dict[str, Any]:
  397. results.update(
  398. zip(
  399. awaitable_fields,
  400. await gather(*(results[field] for field in awaitable_fields)),
  401. )
  402. )
  403. return results
  404. return get_results()
  405. def build_resolve_info(
  406. self,
  407. field_def: GraphQLField,
  408. field_nodes: List[FieldNode],
  409. parent_type: GraphQLObjectType,
  410. path: Path,
  411. ) -> GraphQLResolveInfo:
  412. """Build the GraphQLResolveInfo object.
  413. For internal use only."""
  414. # The resolve function's first argument is a collection of information about
  415. # the current execution state.
  416. return GraphQLResolveInfo(
  417. field_nodes[0].name.value,
  418. field_nodes,
  419. field_def.type,
  420. parent_type,
  421. path,
  422. self.schema,
  423. self.fragments,
  424. self.root_value,
  425. self.operation,
  426. self.variable_values,
  427. self.context_value,
  428. self.is_awaitable,
  429. )
  430. def execute_field(
  431. self,
  432. parent_type: GraphQLObjectType,
  433. source: Any,
  434. field_nodes: List[FieldNode],
  435. path: Path,
  436. ) -> AwaitableOrValue[Any]:
  437. """Resolve the field on the given source object.
  438. Implements the "Executing fields" section of the spec.
  439. In particular, this method figures out the value that the field returns by
  440. calling its resolve function, then calls complete_value to await coroutine
  441. objects, serialize scalars, or execute the sub-selection-set for objects.
  442. """
  443. field_def = get_field_def(self.schema, parent_type, field_nodes[0])
  444. if not field_def:
  445. return Undefined
  446. return_type = field_def.type
  447. resolve_fn = field_def.resolve or self.field_resolver
  448. if self.middleware_manager:
  449. resolve_fn = self.middleware_manager.get_field_resolver(resolve_fn)
  450. info = self.build_resolve_info(field_def, field_nodes, parent_type, path)
  451. # Get the resolve function, regardless of if its result is normal or abrupt
  452. # (error).
  453. try:
  454. # Build a dictionary of arguments from the field.arguments AST, using the
  455. # variables scope to fulfill any variable references.
  456. args = get_argument_values(field_def, field_nodes[0], self.variable_values)
  457. # Note that contrary to the JavaScript implementation, we pass the context
  458. # value as part of the resolve info.
  459. result = resolve_fn(source, info, **args)
  460. if self.is_awaitable(result):
  461. # noinspection PyShadowingNames
  462. async def await_result() -> Any:
  463. try:
  464. completed = self.complete_value(
  465. return_type, field_nodes, info, path, await result
  466. )
  467. if self.is_awaitable(completed):
  468. return await completed
  469. return completed
  470. except Exception as raw_error:
  471. error = located_error(raw_error, field_nodes, path.as_list())
  472. self.handle_field_error(error, return_type)
  473. return None
  474. return await_result()
  475. completed = self.complete_value(
  476. return_type, field_nodes, info, path, result
  477. )
  478. if self.is_awaitable(completed):
  479. # noinspection PyShadowingNames
  480. async def await_completed() -> Any:
  481. try:
  482. return await completed
  483. except Exception as raw_error:
  484. error = located_error(raw_error, field_nodes, path.as_list())
  485. self.handle_field_error(error, return_type)
  486. return None
  487. return await_completed()
  488. return completed
  489. except Exception as raw_error:
  490. error = located_error(raw_error, field_nodes, path.as_list())
  491. self.handle_field_error(error, return_type)
  492. return None
  493. def handle_field_error(
  494. self,
  495. error: GraphQLError,
  496. return_type: GraphQLOutputType,
  497. ) -> None:
  498. # If the field type is non-nullable, then it is resolved without any protection
  499. # from errors, however it still properly locates the error.
  500. if is_non_null_type(return_type):
  501. raise error
  502. # Otherwise, error protection is applied, logging the error and resolving a
  503. # null value for this field if one is encountered.
  504. self.errors.append(error)
  505. return None
  506. def complete_value(
  507. self,
  508. return_type: GraphQLOutputType,
  509. field_nodes: List[FieldNode],
  510. info: GraphQLResolveInfo,
  511. path: Path,
  512. result: Any,
  513. ) -> AwaitableOrValue[Any]:
  514. """Complete a value.
  515. Implements the instructions for completeValue as defined in the
  516. "Value completion" section of the spec.
  517. If the field type is Non-Null, then this recursively completes the value
  518. for the inner type. It throws a field error if that completion returns null,
  519. as per the "Nullability" section of the spec.
  520. If the field type is a List, then this recursively completes the value
  521. for the inner type on each item in the list.
  522. If the field type is a Scalar or Enum, ensures the completed value is a legal
  523. value of the type by calling the ``serialize`` method of GraphQL type
  524. definition.
  525. If the field is an abstract type, determine the runtime type of the value and
  526. then complete based on that type.
  527. Otherwise, the field type expects a sub-selection set, and will complete the
  528. value by evaluating all sub-selections.
  529. """
  530. # If result is an Exception, throw a located error.
  531. if isinstance(result, Exception):
  532. raise result
  533. # If field type is NonNull, complete for inner type, and throw field error if
  534. # result is null.
  535. if is_non_null_type(return_type):
  536. completed = self.complete_value(
  537. cast(GraphQLNonNull, return_type).of_type,
  538. field_nodes,
  539. info,
  540. path,
  541. result,
  542. )
  543. if completed is None:
  544. raise TypeError(
  545. "Cannot return null for non-nullable field"
  546. f" {info.parent_type.name}.{info.field_name}."
  547. )
  548. return completed
  549. # If result value is null or undefined then return null.
  550. if result is None or result is Undefined:
  551. return None
  552. # If field type is List, complete each item in the list with inner type
  553. if is_list_type(return_type):
  554. return self.complete_list_value(
  555. cast(GraphQLList, return_type), field_nodes, info, path, result
  556. )
  557. # If field type is a leaf type, Scalar or Enum, serialize to a valid value,
  558. # returning null if serialization is not possible.
  559. if is_leaf_type(return_type):
  560. return self.complete_leaf_value(cast(GraphQLLeafType, return_type), result)
  561. # If field type is an abstract type, Interface or Union, determine the runtime
  562. # Object type and complete for that type.
  563. if is_abstract_type(return_type):
  564. return self.complete_abstract_value(
  565. cast(GraphQLAbstractType, return_type), field_nodes, info, path, result
  566. )
  567. # If field type is Object, execute and complete all sub-selections.
  568. if is_object_type(return_type):
  569. return self.complete_object_value(
  570. cast(GraphQLObjectType, return_type), field_nodes, info, path, result
  571. )
  572. # Not reachable. All possible output types have been considered.
  573. raise TypeError( # pragma: no cover
  574. "Cannot complete value of unexpected output type:"
  575. f" '{inspect(return_type)}'."
  576. )
  577. def complete_list_value(
  578. self,
  579. return_type: GraphQLList[GraphQLOutputType],
  580. field_nodes: List[FieldNode],
  581. info: GraphQLResolveInfo,
  582. path: Path,
  583. result: Union[AsyncIterable[Any], Iterable[Any]],
  584. ) -> AwaitableOrValue[List[Any]]:
  585. """Complete a list value.
  586. Complete a list value by completing each item in the list with the inner type.
  587. """
  588. if not is_iterable(result):
  589. # experimental: allow async iterables
  590. if isinstance(result, AsyncIterable):
  591. # noinspection PyShadowingNames
  592. async def async_iterable_to_list(
  593. async_result: AsyncIterable[Any],
  594. ) -> Any:
  595. sync_result = [item async for item in async_result]
  596. return self.complete_list_value(
  597. return_type, field_nodes, info, path, sync_result
  598. )
  599. return async_iterable_to_list(result)
  600. raise GraphQLError(
  601. "Expected Iterable, but did not find one for field"
  602. f" '{info.parent_type.name}.{info.field_name}'."
  603. )
  604. result = cast(Iterable[Any], result)
  605. # This is specified as a simple map, however we're optimizing the path where
  606. # the list contains no coroutine objects by avoiding creating another coroutine
  607. # object.
  608. item_type = return_type.of_type
  609. is_awaitable = self.is_awaitable
  610. awaitable_indices: List[int] = []
  611. append_awaitable = awaitable_indices.append
  612. completed_results: List[Any] = []
  613. append_result = completed_results.append
  614. for index, item in enumerate(result):
  615. # No need to modify the info object containing the path, since from here on
  616. # it is not ever accessed by resolver functions.
  617. item_path = path.add_key(index, None)
  618. completed_item: AwaitableOrValue[Any]
  619. if is_awaitable(item):
  620. # noinspection PyShadowingNames
  621. async def await_completed(item: Any, item_path: Path) -> Any:
  622. try:
  623. completed = self.complete_value(
  624. item_type, field_nodes, info, item_path, await item
  625. )
  626. if is_awaitable(completed):
  627. return await completed
  628. return completed
  629. except Exception as raw_error:
  630. error = located_error(
  631. raw_error, field_nodes, item_path.as_list()
  632. )
  633. self.handle_field_error(error, item_type)
  634. return None
  635. completed_item = await_completed(item, item_path)
  636. else:
  637. try:
  638. completed_item = self.complete_value(
  639. item_type, field_nodes, info, item_path, item
  640. )
  641. if is_awaitable(completed_item):
  642. # noinspection PyShadowingNames
  643. async def await_completed(item: Any, item_path: Path) -> Any:
  644. try:
  645. return await item
  646. except Exception as raw_error:
  647. error = located_error(
  648. raw_error, field_nodes, item_path.as_list()
  649. )
  650. self.handle_field_error(error, item_type)
  651. return None
  652. completed_item = await_completed(completed_item, item_path)
  653. except Exception as raw_error:
  654. error = located_error(raw_error, field_nodes, item_path.as_list())
  655. self.handle_field_error(error, item_type)
  656. completed_item = None
  657. if is_awaitable(completed_item):
  658. append_awaitable(index)
  659. append_result(completed_item)
  660. if not awaitable_indices:
  661. return completed_results
  662. # noinspection PyShadowingNames
  663. async def get_completed_results() -> List[Any]:
  664. for index, result in zip(
  665. awaitable_indices,
  666. await gather(
  667. *(completed_results[index] for index in awaitable_indices)
  668. ),
  669. ):
  670. completed_results[index] = result
  671. return completed_results
  672. return get_completed_results()
  673. @staticmethod
  674. def complete_leaf_value(return_type: GraphQLLeafType, result: Any) -> Any:
  675. """Complete a leaf value.
  676. Complete a Scalar or Enum by serializing to a valid value, returning null if
  677. serialization is not possible.
  678. """
  679. serialized_result = return_type.serialize(result)
  680. if serialized_result is Undefined or serialized_result is None:
  681. raise TypeError(
  682. f"Expected `{inspect(return_type)}.serialize({inspect(result)})`"
  683. f" to return non-nullable value, returned: {inspect(serialized_result)}"
  684. )
  685. return serialized_result
  686. def complete_abstract_value(
  687. self,
  688. return_type: GraphQLAbstractType,
  689. field_nodes: List[FieldNode],
  690. info: GraphQLResolveInfo,
  691. path: Path,
  692. result: Any,
  693. ) -> AwaitableOrValue[Any]:
  694. """Complete an abstract value.
  695. Complete a value of an abstract type by determining the runtime object type of
  696. that value, then complete the value for that type.
  697. """
  698. resolve_type_fn = return_type.resolve_type or self.type_resolver
  699. runtime_type = resolve_type_fn(result, info, return_type) # type: ignore
  700. if self.is_awaitable(runtime_type):
  701. runtime_type = cast(Awaitable, runtime_type)
  702. async def await_complete_object_value() -> Any:
  703. value = self.complete_object_value(
  704. self.ensure_valid_runtime_type(
  705. await runtime_type, # type: ignore
  706. return_type,
  707. field_nodes,
  708. info,
  709. result,
  710. ),
  711. field_nodes,
  712. info,
  713. path,
  714. result,
  715. )
  716. if self.is_awaitable(value):
  717. return await value # type: ignore
  718. return value # pragma: no cover
  719. return await_complete_object_value()
  720. runtime_type = cast(Optional[str], runtime_type)
  721. return self.complete_object_value(
  722. self.ensure_valid_runtime_type(
  723. runtime_type, return_type, field_nodes, info, result
  724. ),
  725. field_nodes,
  726. info,
  727. path,
  728. result,
  729. )
  730. def ensure_valid_runtime_type(
  731. self,
  732. runtime_type_name: Any,
  733. return_type: GraphQLAbstractType,
  734. field_nodes: List[FieldNode],
  735. info: GraphQLResolveInfo,
  736. result: Any,
  737. ) -> GraphQLObjectType:
  738. if runtime_type_name is None:
  739. raise GraphQLError(
  740. f"Abstract type '{return_type.name}' must resolve"
  741. " to an Object type at runtime"
  742. f" for field '{info.parent_type.name}.{info.field_name}'."
  743. f" Either the '{return_type.name}' type should provide"
  744. " a 'resolve_type' function or each possible type should provide"
  745. " an 'is_type_of' function.",
  746. field_nodes,
  747. )
  748. if is_object_type(runtime_type_name): # pragma: no cover
  749. raise GraphQLError(
  750. "Support for returning GraphQLObjectType from resolve_type was"
  751. " removed in GraphQL-core 3.2, please return type name instead."
  752. )
  753. if not isinstance(runtime_type_name, str):
  754. raise GraphQLError(
  755. f"Abstract type '{return_type.name}' must resolve"
  756. " to an Object type at runtime"
  757. f" for field '{info.parent_type.name}.{info.field_name}' with value"
  758. f" {inspect(result)}, received '{inspect(runtime_type_name)}'.",
  759. field_nodes,
  760. )
  761. runtime_type = self.schema.get_type(runtime_type_name)
  762. if runtime_type is None:
  763. raise GraphQLError(
  764. f"Abstract type '{return_type.name}' was resolved to a type"
  765. f" '{runtime_type_name}' that does not exist inside the schema.",
  766. field_nodes,
  767. )
  768. if not is_object_type(runtime_type):
  769. raise GraphQLError(
  770. f"Abstract type '{return_type.name}' was resolved"
  771. f" to a non-object type '{runtime_type_name}'.",
  772. field_nodes,
  773. )
  774. runtime_type = cast(GraphQLObjectType, runtime_type)
  775. if not self.schema.is_sub_type(return_type, runtime_type):
  776. raise GraphQLError(
  777. f"Runtime Object type '{runtime_type.name}' is not a possible"
  778. f" type for '{return_type.name}'.",
  779. field_nodes,
  780. )
  781. return runtime_type
  782. def complete_object_value(
  783. self,
  784. return_type: GraphQLObjectType,
  785. field_nodes: List[FieldNode],
  786. info: GraphQLResolveInfo,
  787. path: Path,
  788. result: Any,
  789. ) -> AwaitableOrValue[Dict[str, Any]]:
  790. """Complete an Object value by executing all sub-selections."""
  791. # Collect sub-fields to execute to complete this value.
  792. sub_field_nodes = self.collect_subfields(return_type, field_nodes)
  793. # If there is an `is_type_of()` predicate function, call it with the current
  794. # result. If `is_type_of()` returns False, then raise an error rather than
  795. # continuing execution.
  796. if return_type.is_type_of:
  797. is_type_of = return_type.is_type_of(result, info)
  798. if self.is_awaitable(is_type_of):
  799. async def execute_subfields_async() -> Dict[str, Any]:
  800. if not await is_type_of: # type: ignore
  801. raise invalid_return_type_error(
  802. return_type, result, field_nodes
  803. )
  804. return self.execute_fields(
  805. return_type, result, path, sub_field_nodes
  806. ) # type: ignore
  807. return execute_subfields_async()
  808. if not is_type_of:
  809. raise invalid_return_type_error(return_type, result, field_nodes)
  810. return self.execute_fields(return_type, result, path, sub_field_nodes)
  811. def collect_subfields(
  812. self, return_type: GraphQLObjectType, field_nodes: List[FieldNode]
  813. ) -> Dict[str, List[FieldNode]]:
  814. """Collect subfields.
  815. A cached collection of relevant subfields with regard to the return type is
  816. kept in the execution context as ``_subfields_cache``. This ensures the
  817. subfields are not repeatedly calculated, which saves overhead when resolving
  818. lists of values.
  819. """
  820. cache = self._subfields_cache
  821. # We cannot use the field_nodes themselves as key for the cache, since they
  822. # are not hashable as a list. We also do not want to use the field_nodes
  823. # themselves (converted to a tuple) as keys, since hashing them is slow.
  824. # Therefore we use the ids of the field_nodes as keys. Note that we do not
  825. # use the id of the list, since we want to hit the cache for all lists of
  826. # the same nodes, not only for the same list of nodes. Also, the list id may
  827. # even be reused, in which case we would get wrong results from the cache.
  828. key = (
  829. (return_type, id(field_nodes[0]))
  830. if len(field_nodes) == 1 # optimize most frequent case
  831. else tuple((return_type, *map(id, field_nodes)))
  832. )
  833. sub_field_nodes = cache.get(key)
  834. if sub_field_nodes is None:
  835. sub_field_nodes = collect_sub_fields(
  836. self.schema,
  837. self.fragments,
  838. self.variable_values,
  839. return_type,
  840. field_nodes,
  841. )
  842. cache[key] = sub_field_nodes
  843. return sub_field_nodes
  844. def execute(
  845. schema: GraphQLSchema,
  846. document: DocumentNode,
  847. root_value: Any = None,
  848. context_value: Any = None,
  849. variable_values: Optional[Dict[str, Any]] = None,
  850. operation_name: Optional[str] = None,
  851. field_resolver: Optional[GraphQLFieldResolver] = None,
  852. type_resolver: Optional[GraphQLTypeResolver] = None,
  853. subscribe_field_resolver: Optional[GraphQLFieldResolver] = None,
  854. middleware: Optional[Middleware] = None,
  855. execution_context_class: Optional[Type["ExecutionContext"]] = None,
  856. is_awaitable: Optional[Callable[[Any], bool]] = None,
  857. ) -> AwaitableOrValue[ExecutionResult]:
  858. """Execute a GraphQL operation.
  859. Implements the "Executing requests" section of the GraphQL specification.
  860. Returns an ExecutionResult (if all encountered resolvers are synchronous),
  861. or a coroutine object eventually yielding an ExecutionResult.
  862. If the arguments to this function do not result in a legal execution context,
  863. a GraphQLError will be thrown immediately explaining the invalid input.
  864. """
  865. # If arguments are missing or incorrect, throw an error.
  866. assert_valid_execution_arguments(schema, document, variable_values)
  867. if execution_context_class is None:
  868. execution_context_class = ExecutionContext
  869. # If a valid execution context cannot be created due to incorrect arguments,
  870. # a "Response" with only errors is returned.
  871. exe_context = execution_context_class.build(
  872. schema,
  873. document,
  874. root_value,
  875. context_value,
  876. variable_values,
  877. operation_name,
  878. field_resolver,
  879. type_resolver,
  880. subscribe_field_resolver,
  881. middleware,
  882. is_awaitable,
  883. )
  884. # Return early errors if execution context failed.
  885. if isinstance(exe_context, list):
  886. return ExecutionResult(data=None, errors=exe_context)
  887. # Return a possible coroutine object that will eventually yield the data described
  888. # by the "Response" section of the GraphQL specification.
  889. #
  890. # If errors are encountered while executing a GraphQL field, only that field and
  891. # its descendants will be omitted, and sibling fields will still be executed. An
  892. # execution which encounters errors will still result in a coroutine object that
  893. # can be executed without errors.
  894. #
  895. # Errors from sub-fields of a NonNull type may propagate to the top level,
  896. # at which point we still log the error and null the parent field, which
  897. # in this case is the entire response.
  898. errors = exe_context.errors
  899. build_response = exe_context.build_response
  900. try:
  901. operation = exe_context.operation
  902. result = exe_context.execute_operation(operation, root_value)
  903. if exe_context.is_awaitable(result):
  904. # noinspection PyShadowingNames
  905. async def await_result() -> Any:
  906. try:
  907. return build_response(await result, errors) # type: ignore
  908. except GraphQLError as error:
  909. errors.append(error)
  910. return build_response(None, errors)
  911. return await_result()
  912. except GraphQLError as error:
  913. errors.append(error)
  914. return build_response(None, errors)
  915. else:
  916. return build_response(result, errors) # type: ignore
  917. def assume_not_awaitable(_value: Any) -> bool:
  918. """Replacement for isawaitable if everything is assumed to be synchronous."""
  919. return False
  920. def execute_sync(
  921. schema: GraphQLSchema,
  922. document: DocumentNode,
  923. root_value: Any = None,
  924. context_value: Any = None,
  925. variable_values: Optional[Dict[str, Any]] = None,
  926. operation_name: Optional[str] = None,
  927. field_resolver: Optional[GraphQLFieldResolver] = None,
  928. type_resolver: Optional[GraphQLTypeResolver] = None,
  929. middleware: Optional[Middleware] = None,
  930. execution_context_class: Optional[Type["ExecutionContext"]] = None,
  931. check_sync: bool = False,
  932. ) -> ExecutionResult:
  933. """Execute a GraphQL operation synchronously.
  934. Also implements the "Executing requests" section of the GraphQL specification.
  935. However, it guarantees to complete synchronously (or throw an error) assuming
  936. that all field resolvers are also synchronous.
  937. Set check_sync to True to still run checks that no awaitable values are returned.
  938. """
  939. is_awaitable = (
  940. check_sync
  941. if callable(check_sync)
  942. else (None if check_sync else assume_not_awaitable)
  943. )
  944. result = execute(
  945. schema,
  946. document,
  947. root_value,
  948. context_value,
  949. variable_values,
  950. operation_name,
  951. field_resolver,
  952. type_resolver,
  953. None,
  954. middleware,
  955. execution_context_class,
  956. is_awaitable,
  957. )
  958. # Assert that the execution was synchronous.
  959. if isawaitable(result):
  960. ensure_future(cast(Awaitable[ExecutionResult], result)).cancel()
  961. raise RuntimeError("GraphQL execution failed to complete synchronously.")
  962. return cast(ExecutionResult, result)
  963. def assert_valid_execution_arguments(
  964. schema: GraphQLSchema,
  965. document: DocumentNode,
  966. raw_variable_values: Optional[Dict[str, Any]] = None,
  967. ) -> None:
  968. """Check that the arguments are acceptable.
  969. Essential assertions before executing to provide developer feedback for improper use
  970. of the GraphQL library.
  971. For internal use only.
  972. """
  973. if not document:
  974. raise TypeError("Must provide document.")
  975. # If the schema used for execution is invalid, throw an error.
  976. assert_valid_schema(schema)
  977. # Variables, if provided, must be a dictionary.
  978. if not (raw_variable_values is None or isinstance(raw_variable_values, dict)):
  979. raise TypeError(
  980. "Variable values must be provided as a dictionary"
  981. " with variable names as keys. Perhaps look to see"
  982. " if an unparsed JSON string was provided."
  983. )
  984. def get_field_def(
  985. schema: GraphQLSchema, parent_type: GraphQLObjectType, field_node: FieldNode
  986. ) -> GraphQLField:
  987. """Get field definition.
  988. This method looks up the field on the given type definition. It has special casing
  989. for the three introspection fields, ``__schema``, ``__type`, and ``__typename``.
  990. ``__typename`` is special because it can always be queried as a field, even in
  991. situations where no other fields are allowed, like on a Union. ``__schema`` and
  992. ``__type`` could get automatically added to the query type, but that would require
  993. mutating type definitions, which would cause issues.
  994. For internal use only.
  995. """
  996. field_name = field_node.name.value
  997. if field_name == "__schema" and schema.query_type == parent_type:
  998. return SchemaMetaFieldDef
  999. elif field_name == "__type" and schema.query_type == parent_type:
  1000. return TypeMetaFieldDef
  1001. elif field_name == "__typename":
  1002. return TypeNameMetaFieldDef
  1003. return parent_type.fields.get(field_name)
  1004. def invalid_return_type_error(
  1005. return_type: GraphQLObjectType, result: Any, field_nodes: List[FieldNode]
  1006. ) -> GraphQLError:
  1007. """Create a GraphQLError for an invalid return type."""
  1008. return GraphQLError(
  1009. f"Expected value of type '{return_type.name}' but got: {inspect(result)}.",
  1010. field_nodes,
  1011. )
  1012. def get_typename(value: Any) -> Optional[str]:
  1013. """Get the ``__typename`` property of the given value."""
  1014. if isinstance(value, Mapping):
  1015. return value.get("__typename")
  1016. # need to de-mangle the attribute assumed to be "private" in Python
  1017. for cls in value.__class__.__mro__:
  1018. __typename = getattr(value, f"_{cls.__name__}__typename", None)
  1019. if __typename:
  1020. return __typename
  1021. return None
  1022. def default_type_resolver(
  1023. value: Any, info: GraphQLResolveInfo, abstract_type: GraphQLAbstractType
  1024. ) -> AwaitableOrValue[Optional[str]]:
  1025. """Default type resolver function.
  1026. If a resolve_type function is not given, then a default resolve behavior is used
  1027. which attempts two strategies:
  1028. First, See if the provided value has a ``__typename`` field defined, if so, use that
  1029. value as name of the resolved type.
  1030. Otherwise, test each possible type for the abstract type by calling
  1031. :meth:`~graphql.type.GraphQLObjectType.is_type_of` for the object
  1032. being coerced, returning the first type that matches.
  1033. """
  1034. # First, look for `__typename`.
  1035. type_name = get_typename(value)
  1036. if isinstance(type_name, str):
  1037. return type_name
  1038. # Otherwise, test each possible type.
  1039. possible_types = info.schema.get_possible_types(abstract_type)
  1040. is_awaitable = info.is_awaitable
  1041. awaitable_is_type_of_results: List[Awaitable] = []
  1042. append_awaitable_results = awaitable_is_type_of_results.append
  1043. awaitable_types: List[GraphQLObjectType] = []
  1044. append_awaitable_types = awaitable_types.append
  1045. for type_ in possible_types:
  1046. if type_.is_type_of:
  1047. is_type_of_result = type_.is_type_of(value, info)
  1048. if is_awaitable(is_type_of_result):
  1049. append_awaitable_results(cast(Awaitable, is_type_of_result))
  1050. append_awaitable_types(type_)
  1051. elif is_type_of_result:
  1052. return type_.name
  1053. if awaitable_is_type_of_results:
  1054. # noinspection PyShadowingNames
  1055. async def get_type() -> Optional[str]:
  1056. is_type_of_results = await gather(*awaitable_is_type_of_results)
  1057. for is_type_of_result, type_ in zip(is_type_of_results, awaitable_types):
  1058. if is_type_of_result:
  1059. return type_.name
  1060. return None
  1061. return get_type()
  1062. return None
  1063. def default_field_resolver(source: Any, info: GraphQLResolveInfo, **args: Any) -> Any:
  1064. """Default field resolver.
  1065. If a resolve function is not given, then a default resolve behavior is used which
  1066. takes the property of the source object of the same name as the field and returns
  1067. it as the result, or if it's a function, returns the result of calling that function
  1068. while passing along args and context.
  1069. For dictionaries, the field names are used as keys, for all other objects they are
  1070. used as attribute names.
  1071. """
  1072. # Ensure source is a value for which property access is acceptable.
  1073. field_name = info.field_name
  1074. value = (
  1075. source.get(field_name)
  1076. if isinstance(source, Mapping)
  1077. else getattr(source, field_name, None)
  1078. )
  1079. if callable(value):
  1080. return value(info, **args)
  1081. return value