strawberry-graphql 0.266.0.dev1744797470__py3-none-any.whl → 0.266.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.
strawberry/__init__.py CHANGED
@@ -11,7 +11,6 @@ from .permission import BasePermission
11
11
  from .scalars import ID
12
12
  from .schema import Schema
13
13
  from .schema_directive import schema_directive
14
- from .streamable import Streamable
15
14
  from .types.arguments import argument
16
15
  from .types.auto import auto
17
16
  from .types.cast import cast
@@ -19,6 +18,7 @@ from .types.enum import enum, enum_value
19
18
  from .types.field import field
20
19
  from .types.info import Info
21
20
  from .types.lazy_type import LazyType, lazy
21
+ from .types.maybe import Maybe, Some
22
22
  from .types.mutation import mutation, subscription
23
23
  from .types.object_type import asdict, input, interface, type # noqa: A004
24
24
  from .types.private import Private
@@ -32,10 +32,11 @@ __all__ = [
32
32
  "BasePermission",
33
33
  "Info",
34
34
  "LazyType",
35
+ "Maybe",
35
36
  "Parent",
36
37
  "Private",
37
38
  "Schema",
38
- "Streamable",
39
+ "Some",
39
40
  "argument",
40
41
  "asdict",
41
42
  "auto",
strawberry/annotation.py CHANGED
@@ -17,9 +17,9 @@ from typing import (
17
17
  )
18
18
  from typing_extensions import Self, get_args, get_origin
19
19
 
20
- from strawberry.streamable import StrawberryStreamable
21
20
  from strawberry.types.base import (
22
21
  StrawberryList,
22
+ StrawberryMaybe,
23
23
  StrawberryObjectDefinition,
24
24
  StrawberryOptional,
25
25
  StrawberryTypeVar,
@@ -29,6 +29,7 @@ from strawberry.types.base import (
29
29
  from strawberry.types.enum import EnumDefinition
30
30
  from strawberry.types.enum import enum as strawberry_enum
31
31
  from strawberry.types.lazy_type import LazyType
32
+ from strawberry.types.maybe import _annotation_is_maybe
32
33
  from strawberry.types.private import is_private
33
34
  from strawberry.types.scalar import ScalarDefinition
34
35
  from strawberry.types.unset import UNSET
@@ -142,10 +143,12 @@ class StrawberryAnnotation:
142
143
 
143
144
  if self._is_lazy_type(evaled_type):
144
145
  return evaled_type
145
- if self._is_streamable(evaled_type, args):
146
- return self.create_list(list[evaled_type])
147
146
  if self._is_list(evaled_type):
148
147
  return self.create_list(evaled_type)
148
+ if type_of := self._get_maybe_type(evaled_type):
149
+ return StrawberryMaybe(
150
+ of_type=type_of,
151
+ )
149
152
 
150
153
  if self._is_graphql_generic(evaled_type):
151
154
  if any(is_type_var(type_) for type_ in get_args(evaled_type)):
@@ -317,8 +320,8 @@ class StrawberryAnnotation:
317
320
  )
318
321
 
319
322
  @classmethod
320
- def _is_streamable(cls, annotation: Any, args: list[Any]) -> bool:
321
- return any(isinstance(arg, StrawberryStreamable) for arg in args)
323
+ def _get_maybe_type(cls, annotation: Any) -> type | None:
324
+ return get_args(annotation)[0] if _annotation_is_maybe(annotation) else None
322
325
 
323
326
  @classmethod
324
327
  def _is_strawberry_type(cls, evaled_type: Any) -> bool:
@@ -20,6 +20,7 @@ if TYPE_CHECKING:
20
20
 
21
21
  def enum_value(
22
22
  value: Any,
23
+ name: Optional[str] = None,
23
24
  deprecation_reason: Optional[str] = None,
24
25
  directives: Iterable[object] = (),
25
26
  inaccessible: bool = False,
@@ -35,7 +36,12 @@ def enum_value(
35
36
  if tags:
36
37
  directives.extend(Tag(name=tag) for tag in tags)
37
38
 
38
- return base_enum_value(value, deprecation_reason, directives)
39
+ return base_enum_value(
40
+ value=value,
41
+ name=name,
42
+ deprecation_reason=deprecation_reason,
43
+ directives=directives,
44
+ )
39
45
 
40
46
 
41
47
  @overload
@@ -1,13 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from typing import Any, Optional
4
+ from typing import TYPE_CHECKING, Any, Optional
5
5
  from typing_extensions import Literal, TypedDict
6
6
 
7
- from strawberry.schema._graphql_core import (
8
- GraphQLIncrementalExecutionResults,
9
- ResultType,
10
- )
7
+ if TYPE_CHECKING:
8
+ from strawberry.types import ExecutionResult
11
9
 
12
10
 
13
11
  class GraphQLHTTPResponse(TypedDict, total=False):
@@ -16,16 +14,13 @@ class GraphQLHTTPResponse(TypedDict, total=False):
16
14
  extensions: Optional[dict[str, object]]
17
15
 
18
16
 
19
- def process_result(result: ResultType) -> GraphQLHTTPResponse:
20
- if isinstance(result, GraphQLIncrementalExecutionResults):
21
- return result
17
+ def process_result(result: ExecutionResult) -> GraphQLHTTPResponse:
18
+ data: GraphQLHTTPResponse = {"data": result.data}
22
19
 
23
- errors, extensions = result.errors, result.extensions
24
- data: GraphQLHTTPResponse = {
25
- "data": result.data,
26
- **({"errors": [err.formatted for err in errors]} if errors else {}),
27
- **({"extensions": extensions} if extensions else {}),
28
- }
20
+ if result.errors:
21
+ data["errors"] = [err.formatted for err in result.errors]
22
+ if result.extensions:
23
+ data["extensions"] = result.extensions
29
24
 
30
25
  return data
31
26
 
@@ -25,9 +25,6 @@ from strawberry.http import (
25
25
  process_result,
26
26
  )
27
27
  from strawberry.http.ides import GraphQL_IDE
28
- from strawberry.schema._graphql_core import (
29
- GraphQLIncrementalExecutionResults,
30
- )
31
28
  from strawberry.schema.base import BaseSchema
32
29
  from strawberry.schema.exceptions import InvalidOperationTypeError
33
30
  from strawberry.subscriptions import GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL
@@ -261,7 +258,7 @@ class AsyncBaseHTTPView(
261
258
  root_value: Optional[RootValue] = UNSET,
262
259
  ) -> WebSocketResponse: ...
263
260
 
264
- async def run( # noqa: PLR0915
261
+ async def run(
265
262
  self,
266
263
  request: Union[Request, WebSocketRequest],
267
264
  context: Optional[Context] = UNSET,
@@ -352,75 +349,6 @@ class AsyncBaseHTTPView(
352
349
  "Content-Type": "multipart/mixed;boundary=graphql;subscriptionSpec=1.0,application/json",
353
350
  },
354
351
  )
355
- if isinstance(result, GraphQLIncrementalExecutionResults):
356
-
357
- async def stream() -> AsyncGenerator[str, None]:
358
- yield "---"
359
-
360
- response = await self.process_result(request, result.initial_result)
361
-
362
- response["hasNext"] = result.initial_result.has_next
363
- response["pending"] = [
364
- p.formatted for p in result.initial_result.pending
365
- ]
366
- response["extensions"] = result.initial_result.extensions
367
-
368
- yield self.encode_multipart_data(response, "-")
369
-
370
- all_pending = result.initial_result.pending
371
-
372
- async for value in result.subsequent_results:
373
- response = {
374
- "hasNext": value.has_next,
375
- "extensions": value.extensions,
376
- }
377
-
378
- if value.pending:
379
- response["pending"] = [p.formatted for p in value.pending]
380
-
381
- if value.completed:
382
- response["completed"] = [p.formatted for p in value.completed]
383
-
384
- if value.incremental:
385
- incremental = []
386
-
387
- all_pending.extend(value.pending)
388
-
389
- for incremental_value in value.incremental:
390
- pending_value = next(
391
- (
392
- v
393
- for v in all_pending
394
- if v.id == incremental_value.id
395
- ),
396
- None,
397
- )
398
-
399
- assert pending_value
400
-
401
- incremental.append(
402
- {
403
- **incremental_value.formatted,
404
- "path": pending_value.path,
405
- "label": pending_value.label,
406
- }
407
- )
408
-
409
- response["incremental"] = incremental
410
-
411
- yield self.encode_multipart_data(response, "-")
412
-
413
- yield "--\r\n"
414
-
415
- return await self.create_streaming_response(
416
- request,
417
- stream,
418
- sub_response,
419
- headers={
420
- "Transfer-Encoding": "chunked",
421
- "Content-Type": 'multipart/mixed; boundary="-"',
422
- },
423
- )
424
352
 
425
353
  response_data = await self.process_result(request=request, result=result)
426
354
 
@@ -432,16 +360,12 @@ class AsyncBaseHTTPView(
432
360
  )
433
361
 
434
362
  def encode_multipart_data(self, data: Any, separator: str) -> str:
435
- encoded_data = self.encode_json(data)
436
-
437
363
  return "".join(
438
364
  [
439
- "\r\n",
440
- "Content-Type: application/json; charset=utf-8\r\n",
441
- "Content-Length: " + str(len(encoded_data)) + "\r\n",
442
- "\r\n",
443
- encoded_data,
444
- f"\r\n--{separator}",
365
+ f"\r\n--{separator}\r\n",
366
+ "Content-Type: application/json\r\n\r\n",
367
+ self.encode_json(data),
368
+ "\n",
445
369
  ]
446
370
  )
447
371
 
@@ -561,9 +561,9 @@ def print_schema_definition(
561
561
  def print_directive(
562
562
  directive: GraphQLDirective, *, schema: BaseSchema
563
563
  ) -> Optional[str]:
564
- strawberry_directive = directive.extensions.get("strawberry-definition")
564
+ strawberry_directive = directive.extensions["strawberry-definition"]
565
565
 
566
- if strawberry_directive is None or (
566
+ if (
567
567
  isinstance(strawberry_directive, StrawberrySchemaDirective)
568
568
  and not strawberry_directive.print_definition
569
569
  ):
@@ -16,7 +16,6 @@ class StrawberryConfig:
16
16
  relay_max_results: int = 100
17
17
  disable_field_suggestions: bool = False
18
18
  info_class: type[Info] = Info
19
- enable_experimental_incremental_execution: bool = False
20
19
 
21
20
  def __post_init__(
22
21
  self,
@@ -29,6 +29,8 @@ from graphql import (
29
29
  parse,
30
30
  validate_schema,
31
31
  )
32
+ from graphql.execution import ExecutionContext as GraphQLExecutionContext
33
+ from graphql.execution import execute, subscribe
32
34
  from graphql.execution.middleware import MiddlewareManager
33
35
  from graphql.type.directives import specified_directives
34
36
  from graphql.validation import validate
@@ -62,15 +64,6 @@ from strawberry.utils.aio import aclosing
62
64
  from strawberry.utils.await_maybe import await_maybe
63
65
 
64
66
  from . import compat
65
- from ._graphql_core import (
66
- GraphQLExecutionContext,
67
- GraphQLIncrementalExecutionResults,
68
- ResultType,
69
- execute,
70
- experimental_execute_incrementally,
71
- incremental_execution_directives,
72
- subscribe,
73
- )
74
67
  from .base import BaseSchema
75
68
  from .config import StrawberryConfig
76
69
  from .exceptions import InvalidOperationTypeError
@@ -99,7 +92,6 @@ OriginSubscriptionResult = Union[
99
92
  AsyncIterator[OriginalExecutionResult],
100
93
  ]
101
94
 
102
-
103
95
  DEFAULT_ALLOWED_OPERATION_TYPES = {
104
96
  OperationType.QUERY,
105
97
  OperationType.MUTATION,
@@ -270,16 +262,11 @@ class Schema(BaseSchema):
270
262
  graphql_types.append(graphql_type)
271
263
 
272
264
  try:
273
- directives = specified_directives + tuple(graphql_directives)
274
-
275
- if self.config.enable_experimental_incremental_execution:
276
- directives = tuple(directives) + tuple(incremental_execution_directives)
277
-
278
265
  self._schema = GraphQLSchema(
279
266
  query=query_type,
280
267
  mutation=mutation_type,
281
268
  subscription=subscription_type if subscription else None,
282
- directives=directives,
269
+ directives=specified_directives + tuple(graphql_directives),
283
270
  types=graphql_types,
284
271
  extensions={
285
272
  GraphQLCoreConverter.DEFINITION_BACKREF: self,
@@ -457,16 +444,12 @@ class Schema(BaseSchema):
457
444
  async def _handle_execution_result(
458
445
  self,
459
446
  context: ExecutionContext,
460
- result: ResultType,
447
+ result: Union[GraphQLExecutionResult, ExecutionResult],
461
448
  extensions_runner: SchemaExtensionsRunner,
462
449
  *,
463
450
  # TODO: can we remove this somehow, see comment in execute
464
451
  skip_process_errors: bool = False,
465
452
  ) -> ExecutionResult:
466
- # TODO: handle this, also, why do we have both GraphQLExecutionResult and ExecutionResult?
467
- if isinstance(result, GraphQLIncrementalExecutionResults):
468
- return result
469
-
470
453
  # Set errors on the context so that it's easier
471
454
  # to access in extensions
472
455
  if result.errors:
@@ -507,17 +490,6 @@ class Schema(BaseSchema):
507
490
  extensions_runner = self.create_extensions_runner(execution_context, extensions)
508
491
  middleware_manager = self._get_middleware_manager(extensions)
509
492
 
510
- execute_function = execute
511
-
512
- if self.config.enable_experimental_incremental_execution:
513
- execute_function = experimental_execute_incrementally
514
-
515
- if execute_function is None:
516
- raise RuntimeError(
517
- "Incremental execution is enabled but experimental_execute_incrementally is not available, "
518
- "please install graphql-core>=3.3.0"
519
- )
520
-
521
493
  try:
522
494
  async with extensions_runner.operation():
523
495
  # Note: In graphql-core the schema would be validated here but in
@@ -536,7 +508,7 @@ class Schema(BaseSchema):
536
508
  async with extensions_runner.executing():
537
509
  if not execution_context.result:
538
510
  result = await await_maybe(
539
- execute_function(
511
+ execute(
540
512
  self._schema,
541
513
  execution_context.graphql_document,
542
514
  root_value=execution_context.root_value,
@@ -552,9 +524,7 @@ class Schema(BaseSchema):
552
524
  result = execution_context.result
553
525
  # Also set errors on the execution_context so that it's easier
554
526
  # to access in extensions
555
-
556
- # TODO: maybe here use the first result from incremental execution if it exists
557
- if isinstance(result, GraphQLExecutionResult) and result.errors:
527
+ if result.errors:
558
528
  execution_context.errors = result.errors
559
529
 
560
530
  # Run the `Schema.process_errors` function here before
@@ -604,16 +574,6 @@ class Schema(BaseSchema):
604
574
  extensions_runner = self.create_extensions_runner(execution_context, extensions)
605
575
  middleware_manager = self._get_middleware_manager(extensions)
606
576
 
607
- execute_function = execute
608
-
609
- if self.config.enable_experimental_incremental_execution:
610
- execute_function = experimental_execute_incrementally
611
-
612
- if execute_function is None:
613
- raise RuntimeError(
614
- "Incremental execution is enabled but experimental_execute_incrementally is not available, "
615
- "please install graphql-core>=3.3.0"
616
- )
617
577
  try:
618
578
  with extensions_runner.operation():
619
579
  # Note: In graphql-core the schema would be validated here but in
@@ -655,7 +615,7 @@ class Schema(BaseSchema):
655
615
 
656
616
  with extensions_runner.executing():
657
617
  if not execution_context.result:
658
- result = execute_function(
618
+ result = execute(
659
619
  self._schema,
660
620
  execution_context.graphql_document,
661
621
  root_value=execution_context.root_value,
@@ -52,6 +52,7 @@ from strawberry.schema.types.scalar import _make_scalar_type
52
52
  from strawberry.types.arguments import StrawberryArgument, convert_arguments
53
53
  from strawberry.types.base import (
54
54
  StrawberryList,
55
+ StrawberryMaybe,
55
56
  StrawberryObjectDefinition,
56
57
  StrawberryOptional,
57
58
  StrawberryType,
@@ -254,7 +255,10 @@ class GraphQLCoreConverter:
254
255
  argument_type = cast(
255
256
  "GraphQLInputType", self.from_maybe_optional(argument.type)
256
257
  )
257
- default_value = Undefined if argument.default is UNSET else argument.default
258
+ if argument.is_maybe:
259
+ default_value: Any = Undefined
260
+ else:
261
+ default_value = Undefined if argument.default is UNSET else argument.default
258
262
 
259
263
  return GraphQLArgument(
260
264
  type_=argument_type,
@@ -419,8 +423,9 @@ class GraphQLCoreConverter:
419
423
  ),
420
424
  )
421
425
  default_value: object
422
-
423
- if field.default_value is UNSET or field.default_value is dataclasses.MISSING:
426
+ if isinstance(field.type, StrawberryMaybe):
427
+ default_value = Undefined
428
+ elif field.default_value is UNSET or field.default_value is dataclasses.MISSING:
424
429
  default_value = Undefined
425
430
  else:
426
431
  default_value = field.default_value
@@ -1,4 +1,4 @@
1
- <!doctype html>
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <title>Strawberry GraphiQL</title>
@@ -61,8 +61,8 @@
61
61
  <link
62
62
  crossorigin
63
63
  rel="stylesheet"
64
- href="https://unpkg.com/graphiql@3.8.3/graphiql.min.css"
65
- integrity="sha384-Mq3vbRBY71jfjQAt/DcjxUIYY33ksal4cgdRt9U/hNPvHBCaT2JfJ/PTRiPKf0aM"
64
+ href="https://unpkg.com/graphiql@3.0.9/graphiql.min.css"
65
+ integrity="sha384-yz3/sqpuplkA7msMo0FE4ekg0xdwdvZ8JX9MVZREsxipqjU4h8IRfmAMRcb1QpUy"
66
66
  />
67
67
 
68
68
  <link
@@ -77,8 +77,8 @@
77
77
  <div id="graphiql" class="graphiql-container">Loading...</div>
78
78
  <script
79
79
  crossorigin
80
- src="https://unpkg.com/graphiql@3.8.3/graphiql.min.js"
81
- integrity="sha384-HbRVEFG0JGJZeAHCJ9Xm2+tpknBQ7QZmNlO/DgZtkZ0aJSypT96YYGRNod99l9Ie"
80
+ src="https://unpkg.com/graphiql@3.0.9/graphiql.min.js"
81
+ integrity="sha384-Mjte+vxCWz1ZYCzszGHiJqJa5eAxiqI4mc3BErq7eDXnt+UGLXSEW7+i0wmfPiji"
82
82
  ></script>
83
83
  <script
84
84
  crossorigin
@@ -17,13 +17,17 @@ from strawberry.exceptions import MultipleStrawberryArgumentsError, UnsupportedT
17
17
  from strawberry.scalars import is_scalar
18
18
  from strawberry.types.base import (
19
19
  StrawberryList,
20
+ StrawberryMaybe,
20
21
  StrawberryOptional,
21
22
  has_object_definition,
22
23
  )
23
24
  from strawberry.types.enum import EnumDefinition
24
25
  from strawberry.types.lazy_type import LazyType, StrawberryLazyReference
26
+ from strawberry.types.maybe import Some
25
27
  from strawberry.types.unset import UNSET as _deprecated_UNSET # noqa: N811
26
- from strawberry.types.unset import _deprecated_is_unset # noqa: F401
28
+ from strawberry.types.unset import (
29
+ _deprecated_is_unset, # noqa: F401
30
+ )
27
31
 
28
32
  if TYPE_CHECKING:
29
33
  from collections.abc import Iterable, Mapping
@@ -135,6 +139,10 @@ class StrawberryArgument:
135
139
 
136
140
  return is_graphql_generic(self.type)
137
141
 
142
+ @property
143
+ def is_maybe(self) -> bool:
144
+ return isinstance(self.type, StrawberryMaybe)
145
+
138
146
 
139
147
  def convert_argument(
140
148
  value: object,
@@ -143,6 +151,10 @@ def convert_argument(
143
151
  config: StrawberryConfig,
144
152
  ) -> object:
145
153
  # TODO: move this somewhere else and make it first class
154
+ if isinstance(type_, StrawberryOptional):
155
+ res = convert_argument(value, type_.of_type, scalar_registry, config)
156
+
157
+ return Some(res) if isinstance(type_, StrawberryMaybe) else res
146
158
 
147
159
  if value is None:
148
160
  return None
@@ -150,9 +162,6 @@ def convert_argument(
150
162
  if value is _deprecated_UNSET:
151
163
  return _deprecated_UNSET
152
164
 
153
- if isinstance(type_, StrawberryOptional):
154
- return convert_argument(value, type_.of_type, scalar_registry, config)
155
-
156
165
  if isinstance(type_, StrawberryList):
157
166
  value_list = cast("Iterable", value)
158
167
  return [
strawberry/types/base.py CHANGED
@@ -152,7 +152,16 @@ class StrawberryContainer(StrawberryType):
152
152
  class StrawberryList(StrawberryContainer): ...
153
153
 
154
154
 
155
- class StrawberryOptional(StrawberryContainer): ...
155
+ class StrawberryOptional(StrawberryContainer):
156
+ def __init__(
157
+ self,
158
+ of_type: Union[StrawberryType, type[WithStrawberryObjectDefinition], type],
159
+ ) -> None:
160
+ super().__init__(of_type)
161
+
162
+
163
+ class StrawberryMaybe(StrawberryOptional):
164
+ pass
156
165
 
157
166
 
158
167
  class StrawberryTypeVar(StrawberryType):
strawberry/types/enum.py CHANGED
@@ -50,6 +50,7 @@ class EnumDefinition(StrawberryType):
50
50
  @dataclasses.dataclass
51
51
  class EnumValueDefinition:
52
52
  value: Any
53
+ graphql_name: Optional[str] = None
53
54
  deprecation_reason: Optional[str] = None
54
55
  directives: Iterable[object] = ()
55
56
  description: Optional[str] = None
@@ -60,6 +61,7 @@ class EnumValueDefinition:
60
61
 
61
62
  def enum_value(
62
63
  value: Any,
64
+ name: Optional[str] = None,
63
65
  deprecation_reason: Optional[str] = None,
64
66
  directives: Iterable[object] = (),
65
67
  description: Optional[str] = None,
@@ -68,6 +70,7 @@ def enum_value(
68
70
 
69
71
  Args:
70
72
  value: The value of the enum member.
73
+ name: The GraphQL name of the enum member.
71
74
  deprecation_reason: The deprecation reason of the enum member,
72
75
  setting this will mark the enum member as deprecated.
73
76
  directives: The directives to attach to the enum member.
@@ -90,6 +93,7 @@ def enum_value(
90
93
  """
91
94
  return EnumValueDefinition(
92
95
  value=value,
96
+ graphql_name=name,
93
97
  deprecation_reason=deprecation_reason,
94
98
  directives=directives,
95
99
  description=description,
@@ -123,12 +127,16 @@ def _process_enum(
123
127
  item_directives = item_value.directives
124
128
  enum_value_description = item_value.description
125
129
  deprecation_reason = item_value.deprecation_reason
126
- item_value = item_value.value
127
130
 
128
131
  # update _value2member_map_ so that doing `MyEnum.MY_VALUE` and
129
132
  # `MyEnum['MY_VALUE']` both work
130
- cls._value2member_map_[item_value] = item
131
- cls._member_map_[item_name]._value_ = item_value
133
+ cls._value2member_map_[item_value.value] = item
134
+ cls._member_map_[item_name]._value_ = item_value.value
135
+
136
+ if item_value.graphql_name:
137
+ item_name = item_value.graphql_name
138
+
139
+ item_value = item_value.value
132
140
 
133
141
  value = EnumValue(
134
142
  item_name,
@@ -0,0 +1,47 @@
1
+ import typing
2
+ from typing import TYPE_CHECKING, Any, Generic, TypeVar, Union
3
+ from typing_extensions import TypeAlias
4
+
5
+ T = TypeVar("T")
6
+
7
+
8
+ class Some(Generic[T]):
9
+ """A special value that can be used to represent an unset value in a field or argument.
10
+
11
+ Similar to `undefined` in JavaScript, this value can be used to differentiate between
12
+ a field that was not set and a field that was set to `None` or `null`.
13
+ """
14
+
15
+ __slots__ = ("value",)
16
+
17
+ def __init__(self, value: T) -> None:
18
+ self.value = value
19
+
20
+ def __repr__(self) -> str:
21
+ return f"Some({self.value!r})"
22
+
23
+ def __eq__(self, other: object) -> bool:
24
+ return self.value == other.value if isinstance(other, Some) else False
25
+
26
+ def __hash__(self) -> int:
27
+ return hash(self.value)
28
+
29
+ def __bool__(self) -> bool:
30
+ return True
31
+
32
+
33
+ if TYPE_CHECKING:
34
+ Maybe: TypeAlias = Union[Some[Union[T, None]], None]
35
+ else:
36
+ # we do this trick so we can inspect that at runtime
37
+ class Maybe(Generic[T]): ...
38
+
39
+
40
+ def _annotation_is_maybe(annotation: Any) -> bool:
41
+ return (orig := typing.get_origin(annotation)) and orig is Maybe
42
+
43
+
44
+ __all__ = [
45
+ "Maybe",
46
+ "Some",
47
+ ]
@@ -20,6 +20,7 @@ from strawberry.exceptions import (
20
20
  ObjectIsNotClassError,
21
21
  )
22
22
  from strawberry.types.base import get_object_definition
23
+ from strawberry.types.maybe import _annotation_is_maybe
23
24
  from strawberry.utils.deprecations import DEPRECATION_MESSAGES, DeprecatedDescriptor
24
25
  from strawberry.utils.str_converters import to_camel_case
25
26
 
@@ -122,6 +123,15 @@ def _wrap_dataclass(cls: builtins.type[T]) -> builtins.type[T]:
122
123
  return dclass
123
124
 
124
125
 
126
+ def _inject_default_for_maybe_annotations(
127
+ cls: builtins.type[T], annotations: dict[str, Any]
128
+ ) -> None:
129
+ """Inject `= None` for fields with `Maybe` annotations and no default value."""
130
+ for name, annotation in annotations.copy().items():
131
+ if _annotation_is_maybe(annotation) and not hasattr(cls, name):
132
+ setattr(cls, name, None)
133
+
134
+
125
135
  def _process_type(
126
136
  cls: T,
127
137
  *,
@@ -286,7 +296,8 @@ def type(
286
296
 
287
297
  if field and isinstance(field, StrawberryField) and field.type_annotation:
288
298
  original_type_annotations[field_name] = field.type_annotation.annotation
289
-
299
+ if is_input:
300
+ _inject_default_for_maybe_annotations(cls, annotations)
290
301
  wrapped = _wrap_dataclass(cls)
291
302
 
292
303
  return _process_type( # type: ignore
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: strawberry-graphql
3
- Version: 0.266.0.dev1744797470
3
+ Version: 0.266.1
4
4
  Summary: A library for creating GraphQL APIs
5
5
  License: MIT
6
6
  Keywords: graphql,api,rest,starlette,async
@@ -1,10 +1,10 @@
1
- strawberry/__init__.py,sha256=HqViVAW5hyZLiG0CvWgLvdBotbbDAimuGgKSzevP-O8,1482
1
+ strawberry/__init__.py,sha256=-K---AYIgHvBVYF_9oovgEPNBbymXH673bntlV9sOeU,1491
2
2
  strawberry/__main__.py,sha256=3U77Eu21mJ-LY27RG-JEnpbh6Z63wGOom4i-EoLtUcY,59
3
3
  strawberry/aiohttp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  strawberry/aiohttp/test/__init__.py,sha256=4xxdUZtIISSOwjrcnmox7AvT4WWjowCm5bUuPdQneMg,71
5
5
  strawberry/aiohttp/test/client.py,sha256=8FKZTnvawxYpgEICOri-34O3wHRHLhRpjH_Ktp2EupQ,1801
6
6
  strawberry/aiohttp/views.py,sha256=AQVBbZTBa127TbQRwoBelTHrVdZnJeGdMYcTfNmoaSc,7887
7
- strawberry/annotation.py,sha256=XjsP7g40_BwxNoBEUtj8Y9g_i_c09d24ux70Lc5tfIg,13440
7
+ strawberry/annotation.py,sha256=iqSXtJ4pTTLDZRPyil0f-yzpcCm8UYRiwvFWkD5LgpQ,13498
8
8
  strawberry/asgi/__init__.py,sha256=psdKl_52LGkxKKbzZlmwNGZ9jz2FLyLSC7fUhys4FqY,8169
9
9
  strawberry/asgi/test/__init__.py,sha256=4xxdUZtIISSOwjrcnmox7AvT4WWjowCm5bUuPdQneMg,71
10
10
  strawberry/asgi/test/client.py,sha256=kp2O5znHWuAB5VVYO8p4XPSTEDDXBSjNz5WHqW0r6GM,1473
@@ -113,7 +113,7 @@ strawberry/fastapi/context.py,sha256=O_cDNppfUJJecM0ZU_RJ-dhdF0o1x39JfYvYg-7uob4
113
113
  strawberry/fastapi/router.py,sha256=cfRGP1SL_QaSNjCk3Zi7YDQte1EsIljvqTDB1J0O4fQ,12018
114
114
  strawberry/federation/__init__.py,sha256=Pw01N0rG9o0NaUxXLMNGeW5oLENeWVx_d8Kuef1ES4s,549
115
115
  strawberry/federation/argument.py,sha256=rs71S1utiNUd4XOLRa9KVtSMA3yqvKJnR_qdJqX6PPM,860
116
- strawberry/federation/enum.py,sha256=MdtblT4Z8_-2L8gUdo0ROnw3aY8RAAtTvyfHbCBBPrA,3033
116
+ strawberry/federation/enum.py,sha256=geyNA00IjUBroBc6EFrTK0n6DGIVyKOeSE_3aqiwUaQ,3151
117
117
  strawberry/federation/field.py,sha256=pcFgl33xgJcunb6TxfOPuzsAQTGbbzjKi41SUUSV3w4,8914
118
118
  strawberry/federation/mutation.py,sha256=5t2E419m4K2W6LoWEOzWgMdL2J0PwHnsffYkpChqqDQ,67
119
119
  strawberry/federation/object_type.py,sha256=tuUn_YqtOcvivVSHrXESSFr2kae79xW_SLUV3oNINdE,9381
@@ -130,8 +130,8 @@ strawberry/file_uploads/scalars.py,sha256=NRDeB7j8aotqIkz9r62ISTf4DrxQxEZYUuHsX5
130
130
  strawberry/file_uploads/utils.py,sha256=-c6TbqUI-Dkb96hWCrZabh6TL2OabBuQNkCarOqgDm4,1181
131
131
  strawberry/flask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
132
  strawberry/flask/views.py,sha256=MCvAsNgTZLU8RvTYKWfnLU2w7Wv1ZZpxW9W3TyTZuPY,6355
133
- strawberry/http/__init__.py,sha256=nvy1c7CGHMJlOE9rSiTl6D7eiqWixC1G6x4evgIEKgk,1275
134
- strawberry/http/async_base_view.py,sha256=hDHVAS9ZVsY0apn109oMX-HLNbMiQinPrp8iYYf6rBQ,19151
133
+ strawberry/http/__init__.py,sha256=BV_JpUwNongW38UzFstM72hDXNUjSxdJm_M96pDFU1c,1122
134
+ strawberry/http/async_base_view.py,sha256=9micSD_KpoB8oBHAPlcTpt44bVABDYScvyfHa3NP4rE,16352
135
135
  strawberry/http/base.py,sha256=Lz-u5SWg2uQp3l5GMKZDPQuJOR42LXHgjV1PZHwiapE,2373
136
136
  strawberry/http/exceptions.py,sha256=9E2dreS1crRoJVUEPuHyx23NcDELDHNzkAOa-rGv-8I,348
137
137
  strawberry/http/ides.py,sha256=WjU0nsMDgr3Bd1ebWkUEkO2d1hk0dI16mLqXyCHqklA,613
@@ -146,7 +146,7 @@ strawberry/parent.py,sha256=wViSVYl5ADuyy2EGaS98by_iT1ep9xTP2od8NB_EIuw,742
146
146
  strawberry/permission.py,sha256=dSRJMjSCmTlXfvfC24kCSrAk0txTjYKTJ5ZVU5IW91Y,7537
147
147
  strawberry/printer/__init__.py,sha256=DmepjmgtkdF5RxK_7yC6qUyRWn56U-9qeZMbkztYB9w,62
148
148
  strawberry/printer/ast_from_value.py,sha256=Tkme60qlykbN2m3dNPNMOe65X-wj6EmcDQwgQv7gUkc,4987
149
- strawberry/printer/printer.py,sha256=b5swhNmgSLkOmyXZGMosIVmtKEmiBtKQTHyJ9HJs2VE,18850
149
+ strawberry/printer/printer.py,sha256=49u3QwttTGvh13HXZtbTnkZzBwL1k5SLf8rXQLiTpl4,18814
150
150
  strawberry/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
151
151
  strawberry/quart/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
152
152
  strawberry/quart/views.py,sha256=Hjm93A9j9fy--DQVhsPQ_PakqYtajyWeuH7wUnSLYoA,4449
@@ -162,14 +162,13 @@ strawberry/sanic/utils.py,sha256=XjUVBFuBWfECBCZbx_YtrjQnFTUyIGTo7aISIeB22Gc,100
162
162
  strawberry/sanic/views.py,sha256=F5ZrKt-R3135evKLfhQuPd1isOexI0Lrzevm_6Te4Eg,7069
163
163
  strawberry/scalars.py,sha256=FcFTbu-yKbBfPCuAfXNa6DbTbEzF3eiQHs5nlt6GJdM,2234
164
164
  strawberry/schema/__init__.py,sha256=u1QCyDVQExUVDA20kyosKPz3TS5HMCN2NrXclhiFAL4,92
165
- strawberry/schema/_graphql_core.py,sha256=XHsNZLkCyiH55jANK4XJIjq6VCMhN_MgZBEFWEYj5Jc,1237
166
165
  strawberry/schema/base.py,sha256=q5UAw6do4Ele5Cf8dNAouiPjNmZoCBNFqh5Vl05caCI,3864
167
166
  strawberry/schema/compat.py,sha256=9qJ0lhYJeaN43ayFgVz708ZMvedBhofiTSw9kpFqmjU,1830
168
- strawberry/schema/config.py,sha256=Nl-CWXlKyzcC0ZHoeJmGMXT5jPieC87NU7OqUltbAIk,984
167
+ strawberry/schema/config.py,sha256=6BpCbNNCuekGgiKEPt2mliMqLH_wIjJmSW0tLbnJwk4,924
169
168
  strawberry/schema/exceptions.py,sha256=rqVNb_oYrKM0dHPgvAemqCG6Um282LPPu4zwQ5cZqs4,584
170
169
  strawberry/schema/name_converter.py,sha256=xFOXEgqldFkxXRkIQvsJN1dPkWbEUaIrTYNOMYSEVwQ,6945
171
- strawberry/schema/schema.py,sha256=Jcdwv8M0HZD7T0T7XkaeI5l2WmqttPFmXMZaRXAyu-Y,36055
172
- strawberry/schema/schema_converter.py,sha256=OkJaYrWKGqcxdhoTeuf0aGqiTnWtDuZwYddY5uBlf8Q,37521
170
+ strawberry/schema/schema.py,sha256=qthZttzb9a0GEcwh7trqBKHmuPXOgQlnceqiCRPj4_s,34566
171
+ strawberry/schema/schema_converter.py,sha256=ZNgpE-cTt0Hqw21yoT-3Fu2xk8SVC3uDq85V9JeKI7Q,37724
173
172
  strawberry/schema/types/__init__.py,sha256=oHO3COWhL3L1KLYCJNY1XFf5xt2GGtHiMC-UaYbFfnA,68
174
173
  strawberry/schema/types/base_scalars.py,sha256=JRUq0WjEkR9dFewstZnqnZKp0uOEipo4UXNF5dzRf4M,1971
175
174
  strawberry/schema/types/concrete_type.py,sha256=axIyFZgdwNv-XYkiqX67464wuFX6Vp0jYATwnBZSUvM,750
@@ -180,9 +179,8 @@ strawberry/schema_codegen/__init__.py,sha256=mN4Qmu5Iakht6nHpRpt9hCs8e--oTPlVtDJ
180
179
  strawberry/schema_directive.py,sha256=CbjdX54EIeWGkJu4SgiLR8mph5_8wyNsgJk2oLoQK_0,2023
181
180
  strawberry/schema_directives.py,sha256=KGKFWCODjm1Ah9qNV_bBwbic7Mld4qLWnWQkev-PG8A,175
182
181
  strawberry/static/apollo-sandbox.html,sha256=2XzkbE0dqsFHqehE-jul9_J9TFOpwA6Ylrlo0Kdx_9w,973
183
- strawberry/static/graphiql.html,sha256=0e3pvTnAet-lNEqA_pgJ8Ak2CdMt34zPKMMMzpAkEVU,4257
182
+ strawberry/static/graphiql.html,sha256=BkiqZlC63f1sHBDs_UpMzcibcNrHKh7K41Sp23yttfo,4257
184
183
  strawberry/static/pathfinder.html,sha256=0DPx9AmJ2C_sJstFXnWOz9k5tVQHeHaK7qdVY4lAlmk,1547
185
- strawberry/streamable.py,sha256=ylfMt5lfX7RRKGi86wWokvIgYQk5jZCvQVc3shK0epk,645
186
184
  strawberry/subscriptions/__init__.py,sha256=1VGmiCzFepqRFyCikagkUoHHdoTG3XYlFu9GafoQMws,170
187
185
  strawberry/subscriptions/protocols/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
188
186
  strawberry/subscriptions/protocols/graphql_transport_ws/__init__.py,sha256=wN6dkMu6WiaIZTE19PGoN9xXpIN_RdDE_q7F7ZgjCxk,138
@@ -197,11 +195,11 @@ strawberry/tools/__init__.py,sha256=pdGpZx8wpq03VfUZJyF9JtYxZhGqzzxCiipsalWxJX4,
197
195
  strawberry/tools/create_type.py,sha256=--DgfZOmXJBKGcVxehNISyvpw1HzwFvRtUUPc0634MA,2056
198
196
  strawberry/tools/merge_types.py,sha256=hUMRRNM28FyPp70jRA3d4svv9WoEBjaNpihBt3DaY0I,1023
199
197
  strawberry/types/__init__.py,sha256=baWEdDkkmCcITOhkg2hNUOenrNV1OYdxGE5qgvIRwwU,351
200
- strawberry/types/arguments.py,sha256=Ny4meiKYtcXpAV0rFKWJXOJK5iQB-zs-23n0w8S8zVc,9458
198
+ strawberry/types/arguments.py,sha256=y-1yQBZ8ua4lcrlas9PKNZE02seHn95TjGAoTCRc5e8,9700
201
199
  strawberry/types/auto.py,sha256=WZ2cQAI8nREUigBzpzFqIKGjJ_C2VqpAPNe8vPjTciM,3007
202
- strawberry/types/base.py,sha256=rx7J9dGUCUCap0lgb5Yyb_WXnB95FZEY6gQcYasiI9w,14907
200
+ strawberry/types/base.py,sha256=tZSqxtrxXa1Y964HS2uakCbCgLyGO9A4WpODiegWzF8,15122
203
201
  strawberry/types/cast.py,sha256=fx86MkLW77GIximBAwUk5vZxSGwDqUA6XicXvz8EXwQ,916
204
- strawberry/types/enum.py,sha256=gy4gZvhprZqXJrjeBtokW-0CUcOl6BUOaI2apOSn2mc,5974
202
+ strawberry/types/enum.py,sha256=IcCz0FLswJtDC_bU8aG1cjreawcqHywAzzVRBZUSAqs,6229
205
203
  strawberry/types/execution.py,sha256=Ylc0lH0nyHyQW509mVqBh2sIN5qpf4cJtt8QhVmWGgI,3749
206
204
  strawberry/types/field.py,sha256=vxb7JvkHfRmDCYsjhDmVnO2lMbtSOteQm3jQUeSFu6g,21605
207
205
  strawberry/types/fields/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -209,9 +207,10 @@ strawberry/types/fields/resolver.py,sha256=iYYVUVpm-JM3AFQHuQFeOooftiQWFw3kg64pq
209
207
  strawberry/types/graphql.py,sha256=gXKzawwKiow7hvoJhq5ApNJOMUCnKmvTiHaKY5CK1Lw,867
210
208
  strawberry/types/info.py,sha256=bPP7XTQQScmskJcmVv36iqLAWpdGmF2nhYjI1pJ-csI,4709
211
209
  strawberry/types/lazy_type.py,sha256=dlP9VcMjZc9sdgriiQGzOZa0TToB6Ee7zpIP8h7TLC0,5079
210
+ strawberry/types/maybe.py,sha256=Zdv4pAJwgUmaFNU8WKlwjk50qwgYEzT90WteURZBzAo,1174
212
211
  strawberry/types/mutation.py,sha256=cg-_O2WWnZ-GSwOIv0toSdxlGeY2lhBBxZ24AifJuSM,11978
213
212
  strawberry/types/nodes.py,sha256=RwZB43OT9BS3Cqjgq4AazqOfyq_y0GD2ysC86EDBv5U,5134
214
- strawberry/types/object_type.py,sha256=CW-detiYjGmk4kHJP-vUK9sBkBuDic4nswDub4zUyvc,15075
213
+ strawberry/types/object_type.py,sha256=SZOzxaS318079G-pr-1PM5iMoTddxdw8KD4cI67IhzI,15579
215
214
  strawberry/types/private.py,sha256=DhJs50XVGtOXlxWZFkRpMxQ5_6oki0-x_WQsV1bGUxk,518
216
215
  strawberry/types/scalar.py,sha256=CM24Ixg4DKxxI1C6hTNGYVitohJibs8BpGtntRZvMXw,6284
217
216
  strawberry/types/type_resolver.py,sha256=fH2ZOK4dAGgu8AMPi-JAXe_kEAbvvw2MCYXqbpx-kTc,6529
@@ -230,8 +229,8 @@ strawberry/utils/logging.py,sha256=U1cseHGquN09YFhFmRkiphfASKCyK0HUZREImPgVb0c,7
230
229
  strawberry/utils/operation.py,sha256=s7ajvLg_q6v2mg47kEMQPjO_J-XluMKTCwo4d47mGvE,1195
231
230
  strawberry/utils/str_converters.py,sha256=-eH1Cl16IO_wrBlsGM-km4IY0IKsjhjnSNGRGOwQjVM,897
232
231
  strawberry/utils/typing.py,sha256=Xmnhwvnw8RIQVIc5D5iI4_9qM4Thpk7tWx8xf-RW_So,13383
233
- strawberry_graphql-0.266.0.dev1744797470.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
234
- strawberry_graphql-0.266.0.dev1744797470.dist-info/METADATA,sha256=qYlyY3P9sps8QGvKZoGGO-8meZWobdRFgqzNCrde3Fc,7693
235
- strawberry_graphql-0.266.0.dev1744797470.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
236
- strawberry_graphql-0.266.0.dev1744797470.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
237
- strawberry_graphql-0.266.0.dev1744797470.dist-info/RECORD,,
232
+ strawberry_graphql-0.266.1.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
233
+ strawberry_graphql-0.266.1.dist-info/METADATA,sha256=_RqVVXjFJ7svPPZ9xGPZHsBg5fjlnPAue2seThG3Tjo,7679
234
+ strawberry_graphql-0.266.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
235
+ strawberry_graphql-0.266.1.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
236
+ strawberry_graphql-0.266.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.2
2
+ Generator: poetry-core 2.1.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,46 +0,0 @@
1
- from typing import Union
2
-
3
- from graphql.execution import ExecutionContext as GraphQLExecutionContext
4
- from graphql.execution import ExecutionResult as GraphQLExecutionResult
5
- from graphql.execution import execute, subscribe
6
-
7
- from strawberry.types import ExecutionResult
8
-
9
- try:
10
- from graphql import (
11
- ExperimentalIncrementalExecutionResults as GraphQLIncrementalExecutionResults,
12
- )
13
- from graphql.execution import experimental_execute_incrementally
14
- from graphql.type.directives import (
15
- GraphQLDeferDirective,
16
- GraphQLStreamDirective,
17
- )
18
-
19
- incremental_execution_directives = (
20
- GraphQLDeferDirective,
21
- GraphQLStreamDirective,
22
- )
23
-
24
- except ImportError:
25
- GraphQLIncrementalExecutionResults = type(None)
26
-
27
- incremental_execution_directives = []
28
- experimental_execute_incrementally = None
29
-
30
-
31
- # TODO: give this a better name, maybe also a better place
32
- ResultType = Union[
33
- GraphQLExecutionResult,
34
- GraphQLIncrementalExecutionResults,
35
- ExecutionResult,
36
- ]
37
-
38
- __all__ = [
39
- "GraphQLExecutionContext",
40
- "GraphQLIncrementalExecutionResults",
41
- "ResultType",
42
- "execute",
43
- "experimental_execute_incrementally",
44
- "incremental_execution_directives",
45
- "subscribe",
46
- ]
strawberry/streamable.py DELETED
@@ -1,36 +0,0 @@
1
- from collections.abc import AsyncGenerator
2
- from typing import Annotated, TypeVar
3
-
4
-
5
- class StrawberryStreamable: ...
6
-
7
-
8
- T = TypeVar("T")
9
-
10
- Streamable = Annotated[AsyncGenerator[T, None], StrawberryStreamable()]
11
- """Represents a list that can be streamed using @stream.
12
-
13
- Example:
14
-
15
- ```python
16
- import strawberry
17
- from dataclasses import dataclass
18
-
19
-
20
- @strawberry.type
21
- class Comment:
22
- id: strawberry.ID
23
- content: str
24
-
25
-
26
- @strawberry.type
27
- class Article:
28
- @strawberry.field
29
- @staticmethod
30
- async def comments() -> strawberry.Streamable[Comment]:
31
- for comment in fetch_comments():
32
- yield comment
33
- ```
34
- """
35
-
36
- __all__ = ["Streamable"]