strawberry-graphql 0.224.1__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.
@@ -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):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: strawberry-graphql
3
- Version: 0.224.1
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
@@ -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
@@ -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.1.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
245
- strawberry_graphql-0.224.1.dist-info/METADATA,sha256=8x-11vR1Vr3D9yG5l3l7_X2Sa4GzvpYXan2Od0XrwcM,7740
246
- strawberry_graphql-0.224.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
247
- strawberry_graphql-0.224.1.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
248
- strawberry_graphql-0.224.1.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,,