strawberry-graphql 0.224.0.dev1711748192__py3-none-any.whl → 0.224.2__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.
@@ -205,15 +205,24 @@ class PydanticV1Compat:
205
205
 
206
206
  def get_basic_type(self, type_: Any) -> Type[Any]:
207
207
  if IS_PYDANTIC_V1:
208
- # only pydantic v1 has these
209
- if lenient_issubclass(type_, pydantic.ConstrainedInt):
210
- return int
211
- if lenient_issubclass(type_, pydantic.ConstrainedFloat):
212
- return float
213
- if lenient_issubclass(type_, pydantic.ConstrainedStr):
214
- return str
215
- if lenient_issubclass(type_, pydantic.ConstrainedList):
216
- return List[self.get_basic_type(type_.item_type)] # type: ignore
208
+ ConstrainedInt = pydantic.ConstrainedInt
209
+ ConstrainedFloat = pydantic.ConstrainedFloat
210
+ ConstrainedStr = pydantic.ConstrainedStr
211
+ ConstrainedList = pydantic.ConstrainedList
212
+ else:
213
+ ConstrainedInt = pydantic.v1.ConstrainedInt
214
+ ConstrainedFloat = pydantic.v1.ConstrainedFloat
215
+ ConstrainedStr = pydantic.v1.ConstrainedStr
216
+ ConstrainedList = pydantic.v1.ConstrainedList
217
+
218
+ if lenient_issubclass(type_, ConstrainedInt):
219
+ return int
220
+ if lenient_issubclass(type_, ConstrainedFloat):
221
+ return float
222
+ if lenient_issubclass(type_, ConstrainedStr):
223
+ return str
224
+ if lenient_issubclass(type_, ConstrainedList):
225
+ return List[self.get_basic_type(type_.item_type)] # type: ignore
217
226
 
218
227
  if type_ in self.fields_map:
219
228
  type_ = self.fields_map[type_]
@@ -2,14 +2,15 @@ from __future__ import annotations
2
2
 
3
3
  import contextlib
4
4
  import inspect
5
+ import types
5
6
  import warnings
6
7
  from asyncio import iscoroutinefunction
7
8
  from typing import (
8
9
  TYPE_CHECKING,
9
10
  Any,
10
- AsyncIterator,
11
+ AsyncContextManager,
11
12
  Callable,
12
- Iterator,
13
+ ContextManager,
13
14
  List,
14
15
  NamedTuple,
15
16
  Optional,
@@ -28,12 +29,18 @@ if TYPE_CHECKING:
28
29
 
29
30
  class WrappedHook(NamedTuple):
30
31
  extension: SchemaExtension
31
- initialized_hook: Union[AsyncIterator[None], Iterator[None]]
32
+ hook: Callable[..., Union[AsyncContextManager[None], ContextManager[None]]]
32
33
  is_async: bool
33
34
 
34
35
 
35
36
  class ExtensionContextManagerBase:
36
- __slots__ = ("hooks", "deprecation_message", "default_hook")
37
+ __slots__ = (
38
+ "hooks",
39
+ "deprecation_message",
40
+ "default_hook",
41
+ "async_exit_stack",
42
+ "exit_stack",
43
+ )
37
44
 
38
45
  def __init_subclass__(cls):
39
46
  cls.DEPRECATION_MESSAGE = (
@@ -73,10 +80,20 @@ class ExtensionContextManagerBase:
73
80
 
74
81
  if hook_fn:
75
82
  if inspect.isgeneratorfunction(hook_fn):
76
- return WrappedHook(extension, hook_fn(extension), False)
83
+ context_manager = contextlib.contextmanager(
84
+ types.MethodType(hook_fn, extension)
85
+ )
86
+ return WrappedHook(
87
+ extension=extension, hook=context_manager, is_async=False
88
+ )
77
89
 
78
90
  if inspect.isasyncgenfunction(hook_fn):
79
- return WrappedHook(extension, hook_fn(extension), True)
91
+ context_manager_async = contextlib.asynccontextmanager(
92
+ types.MethodType(hook_fn, extension)
93
+ )
94
+ return WrappedHook(
95
+ extension=extension, hook=context_manager_async, is_async=True
96
+ )
80
97
 
81
98
  if callable(hook_fn):
82
99
  return self.from_callable(extension, hook_fn)
@@ -96,27 +113,31 @@ class ExtensionContextManagerBase:
96
113
  ) -> WrappedHook:
97
114
  if iscoroutinefunction(on_start) or iscoroutinefunction(on_end):
98
115
 
116
+ @contextlib.asynccontextmanager
99
117
  async def iterator():
100
118
  if on_start:
101
119
  await await_maybe(on_start())
120
+
102
121
  yield
122
+
103
123
  if on_end:
104
124
  await await_maybe(on_end())
105
125
 
106
- hook = iterator()
107
- return WrappedHook(extension, hook, True)
126
+ return WrappedHook(extension=extension, hook=iterator, is_async=True)
108
127
 
109
128
  else:
110
129
 
111
- def iterator():
130
+ @contextlib.contextmanager
131
+ def iterator_async():
112
132
  if on_start:
113
133
  on_start()
134
+
114
135
  yield
136
+
115
137
  if on_end:
116
138
  on_end()
117
139
 
118
- hook = iterator()
119
- return WrappedHook(extension, hook, False)
140
+ return WrappedHook(extension=extension, hook=iterator_async, is_async=False)
120
141
 
121
142
  @staticmethod
122
143
  def from_callable(
@@ -125,59 +146,34 @@ class ExtensionContextManagerBase:
125
146
  ) -> WrappedHook:
126
147
  if iscoroutinefunction(func):
127
148
 
128
- async def async_iterator():
149
+ @contextlib.asynccontextmanager
150
+ async def iterator():
129
151
  await func(extension)
130
152
  yield
131
153
 
132
- hook = async_iterator()
133
- return WrappedHook(extension, hook, True)
154
+ return WrappedHook(extension=extension, hook=iterator, is_async=True)
134
155
  else:
135
156
 
157
+ @contextlib.contextmanager
136
158
  def iterator():
137
159
  func(extension)
138
160
  yield
139
161
 
140
- hook = iterator()
141
- return WrappedHook(extension, hook, False)
162
+ return WrappedHook(extension=extension, hook=iterator, is_async=False)
142
163
 
143
- def run_hooks_sync(self, is_exit: bool = False) -> None:
144
- """Run extensions synchronously."""
145
- ctx = (
146
- contextlib.suppress(StopIteration, StopAsyncIteration)
147
- if is_exit
148
- else contextlib.nullcontext()
149
- )
150
- for hook in self.hooks:
151
- with ctx:
152
- if hook.is_async:
153
- raise RuntimeError(
154
- f"SchemaExtension hook {hook.extension}.{self.HOOK_NAME} "
155
- "failed to complete synchronously."
156
- )
157
- else:
158
- hook.initialized_hook.__next__() # type: ignore[union-attr]
159
-
160
- async def run_hooks_async(self, is_exit: bool = False) -> None:
161
- """Run extensions asynchronously with support for sync lifecycle hooks.
162
-
163
- The ``is_exit`` flag is required as a `StopIteration` cannot be raised from
164
- within a coroutine.
165
- """
166
- ctx = (
167
- contextlib.suppress(StopIteration, StopAsyncIteration)
168
- if is_exit
169
- else contextlib.nullcontext()
170
- )
164
+ def __enter__(self) -> None:
165
+ self.exit_stack = contextlib.ExitStack()
171
166
 
172
- for hook in self.hooks:
173
- with ctx:
174
- if hook.is_async:
175
- await hook.initialized_hook.__anext__() # type: ignore[union-attr]
176
- else:
177
- hook.initialized_hook.__next__() # type: ignore[union-attr]
167
+ self.exit_stack.__enter__()
178
168
 
179
- def __enter__(self):
180
- self.run_hooks_sync()
169
+ for hook in self.hooks:
170
+ if hook.is_async:
171
+ raise RuntimeError(
172
+ f"SchemaExtension hook {hook.extension}.{self.HOOK_NAME} "
173
+ "failed to complete synchronously."
174
+ )
175
+ else:
176
+ self.exit_stack.enter_context(hook.hook()) # type: ignore
181
177
 
182
178
  def __exit__(
183
179
  self,
@@ -185,10 +181,18 @@ class ExtensionContextManagerBase:
185
181
  exc_val: Optional[BaseException],
186
182
  exc_tb: Optional[TracebackType],
187
183
  ):
188
- self.run_hooks_sync(is_exit=True)
184
+ self.exit_stack.__exit__(exc_type, exc_val, exc_tb)
189
185
 
190
- async def __aenter__(self):
191
- await self.run_hooks_async()
186
+ async def __aenter__(self) -> None:
187
+ self.async_exit_stack = contextlib.AsyncExitStack()
188
+
189
+ await self.async_exit_stack.__aenter__()
190
+
191
+ for hook in self.hooks:
192
+ if hook.is_async:
193
+ await self.async_exit_stack.enter_async_context(hook.hook()) # type: ignore
194
+ else:
195
+ self.async_exit_stack.enter_context(hook.hook()) # type: ignore
192
196
 
193
197
  async def __aexit__(
194
198
  self,
@@ -196,7 +200,7 @@ class ExtensionContextManagerBase:
196
200
  exc_val: Optional[BaseException],
197
201
  exc_tb: Optional[TracebackType],
198
202
  ):
199
- await self.run_hooks_async(is_exit=True)
203
+ await self.async_exit_stack.__aexit__(exc_type, exc_val, exc_tb)
200
204
 
201
205
 
202
206
  class OperationContextManager(ExtensionContextManagerBase):
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import dataclasses
4
4
  import time
5
- from datetime import datetime
5
+ from datetime import datetime, timezone
6
6
  from inspect import isawaitable
7
7
  from typing import TYPE_CHECKING, Any, Callable, Dict, Generator, List, Optional
8
8
 
@@ -86,10 +86,10 @@ class ApolloTracingExtension(SchemaExtension):
86
86
 
87
87
  def on_operation(self) -> Generator[None, None, None]:
88
88
  self.start_timestamp = self.now()
89
- self.start_time = datetime.utcnow()
89
+ self.start_time = datetime.now(timezone.utc)
90
90
  yield
91
91
  self.end_timestamp = self.now()
92
- self.end_time = datetime.utcnow()
92
+ self.end_time = datetime.now(timezone.utc)
93
93
 
94
94
  def on_parse(self) -> Generator[None, None, None]:
95
95
  self._start_parsing = self.now()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: strawberry-graphql
3
- Version: 0.224.0.dev1711748192
3
+ Version: 0.224.2
4
4
  Summary: A library for creating GraphQL APIs
5
5
  Home-page: https://strawberry.rocks/
6
6
  License: MIT
@@ -83,7 +83,7 @@ strawberry/exceptions/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
83
83
  strawberry/exceptions/utils/source_finder.py,sha256=AcuevLgWwOSOR5zBDJbVyXMGRUxsTzrr07XUB0UqNiI,20044
84
84
  strawberry/experimental/__init__.py,sha256=2HP5XtxL8ZKsPp4EDRAbMCqiP7p2V4Cca278JUGxnt0,102
85
85
  strawberry/experimental/pydantic/__init__.py,sha256=jlsYH1j_9W4ieRpUKgt5zQPERDL7nc1ZBNQ3dAhJs8w,241
86
- strawberry/experimental/pydantic/_compat.py,sha256=3jVTeyko52HuTt52zueelvFEUFBw5wMbka_fvKBcWgM,7785
86
+ strawberry/experimental/pydantic/_compat.py,sha256=sBWil9Ggf-OqfK35XB-0-rx9MS66QFVEqptPkF3sjC0,8139
87
87
  strawberry/experimental/pydantic/conversion.py,sha256=_YMz4cYCwLUazkT2oCQ4B1gusksnXDHdFm1DldIrU7Q,4213
88
88
  strawberry/experimental/pydantic/conversion_types.py,sha256=psVRmKE5fVcBAUT0Z2vCOLAXHddat2A0jJ-0SB1XDn8,963
89
89
  strawberry/experimental/pydantic/error_type.py,sha256=s8v0weIVM-9c0e3zqySaaa3pGZan7RvKTGuTtXLGPmE,4366
@@ -100,7 +100,7 @@ strawberry/ext/mypy_plugin.py,sha256=0ojGmGM9zorviaQVEC6DCzVQx_4o9uUNKm_rn9qcPxk
100
100
  strawberry/extensions/__init__.py,sha256=IfICBQvMNNrulV-mD4Y3HKLE9yDyHi_UFWxWbck_Urg,1199
101
101
  strawberry/extensions/add_validation_rules.py,sha256=U-_U3aTNGqWd88zbzqedrLGjP1R-Pv1KyF8x_hIOoEw,1358
102
102
  strawberry/extensions/base_extension.py,sha256=IRsssFnsipe2FJyZ3gK6fZPhB4TjUCpGVra7iWU77-8,1992
103
- strawberry/extensions/context.py,sha256=hBCbOEzf3S0V3Q0-xj9CaLKgO-rSVrtjGtl_JoTnvgg,6964
103
+ strawberry/extensions/context.py,sha256=3jH8Uw355xd1QQBw9NKt_426stzRFHCxhmqIYCNUo8I,7069
104
104
  strawberry/extensions/directives.py,sha256=ulS80mDTDE-pM8d9IEk16O84kzjkXM1P4vMcqYp5Q1U,2968
105
105
  strawberry/extensions/disable_validation.py,sha256=eLlZ0SEuvK3HUSvLm4PpdgrtP30ckG25sV3hGd2W-sM,720
106
106
  strawberry/extensions/field_extension.py,sha256=1UXGdrPEz9y1m6OcsZTKTnPD1vMvWph3YOsk6QYtG5k,5643
@@ -112,7 +112,7 @@ strawberry/extensions/pyinstrument.py,sha256=hJZdF48eJ7QY-6rKalnUGNWK2ZrpFayUi1J
112
112
  strawberry/extensions/query_depth_limiter.py,sha256=sl9g2Lv-0SS8uPwS1NDaIL-bB2KQl68z7xrhYO25tR4,9890
113
113
  strawberry/extensions/runner.py,sha256=u_aPiHMjMRgdXGLzJMsxaACJ-K6jUrSrc4kQ7EAj9RI,2688
114
114
  strawberry/extensions/tracing/__init__.py,sha256=16fGa81RLkjFi4wwKNfBWGA5AivVPXnY7sH7EvMXg5M,1388
115
- strawberry/extensions/tracing/apollo.py,sha256=d85NIfUz5Ljz7K28--tCxZmJAb0WVFubMJ7efCZizJA,5775
115
+ strawberry/extensions/tracing/apollo.py,sha256=k95C5VgAYLCc71RygftUJnzIq3gYPJPcZ2-7jSDiPcI,5803
116
116
  strawberry/extensions/tracing/datadog.py,sha256=SOV_1uApEP3H8WGnzIHTBJ685EAJu2gqCc8yCMqsi44,5287
117
117
  strawberry/extensions/tracing/opentelemetry.py,sha256=W0WorzHGM6io5cekh6dRVlMnXo8aZODMoyXCQFL8wEI,7204
118
118
  strawberry/extensions/tracing/sentry.py,sha256=XnZ_mTITPYwazk5dGUOa340dmWA_7uS4hVhpvEDKXEo,4939
@@ -241,8 +241,8 @@ strawberry/utils/logging.py,sha256=flS7hV0JiIOEdXcrIjda4WyIWix86cpHHFNJL8gl1y4,7
241
241
  strawberry/utils/operation.py,sha256=Um-tBCPl3_bVFN2Ph7o1mnrxfxBes4HFCj6T0x4kZxE,1135
242
242
  strawberry/utils/str_converters.py,sha256=avIgPVLg98vZH9mA2lhzVdyyjqzLsK2NdBw9mJQ02Xk,813
243
243
  strawberry/utils/typing.py,sha256=Qxz1LwyVsNGV7LQW1dFsaUbsswj5LHBOdKLMom5eyEA,13491
244
- strawberry_graphql-0.224.0.dev1711748192.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
245
- strawberry_graphql-0.224.0.dev1711748192.dist-info/METADATA,sha256=a6vg4VzUefQlEIvHHNnf8OsntvU58jVqcmsatWhUTDA,7754
246
- strawberry_graphql-0.224.0.dev1711748192.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
247
- strawberry_graphql-0.224.0.dev1711748192.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
248
- strawberry_graphql-0.224.0.dev1711748192.dist-info/RECORD,,
244
+ strawberry_graphql-0.224.2.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
245
+ strawberry_graphql-0.224.2.dist-info/METADATA,sha256=HK0p-p7CbffXGWVDcoe8Ka2NV7bTvd8LaVoYNB3Y0VY,7740
246
+ strawberry_graphql-0.224.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
247
+ strawberry_graphql-0.224.2.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
248
+ strawberry_graphql-0.224.2.dist-info/RECORD,,