strawberry-graphql 0.277.1__py3-none-any.whl → 0.279.0.dev1754138688__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.
strawberry/__init__.py CHANGED
@@ -4,7 +4,7 @@ Strawberry is a Python library for GraphQL that aims to stay close to the GraphQ
4
4
  specification and allow for a more natural way of defining GraphQL schemas.
5
5
  """
6
6
 
7
- from . import experimental, federation, relay
7
+ from . import experimental, federation, pydantic, relay
8
8
  from .directive import directive, directive_field
9
9
  from .parent import Parent
10
10
  from .permission import BasePermission
@@ -54,6 +54,7 @@ __all__ = [
54
54
  "interface",
55
55
  "lazy",
56
56
  "mutation",
57
+ "pydantic",
57
58
  "relay",
58
59
  "scalar",
59
60
  "schema_directive",
@@ -210,7 +210,9 @@ class GraphQLView(
210
210
  return {"request": request, "response": response} # type: ignore
211
211
 
212
212
  def create_response(
213
- self, response_data: GraphQLHTTPResponse, sub_response: web.Response
213
+ self,
214
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
215
+ sub_response: web.Response,
214
216
  ) -> web.Response:
215
217
  sub_response.text = self.encode_json(response_data)
216
218
  sub_response.content_type = "application/json"
@@ -205,7 +205,9 @@ class GraphQL(
205
205
  return HTMLResponse(self.graphql_ide_html)
206
206
 
207
207
  def create_response(
208
- self, response_data: GraphQLHTTPResponse, sub_response: Response
208
+ self,
209
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
210
+ sub_response: Response,
209
211
  ) -> Response:
210
212
  response = Response(
211
213
  self.encode_json(response_data),
@@ -114,7 +114,9 @@ class GraphQLView(
114
114
  return {"request": request, "response": response} # type: ignore
115
115
 
116
116
  def create_response(
117
- self, response_data: GraphQLHTTPResponse, sub_response: TemporalResponse
117
+ self,
118
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
119
+ sub_response: TemporalResponse,
118
120
  ) -> Response:
119
121
  status_code = 200
120
122
 
@@ -5,13 +5,7 @@ import json
5
5
  import warnings
6
6
  from functools import cached_property
7
7
  from io import BytesIO
8
- from typing import (
9
- TYPE_CHECKING,
10
- Any,
11
- Callable,
12
- Optional,
13
- Union,
14
- )
8
+ from typing import TYPE_CHECKING, Any, Callable, Optional, Union
15
9
  from typing_extensions import TypeGuard, assert_never
16
10
  from urllib.parse import parse_qs
17
11
 
@@ -186,7 +180,9 @@ class BaseGraphQLHTTPConsumer(ChannelsConsumer, AsyncHttpConsumer):
186
180
  super().__init__(**kwargs)
187
181
 
188
182
  def create_response(
189
- self, response_data: GraphQLHTTPResponse, sub_response: TemporalResponse
183
+ self,
184
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
185
+ sub_response: TemporalResponse,
190
186
  ) -> ChannelsResponse:
191
187
  return ChannelsResponse(
192
188
  content=json.dumps(response_data).encode(),
@@ -164,7 +164,9 @@ class GraphQLWSConsumer(
164
164
  raise NotImplementedError
165
165
 
166
166
  def create_response(
167
- self, response_data: GraphQLHTTPResponse, sub_response: GraphQLWSConsumer
167
+ self,
168
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
169
+ sub_response: GraphQLWSConsumer,
168
170
  ) -> GraphQLWSConsumer:
169
171
  raise NotImplementedError
170
172
 
@@ -163,7 +163,9 @@ class BaseView:
163
163
  super().__init__(**kwargs)
164
164
 
165
165
  def create_response(
166
- self, response_data: GraphQLHTTPResponse, sub_response: HttpResponse
166
+ self,
167
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
168
+ sub_response: HttpResponse,
167
169
  ) -> HttpResponseBase:
168
170
  data = self.encode_json(response_data)
169
171
 
@@ -8,7 +8,6 @@ from uuid import UUID
8
8
  import pydantic
9
9
  from pydantic import BaseModel
10
10
  from pydantic.version import VERSION as PYDANTIC_VERSION
11
-
12
11
  from strawberry.experimental.pydantic.exceptions import UnsupportedTypeError
13
12
 
14
13
  if TYPE_CHECKING:
@@ -12,7 +12,6 @@ from typing import (
12
12
  )
13
13
 
14
14
  from pydantic import BaseModel
15
-
16
15
  from strawberry.experimental.pydantic._compat import (
17
16
  CompatModelField,
18
17
  PydanticCompat,
@@ -2,7 +2,6 @@ import builtins
2
2
  from typing import Annotated, Any, Union
3
3
 
4
4
  from pydantic import BaseModel
5
-
6
5
  from strawberry.experimental.pydantic._compat import (
7
6
  PydanticCompat,
8
7
  get_args,
@@ -10,7 +10,6 @@ from typing import (
10
10
  )
11
11
 
12
12
  from pydantic import BaseModel
13
-
14
13
  from strawberry.experimental.pydantic._compat import (
15
14
  CompatModelField,
16
15
  PydanticCompat,
@@ -276,7 +276,9 @@ class GraphQLRouter(
276
276
  return self.temporal_response
277
277
 
278
278
  def create_response(
279
- self, response_data: GraphQLHTTPResponse, sub_response: Response
279
+ self,
280
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
281
+ sub_response: Response,
280
282
  ) -> Response:
281
283
  response = Response(
282
284
  self.encode_json(response_data),
strawberry/flask/views.py CHANGED
@@ -91,7 +91,9 @@ class BaseGraphQLView:
91
91
  self.graphql_ide = graphql_ide
92
92
 
93
93
  def create_response(
94
- self, response_data: GraphQLHTTPResponse, sub_response: Response
94
+ self,
95
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
96
+ sub_response: Response,
95
97
  ) -> Response:
96
98
  sub_response.set_data(self.encode_json(response_data)) # type: ignore
97
99
 
@@ -8,12 +8,13 @@ from typing import (
8
8
  Any,
9
9
  Callable,
10
10
  Generic,
11
+ Literal,
11
12
  Optional,
12
13
  Union,
13
14
  cast,
14
15
  overload,
15
16
  )
16
- from typing_extensions import Literal, TypeGuard
17
+ from typing_extensions import TypeGuard
17
18
 
18
19
  from graphql import GraphQLError
19
20
 
@@ -153,7 +154,9 @@ class AsyncBaseHTTPView(
153
154
 
154
155
  @abc.abstractmethod
155
156
  def create_response(
156
- self, response_data: GraphQLHTTPResponse, sub_response: SubResponse
157
+ self,
158
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
159
+ sub_response: SubResponse,
157
160
  ) -> Response: ...
158
161
 
159
162
  @abc.abstractmethod
@@ -184,8 +187,12 @@ class AsyncBaseHTTPView(
184
187
  ) -> WebSocketResponse: ...
185
188
 
186
189
  async def execute_operation(
187
- self, request: Request, context: Context, root_value: Optional[RootValue]
188
- ) -> Union[ExecutionResult, SubscriptionExecutionResult]:
190
+ self,
191
+ request: Request,
192
+ context: Context,
193
+ root_value: Optional[RootValue],
194
+ sub_response: SubResponse,
195
+ ) -> Union[ExecutionResult, list[ExecutionResult], SubscriptionExecutionResult]:
189
196
  request_adapter = self.request_adapter_class(request)
190
197
 
191
198
  try:
@@ -201,6 +208,22 @@ class AsyncBaseHTTPView(
201
208
  if not self.allow_queries_via_get and request_adapter.method == "GET":
202
209
  allowed_operation_types = allowed_operation_types - {OperationType.QUERY}
203
210
 
211
+ if isinstance(request_data, list):
212
+ # batch GraphQL requests
213
+ return await asyncio.gather(
214
+ *[
215
+ self.execute_single(
216
+ request=request,
217
+ request_adapter=request_adapter,
218
+ sub_response=sub_response,
219
+ context=context,
220
+ root_value=root_value,
221
+ request_data=data,
222
+ )
223
+ for data in request_data
224
+ ]
225
+ )
226
+
204
227
  if request_data.protocol == "multipart-subscription":
205
228
  return await self.schema.subscribe(
206
229
  request_data.query, # type: ignore
@@ -211,16 +234,50 @@ class AsyncBaseHTTPView(
211
234
  operation_extensions=request_data.extensions,
212
235
  )
213
236
 
214
- return await self.schema.execute(
215
- request_data.query,
237
+ return await self.execute_single(
238
+ request=request,
239
+ request_adapter=request_adapter,
240
+ sub_response=sub_response,
241
+ context=context,
216
242
  root_value=root_value,
217
- variable_values=request_data.variables,
218
- context_value=context,
219
- operation_name=request_data.operation_name,
220
- allowed_operation_types=allowed_operation_types,
221
- operation_extensions=request_data.extensions,
243
+ request_data=request_data,
222
244
  )
223
245
 
246
+ async def execute_single(
247
+ self,
248
+ request: Request,
249
+ request_adapter: AsyncHTTPRequestAdapter,
250
+ sub_response: SubResponse,
251
+ context: Context,
252
+ root_value: Optional[RootValue],
253
+ request_data: GraphQLRequestData,
254
+ ) -> ExecutionResult:
255
+ allowed_operation_types = OperationType.from_http(request_adapter.method)
256
+
257
+ if not self.allow_queries_via_get and request_adapter.method == "GET":
258
+ allowed_operation_types = allowed_operation_types - {OperationType.QUERY}
259
+
260
+ try:
261
+ result = await self.schema.execute(
262
+ request_data.query,
263
+ root_value=root_value,
264
+ variable_values=request_data.variables,
265
+ context_value=context,
266
+ operation_name=request_data.operation_name,
267
+ allowed_operation_types=allowed_operation_types,
268
+ operation_extensions=request_data.extensions,
269
+ )
270
+ except CannotGetOperationTypeError as e:
271
+ raise HTTPException(400, e.as_http_error_reason()) from e
272
+ except InvalidOperationTypeError as e:
273
+ raise HTTPException(
274
+ 400, e.as_http_error_reason(request_adapter.method)
275
+ ) from e
276
+ except MissingQueryError as e:
277
+ raise HTTPException(400, "No GraphQL query found in the request") from e
278
+
279
+ return result
280
+
224
281
  async def parse_multipart(self, request: AsyncHTTPRequestAdapter) -> dict[str, str]:
225
282
  try:
226
283
  form_data = await request.get_form_data()
@@ -330,18 +387,12 @@ class AsyncBaseHTTPView(
330
387
  return await self.render_graphql_ide(request)
331
388
  raise HTTPException(404, "Not Found")
332
389
 
333
- try:
334
- result = await self.execute_operation(
335
- request=request, context=context, root_value=root_value
336
- )
337
- except CannotGetOperationTypeError as e:
338
- raise HTTPException(400, e.as_http_error_reason()) from e
339
- except InvalidOperationTypeError as e:
340
- raise HTTPException(
341
- 400, e.as_http_error_reason(request_adapter.method)
342
- ) from e
343
- except MissingQueryError as e:
344
- raise HTTPException(400, "No GraphQL query found in the request") from e
390
+ result = await self.execute_operation(
391
+ request=request,
392
+ context=context,
393
+ root_value=root_value,
394
+ sub_response=sub_response,
395
+ )
345
396
 
346
397
  if isinstance(result, SubscriptionExecutionResult):
347
398
  stream = self._get_stream(request, result)
@@ -425,10 +476,22 @@ class AsyncBaseHTTPView(
425
476
  },
426
477
  )
427
478
 
428
- response_data = await self.process_result(request=request, result=result)
479
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]]
480
+
481
+ if isinstance(result, list):
482
+ response_data = []
483
+ for execution_result in result:
484
+ processed_result = await self.process_result(
485
+ request=request, result=execution_result
486
+ )
487
+ if execution_result.errors:
488
+ self._handle_errors(execution_result.errors, processed_result)
489
+ response_data.append(processed_result)
490
+ else:
491
+ response_data = await self.process_result(request=request, result=result)
429
492
 
430
- if result.errors:
431
- self._handle_errors(result.errors, response_data)
493
+ if result.errors:
494
+ self._handle_errors(result.errors, response_data)
432
495
 
433
496
  return self.create_response(
434
497
  response_data=response_data, sub_response=sub_response
@@ -584,15 +647,16 @@ class AsyncBaseHTTPView(
584
647
 
585
648
  async def parse_http_body(
586
649
  self, request: AsyncHTTPRequestAdapter
587
- ) -> GraphQLRequestData:
650
+ ) -> Union[GraphQLRequestData, list[GraphQLRequestData]]:
588
651
  headers = {key.lower(): value for key, value in request.headers.items()}
589
652
  content_type, _ = parse_content_type(request.content_type or "")
590
653
  accept = headers.get("accept", "")
591
654
 
592
- protocol: Literal["http", "multipart-subscription"] = "http"
593
-
594
- if self._is_multipart_subscriptions(*parse_content_type(accept)):
595
- protocol = "multipart-subscription"
655
+ protocol: Literal["http", "multipart-subscription"] = (
656
+ "multipart-subscription"
657
+ if self._is_multipart_subscriptions(*parse_content_type(accept))
658
+ else "http"
659
+ )
596
660
 
597
661
  if request.method == "GET":
598
662
  data = self.parse_query_params(request.query_params)
@@ -603,6 +667,19 @@ class AsyncBaseHTTPView(
603
667
  else:
604
668
  raise HTTPException(400, "Unsupported content type")
605
669
 
670
+ if isinstance(data, list):
671
+ self._validate_batch_request(data, protocol=protocol)
672
+ return [
673
+ GraphQLRequestData(
674
+ query=item.get("query"),
675
+ variables=item.get("variables"),
676
+ operation_name=item.get("operationName"),
677
+ extensions=item.get("extensions"),
678
+ protocol=protocol,
679
+ )
680
+ for item in data
681
+ ]
682
+
606
683
  query = data.get("query")
607
684
  if not isinstance(query, (str, type(None))):
608
685
  raise HTTPException(
strawberry/http/base.py CHANGED
@@ -3,8 +3,10 @@ from collections.abc import Mapping
3
3
  from typing import Any, Generic, Optional, Union
4
4
  from typing_extensions import Protocol
5
5
 
6
+ from strawberry.http import GraphQLRequestData
6
7
  from strawberry.http.ides import GraphQL_IDE, get_graphql_ide_html
7
8
  from strawberry.http.types import HTTPMethod, QueryParams
9
+ from strawberry.schema.base import BaseSchema
8
10
 
9
11
  from .exceptions import HTTPException
10
12
  from .typevars import Request
@@ -24,6 +26,7 @@ class BaseRequestProtocol(Protocol):
24
26
  class BaseView(Generic[Request]):
25
27
  graphql_ide: Optional[GraphQL_IDE]
26
28
  multipart_uploads_enabled: bool = False
29
+ schema: BaseSchema
27
30
 
28
31
  def should_render_graphql_ide(self, request: BaseRequestProtocol) -> bool:
29
32
  return (
@@ -82,5 +85,19 @@ class BaseView(Generic[Request]):
82
85
 
83
86
  return params.get("subscriptionspec", "").startswith("1.0")
84
87
 
88
+ def _validate_batch_request(
89
+ self, request_data: list[GraphQLRequestData], protocol: str
90
+ ) -> None:
91
+ if self.schema.config.batching_config is None:
92
+ raise HTTPException(400, "Batching is not enabled")
93
+
94
+ if protocol == "multipart-subscription":
95
+ raise HTTPException(
96
+ 400, "Batching is not supported for multipart subscriptions"
97
+ )
98
+
99
+ if len(request_data) > self.schema.config.batching_config["max_operations"]:
100
+ raise HTTPException(400, "Too many operations")
101
+
85
102
 
86
103
  __all__ = ["BaseView"]
@@ -5,6 +5,7 @@ from typing import (
5
5
  Any,
6
6
  Callable,
7
7
  Generic,
8
+ Literal,
8
9
  Optional,
9
10
  Union,
10
11
  )
@@ -92,15 +93,21 @@ class SyncBaseHTTPView(
92
93
 
93
94
  @abc.abstractmethod
94
95
  def create_response(
95
- self, response_data: GraphQLHTTPResponse, sub_response: SubResponse
96
+ self,
97
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
98
+ sub_response: SubResponse,
96
99
  ) -> Response: ...
97
100
 
98
101
  @abc.abstractmethod
99
102
  def render_graphql_ide(self, request: Request) -> Response: ...
100
103
 
101
104
  def execute_operation(
102
- self, request: Request, context: Context, root_value: Optional[RootValue]
103
- ) -> ExecutionResult:
105
+ self,
106
+ request: Request,
107
+ context: Context,
108
+ root_value: Optional[RootValue],
109
+ sub_response: SubResponse,
110
+ ) -> Union[ExecutionResult, list[ExecutionResult]]:
104
111
  request_adapter = self.request_adapter_class(request)
105
112
 
106
113
  try:
@@ -116,16 +123,64 @@ class SyncBaseHTTPView(
116
123
  if not self.allow_queries_via_get and request_adapter.method == "GET":
117
124
  allowed_operation_types = allowed_operation_types - {OperationType.QUERY}
118
125
 
119
- return self.schema.execute_sync(
120
- request_data.query,
126
+ if isinstance(request_data, list):
127
+ # batch GraphQL requests
128
+ return [
129
+ self.execute_single(
130
+ request=request,
131
+ request_adapter=request_adapter,
132
+ sub_response=sub_response,
133
+ context=context,
134
+ root_value=root_value,
135
+ request_data=data,
136
+ )
137
+ for data in request_data
138
+ ]
139
+
140
+ return self.execute_single(
141
+ request=request,
142
+ request_adapter=request_adapter,
143
+ sub_response=sub_response,
144
+ context=context,
121
145
  root_value=root_value,
122
- variable_values=request_data.variables,
123
- context_value=context,
124
- operation_name=request_data.operation_name,
125
- allowed_operation_types=allowed_operation_types,
126
- operation_extensions=request_data.extensions,
146
+ request_data=request_data,
127
147
  )
128
148
 
149
+ def execute_single(
150
+ self,
151
+ request: Request,
152
+ request_adapter: SyncHTTPRequestAdapter,
153
+ sub_response: SubResponse,
154
+ context: Context,
155
+ root_value: Optional[RootValue],
156
+ request_data: GraphQLRequestData,
157
+ ) -> ExecutionResult:
158
+ allowed_operation_types = OperationType.from_http(request_adapter.method)
159
+
160
+ if not self.allow_queries_via_get and request_adapter.method == "GET":
161
+ allowed_operation_types = allowed_operation_types - {OperationType.QUERY}
162
+
163
+ try:
164
+ result = self.schema.execute_sync(
165
+ request_data.query,
166
+ root_value=root_value,
167
+ variable_values=request_data.variables,
168
+ context_value=context,
169
+ operation_name=request_data.operation_name,
170
+ allowed_operation_types=allowed_operation_types,
171
+ operation_extensions=request_data.extensions,
172
+ )
173
+ except CannotGetOperationTypeError as e:
174
+ raise HTTPException(400, e.as_http_error_reason()) from e
175
+ except InvalidOperationTypeError as e:
176
+ raise HTTPException(
177
+ 400, e.as_http_error_reason(request_adapter.method)
178
+ ) from e
179
+ except MissingQueryError as e:
180
+ raise HTTPException(400, "No GraphQL query found in the request") from e
181
+
182
+ return result
183
+
129
184
  def parse_multipart(self, request: SyncHTTPRequestAdapter) -> dict[str, str]:
130
185
  operations = self.parse_json(request.post_data.get("operations", "{}"))
131
186
  files_map = self.parse_json(request.post_data.get("map", "{}"))
@@ -135,8 +190,18 @@ class SyncBaseHTTPView(
135
190
  except KeyError as e:
136
191
  raise HTTPException(400, "File(s) missing in form data") from e
137
192
 
138
- def parse_http_body(self, request: SyncHTTPRequestAdapter) -> GraphQLRequestData:
193
+ def parse_http_body(
194
+ self, request: SyncHTTPRequestAdapter
195
+ ) -> Union[GraphQLRequestData, list[GraphQLRequestData]]:
196
+ headers = {key.lower(): value for key, value in request.headers.items()}
139
197
  content_type, params = parse_content_type(request.content_type or "")
198
+ accept = headers.get("accept", "")
199
+
200
+ protocol: Literal["http", "multipart-subscription"] = (
201
+ "multipart-subscription"
202
+ if self._is_multipart_subscriptions(*parse_content_type(accept))
203
+ else "http"
204
+ )
140
205
 
141
206
  if request.method == "GET":
142
207
  data = self.parse_query_params(request.query_params)
@@ -152,6 +217,18 @@ class SyncBaseHTTPView(
152
217
  else:
153
218
  raise HTTPException(400, "Unsupported content type")
154
219
 
220
+ if isinstance(data, list):
221
+ self._validate_batch_request(data, protocol=protocol)
222
+ return [
223
+ GraphQLRequestData(
224
+ query=item.get("query"),
225
+ variables=item.get("variables"),
226
+ operation_name=item.get("operationName"),
227
+ extensions=item.get("extensions"),
228
+ )
229
+ for item in data
230
+ ]
231
+
155
232
  query = data.get("query")
156
233
  if not isinstance(query, (str, type(None))):
157
234
  raise HTTPException(
@@ -209,25 +286,29 @@ class SyncBaseHTTPView(
209
286
  )
210
287
  root_value = self.get_root_value(request) if root_value is UNSET else root_value
211
288
 
212
- try:
213
- result = self.execute_operation(
214
- request=request,
215
- context=context,
216
- root_value=root_value,
217
- )
218
- except CannotGetOperationTypeError as e:
219
- raise HTTPException(400, e.as_http_error_reason()) from e
220
- except InvalidOperationTypeError as e:
221
- raise HTTPException(
222
- 400, e.as_http_error_reason(request_adapter.method)
223
- ) from e
224
- except MissingQueryError as e:
225
- raise HTTPException(400, "No GraphQL query found in the request") from e
289
+ result = self.execute_operation(
290
+ request=request,
291
+ context=context,
292
+ root_value=root_value,
293
+ sub_response=sub_response,
294
+ )
226
295
 
227
- response_data = self.process_result(request=request, result=result)
296
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]]
297
+
298
+ if isinstance(result, list):
299
+ response_data = []
300
+ for execution_result in result:
301
+ processed_result = self.process_result(
302
+ request=request, result=execution_result
303
+ )
304
+ if execution_result.errors:
305
+ self._handle_errors(execution_result.errors, processed_result)
306
+ response_data.append(processed_result)
307
+ else:
308
+ response_data = self.process_result(request=request, result=result)
228
309
 
229
- if result.errors:
230
- self._handle_errors(result.errors, response_data)
310
+ if result.errors:
311
+ self._handle_errors(result.errors, response_data)
231
312
 
232
313
  return self.create_response(
233
314
  response_data=response_data, sub_response=sub_response
@@ -302,7 +302,9 @@ class GraphQLController(
302
302
  return Response(self.graphql_ide_html, media_type=MediaType.HTML)
303
303
 
304
304
  def create_response(
305
- self, response_data: GraphQLHTTPResponse, sub_response: Response[bytes]
305
+ self,
306
+ response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
307
+ sub_response: Response[bytes],
306
308
  ) -> Response[bytes]:
307
309
  response = Response(
308
310
  self.encode_json(response_data).encode(),
@@ -0,0 +1,21 @@
1
+ """Strawberry Pydantic integration.
2
+
3
+ This module provides first-class support for Pydantic models in Strawberry GraphQL.
4
+ You can directly decorate Pydantic BaseModel classes to create GraphQL types.
5
+
6
+ Example:
7
+ @strawberry.pydantic.type
8
+ class User(BaseModel):
9
+ name: str
10
+ age: int
11
+ """
12
+
13
+ from .object_type import input as input_decorator
14
+ from .object_type import interface
15
+ from .object_type import type as type_decorator
16
+
17
+ # Re-export with proper names
18
+ input = input_decorator
19
+ type = type_decorator
20
+
21
+ __all__ = ["input", "interface", "type"]