strawberry-graphql 0.183.3__py3-none-any.whl → 0.183.4__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.
@@ -1,5 +1,4 @@
1
1
  import ast
2
- import re
3
2
  import sys
4
3
  import typing
5
4
  from functools import lru_cache
@@ -12,6 +11,7 @@ from typing import ( # type: ignore
12
11
  Dict,
13
12
  ForwardRef,
14
13
  Generic,
14
+ List,
15
15
  Optional,
16
16
  Tuple,
17
17
  Type,
@@ -222,9 +222,66 @@ def _ast_replace_union_operation(
222
222
  return expr
223
223
 
224
224
 
225
- _annotated_re = re.compile(
226
- r"(Annotated\[)(?P<type>\w*),(?P<args>.*)(\])",
227
- )
225
+ def _get_namespace_from_ast(
226
+ expr: Union[ast.Expr, ast.expr],
227
+ globalns: Optional[Dict] = None,
228
+ localns: Optional[Dict] = None,
229
+ ) -> Dict[str, Type]:
230
+ from strawberry.lazy_type import StrawberryLazyReference
231
+
232
+ extra = {}
233
+
234
+ if isinstance(expr, ast.Expr) and isinstance(
235
+ expr.value, (ast.BinOp, ast.Subscript)
236
+ ):
237
+ extra.update(_get_namespace_from_ast(expr.value, globalns, localns))
238
+ elif isinstance(expr, ast.BinOp):
239
+ for elt in (expr.left, expr.right):
240
+ extra.update(_get_namespace_from_ast(elt, globalns, localns))
241
+ elif (
242
+ isinstance(expr, ast.Subscript)
243
+ and isinstance(expr.value, ast.Name)
244
+ and expr.value.id == "Union"
245
+ ):
246
+ if hasattr(ast, "Index") and isinstance(expr.slice, ast.Index):
247
+ # The cast is required for mypy on python 3.7 and 3.8
248
+ expr_slice = cast(Any, expr.slice).value
249
+ else:
250
+ expr_slice = expr.slice
251
+
252
+ for elt in cast(ast.Tuple, expr_slice).elts:
253
+ extra.update(_get_namespace_from_ast(elt, globalns, localns))
254
+ elif (
255
+ isinstance(expr, ast.Subscript)
256
+ and isinstance(expr.value, ast.Name)
257
+ and expr.value.id == "Annotated"
258
+ ):
259
+ assert ast_unparse
260
+
261
+ if hasattr(ast, "Index") and isinstance(expr.slice, ast.Index):
262
+ # The cast is required for mypy on python 3.7 and 3.8
263
+ expr_slice = cast(Any, expr.slice).value
264
+ else:
265
+ expr_slice = expr.slice
266
+
267
+ args: List[str] = []
268
+ for elt in cast(ast.Tuple, expr_slice).elts:
269
+ extra.update(_get_namespace_from_ast(elt, globalns, localns))
270
+ args.append(ast_unparse(elt))
271
+
272
+ # When using forward refs, the whole
273
+ # Annotated[SomeType, strawberry.lazy("type.module")] is a forward ref,
274
+ # and trying to _eval_type on it will fail. Take a different approach
275
+ # here to resolve lazy types by execing the annotated args, resolving the
276
+ # type directly and then adding it to extra namespace, so that _eval_type
277
+ # can properly resolve it later
278
+ type_name = args[0]
279
+ for arg in args[1:]:
280
+ evaled_arg = eval(arg, globalns, localns) # noqa: PGH001
281
+ if isinstance(evaled_arg, StrawberryLazyReference):
282
+ extra[type_name] = evaled_arg.resolve_forward_ref(ForwardRef(type_name))
283
+
284
+ return extra
228
285
 
229
286
 
230
287
  def eval_type(
@@ -240,51 +297,22 @@ def eval_type(
240
297
  globalns = globalns or {}
241
298
  # If this is not a string, maybe its args are (e.g. List["Foo"])
242
299
  if isinstance(type_, ForwardRef):
300
+ ast_obj = cast(ast.Expr, ast.parse(type_.__forward_arg__).body[0])
301
+
243
302
  # For Python 3.10+, we can use the built-in _eval_type function directly.
244
303
  # It will handle "|" notations properly
245
304
  if sys.version_info < (3, 10):
246
- parsed = _ast_replace_union_operation(
247
- cast(ast.Expr, ast.parse(type_.__forward_arg__).body[0])
248
- )
305
+ ast_obj = _ast_replace_union_operation(ast_obj)
249
306
 
250
307
  # We replaced "a | b" with "Union[a, b], so make sure Union can be resolved
251
308
  # at globalns because it may not be there
252
309
  if "Union" not in globalns:
253
310
  globalns["Union"] = Union
254
311
 
255
- assert ast_unparse
256
- type_ = ForwardRef(ast_unparse(parsed))
257
-
258
- # When using forward refs, the whole
259
- # Annotated[SomeType, strabwerry.lazy("type.module")] is a forward ref,
260
- # and trying to _eval_type on it will fail. Take a different approach
261
- # here to resolve lazy types by execing the annotated args and resolving
262
- # the type directly.
263
- annotated_match = _annotated_re.search(type_.__forward_arg__)
264
- if annotated_match:
265
- gdict = annotated_match.groupdict()
266
- # FIXME: Eval the remaining annotated args to get their real values
267
- # We might want to refactor how we import lazy modules to avoid having
268
- # to eval the code in here
269
- args = eval(f'({gdict["args"]}, )', globalns, localns) # noqa: PGH001
270
- lazy_ref = next(
271
- (arg for arg in args if isinstance(arg, StrawberryLazyReference)),
272
- None,
273
- )
274
- if lazy_ref is not None:
275
- remaining = [
276
- a for a in args if not isinstance(a, StrawberryLazyReference)
277
- ]
278
- type_ = lazy_ref.resolve_forward_ref(ForwardRef(gdict["type"]))
279
- # If we only had a StrawberryLazyReference, we can return the type
280
- # directly. It already did its job!
281
- if not remaining:
282
- return type_
312
+ globalns.update(_get_namespace_from_ast(ast_obj, globalns, localns))
283
313
 
284
- # Otherwise return the type annotated with the remaining annotations
285
- return Annotated.__class_getitem__( # type: ignore
286
- (type_, *remaining),
287
- )
314
+ assert ast_unparse
315
+ type_ = ForwardRef(ast_unparse(ast_obj))
288
316
 
289
317
  return _eval_type(type_, globalns, localns)
290
318
 
@@ -302,7 +330,12 @@ def eval_type(
302
330
  for a in args[1:]
303
331
  if not isinstance(arg, StrawberryLazyReference)
304
332
  ]
305
- args = (arg.resolve_forward_ref(args[0]), *remaining_args)
333
+ type_arg = (
334
+ arg.resolve_forward_ref(args[0])
335
+ if isinstance(args[0], ForwardRef)
336
+ else args[0]
337
+ )
338
+ args = (type_arg, *remaining_args)
306
339
  break
307
340
  if isinstance(arg, StrawberryAuto):
308
341
  remaining_args = [
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: strawberry-graphql
3
- Version: 0.183.3
3
+ Version: 0.183.4
4
4
  Summary: A library for creating GraphQL APIs
5
5
  Home-page: https://strawberry.rocks/
6
6
  License: MIT
@@ -222,9 +222,9 @@ strawberry/utils/inspect.py,sha256=wax9UsOwBrVX0KZad61VOiqsyKgBrODWTAldxE_5woM,3
222
222
  strawberry/utils/logging.py,sha256=pz1pRJtx5xX2ejGKNN-fG8zPA4SJjnq1HK9xaQpjd4s,1106
223
223
  strawberry/utils/operation.py,sha256=Um-tBCPl3_bVFN2Ph7o1mnrxfxBes4HFCj6T0x4kZxE,1135
224
224
  strawberry/utils/str_converters.py,sha256=VdOnzaxhwJnmQl1Lon0VOjl72uXhM8tLfGxoGwn3arI,657
225
- strawberry/utils/typing.py,sha256=4xa5qGt8TVeknAmLZIcDekom-rh--0GU3qBMGRQhhVM,11697
226
- strawberry_graphql-0.183.3.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
227
- strawberry_graphql-0.183.3.dist-info/METADATA,sha256=UdEj0XUFi6EmFVp6cPVO2Xgh5IU93bFGSNAtJHBMhhg,7644
228
- strawberry_graphql-0.183.3.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
229
- strawberry_graphql-0.183.3.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
230
- strawberry_graphql-0.183.3.dist-info/RECORD,,
225
+ strawberry/utils/typing.py,sha256=MpKjtblkpDBCbjS-yeNSxnOo594_2FLHBOdXiYlAjLM,12716
226
+ strawberry_graphql-0.183.4.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
227
+ strawberry_graphql-0.183.4.dist-info/METADATA,sha256=wKAsyfxwdo9U3murKB1PeRmNJRIhWkdqjjHNGF-TM9c,7644
228
+ strawberry_graphql-0.183.4.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
229
+ strawberry_graphql-0.183.4.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
230
+ strawberry_graphql-0.183.4.dist-info/RECORD,,