strawberry-graphql 0.232.1__py3-none-any.whl → 0.233.0__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.
@@ -10,7 +10,6 @@ from typing import (
10
10
  Mapping,
11
11
  NewType,
12
12
  Optional,
13
- Type,
14
13
  TypeVar,
15
14
  Union,
16
15
  overload,
@@ -85,7 +84,7 @@ class ScalarWrapper:
85
84
 
86
85
 
87
86
  def _process_scalar(
88
- cls: Type[_T],
87
+ cls: _T,
89
88
  *,
90
89
  name: Optional[str] = None,
91
90
  description: Optional[str] = None,
@@ -94,10 +93,10 @@ def _process_scalar(
94
93
  parse_value: Optional[Callable] = None,
95
94
  parse_literal: Optional[Callable] = None,
96
95
  directives: Iterable[object] = (),
97
- ):
96
+ ) -> ScalarWrapper:
98
97
  from strawberry.exceptions.handler import should_use_rich_exceptions
99
98
 
100
- name = name or to_camel_case(cls.__name__)
99
+ name = name or to_camel_case(cls.__name__) # type: ignore[union-attr]
101
100
 
102
101
  _source_file = None
103
102
  _source_line = None
@@ -155,7 +154,7 @@ def scalar(
155
154
  # here or else it won't let us use any custom scalar to annotate attributes in
156
155
  # dataclasses/types. This should be properly solved when implementing StrawberryScalar
157
156
  def scalar(
158
- cls=None,
157
+ cls: Optional[_T] = None,
159
158
  *,
160
159
  name: Optional[str] = None,
161
160
  description: Optional[str] = None,
@@ -194,7 +193,7 @@ def scalar(
194
193
  if parse_value is None:
195
194
  parse_value = cls
196
195
 
197
- def wrap(cls: Type):
196
+ def wrap(cls: _T) -> ScalarWrapper:
198
197
  return _process_scalar(
199
198
  cls,
200
199
  name=name,
@@ -21,7 +21,7 @@ def _convert_from_pydantic_to_strawberry_type(
21
21
  type_: Union[StrawberryType, type],
22
22
  data_from_model=None, # noqa: ANN001
23
23
  extra=None, # noqa: ANN001
24
- ):
24
+ ) -> Any:
25
25
  data = data_from_model if data_from_model is not None else extra
26
26
 
27
27
  if isinstance(type_, StrawberryOptional):
@@ -291,11 +291,11 @@ class GraphQLRouter(
291
291
  websocket: WebSocket,
292
292
  context: Context = Depends(self.context_getter),
293
293
  root_value: RootValue = Depends(self.root_value_getter),
294
- ):
295
- async def _get_context():
294
+ ) -> None:
295
+ async def _get_context() -> Context:
296
296
  return context
297
297
 
298
- async def _get_root_value():
298
+ async def _get_root_value() -> RootValue:
299
299
  return root_value
300
300
 
301
301
  preferred_protocol = self.pick_preferred_protocol(websocket)
@@ -6,13 +6,12 @@ from typing import (
6
6
  List,
7
7
  NewType,
8
8
  Optional,
9
- Type,
10
9
  TypeVar,
11
10
  Union,
12
11
  overload,
13
12
  )
14
13
 
15
- from strawberry.custom_scalar import _process_scalar
14
+ from strawberry.custom_scalar import ScalarWrapper, _process_scalar
16
15
 
17
16
  # in python 3.10+ NewType is a class
18
17
  if sys.version_info >= (3, 10):
@@ -63,7 +62,7 @@ def scalar(
63
62
 
64
63
 
65
64
  def scalar(
66
- cls=None,
65
+ cls: Optional[_T] = None,
67
66
  *,
68
67
  name: Optional[str] = None,
69
68
  description: Optional[str] = None,
@@ -131,7 +130,7 @@ def scalar(
131
130
  if tags:
132
131
  directives.extend(Tag(name=tag) for tag in tags)
133
132
 
134
- def wrap(cls: Type):
133
+ def wrap(cls: _T) -> ScalarWrapper:
135
134
  return _process_scalar(
136
135
  cls,
137
136
  name=name,
@@ -1,5 +1,4 @@
1
1
  from collections import defaultdict
2
- from copy import copy
3
2
  from functools import cached_property, partial
4
3
  from itertools import chain
5
4
  from typing import (
@@ -10,6 +9,7 @@ from typing import (
10
9
  Iterable,
11
10
  List,
12
11
  Mapping,
12
+ NewType,
13
13
  Optional,
14
14
  Set,
15
15
  Type,
@@ -17,36 +17,36 @@ from typing import (
17
17
  cast,
18
18
  )
19
19
 
20
- from graphql import (
21
- GraphQLError,
22
- GraphQLField,
23
- GraphQLInterfaceType,
24
- GraphQLList,
25
- GraphQLNonNull,
26
- GraphQLScalarType,
27
- GraphQLUnionType,
28
- )
29
- from graphql.type.definition import GraphQLArgument
20
+ from graphql import GraphQLError
30
21
 
22
+ from strawberry.annotation import StrawberryAnnotation
23
+ from strawberry.custom_scalar import scalar
31
24
  from strawberry.printer import print_schema
32
25
  from strawberry.schema import Schema as BaseSchema
26
+ from strawberry.type import (
27
+ StrawberryContainer,
28
+ WithStrawberryObjectDefinition,
29
+ get_object_definition,
30
+ )
31
+ from strawberry.types.info import Info
33
32
  from strawberry.types.types import StrawberryObjectDefinition
33
+ from strawberry.union import StrawberryUnion
34
34
  from strawberry.utils.inspect import get_func_args
35
35
 
36
36
  from .schema_directive import StrawberryFederationSchemaDirective
37
37
 
38
38
  if TYPE_CHECKING:
39
39
  from graphql import ExecutionContext as GraphQLExecutionContext
40
- from graphql import GraphQLObjectType
41
40
 
42
41
  from strawberry.custom_scalar import ScalarDefinition, ScalarWrapper
43
42
  from strawberry.enum import EnumDefinition
44
43
  from strawberry.extensions import SchemaExtension
45
44
  from strawberry.federation.schema_directives import ComposeDirective
46
45
  from strawberry.schema.config import StrawberryConfig
47
- from strawberry.schema.types.concrete_type import TypeMap
48
46
  from strawberry.schema_directive import StrawberrySchemaDirective
49
- from strawberry.union import StrawberryUnion
47
+
48
+
49
+ FederationAny = scalar(NewType("_Any", object), name="_Any") # type: ignore
50
50
 
51
51
 
52
52
  class Schema(BaseSchema):
@@ -67,7 +67,8 @@ class Schema(BaseSchema):
67
67
  schema_directives: Iterable[object] = (),
68
68
  enable_federation_2: bool = False,
69
69
  ) -> None:
70
- query = self._get_federation_query_type(query)
70
+ query = self._get_federation_query_type(query, mutation, subscription, types)
71
+ types = [*types, FederationAny]
71
72
 
72
73
  super().__init__(
73
74
  query=query,
@@ -84,16 +85,19 @@ class Schema(BaseSchema):
84
85
 
85
86
  self.schema_directives = list(schema_directives)
86
87
 
87
- self._add_scalars()
88
- self._add_entities_to_query()
89
-
90
88
  if enable_federation_2:
91
89
  composed_directives = self._add_compose_directives()
92
90
  self._add_link_directives(composed_directives) # type: ignore
93
91
  else:
94
92
  self._remove_resolvable_field()
95
93
 
96
- def _get_federation_query_type(self, query: Optional[Type]) -> Type:
94
+ def _get_federation_query_type(
95
+ self,
96
+ query: Optional[Type[WithStrawberryObjectDefinition]],
97
+ mutation: Optional[Type[WithStrawberryObjectDefinition]],
98
+ subscription: Optional[Type[WithStrawberryObjectDefinition]],
99
+ additional_types: Iterable[Type[WithStrawberryObjectDefinition]],
100
+ ) -> Type:
97
101
  """Returns a new query type that includes the _service field.
98
102
 
99
103
  If the query type is provided, it will be used as the base for the new
@@ -109,13 +113,6 @@ class Schema(BaseSchema):
109
113
  added if the schema contains an entity type.
110
114
  """
111
115
 
112
- # note we don't add the _entities field here, as we need to know if the
113
- # schema contains an entity type first and we do that by leveraging
114
- # the schema converter type map, so we don't have to do that twice
115
- # TODO: ideally we should be able to do this without using the schema
116
- # converter, but for now this is the easiest way to do it
117
- # see `_add_entities_to_query`
118
-
119
116
  import strawberry
120
117
  from strawberry.tools.create_type import create_type
121
118
  from strawberry.tools.merge_types import merge_types
@@ -132,6 +129,19 @@ class Schema(BaseSchema):
132
129
 
133
130
  fields = [service]
134
131
 
132
+ entity_type = _get_entity_type(query, mutation, subscription, additional_types)
133
+
134
+ if entity_type:
135
+ self.entities_resolver.__annotations__["return"] = List[
136
+ Optional[entity_type] # type: ignore
137
+ ]
138
+
139
+ entities_field = strawberry.field(
140
+ name="_entities", resolver=self.entities_resolver
141
+ )
142
+
143
+ fields.insert(0, entities_field)
144
+
135
145
  FederationQuery = create_type(name="Query", fields=fields)
136
146
 
137
147
  if query is None:
@@ -139,10 +149,7 @@ class Schema(BaseSchema):
139
149
 
140
150
  query_type = merge_types(
141
151
  "Query",
142
- (
143
- FederationQuery,
144
- query,
145
- ),
152
+ (FederationQuery, query),
146
153
  )
147
154
 
148
155
  # TODO: this should be probably done in merge_types
@@ -151,31 +158,9 @@ class Schema(BaseSchema):
151
158
 
152
159
  return query_type
153
160
 
154
- def _add_entities_to_query(self):
155
- entity_type = _get_entity_type(self.schema_converter.type_map)
156
-
157
- if not entity_type:
158
- return
159
-
160
- self._schema.type_map[entity_type.name] = entity_type
161
- fields = {"_entities": self._get_entities_field(entity_type)}
162
-
163
- # Copy the query type, update it to use the modified fields
164
- query_type = cast("GraphQLObjectType", self._schema.query_type)
165
- fields.update(query_type.fields)
166
-
167
- query_type = copy(query_type)
168
- query_type.fields = fields
169
-
170
- self._schema.query_type = query_type
171
- self._schema.type_map[query_type.name] = query_type
172
-
173
161
  def entities_resolver(
174
- self,
175
- root, # noqa: ANN001
176
- info, # noqa: ANN001
177
- representations, # noqa: ANN001
178
- ) -> List[object]:
162
+ self, info: Info, representations: List[FederationAny]
163
+ ) -> List[FederationAny]:
179
164
  results = []
180
165
 
181
166
  for representation in representations:
@@ -198,9 +183,8 @@ class Schema(BaseSchema):
198
183
  else:
199
184
  from strawberry.arguments import convert_argument
200
185
 
201
- strawberry_schema = info.schema.extensions["strawberry-definition"]
202
- config = strawberry_schema.config
203
- scalar_registry = strawberry_schema.schema_converter.scalar_registry
186
+ config = info.schema.config
187
+ scalar_registry = info.schema.schema_converter.scalar_registry
204
188
 
205
189
  get_result = partial(
206
190
  convert_argument,
@@ -222,11 +206,6 @@ class Schema(BaseSchema):
222
206
 
223
207
  return results
224
208
 
225
- def _add_scalars(self):
226
- self.Any = GraphQLScalarType("_Any")
227
-
228
- self._schema.type_map["_Any"] = self.Any
229
-
230
209
  def _remove_resolvable_field(self) -> None:
231
210
  # this might be removed when we remove support for federation 1
232
211
  # or when we improve how we print the directives
@@ -283,7 +262,7 @@ class Schema(BaseSchema):
283
262
 
284
263
  def _add_link_directives(
285
264
  self, additional_directives: Optional[List[object]] = None
286
- ):
265
+ ) -> None:
287
266
  from .schema_directives import FederationDirective, Link
288
267
 
289
268
  directive_by_url: DefaultDict[str, Set[str]] = defaultdict(set)
@@ -335,17 +314,6 @@ class Schema(BaseSchema):
335
314
 
336
315
  return compose_directives
337
316
 
338
- def _get_entities_field(self, entity_type: GraphQLUnionType) -> GraphQLField:
339
- return GraphQLField(
340
- GraphQLNonNull(GraphQLList(entity_type)),
341
- args={
342
- "representations": GraphQLArgument(
343
- GraphQLNonNull(GraphQLList(GraphQLNonNull(self.Any)))
344
- )
345
- },
346
- resolve=self.entities_resolver,
347
- )
348
-
349
317
  def _warn_for_federation_directives(self) -> None:
350
318
  # this is used in the main schema to raise if there's a directive
351
319
  # that's for federation, but in this class we don't want to warn,
@@ -354,33 +322,56 @@ class Schema(BaseSchema):
354
322
  pass
355
323
 
356
324
 
357
- def _get_entity_type(type_map: "TypeMap"):
358
- # https://www.apollographql.com/docs/apollo-server/federation/federation-spec/#resolve-requests-for-entities
325
+ def _get_entity_type(
326
+ query: Optional[Type[WithStrawberryObjectDefinition]],
327
+ mutation: Optional[Type[WithStrawberryObjectDefinition]],
328
+ subscription: Optional[Type[WithStrawberryObjectDefinition]],
329
+ additional_types: Iterable[Type[WithStrawberryObjectDefinition]],
330
+ ) -> Optional[StrawberryUnion]:
331
+ # recursively iterate over the schema to find all types annotated with @key
332
+ # if no types are annotated with @key, then the _Entity union and Query._entities
333
+ # field should not be added to the schema
359
334
 
360
- # To implement the _Entity union, each type annotated with @key
361
- # should be added to the _Entity union.
335
+ entity_types = set()
362
336
 
363
- federation_key_types = [
364
- type.implementation
365
- for type in type_map.values()
366
- if _has_federation_keys(type.definition)
367
- # TODO: check this
368
- and not isinstance(type.implementation, GraphQLInterfaceType)
369
- ]
337
+ # need a stack to keep track of the types we need to visit
338
+ stack: List[Any] = [query, mutation, subscription, *additional_types]
370
339
 
371
- # If no types are annotated with the key directive, then the _Entity
372
- # union and Query._entities field should be removed from the schema.
373
- if not federation_key_types:
374
- return None
340
+ seen = set()
375
341
 
376
- entity_type = GraphQLUnionType("_Entity", federation_key_types) # type: ignore
342
+ while stack:
343
+ type_ = stack.pop()
377
344
 
378
- def _resolve_type(self, value, _type): # noqa: ANN001
379
- return self.__strawberry_definition__.name
345
+ if type_ is None:
346
+ continue
347
+
348
+ while isinstance(type_, StrawberryContainer):
349
+ type_ = type_.of_type
350
+
351
+ type_definition = get_object_definition(type_, strict=False)
352
+
353
+ if type_definition is None:
354
+ continue
355
+
356
+ if type_definition.is_object_type and _has_federation_keys(type_definition):
357
+ entity_types.add(type_)
358
+
359
+ for field in type_definition.fields:
360
+ if field.type and field.type in seen:
361
+ continue
362
+
363
+ seen.add(field.type)
364
+ stack.append(field.type)
365
+
366
+ if not entity_types:
367
+ return None
380
368
 
381
- entity_type.resolve_type = _resolve_type
369
+ sorted_types = sorted(entity_types, key=lambda t: t.__strawberry_definition__.name)
382
370
 
383
- return entity_type
371
+ return StrawberryUnion(
372
+ "_Entity",
373
+ type_annotations=tuple(StrawberryAnnotation(type_) for type_ in sorted_types),
374
+ )
384
375
 
385
376
 
386
377
  def _is_key(directive: Any) -> bool:
@@ -38,7 +38,7 @@ def schema_directive(
38
38
  import_url: Optional[str] = None,
39
39
  ) -> Callable[..., T]:
40
40
  def _wrap(cls: T) -> T:
41
- cls = _wrap_dataclass(cls)
41
+ cls = _wrap_dataclass(cls) # type: ignore
42
42
  fields = _get_fields(cls, {})
43
43
 
44
44
  cls.__strawberry_directive__ = StrawberryFederationSchemaDirective(
strawberry/object_type.py CHANGED
@@ -44,7 +44,7 @@ def _get_interfaces(cls: Type[Any]) -> List[StrawberryObjectDefinition]:
44
44
  return interfaces
45
45
 
46
46
 
47
- def _check_field_annotations(cls: Type[Any]):
47
+ def _check_field_annotations(cls: Type[Any]) -> None:
48
48
  """Are any of the dataclass Fields missing type annotations?
49
49
 
50
50
  This is similar to the check that dataclasses do during creation, but allows us to
@@ -102,7 +102,7 @@ def _check_field_annotations(cls: Type[Any]):
102
102
  raise MissingFieldAnnotationError(field_name, cls)
103
103
 
104
104
 
105
- def _wrap_dataclass(cls: Type[Any]):
105
+ def _wrap_dataclass(cls: Type[T]) -> Type[T]:
106
106
  """Wrap a strawberry.type class with a dataclass and check for any issues
107
107
  before doing so"""
108
108
 
@@ -239,7 +239,7 @@ def type(
239
239
  >>> field_abc: str = "ABC"
240
240
  """
241
241
 
242
- def wrap(cls: Type) -> T:
242
+ def wrap(cls: T) -> T:
243
243
  if not inspect.isclass(cls):
244
244
  if is_input:
245
245
  exc = ObjectIsNotClassError.input
@@ -268,7 +268,7 @@ def type(
268
268
 
269
269
  wrapped = _wrap_dataclass(cls)
270
270
 
271
- return _process_type(
271
+ return _process_type( # type: ignore
272
272
  wrapped,
273
273
  name=name,
274
274
  is_input=is_input,
@@ -566,7 +566,7 @@ def print_schema(schema: BaseSchema) -> str:
566
566
  None, [print_directive(directive, schema=schema) for directive in directives]
567
567
  )
568
568
 
569
- def _name_getter(type_: Any):
569
+ def _name_getter(type_: Any) -> str:
570
570
  if hasattr(type_, "name"):
571
571
  return type_.name
572
572
  if isinstance(type_, ScalarWrapper):
@@ -9,6 +9,7 @@ from typing import (
9
9
  TYPE_CHECKING,
10
10
  Any,
11
11
  AsyncIterator,
12
+ Awaitable,
12
13
  Callable,
13
14
  DefaultDict,
14
15
  Dict,
@@ -35,6 +36,7 @@ from strawberry.extensions.field_extension import (
35
36
  SyncExtensionResolver,
36
37
  )
37
38
  from strawberry.field import _RESOLVER_TYPE, StrawberryField, field
39
+ from strawberry.lazy_type import LazyType
38
40
  from strawberry.relay.exceptions import (
39
41
  RelayWrongAnnotationError,
40
42
  RelayWrongResolverAnnotationError,
@@ -42,7 +44,7 @@ from strawberry.relay.exceptions import (
42
44
  from strawberry.type import StrawberryList, StrawberryOptional
43
45
  from strawberry.types.fields.resolver import StrawberryResolver
44
46
  from strawberry.utils.aio import asyncgen_to_list
45
- from strawberry.utils.typing import eval_type
47
+ from strawberry.utils.typing import eval_type, is_generic_alias
46
48
 
47
49
  from .types import Connection, GlobalID, Node, NodeIterableType, NodeType
48
50
 
@@ -86,7 +88,7 @@ class NodeExtension(FieldExtension):
86
88
  def resolver(
87
89
  info: Info,
88
90
  id: Annotated[GlobalID, argument(description="The ID of the object.")],
89
- ):
91
+ ) -> Union[Node, None, Awaitable[Union[Node, None]]]:
90
92
  return id.resolve_type(info).resolve_node(
91
93
  id.node_id,
92
94
  info=info,
@@ -105,7 +107,7 @@ class NodeExtension(FieldExtension):
105
107
  ids: Annotated[
106
108
  List[GlobalID], argument(description="The IDs of the objects.")
107
109
  ],
108
- ):
110
+ ) -> Union[List[Node], Awaitable[List[Node]]]:
109
111
  nodes_map: DefaultDict[Type[Node], List[str]] = defaultdict(list)
110
112
  # Store the index of the node in the list of nodes of the same type
111
113
  # so that we can return them in the same order while also supporting
@@ -138,7 +140,7 @@ class NodeExtension(FieldExtension):
138
140
 
139
141
  if awaitable_nodes or asyncgen_nodes:
140
142
 
141
- async def resolve(resolved=resolved_nodes): # noqa: ANN001
143
+ async def resolve(resolved: Any = resolved_nodes) -> List[Node]:
142
144
  resolved.update(
143
145
  zip(
144
146
  [
@@ -222,7 +224,13 @@ class ConnectionExtension(FieldExtension):
222
224
  ]
223
225
 
224
226
  f_type = field.type
225
- if not isinstance(f_type, type) or not issubclass(f_type, Connection):
227
+
228
+ if isinstance(f_type, LazyType):
229
+ f_type = f_type.resolve_type()
230
+ field.type = f_type
231
+
232
+ type_origin = get_origin(f_type) if is_generic_alias(f_type) else f_type
233
+ if not isinstance(type_origin, type) or not issubclass(type_origin, Connection):
226
234
  raise RelayWrongAnnotationError(field.name, cast(type, field.origin))
227
235
 
228
236
  assert field.base_resolver
strawberry/relay/types.py CHANGED
@@ -859,7 +859,7 @@ class ListConnection(Connection[NodeType]):
859
859
 
860
860
  if isinstance(nodes, (AsyncIterator, AsyncIterable)) and in_async_context():
861
861
 
862
- async def resolver():
862
+ async def resolver() -> Self:
863
863
  try:
864
864
  iterator = cast(
865
865
  Union[AsyncIterator[NodeType], AsyncIterable[NodeType]],
@@ -324,7 +324,7 @@ class Schema(BaseSchema):
324
324
  operation_name=operation_name,
325
325
  )
326
326
 
327
- def _resolve_node_ids(self):
327
+ def _resolve_node_ids(self) -> None:
328
328
  for concrete_type in self.schema_converter.type_map.values():
329
329
  type_def = concrete_type.definition
330
330
 
@@ -355,7 +355,7 @@ class Schema(BaseSchema):
355
355
  if not has_custom_resolve_id:
356
356
  origin.resolve_id_attr()
357
357
 
358
- def _warn_for_federation_directives(self):
358
+ def _warn_for_federation_directives(self) -> None:
359
359
  """Raises a warning if the schema has any federation directives."""
360
360
  from strawberry.federation.schema_directives import FederationDirective
361
361
 
@@ -378,7 +378,7 @@ class Schema(BaseSchema):
378
378
  stacklevel=3,
379
379
  )
380
380
 
381
- def _extend_introspection(self):
381
+ def _extend_introspection(self) -> None:
382
382
  def _resolve_is_one_of(obj: Any, info: Any) -> bool:
383
383
  return obj.extensions["strawberry-definition"].is_one_of
384
384
 
@@ -462,7 +462,12 @@ class GraphQLCoreConverter:
462
462
  assert isinstance(graphql_interface, GraphQLInterfaceType) # For mypy
463
463
  return graphql_interface
464
464
 
465
- def _get_resolve_type():
465
+ def _get_resolve_type() -> (
466
+ Callable[
467
+ [Any, GraphQLResolveInfo, GraphQLAbstractType],
468
+ Union[Awaitable[Optional[str]], str, None],
469
+ ]
470
+ ):
466
471
  if interface.resolve_type:
467
472
  return interface.resolve_type
468
473
 
@@ -594,7 +599,7 @@ class GraphQLCoreConverter:
594
599
 
595
600
  if field.is_basic_field:
596
601
 
597
- def _get_basic_result(_source: Any, *args: str, **kwargs: Any):
602
+ def _get_basic_result(_source: Any, *args: str, **kwargs: Any) -> Any:
598
603
  # Call `get_result` without an info object or any args or
599
604
  # kwargs because this is a basic field with no resolver.
600
605
  return field.get_result(_source, info=None, args=[], kwargs={})
@@ -664,7 +669,7 @@ class GraphQLCoreConverter:
664
669
  info: Info,
665
670
  field_args: List[Any],
666
671
  field_kwargs: Dict[str, Any],
667
- ):
672
+ ) -> Any:
668
673
  return field.get_result(
669
674
  _source, info=info, args=field_args, kwargs=field_kwargs
670
675
  )
@@ -681,7 +686,7 @@ class GraphQLCoreConverter:
681
686
  _source: Any,
682
687
  info: Info,
683
688
  **kwargs: Any,
684
- ):
689
+ ) -> Any:
685
690
  # parse field arguments into Strawberry input types and convert
686
691
  # field names to Python equivalents
687
692
  field_args, field_kwargs = _get_arguments(
@@ -698,7 +703,7 @@ class GraphQLCoreConverter:
698
703
  # `_get_result` expects `field_args` and `field_kwargs` as
699
704
  # separate arguments so we have to wrap the function so that we
700
705
  # can pass them in
701
- def wrapped_get_result(_source: Any, info: Info, **kwargs: Any):
706
+ def wrapped_get_result(_source: Any, info: Info, **kwargs: Any) -> Any:
702
707
  # if the resolver function requested the info object info
703
708
  # then put it back in the kwargs dictionary
704
709
  if resolver_requested_info:
@@ -719,7 +724,7 @@ class GraphQLCoreConverter:
719
724
 
720
725
  _get_result_with_extensions = wrap_field_extensions()
721
726
 
722
- def _resolver(_source: Any, info: GraphQLResolveInfo, **kwargs: Any):
727
+ def _resolver(_source: Any, info: GraphQLResolveInfo, **kwargs: Any) -> Any:
723
728
  strawberry_info = _strawberry_info_from_graphql(info)
724
729
 
725
730
  return _get_result_with_extensions(
@@ -730,7 +735,7 @@ class GraphQLCoreConverter:
730
735
 
731
736
  async def _async_resolver(
732
737
  _source: Any, info: GraphQLResolveInfo, **kwargs: Any
733
- ):
738
+ ) -> Any:
734
739
  strawberry_info = _strawberry_info_from_graphql(info)
735
740
 
736
741
  return await await_maybe(
@@ -11,7 +11,7 @@ from strawberry.custom_scalar import scalar
11
11
 
12
12
 
13
13
  def wrap_parser(parser: Callable, type_: str) -> Callable:
14
- def inner(value: str):
14
+ def inner(value: str) -> object:
15
15
  try:
16
16
  return parser(value)
17
17
  except ValueError as e:
@@ -53,7 +53,7 @@ def schema_directive(
53
53
  print_definition: bool = True,
54
54
  ) -> Callable[..., T]:
55
55
  def _wrap(cls: T) -> T:
56
- cls = _wrap_dataclass(cls)
56
+ cls = _wrap_dataclass(cls) # type: ignore
57
57
  fields = _get_fields(cls, {})
58
58
 
59
59
  cls.__strawberry_directive__ = StrawberrySchemaDirective(
strawberry/types/types.py CHANGED
@@ -146,6 +146,10 @@ class StrawberryObjectDefinition(StrawberryType):
146
146
  def specialized_type_var_map(self) -> Optional[Dict[str, type]]:
147
147
  return get_specialized_type_var_map(self.origin)
148
148
 
149
+ @property
150
+ def is_object_type(self) -> bool:
151
+ return not self.is_input and not self.is_interface
152
+
149
153
  @property
150
154
  def type_params(self) -> List[TypeVar]:
151
155
  type_params: List[TypeVar] = []
@@ -23,7 +23,7 @@ from typing import ( # type: ignore
23
23
  cast,
24
24
  overload,
25
25
  )
26
- from typing_extensions import Annotated, get_args, get_origin
26
+ from typing_extensions import Annotated, TypeGuard, get_args, get_origin
27
27
 
28
28
  ast_unparse = getattr(ast, "unparse", None)
29
29
  # ast.unparse is only available on python 3.9+. For older versions we will
@@ -63,15 +63,20 @@ def get_generic_alias(type_: Type) -> Type:
63
63
  continue
64
64
 
65
65
  attr = getattr(typing, attr_name)
66
- # _GenericAlias overrides all the methods that we can use to know if
67
- # this is a subclass of it. But if it has an "_inst" attribute
68
- # then it for sure is a _GenericAlias
69
- if hasattr(attr, "_inst") and attr.__origin__ is type_:
66
+ if is_generic_alias(attr) and attr.__origin__ is type_:
70
67
  return attr
71
68
 
72
69
  raise AssertionError(f"No GenericAlias available for {type_}") # pragma: no cover
73
70
 
74
71
 
72
+ def is_generic_alias(type_: Any) -> TypeGuard[_GenericAlias]:
73
+ """Returns True if the type is a generic alias."""
74
+ # _GenericAlias overrides all the methods that we can use to know if
75
+ # this is a subclass of it. But if it has an "_inst" attribute
76
+ # then it for sure is a _GenericAlias
77
+ return hasattr(type_, "_inst")
78
+
79
+
75
80
  def is_list(annotation: object) -> bool:
76
81
  """Returns True if annotation is a List"""
77
82
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: strawberry-graphql
3
- Version: 0.232.1
3
+ Version: 0.233.0
4
4
  Summary: A library for creating GraphQL APIs
5
5
  Home-page: https://strawberry.rocks/
6
6
  License: MIT
@@ -50,7 +50,7 @@ strawberry/codegen/query_codegen.py,sha256=hwkn60vJLuktdJV4C5Nhc1U6slPQOKwjKtZE9
50
50
  strawberry/codegen/types.py,sha256=7q3pJAHADYsEyQ47d16txJUYFVpaMR_bs6qZp2_eAjk,3486
51
51
  strawberry/codemods/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
52
  strawberry/codemods/annotated_unions.py,sha256=TStU8ye5J1---P5mNWXBGeQa8m_J7FyPU_MYjzDZ-RU,5910
53
- strawberry/custom_scalar.py,sha256=oST5Lt8jj66ZoIG3Hx8QpI7lo018mJrLTIn06heeTqc,5681
53
+ strawberry/custom_scalar.py,sha256=IHVEmyTrBY0_O1c7d4P7sGiVEuI6prtwaUCzej5Cdgo,5741
54
54
  strawberry/dataloader.py,sha256=0UDtZZhu46fw-wB8IK8wVBpOL0Ueu0QGkagQnxuwZWQ,7681
55
55
  strawberry/directive.py,sha256=TkUAXBRVUnmczjT-Ubg8ctnCg0z1Ei4GAuXD6LMkJ5c,2303
56
56
  strawberry/django/__init__.py,sha256=07cxG0P0UzHQZPPzG1RNw3YaGSICjPbJrJdPFelxJVI,799
@@ -85,7 +85,7 @@ strawberry/exceptions/utils/source_finder.py,sha256=AcuevLgWwOSOR5zBDJbVyXMGRUxs
85
85
  strawberry/experimental/__init__.py,sha256=2HP5XtxL8ZKsPp4EDRAbMCqiP7p2V4Cca278JUGxnt0,102
86
86
  strawberry/experimental/pydantic/__init__.py,sha256=jlsYH1j_9W4ieRpUKgt5zQPERDL7nc1ZBNQ3dAhJs8w,241
87
87
  strawberry/experimental/pydantic/_compat.py,sha256=Qnuxy6d0cq5agd8SBlJWqvCPrH3wzMa3gm5Wtzmh0cM,8147
88
- strawberry/experimental/pydantic/conversion.py,sha256=_YMz4cYCwLUazkT2oCQ4B1gusksnXDHdFm1DldIrU7Q,4213
88
+ strawberry/experimental/pydantic/conversion.py,sha256=nS79s_-nVDvJJgazE84pIgPx2u4g4r-ouOOzRGMuwlU,4220
89
89
  strawberry/experimental/pydantic/conversion_types.py,sha256=VuuBULz2v6cz_N1fa51ayJMA5_bQkqZmxaCumDsTGRM,931
90
90
  strawberry/experimental/pydantic/error_type.py,sha256=iSDNlbsRYZyU5zrg3mzU3ntREUPnU1f2waGmY_kiXLU,4370
91
91
  strawberry/experimental/pydantic/exceptions.py,sha256=Q8Deq3bNkMgc8fwvIYdcfxHSONXVMu-ZB6jcsh1NQYo,1498
@@ -125,16 +125,16 @@ strawberry/fastapi/context.py,sha256=hxLoihS9TM16iyUPiAGQf-0i4wv975CJYHHI6EwOewA
125
125
  strawberry/fastapi/handlers/__init__.py,sha256=TziBHyibYBOGiidjpCkjNThYbVY7K_nt0hnRLVHVh3I,241
126
126
  strawberry/fastapi/handlers/graphql_transport_ws_handler.py,sha256=k8BhP1xQAFc1GnbQoFhi8KQSWwY1x-ngR9qIDVJW_ic,549
127
127
  strawberry/fastapi/handlers/graphql_ws_handler.py,sha256=U84lpd7Lxl2bEnFr9QroswmEaMO5ipLCZTeYRAaZH-g,504
128
- strawberry/fastapi/router.py,sha256=Sh4V3B_sGhDP0Ej3M0V-0t3ijnv-tVBd6LUVaE6Utlw,13279
128
+ strawberry/fastapi/router.py,sha256=14fB2_-cpmo_huxlG1XeDQJADRofQYnR1t7M2Gfpqeg,13311
129
129
  strawberry/federation/__init__.py,sha256=FeUxLiBVuk9TKBmJJi51SeUaI8c80rS8hbl9No-hjII,535
130
130
  strawberry/federation/argument.py,sha256=5qyJYlQGEZd6iXWseQ7dnnejCYj5HyglfK10jOCIJBg,802
131
131
  strawberry/federation/enum.py,sha256=riVfcf2Qe4ERE7SqPqFJ-yaKNG3ve47DniVC0IHZj2A,2969
132
132
  strawberry/federation/field.py,sha256=eEzEyNSrkbwHRsdT27Ti9RucuDI0hPoDT9ohrBCuI8o,6172
133
133
  strawberry/federation/mutation.py,sha256=0lV5HJwgw4HYR_59pwxWqnPs342HwakTNMc98w5Hb-c,43
134
134
  strawberry/federation/object_type.py,sha256=qY4LgXRc0bRXtOeaGruvv8fJDJ1wD73uB7RmFHu0Hrc,9270
135
- strawberry/federation/scalar.py,sha256=_dwlQyiDGQQF-Qz-ACSOT-LikxjXgIVz9i0HWlUjTSc,3799
136
- strawberry/federation/schema.py,sha256=9g7jp6eUTTP3atW81dLMtaqeY0tQB4YGdR8beKZ-JX8,13715
137
- strawberry/federation/schema_directive.py,sha256=V_8ytK_cbVoVRhFle0o9DTQkrP1k-xwCBTaideJOYag,1723
135
+ strawberry/federation/scalar.py,sha256=178cF0DE8jf4TyIJ3ghy1QpHT0HFPfxHwMvS4_xkDQI,3835
136
+ strawberry/federation/schema.py,sha256=auFGlM8gqjKgS4TA3OvtpRw0j1pVtVLNxnalZMQecog,13295
137
+ strawberry/federation/schema_directive.py,sha256=cypvRzcwKOeYFTl80DJeaWUfLA8yHZy6Tcz4qYEwVLM,1739
138
138
  strawberry/federation/schema_directives.py,sha256=Awb-BqICDptYtDNRF3BUNnbNcrsSTDN8AWAwKxVZ3UQ,6139
139
139
  strawberry/federation/types.py,sha256=mM70g1aLgjplOc3SdtuJjy7NAKFLv35Z4BDC4s_j5us,301
140
140
  strawberry/federation/union.py,sha256=QXeh-nhApqFtXa3To9MX_IwvtwErZBhWYnssUK7JB2E,1005
@@ -161,20 +161,20 @@ strawberry/litestar/controller.py,sha256=BCntaDTmQNoBRHINi8TztuF7G4-FiED-KxEPTZ6
161
161
  strawberry/litestar/handlers/graphql_transport_ws_handler.py,sha256=q_erlgzPsxarohRQXGp1yK0mjKyS8vsWntMYEmrQx4s,2008
162
162
  strawberry/litestar/handlers/graphql_ws_handler.py,sha256=vVpjd5rJOldF8aQWEGjmmNd60WE1p6q6hFmB_DtCzDU,2250
163
163
  strawberry/mutation.py,sha256=NROPvHJU1BBxZB7Wj4Okxw4hDIYM59MCpukAGEmSNYA,255
164
- strawberry/object_type.py,sha256=KQhSHqu4DvOLJX3Znr3_hjfRkFCW5fOLTc2yJ48vQgQ,12764
164
+ strawberry/object_type.py,sha256=Npp_sw_uuyoT5WHhTTSOZ6JSc_5TmCgCPVD8a8Z3RS8,12794
165
165
  strawberry/parent.py,sha256=rmedKjN4zdg4KTnNV8DENrzgNYVL67rXpHjHoBofMS4,825
166
166
  strawberry/permission.py,sha256=dcKx4Zlg4ZhcxEDBOSWzz0CUN4WPkcc_kJUVuvLLs6w,5925
167
167
  strawberry/printer/__init__.py,sha256=DmepjmgtkdF5RxK_7yC6qUyRWn56U-9qeZMbkztYB9w,62
168
168
  strawberry/printer/ast_from_value.py,sha256=MFIX2V51d9ocRvD0Njemjk8YIzKh2BB1g2iUcX6a3d8,4946
169
- strawberry/printer/printer.py,sha256=HUUecFETXWgfQtMzxjx9pNOXP3tDevqlU3sG7TC3AD8,17449
169
+ strawberry/printer/printer.py,sha256=FY2x-eC5ZDH6T8DzE8ErM9Rc9r44PNCNi7eY3LBq0PA,17456
170
170
  strawberry/private.py,sha256=Vl1o0YZBgNJe30nrrQyOIycsJd3r1Nyx327NlLZURjc,530
171
171
  strawberry/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
172
172
  strawberry/quart/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
173
173
  strawberry/quart/views.py,sha256=SDUaDX7bPKsv8PziMPb0C3nH6vre-Q3bhzSQp4uPjbY,3404
174
174
  strawberry/relay/__init__.py,sha256=Vi4btvA_g6Cj9Tk_F9GCSegapIf2WqkOWV8y3P0cTCs,553
175
175
  strawberry/relay/exceptions.py,sha256=b7sU2MhHVWJOfq27lvqdFcqBZ5P_JWk41JWRjtP-AOI,3916
176
- strawberry/relay/fields.py,sha256=0A96V4mQzFJwP9g68tM3zKmbPxnfU2Ix6kbMI-x11LQ,15550
177
- strawberry/relay/types.py,sha256=pCFD0UXXofmdTS2wBURjg8KwIfdioMt2j4qNYfk6GqQ,30710
176
+ strawberry/relay/fields.py,sha256=4V8jhPDECx0hPqtc0ZsNxvmhRYMf5whD_686O2-6_Dc,15934
177
+ strawberry/relay/types.py,sha256=_bCYCDKLG_eCcTf66H6JsmQHX-8mEnpplxr82_2oJcI,30718
178
178
  strawberry/relay/utils.py,sha256=STuJ2j-sTPa70O9juJX21nbhK6yhnHdwiAOWBYKOVdo,3160
179
179
  strawberry/resolvers.py,sha256=g7_g3jmXszziGydY1UG6IItf9s6B1lGLUCnwW1kb8U0,224
180
180
  strawberry/sanic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -189,16 +189,16 @@ strawberry/schema/config.py,sha256=XkWwmxEsmecscH29o4qU0iSe-hgwJJ2X0DPBVlka2OE,6
189
189
  strawberry/schema/exceptions.py,sha256=T-DsvBtjx9svkegIm1YrVPGPswpVEpMTFc0_7flLEkM,542
190
190
  strawberry/schema/execute.py,sha256=dwxMrJrR2Qdd1nPGcIS9-Viq7h5qtPfsD6qdujALoMw,11153
191
191
  strawberry/schema/name_converter.py,sha256=UdNyd-QtqF2HsDCQK-nsOcLGxDTj4hJwYFNvMtZnpq4,6533
192
- strawberry/schema/schema.py,sha256=bfQdLmFXR_BQd80IGO8qa0431cQMUDr22XLNnBL7Tu0,14252
193
- strawberry/schema/schema_converter.py,sha256=hxA1PKo8MwurxVC6-CscMnhQSSKyiD8B5jAaiqXc4JM,36605
192
+ strawberry/schema/schema.py,sha256=ooZYWqy_LWQwbrIbvuoxHFPzOG8o3Ybv7nSZf2RlNrA,14276
193
+ strawberry/schema/schema_converter.py,sha256=dszExcSpy1pakPMePp69Yp3Zcj6AG7ReRQ8URG_EkzM,36822
194
194
  strawberry/schema/types/__init__.py,sha256=oHO3COWhL3L1KLYCJNY1XFf5xt2GGtHiMC-UaYbFfnA,68
195
- strawberry/schema/types/base_scalars.py,sha256=Z_BmgwLicNexLipGyw6MmZ7OBnkGJU3ySgaY9SwBWrw,1837
195
+ strawberry/schema/types/base_scalars.py,sha256=NzGQmDtHdCcBeJpRpyeZQ6EgYRpQBTd8fUf1p9cMWlQ,1847
196
196
  strawberry/schema/types/concrete_type.py,sha256=HB30G1hMUuuvjAvfSe6ADS35iI_T_wKO-EprVOWTMSs,746
197
197
  strawberry/schema/types/scalar.py,sha256=SVJ8HiKncCvOw2xwABI5xYaHcC7KkGHG-tx2WDtSoCA,2802
198
198
  strawberry/schema/validation_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
199
199
  strawberry/schema/validation_rules/one_of.py,sha256=hO0Re1fQQWT9zIqo_7BHLM2bdSsmNJDbKia8AUTSXQQ,2588
200
200
  strawberry/schema_codegen/__init__.py,sha256=PcCVXjS0Y5Buxadm07YAZOVunkQ_DmmwsBrgsH1T4ds,24375
201
- strawberry/schema_directive.py,sha256=XGKwcsxRpHXJQ_qXXMi1gEXlZOG22SbDf4Phxf4tbQ0,1967
201
+ strawberry/schema_directive.py,sha256=yDwLBX7soQTAJwDW5YgH8mAnK4Jmnh9yhH76MbQeqX0,1983
202
202
  strawberry/schema_directives.py,sha256=KGKFWCODjm1Ah9qNV_bBwbic7Mld4qLWnWQkev-PG8A,175
203
203
  strawberry/starlite/__init__.py,sha256=v209swT8H9MljVL-npvANhEO1zz3__PSfxb_Ix-NoeE,134
204
204
  strawberry/starlite/controller.py,sha256=moo2HlaJT6w9AijwjHvXi4UibUydaZfA75JMFZVMJPw,12191
@@ -229,7 +229,7 @@ strawberry/types/graphql.py,sha256=3SWZEsa0Zy1eVW6vy75BnB7t9_lJVi6TBV3_1j3RNBs,6
229
229
  strawberry/types/info.py,sha256=b1ZWW_wUop6XrGNcGHKBQeUYjlX-y8u3s2Wm_XhKPYI,3412
230
230
  strawberry/types/nodes.py,sha256=5tTYmxGpVDshbydicHTTBWEiUe8A7p7mdiaSV8Ry80Y,5027
231
231
  strawberry/types/type_resolver.py,sha256=wuAYCbEjdov0IrnTvkFMNtSwb3lruQsbYI11x35ADeU,6542
232
- strawberry/types/types.py,sha256=FWCZxclY47BgPDVtcYqA0kxTIN6DQ1uyjIbfBU9p4Z8,8387
232
+ strawberry/types/types.py,sha256=xCJrLRIUnR43KVfGMGLepU_uDFFfJsebtjy_vELk7O8,8499
233
233
  strawberry/union.py,sha256=bQ3QBOLLugGvN434vHTZRuelgJdblfy8aJMrUpLgG_g,9585
234
234
  strawberry/unset.py,sha256=4zYRN8vUD7lHQLLpulBFqEPfyvzpx8fl7ZDBUyfMqqk,1112
235
235
  strawberry/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -244,9 +244,9 @@ strawberry/utils/inspect.py,sha256=6z-tJpiWWm6E4-O6OUfhu689W9k1uY0m3FDwAfVCiNs,2
244
244
  strawberry/utils/logging.py,sha256=flS7hV0JiIOEdXcrIjda4WyIWix86cpHHFNJL8gl1y4,713
245
245
  strawberry/utils/operation.py,sha256=Um-tBCPl3_bVFN2Ph7o1mnrxfxBes4HFCj6T0x4kZxE,1135
246
246
  strawberry/utils/str_converters.py,sha256=avIgPVLg98vZH9mA2lhzVdyyjqzLsK2NdBw9mJQ02Xk,813
247
- strawberry/utils/typing.py,sha256=K31YP0DftNDBhsk1yhW0BmYoEegU8nWOD26dvkRx2Xo,13717
248
- strawberry_graphql-0.232.1.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
249
- strawberry_graphql-0.232.1.dist-info/METADATA,sha256=zs5gzLUQ06x4a7CAzFkphdMYnkywuMQ3R9K2hQ8lPkE,7821
250
- strawberry_graphql-0.232.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
251
- strawberry_graphql-0.232.1.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
252
- strawberry_graphql-0.232.1.dist-info/RECORD,,
247
+ strawberry/utils/typing.py,sha256=G92wuT2WhEGQrwjek_On2K8l0nyVFtBW3P7I_cfjG-8,13870
248
+ strawberry_graphql-0.233.0.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
249
+ strawberry_graphql-0.233.0.dist-info/METADATA,sha256=sVmRsJs4RGDdmCJjatgqaicCRFhDB1ALTblDfV7uKQs,7821
250
+ strawberry_graphql-0.233.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
251
+ strawberry_graphql-0.233.0.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
252
+ strawberry_graphql-0.233.0.dist-info/RECORD,,