strawberry-graphql 0.190.0.dev1687447182__py3-none-any.whl → 0.192.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. strawberry/annotation.py +24 -3
  2. strawberry/arguments.py +6 -2
  3. strawberry/channels/testing.py +22 -13
  4. strawberry/cli/__init__.py +4 -4
  5. strawberry/cli/commands/upgrade/__init__.py +75 -0
  6. strawberry/cli/commands/upgrade/_fake_progress.py +21 -0
  7. strawberry/cli/commands/upgrade/_run_codemod.py +74 -0
  8. strawberry/codemods/__init__.py +0 -0
  9. strawberry/codemods/annotated_unions.py +185 -0
  10. strawberry/exceptions/invalid_union_type.py +23 -3
  11. strawberry/exceptions/utils/source_finder.py +147 -11
  12. strawberry/extensions/field_extension.py +2 -5
  13. strawberry/fastapi/router.py +5 -4
  14. strawberry/federation/union.py +4 -5
  15. strawberry/field.py +116 -75
  16. strawberry/http/__init__.py +1 -3
  17. strawberry/permission.py +3 -166
  18. strawberry/relay/fields.py +2 -0
  19. strawberry/relay/types.py +14 -4
  20. strawberry/schema/schema.py +1 -1
  21. strawberry/schema/schema_converter.py +106 -38
  22. strawberry/subscriptions/protocols/graphql_transport_ws/handlers.py +20 -8
  23. strawberry/subscriptions/protocols/graphql_transport_ws/types.py +1 -1
  24. strawberry/subscriptions/protocols/graphql_ws/handlers.py +4 -7
  25. strawberry/type.py +2 -2
  26. strawberry/types/type_resolver.py +7 -29
  27. strawberry/types/types.py +6 -0
  28. strawberry/union.py +46 -17
  29. strawberry/utils/typing.py +21 -0
  30. {strawberry_graphql-0.190.0.dev1687447182.dist-info → strawberry_graphql-0.192.1.dist-info}/METADATA +1 -1
  31. {strawberry_graphql-0.190.0.dev1687447182.dist-info → strawberry_graphql-0.192.1.dist-info}/RECORD +34 -30
  32. strawberry/exceptions/permission_fail_silently_requires_optional.py +0 -52
  33. {strawberry_graphql-0.190.0.dev1687447182.dist-info → strawberry_graphql-0.192.1.dist-info}/LICENSE +0 -0
  34. {strawberry_graphql-0.190.0.dev1687447182.dist-info → strawberry_graphql-0.192.1.dist-info}/WHEEL +0 -0
  35. {strawberry_graphql-0.190.0.dev1687447182.dist-info → strawberry_graphql-0.192.1.dist-info}/entry_points.txt +0 -0
@@ -100,7 +100,7 @@ class LibCSTSourceFinder:
100
100
  return None
101
101
 
102
102
  def _find_function_definition(
103
- self, source: SourcePath, function: Callable
103
+ self, source: SourcePath, function: Callable[..., Any]
104
104
  ) -> Optional[FunctionDef]:
105
105
  import libcst.matchers as m
106
106
 
@@ -114,7 +114,7 @@ class LibCSTSourceFinder:
114
114
  )
115
115
 
116
116
  def _find_class_definition(
117
- self, source: SourcePath, cls: Type
117
+ self, source: SourcePath, cls: Type[Any]
118
118
  ) -> Optional[CSTNode]:
119
119
  import libcst.matchers as m
120
120
 
@@ -123,7 +123,7 @@ class LibCSTSourceFinder:
123
123
  class_defs = self._find(source.code, matcher)
124
124
  return self._find_definition_by_qualname(cls.__qualname__, class_defs)
125
125
 
126
- def find_class(self, cls: Type) -> Optional[ExceptionSource]:
126
+ def find_class(self, cls: Type[Any]) -> Optional[ExceptionSource]:
127
127
  source = self.find_source(cls.__module__)
128
128
 
129
129
  if source is None:
@@ -148,7 +148,7 @@ class LibCSTSourceFinder:
148
148
  )
149
149
 
150
150
  def find_class_attribute(
151
- self, cls: Type, attribute_name: str
151
+ self, cls: Type[Any], attribute_name: str
152
152
  ) -> Optional[ExceptionSource]:
153
153
  source = self.find_source(cls.__module__)
154
154
 
@@ -190,7 +190,7 @@ class LibCSTSourceFinder:
190
190
  error_column_end=attribute_position.end.column,
191
191
  )
192
192
 
193
- def find_function(self, function: Callable) -> Optional[ExceptionSource]:
193
+ def find_function(self, function: Callable[..., Any]) -> Optional[ExceptionSource]:
194
194
  source = self.find_source(function.__module__)
195
195
 
196
196
  if source is None:
@@ -223,7 +223,7 @@ class LibCSTSourceFinder:
223
223
  )
224
224
 
225
225
  def find_argument(
226
- self, function: Callable, argument_name: str
226
+ self, function: Callable[..., Any], argument_name: str
227
227
  ) -> Optional[ExceptionSource]:
228
228
  source = self.find_source(function.__module__)
229
229
 
@@ -372,6 +372,134 @@ class LibCSTSourceFinder:
372
372
  error_column_end=invalid_type_node_position.end.column,
373
373
  )
374
374
 
375
+ def find_annotated_union(
376
+ self, union_definition: StrawberryUnion, invalid_type: object
377
+ ) -> Optional[ExceptionSource]:
378
+ if union_definition._source_file is None:
379
+ return None
380
+
381
+ # find things like Annotated[Union[...], strawberry.union(name="aaa")]
382
+
383
+ import libcst.matchers as m
384
+
385
+ path = Path(union_definition._source_file)
386
+ source = path.read_text()
387
+
388
+ matcher = m.Subscript(
389
+ value=m.Name(value="Annotated"),
390
+ slice=(
391
+ m.SubscriptElement(
392
+ slice=m.Index(
393
+ value=m.Subscript(
394
+ value=m.Name(value="Union"),
395
+ )
396
+ )
397
+ ),
398
+ m.SubscriptElement(
399
+ slice=m.Index(
400
+ value=m.Call(
401
+ func=m.Attribute(
402
+ value=m.Name(value="strawberry"),
403
+ attr=m.Name(value="union"),
404
+ ),
405
+ args=[
406
+ m.Arg(
407
+ value=m.SimpleString(
408
+ value=f"'{union_definition.graphql_name}'"
409
+ )
410
+ | m.SimpleString(
411
+ value=f'"{union_definition.graphql_name}"'
412
+ )
413
+ )
414
+ ],
415
+ )
416
+ )
417
+ ),
418
+ ),
419
+ )
420
+
421
+ annotated_calls = self._find(source, matcher)
422
+ invalid_type_name = getattr(invalid_type, "__name__", None)
423
+
424
+ if hasattr(invalid_type, "_scalar_definition"):
425
+ invalid_type_name = invalid_type._scalar_definition.name
426
+
427
+ if annotated_calls:
428
+ annotated_call_node = annotated_calls[0]
429
+
430
+ if invalid_type_name:
431
+ invalid_type_nodes = m.findall(
432
+ annotated_call_node,
433
+ m.SubscriptElement(slice=m.Index(m.Name(invalid_type_name))),
434
+ )
435
+
436
+ if not invalid_type_nodes:
437
+ return None # pragma: no cover
438
+
439
+ invalid_type_node = invalid_type_nodes[0]
440
+ else:
441
+ invalid_type_node = annotated_call_node
442
+ else:
443
+ matcher = m.Subscript(
444
+ value=m.Name(value="Annotated"),
445
+ slice=(
446
+ m.SubscriptElement(slice=m.Index(value=m.BinaryOperation())),
447
+ m.SubscriptElement(
448
+ slice=m.Index(
449
+ value=m.Call(
450
+ func=m.Attribute(
451
+ value=m.Name(value="strawberry"),
452
+ attr=m.Name(value="union"),
453
+ ),
454
+ args=[
455
+ m.Arg(
456
+ value=m.SimpleString(
457
+ value=f"'{union_definition.graphql_name}'"
458
+ )
459
+ | m.SimpleString(
460
+ value=f'"{union_definition.graphql_name}"'
461
+ )
462
+ )
463
+ ],
464
+ )
465
+ )
466
+ ),
467
+ ),
468
+ )
469
+
470
+ annotated_calls = self._find(source, matcher)
471
+
472
+ if not annotated_calls:
473
+ return None
474
+
475
+ annotated_call_node = annotated_calls[0]
476
+
477
+ if invalid_type_name:
478
+ invalid_type_nodes = m.findall(
479
+ annotated_call_node,
480
+ m.BinaryOperation(left=m.Name(invalid_type_name)),
481
+ )
482
+
483
+ if not invalid_type_nodes:
484
+ return None # pragma: no cover
485
+
486
+ invalid_type_node = invalid_type_nodes[0].left # type: ignore
487
+ else:
488
+ invalid_type_node = annotated_call_node
489
+
490
+ position = self._position_metadata[annotated_call_node]
491
+ invalid_type_node_position = self._position_metadata[invalid_type_node]
492
+
493
+ return ExceptionSource(
494
+ path=path,
495
+ code=source,
496
+ start_line=position.start.line,
497
+ end_line=position.end.line,
498
+ error_line=invalid_type_node_position.start.line,
499
+ error_column=invalid_type_node_position.start.column,
500
+ error_column_end=invalid_type_node_position.end.column,
501
+ )
502
+
375
503
  def find_scalar_call(
376
504
  self, scalar_definition: ScalarDefinition
377
505
  ) -> Optional[ExceptionSource]:
@@ -426,7 +554,6 @@ class LibCSTSourceFinder:
426
554
 
427
555
 
428
556
  class SourceFinder:
429
- # TODO: this might need to become a getter
430
557
  @cached_property
431
558
  def cst(self) -> Optional[LibCSTSourceFinder]:
432
559
  try:
@@ -434,21 +561,21 @@ class SourceFinder:
434
561
  except ImportError:
435
562
  return None # pragma: no cover
436
563
 
437
- def find_class_from_object(self, cls: Type) -> Optional[ExceptionSource]:
564
+ def find_class_from_object(self, cls: Type[Any]) -> Optional[ExceptionSource]:
438
565
  return self.cst.find_class(cls) if self.cst else None
439
566
 
440
567
  def find_class_attribute_from_object(
441
- self, cls: Type, attribute_name: str
568
+ self, cls: Type[Any], attribute_name: str
442
569
  ) -> Optional[ExceptionSource]:
443
570
  return self.cst.find_class_attribute(cls, attribute_name) if self.cst else None
444
571
 
445
572
  def find_function_from_object(
446
- self, function: Callable
573
+ self, function: Callable[..., Any]
447
574
  ) -> Optional[ExceptionSource]:
448
575
  return self.cst.find_function(function) if self.cst else None
449
576
 
450
577
  def find_argument_from_object(
451
- self, function: Callable, argument_name: str
578
+ self, function: Callable[..., Any], argument_name: str
452
579
  ) -> Optional[ExceptionSource]:
453
580
  return self.cst.find_argument(function, argument_name) if self.cst else None
454
581
 
@@ -470,3 +597,12 @@ class SourceFinder:
470
597
  self, scalar_definition: ScalarDefinition
471
598
  ) -> Optional[ExceptionSource]:
472
599
  return self.cst.find_scalar_call(scalar_definition) if self.cst else None
600
+
601
+ def find_annotated_union(
602
+ self, union_definition: StrawberryUnion, invalid_type: object
603
+ ) -> Optional[ExceptionSource]:
604
+ return (
605
+ self.cst.find_annotated_union(union_definition, invalid_type)
606
+ if self.cst
607
+ else None
608
+ )
@@ -6,14 +6,11 @@ from typing import TYPE_CHECKING, Any, Awaitable, Callable, Union
6
6
  from strawberry.utils.cached_property import cached_property
7
7
 
8
8
  if TYPE_CHECKING:
9
- from typing_extensions import TypeAlias
10
-
11
9
  from strawberry.field import StrawberryField
12
10
  from strawberry.types import Info
13
11
 
14
-
15
- SyncExtensionResolver: TypeAlias = Callable[..., Any]
16
- AsyncExtensionResolver: TypeAlias = Callable[..., Awaitable[Any]]
12
+ SyncExtensionResolver = Callable[..., Any]
13
+ AsyncExtensionResolver = Callable[..., Awaitable[Any]]
17
14
 
18
15
 
19
16
  class FieldExtension:
@@ -188,10 +188,12 @@ class GraphQLRouter(
188
188
  "description": "The GraphiQL integrated development environment.",
189
189
  },
190
190
  404: {
191
- "description": "Not found if GraphiQL is not enabled.",
191
+ "description": (
192
+ "Not found if GraphiQL or query via GET are not enabled."
193
+ )
192
194
  },
193
195
  },
194
- include_in_schema=graphiql,
196
+ include_in_schema=graphiql or allow_queries_via_get,
195
197
  )
196
198
  async def handle_http_get( # pyright: ignore
197
199
  request: Request,
@@ -277,8 +279,7 @@ class GraphQLRouter(
277
279
  )
278
280
 
279
281
  def render_graphiql(self, request: Request) -> HTMLResponse:
280
- html = get_graphiql_html()
281
- return HTMLResponse(html)
282
+ return HTMLResponse(get_graphiql_html())
282
283
 
283
284
  @staticmethod
284
285
  def _merge_responses(response: Response, actual_response: Response) -> Response:
@@ -1,19 +1,18 @@
1
- from typing import Iterable, Optional, Tuple, Type, TypeVar, Union
1
+ from typing import Any, Collection, Iterable, Optional, Type
2
2
 
3
+ from strawberry.union import StrawberryUnion
3
4
  from strawberry.union import union as base_union
4
5
 
5
- Types = TypeVar("Types", bound=Type)
6
-
7
6
 
8
7
  def union(
9
8
  name: str,
10
- types: Tuple[Types, ...],
9
+ types: Optional[Collection[Type[Any]]] = None,
11
10
  *,
12
11
  description: Optional[str] = None,
13
12
  directives: Iterable[object] = (),
14
13
  inaccessible: bool = False,
15
14
  tags: Optional[Iterable[str]] = (),
16
- ) -> Union[Types]:
15
+ ) -> StrawberryUnion:
17
16
  """Creates a new named Union type.
18
17
 
19
18
  Example usages:
strawberry/field.py CHANGED
@@ -1,6 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import contextlib
4
+ import copy
3
5
  import dataclasses
6
+ import inspect
4
7
  import sys
5
8
  from typing import (
6
9
  TYPE_CHECKING,
@@ -15,6 +18,7 @@ from typing import (
15
18
  Type,
16
19
  TypeVar,
17
20
  Union,
21
+ cast,
18
22
  overload,
19
23
  )
20
24
 
@@ -37,6 +41,7 @@ if TYPE_CHECKING:
37
41
  from strawberry.arguments import StrawberryArgument
38
42
  from strawberry.extensions.field_extension import FieldExtension
39
43
  from strawberry.types.info import Info
44
+ from strawberry.types.types import StrawberryObjectDefinition
40
45
 
41
46
  from .permission import BasePermission
42
47
 
@@ -138,21 +143,34 @@ class StrawberryField(dataclasses.Field):
138
143
  self.directives = list(directives)
139
144
  self.extensions: List[FieldExtension] = list(extensions)
140
145
 
141
- # Automatically add the permissions extension
142
- if len(self.permission_classes):
143
- from .permission import PermissionExtension
144
-
145
- if not self.extensions:
146
- self.extensions = []
147
- permission_instances = [
148
- permission_class() for permission_class in permission_classes
149
- ]
150
- # Append to make it run first (last is outermost)
151
- self.extensions.append(
152
- PermissionExtension(permission_instances, use_directives=False)
153
- )
154
146
  self.deprecation_reason = deprecation_reason
155
147
 
148
+ def __copy__(self) -> Self:
149
+ new_field = type(self)(
150
+ python_name=self.python_name,
151
+ graphql_name=self.graphql_name,
152
+ type_annotation=self.type_annotation,
153
+ origin=self.origin,
154
+ is_subscription=self.is_subscription,
155
+ description=self.description,
156
+ base_resolver=self.base_resolver,
157
+ permission_classes=(
158
+ self.permission_classes[:]
159
+ if self.permission_classes is not None
160
+ else []
161
+ ),
162
+ default=self.default_value,
163
+ default_factory=self.default_factory,
164
+ metadata=self.metadata.copy() if self.metadata is not None else None,
165
+ deprecation_reason=self.deprecation_reason,
166
+ directives=self.directives[:] if self.directives is not None else [],
167
+ extensions=self.extensions[:] if self.extensions is not None else [],
168
+ )
169
+ new_field._arguments = (
170
+ self._arguments[:] if self._arguments is not None else None
171
+ )
172
+ return new_field
173
+
156
174
  def __call__(self, resolver: _RESOLVER_TYPE) -> Self:
157
175
  """Add a resolver to the field"""
158
176
 
@@ -202,7 +220,11 @@ class StrawberryField(dataclasses.Field):
202
220
  an `Info` object and running any permission checks in the resolver
203
221
  which improves performance.
204
222
  """
205
- return not self.base_resolver and not self.extensions
223
+ return (
224
+ not self.base_resolver
225
+ and not self.permission_classes
226
+ and not self.extensions
227
+ )
206
228
 
207
229
  @property
208
230
  def arguments(self) -> List[StrawberryArgument]:
@@ -261,35 +283,7 @@ class StrawberryField(dataclasses.Field):
261
283
  Type[WithStrawberryObjectDefinition],
262
284
  Literal[UNRESOLVED],
263
285
  ]:
264
- # We are catching NameError because dataclasses tries to fetch the type
265
- # of the field from the class before the class is fully defined.
266
- # This triggers a NameError error when using forward references because
267
- # our `type` property tries to find the field type from the global namespace
268
- # but it is not yet defined.
269
- try:
270
- # Prioritise the field type over the resolver return type
271
- if self.type_annotation is not None:
272
- return self.type_annotation.resolve()
273
-
274
- if self.base_resolver is not None:
275
- # Handle unannotated functions (such as lambdas)
276
- if self.base_resolver.type is not None:
277
- # Generics will raise MissingTypesForGenericError later
278
- # on if we let it be returned. So use `type_annotation` instead
279
- # which is the same behaviour as having no type information.
280
- if not _is_generic(self.base_resolver.type):
281
- return self.base_resolver.type
282
-
283
- # If we get this far it means that we don't have a field type and
284
- # the resolver doesn't have a return type so all we can do is return
285
- # UNRESOLVED here.
286
- # This case will raise a MissingReturnAnnotationError exception in the
287
- # _check_field_annotations function:
288
- # https://github.com/strawberry-graphql/strawberry/blob/846f060a63cb568b3cdc0deb26c308a8d0718190/strawberry/object_type.py#L76-L80
289
- return UNRESOLVED
290
-
291
- except NameError:
292
- return UNRESOLVED
286
+ return self.resolve_type()
293
287
 
294
288
  @type.setter
295
289
  def type(self, type_: Any) -> None:
@@ -315,54 +309,101 @@ class StrawberryField(dataclasses.Field):
315
309
  return self.type.type_params
316
310
  return []
317
311
 
312
+ def resolve_type(
313
+ self,
314
+ *,
315
+ type_definition: Optional[StrawberryObjectDefinition] = None,
316
+ ) -> Union[ # type: ignore [valid-type]
317
+ StrawberryType,
318
+ Type[WithStrawberryObjectDefinition],
319
+ Literal[UNRESOLVED],
320
+ ]:
321
+ # We return UNRESOLVED by default, which means this case will raise a
322
+ # MissingReturnAnnotationError exception in _check_field_annotations
323
+ resolved = UNRESOLVED
324
+
325
+ # We are catching NameError because dataclasses tries to fetch the type
326
+ # of the field from the class before the class is fully defined.
327
+ # This triggers a NameError error when using forward references because
328
+ # our `type` property tries to find the field type from the global namespace
329
+ # but it is not yet defined.
330
+ with contextlib.suppress(NameError):
331
+ # Prioritise the field type over the resolver return type
332
+ if self.type_annotation is not None:
333
+ resolved = self.type_annotation.resolve()
334
+ elif self.base_resolver is not None and self.base_resolver.type is not None:
335
+ # Handle unannotated functions (such as lambdas)
336
+ # Generics will raise MissingTypesForGenericError later
337
+ # on if we let it be returned. So use `type_annotation` instead
338
+ # which is the same behaviour as having no type information.
339
+ resolved = self.base_resolver.type
340
+
341
+ # If this is a generic field, try to resolve it using its origin's
342
+ # specialized type_var_map
343
+ if _is_generic(resolved): # type: ignore
344
+ specialized_type_var_map = (
345
+ type_definition and type_definition.specialized_type_var_map
346
+ )
347
+ if specialized_type_var_map and isinstance(resolved, StrawberryType):
348
+ resolved = resolved.copy_with(specialized_type_var_map)
349
+
350
+ # If the field is still generic, try to resolve it from the type_definition
351
+ # that is asking for it.
352
+ if (
353
+ _is_generic(cast(Union[StrawberryType, type], resolved))
354
+ and type_definition is not None
355
+ and type_definition.type_var_map
356
+ and isinstance(resolved, StrawberryType)
357
+ ):
358
+ resolved = resolved.copy_with(type_definition.type_var_map)
359
+
360
+ return resolved
361
+
318
362
  def copy_with(
319
363
  self, type_var_map: Mapping[TypeVar, Union[StrawberryType, builtins.type]]
320
364
  ) -> Self:
321
- new_type: Union[StrawberryType, type] = self.type
365
+ new_field = copy.copy(self)
322
366
 
323
- if has_object_definition(self.type):
324
- type_definition = self.type.__strawberry_definition__
367
+ override_type: Optional[
368
+ Union[StrawberryType, Type[WithStrawberryObjectDefinition]]
369
+ ] = None
370
+ type_ = self.resolve_type()
371
+ if has_object_definition(type_):
372
+ type_definition = type_.__strawberry_definition__
325
373
 
326
374
  if type_definition.is_generic:
327
375
  type_ = type_definition
328
- new_type = type_.copy_with(type_var_map)
329
- elif isinstance(self.type, StrawberryType):
330
- new_type = self.type.copy_with(type_var_map)
331
-
332
- new_resolver = (
333
- self.base_resolver.copy_with(type_var_map)
334
- if self.base_resolver is not None
335
- else None
336
- )
376
+ override_type = type_.copy_with(type_var_map)
377
+ elif isinstance(type_, StrawberryType):
378
+ override_type = type_.copy_with(type_var_map)
379
+
380
+ if override_type is not None:
381
+ new_field.type_annotation = StrawberryAnnotation(
382
+ override_type,
383
+ namespace=(
384
+ self.type_annotation.namespace if self.type_annotation else None
385
+ ),
386
+ )
387
+
388
+ if self.base_resolver is not None:
389
+ new_field.base_resolver = self.base_resolver.copy_with(type_var_map)
337
390
 
338
- new_field = type(self)(
339
- python_name=self.python_name,
340
- graphql_name=self.graphql_name,
341
- # TODO: do we need to wrap this in `StrawberryAnnotation`?
342
- # see comment related to dataclasses above
343
- type_annotation=StrawberryAnnotation(new_type),
344
- origin=self.origin,
345
- is_subscription=self.is_subscription,
346
- description=self.description,
347
- base_resolver=new_resolver,
348
- permission_classes=self.permission_classes and self.permission_classes[:],
349
- default=self.default_value,
350
- # ignored because of https://github.com/python/mypy/issues/6910
351
- default_factory=self.default_factory,
352
- deprecation_reason=self.deprecation_reason,
353
- directives=self.directives and self.directives[:],
354
- extensions=self.extensions and self.extensions[:],
355
- )
356
- new_field._arguments = self._arguments and self._arguments[:]
357
391
  return new_field
358
392
 
393
+ @property
394
+ def _has_async_permission_classes(self) -> bool:
395
+ for permission_class in self.permission_classes:
396
+ if inspect.iscoroutinefunction(permission_class.has_permission):
397
+ return True
398
+ return False
399
+
359
400
  @property
360
401
  def _has_async_base_resolver(self) -> bool:
361
402
  return self.base_resolver is not None and self.base_resolver.is_async
362
403
 
363
404
  @cached_property
364
405
  def is_async(self) -> bool:
365
- return self._has_async_base_resolver
406
+ return self._has_async_permission_classes or self._has_async_base_resolver
366
407
 
367
408
 
368
409
  @overload
@@ -5,8 +5,6 @@ from dataclasses import dataclass
5
5
  from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional
6
6
  from typing_extensions import TypedDict
7
7
 
8
- from graphql.error.graphql_error import format_error as format_graphql_error
9
-
10
8
  if TYPE_CHECKING:
11
9
  from strawberry.types import ExecutionResult
12
10
 
@@ -21,7 +19,7 @@ def process_result(result: ExecutionResult) -> GraphQLHTTPResponse:
21
19
  data: GraphQLHTTPResponse = {"data": result.data}
22
20
 
23
21
  if result.errors:
24
- data["errors"] = [format_graphql_error(err) for err in result.errors]
22
+ data["errors"] = [err.formatted for err in result.errors]
25
23
  if result.extensions:
26
24
  data["extensions"] = result.extensions
27
25