Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

From future import annotations breaks lazy types #3568

Open
dartt0n opened this issue Jul 11, 2024 · 7 comments
Open

From future import annotations breaks lazy types #3568

dartt0n opened this issue Jul 11, 2024 · 7 comments
Assignees
Labels
bug Something isn't working

Comments

@dartt0n
Copy link

dartt0n commented Jul 11, 2024

Describe the Bug

from __future__ import annotations breaks type resolver which results in TypeError: Model fields cannot be resolved. Unexpected type 'typing.Any'

I did not manage to track down what exactly causes this issue, but whenever I add from __future__ import annotations to the top of the file with strawberry types - strawberry type resolver breaks

System Information

  • Operating system:
  • Strawberry version (if applicable): 0.235.2

Additional Context

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar
@dartt0n dartt0n added the bug Something isn't working label Jul 11, 2024
@dartt0n
Copy link
Author

dartt0n commented Jul 11, 2024

Update: was able to reproduce with the following code

  1. post.py:
from __future__ import annotations

from typing import TYPE_CHECKING, Annotated

import strawberry


if TYPE_CHECKING:
    from .user import User

LazyUser = Annotated["User", strawberry.lazy(".user")]


@strawberry.type
class Post:
    user: LazyUser
  1. user.py:
from typing import TYPE_CHECKING, Annotated
import strawberry

if TYPE_CHECKING:
    from .post import Post


@strawberry.type
class User:
    posts: list[Annotated["Post", strawberry.lazy(".post")]]

Failes with:

Traceback
╭───────────────────────────── Traceback (most recent call last) ─────────────────────────────╮
│ /Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-packages/strawberry/cli/c │
│ ommands/server.py:65 in server                                                              │
│                                                                                             │
│   62 │   │   )                                                                              │
│   63 │   │   raise typer.Exit(1)                                                            │
│   64 │                                                                                      │
│ ❱ 65 │   load_schema(schema, app_dir=app_dir)                                               │
│   66 │                                                                                      │
│   67 │   os.environ[DEBUG_SERVER_SCHEMA_ENV_VAR_KEY] = schema                               │
│   68 │   os.environ[DEBUG_SERVER_LOG_OPERATIONS] = str(log_operations)                      │
│                                                                                             │
│ ╭──────────────────────────────────────── locals ─────────────────────────────────────────╮ │
│ │        app_dir = '.'                                                                    │ │
│ │           host = '0.0.0.0'                                                              │ │
│ │      log_level = <LogLevel.error: 'error'>                                              │ │
│ │ log_operations = True                                                                   │ │
│ │           port = 8000                                                                   │ │
│ │         schema = 'src.schema'                                                           │ │
│ │      starlette = <module 'starlette' from                                               │ │
│ │                  '/Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-pa… │ │
│ │        uvicorn = <module 'uvicorn' from                                                 │ │
│ │                  '/Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-pa… │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                             │
│ /Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-packages/strawberry/cli/u │
│ tils/__init__.py:14 in load_schema                                                          │
│                                                                                             │
│   11 │   sys.path.insert(0, app_dir)                                                        │
│   12 │                                                                                      │
│   13 │   try:                                                                               │
│ ❱ 14 │   │   schema_symbol = import_module_symbol(schema, default_symbol_name="schema")     │
│   15 │   except (ImportError, AttributeError) as exc:                                       │
│   16 │   │   message = str(exc)                                                             │
│   17                                                                                        │
│                                                                                             │
│ ╭──────── locals ────────╮                                                                  │
│ │ app_dir = '.'          │                                                                  │
│ │  schema = 'src.schema' │                                                                  │
│ ╰────────────────────────╯                                                                  │
│                                                                                             │
│ /Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-packages/strawberry/utils │
│ /importer.py:15 in import_module_symbol                                                     │
│                                                                                             │
│   12 │   else:                                                                              │
│   13 │   │   raise ValueError("Selector does not include a symbol name")                    │
│   14 │                                                                                      │
│ ❱ 15 │   module = importlib.import_module(module_name)                                      │
│   16 │   symbol = module                                                                    │
│   17 │                                                                                      │
│   18 │   for attribute_name in symbol_name.split("."):                                      │
│                                                                                             │
│ ╭────────────── locals ──────────────╮                                                      │
│ │ default_symbol_name = 'schema'     │                                                      │
│ │         module_name = 'src.schema' │                                                      │
│ │            selector = 'src.schema' │                                                      │
│ │         symbol_name = 'schema'     │                                                      │
│ ╰────────────────────────────────────╯                                                      │
│                                                                                             │
│ /Users/dartt0n/.rye/py/[email protected]/lib/python3.12/importlib/__init__.py:90 in            │
│ import_module                                                                               │
│                                                                                             │
│    87 │   │   │   if character != '.':                                                      │
│    88 │   │   │   │   break                                                                 │
│    89 │   │   │   level += 1                                                                │
│ ❱  90 │   return _bootstrap._gcd_import(name[level:], package, level)                       │
│    91                                                                                       │
│    92                                                                                       │
│    93 _RELOADING = {}                                                                       │
│                                                                                             │
│ ╭──────── locals ────────╮                                                                  │
│ │   level = 0            │                                                                  │
│ │    name = 'src.schema' │                                                                  │
│ │ package = None         │                                                                  │
│ ╰────────────────────────╯                                                                  │
│ in _gcd_import:1387                                                                         │
│ ╭──────── locals ────────╮                                                                  │
│ │   level = 0            │                                                                  │
│ │    name = 'src.schema' │                                                                  │
│ │ package = None         │                                                                  │
│ ╰────────────────────────╯                                                                  │
│ in _find_and_load:1360                                                                      │
│ ╭──────────────────── locals ─────────────────────╮                                         │
│ │ import_ = <function _gcd_import at 0x1044740e0> │                                         │
│ │  module = <object object at 0x104448060>        │                                         │
│ │    name = 'src.schema'                          │                                         │
│ ╰─────────────────────────────────────────────────╯                                         │
│ in _find_and_load_unlocked:1331                                                             │
│ ╭──────────────────────────────────────── locals ─────────────────────────────────────────╮ │
│ │         child = 'schema'                                                                │ │
│ │       import_ = <function _gcd_import at 0x1044740e0>                                   │ │
│ │          name = 'src.schema'                                                            │ │
│ │        parent = 'src'                                                                   │ │
│ │ parent_module = <module 'src' from                                                      │ │
│ │                 '/Users/dartt0n/Downloads/strawberry-bug/src/__init__.py'>              │ │
│ │   parent_spec = ModuleSpec(name='src',                                                  │ │
│ │                 loader=<_frozen_importlib_external.SourceFileLoader object at           │ │
│ │                 0x107282120>,                                                           │ │
│ │                 origin='/Users/dartt0n/Downloads/strawberry-bug/src/__init__.py',       │ │
│ │                 submodule_search_locations=['/Users/dartt0n/Downloads/strawberry-bug/s… │ │
│ │          path = ['/Users/dartt0n/Downloads/strawberry-bug/src']                         │ │
│ │          spec = ModuleSpec(name='src.schema',                                           │ │
│ │                 loader=<_frozen_importlib_external.SourceFileLoader object at           │ │
│ │                 0x107282420>,                                                           │ │
│ │                 origin='/Users/dartt0n/Downloads/strawberry-bug/src/schema.py')         │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ │
│ in _load_unlocked:935                                                                       │
│ ╭──────────────────────────────────────── locals ─────────────────────────────────────────╮ │
│ │ module = <module 'src.schema' from                                                      │ │
│ │          '/Users/dartt0n/Downloads/strawberry-bug/src/schema.py'>                       │ │
│ │   spec = ModuleSpec(name='src.schema',                                                  │ │
│ │          loader=<_frozen_importlib_external.SourceFileLoader object at 0x107282420>,    │ │
│ │          origin='/Users/dartt0n/Downloads/strawberry-bug/src/schema.py')                │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ │
│ in exec_module:995                                                                          │
│ ╭──────────────────────────────────────── locals ─────────────────────────────────────────╮ │
│ │   code = <code object <module> at 0x1071f2930, file                                     │ │
│ │          "/Users/dartt0n/Downloads/strawberry-bug/src/schema.py", line 1>               │ │
│ │ module = <module 'src.schema' from                                                      │ │
│ │          '/Users/dartt0n/Downloads/strawberry-bug/src/schema.py'>                       │ │
│ │   self = <_frozen_importlib_external.SourceFileLoader object at 0x107282420>            │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ │
│ in _call_with_frames_removed:488                                                            │
│ ╭──────────────────────────────────────── locals ─────────────────────────────────────────╮ │
│ │ args = (                                                                                │ │
│ │        │   <code object <module> at 0x1071f2930, file                                   │ │
│ │        "/Users/dartt0n/Downloads/strawberry-bug/src/schema.py", line 1>,                │ │
│ │        │   {                                                                            │ │
│ │        │   │   '__name__': 'src.schema',                                                │ │
│ │        │   │   '__doc__': None,                                                         │ │
│ │        │   │   '__package__': 'src',                                                    │ │
│ │        │   │   '__loader__': <_frozen_importlib_external.SourceFileLoader object at     │ │
│ │        0x107282420>,                                                                    │ │
│ │        │   │   '__spec__': ModuleSpec(name='src.schema',                                │ │
│ │        loader=<_frozen_importlib_external.SourceFileLoader object at 0x107282420>,      │ │
│ │        origin='/Users/dartt0n/Downloads/strawberry-bug/src/schema.py'),                 │ │
│ │        │   │   '__file__': '/Users/dartt0n/Downloads/strawberry-bug/src/schema.py',     │ │
│ │        │   │   '__cached__':                                                            │ │
│ │        '/Users/dartt0n/Downloads/strawberry-bug/src/__pycache__/schema.cpython-312.pyc… │ │
│ │        │   │   '__builtins__': {                                                        │ │
│ │        │   │   │   '__name__': 'builtins',                                              │ │
│ │        │   │   │   '__doc__': 'Built-in functions, types, exceptions, and other         │ │
│ │        objects.\n\nThis module provides '+346,                                          │ │
│ │        │   │   │   '__package__': '',                                                   │ │
│ │        │   │   │   '__loader__': <class '_frozen_importlib.BuiltinImporter'>,           │ │
│ │        │   │   │   '__spec__': ModuleSpec(name='builtins', loader=<class                │ │
│ │        '_frozen_importlib.BuiltinImporter'>, origin='built-in'),                        │ │
│ │        │   │   │   '__build_class__': <built-in function __build_class__>,              │ │
│ │        │   │   │   '__import__': <built-in function __import__>,                        │ │
│ │        │   │   │   'abs': <built-in function abs>,                                      │ │
│ │        │   │   │   'all': <built-in function all>,                                      │ │
│ │        │   │   │   'any': <built-in function any>,                                      │ │
│ │        │   │   │   ... +147                                                             │ │
│ │        │   │   },                                                                       │ │
│ │        │   │   'strawberry': <module 'strawberry' from                                  │ │
│ │        '/Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-packages/str… │ │
│ │        │   │   'Query': <class 'src.query.Query'>                                       │ │
│ │        │   }                                                                            │ │
│ │        )                                                                                │ │
│ │    f = <built-in function exec>                                                         │ │
│ │ kwds = {}                                                                               │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                             │
│ /Users/dartt0n/Downloads/strawberry-bug/src/schema.py:6 in <module>                         │
│                                                                                             │
│   3 from .query import Query                                                                │
│   4                                                                                         │
│   5                                                                                         │
│ ❱ 6 schema = strawberry.Schema(query=Query)                                                 │
│   7                                                                                         │
│                                                                                             │
│ ╭──────────────────────────────────────── locals ─────────────────────────────────────────╮ │
│ │      Query = <class 'src.query.Query'>                                                  │ │
│ │ strawberry = <module 'strawberry' from                                                  │ │
│ │              '/Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-packag… │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                             │
│ /Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-packages/strawberry/schem │
│ a/schema.py:164 in __init__                                                                 │
│                                                                                             │
│   161 │   │   │   from strawberry.exceptions import StrawberryException                     │
│   162 │   │   │                                                                             │
│   163 │   │   │   if isinstance(error.__cause__, StrawberryException):                      │
│ ❱ 164 │   │   │   │   raise error.__cause__ from None                                       │
│   165 │   │   │                                                                             │
│   166 │   │   │   raise                                                                     │
│   167                                                                                       │
│                                                                                             │
│ ╭──────────────────────────────────────── locals ─────────────────────────────────────────╮ │
│ │                     config = None                                                       │ │
│ │                 directives = ()                                                         │ │
│ │    execution_context_class = None                                                       │ │
│ │                 extensions = ()                                                         │ │
│ │         graphql_directives = []                                                         │ │
│ │              graphql_types = []                                                         │ │
│ │                   mutation = None                                                       │ │
│ │              mutation_type = None                                                       │ │
│ │                      query = <class 'src.query.Query'>                                  │ │
│ │                 query_type = <GraphQLObjectType 'Query'>                                │ │
│ │           scalar_overrides = None                                                       │ │
│ │ SCALAR_OVERRIDES_DICT_TYPE = typing.Dict[object,                                        │ │
│ │                              typing.Union[ForwardRef('ScalarWrapper'),                  │ │
│ │                              ForwardRef('ScalarDefinition')]]                           │ │
│ │            scalar_registry = {                                                          │ │
│ │                              │   <class 'NoneType'>: ScalarDefinition(                  │ │
│ │                              │   │   name='Void',                                       │ │
│ │                              │   │   description='Represents NULL values',              │ │
│ │                              │   │   specified_by_url=None,                             │ │
│ │                              │   │   serialize=<function _verify_void at 0x104e97600>,  │ │
│ │                              │   │   parse_value=<function _verify_void at              │ │
│ │                              0x104e97600>,                                              │ │
│ │                              │   │   parse_literal=None,                                │ │
│ │                              │   │   directives=(),                                     │ │
│ │                              │   │   implementation=None,                               │ │
│ │                              │   │                                                      │ │
│ │                              _source_file='/Users/dartt0n/Downloads/strawberry-bug/.ve… │ │
│ │                              │   │   _source_line=76                                    │ │
│ │                              │   ),                                                     │ │
│ │                              │   None: ScalarDefinition(                                │ │
│ │                              │   │   name='Void',                                       │ │
│ │                              │   │   description='Represents NULL values',              │ │
│ │                              │   │   specified_by_url=None,                             │ │
│ │                              │   │   serialize=<function _verify_void at 0x104e97600>,  │ │
│ │                              │   │   parse_value=<function _verify_void at              │ │
│ │                              0x104e97600>,                                              │ │
│ │                              │   │   parse_literal=None,                                │ │
│ │                              │   │   directives=(),                                     │ │
│ │                              │   │   implementation=None,                               │ │
│ │                              │   │                                                      │ │
│ │                              _source_file='/Users/dartt0n/Downloads/strawberry-bug/.ve… │ │
│ │                              │   │   _source_line=76                                    │ │
│ │                              │   ),                                                     │ │
│ │                              │   <class 'str'>: ScalarDefinition(                       │ │
│ │                              │   │   name='String',                                     │ │
│ │                              │   │   description='String',                              │ │
│ │                              │   │   specified_by_url=None,                             │ │
│ │                              │   │   serialize=<function serialize_string at            │ │
│ │                              0x104b59ee0>,                                              │ │
│ │                              │   │   parse_value=<function coerce_string at             │ │
│ │                              0x104b59f80>,                                              │ │
│ │                              │   │   parse_literal=<function parse_string_literal at    │ │
│ │                              0x104b5a020>,                                              │ │
│ │                              │   │   directives=(),                                     │ │
│ │                              │   │   implementation=<GraphQLScalarType 'String'>,       │ │
│ │                              │   │   _source_file=None,                                 │ │
│ │                              │   │   _source_line=None                                  │ │
│ │                              │   ),                                                     │ │
│ │                              │   <class 'int'>: ScalarDefinition(                       │ │
│ │                              │   │   name='Int',                                        │ │
│ │                              │   │   description='Int',                                 │ │
│ │                              │   │   specified_by_url=None,                             │ │
│ │                              │   │   serialize=<function serialize_int at 0x104b59b20>, │ │
│ │                              │   │   parse_value=<function coerce_int at 0x104b59bc0>,  │ │
│ │                              │   │   parse_literal=<function parse_int_literal at       │ │
│ │                              0x104b59c60>,                                              │ │
│ │                              │   │   directives=(),                                     │ │
│ │                              │   │   implementation=<GraphQLScalarType 'Int'>,          │ │
│ │                              │   │   _source_file=None,                                 │ │
│ │                              │   │   _source_line=None                                  │ │
│ │                              │   ),                                                     │ │
│ │                              │   <class 'float'>: ScalarDefinition(                     │ │
│ │                              │   │   name='Float',                                      │ │
│ │                              │   │   description='Float',                               │ │
│ │                              │   │   specified_by_url=None,                             │ │
│ │                              │   │   serialize=<function serialize_float at             │ │
│ │                              0x104b59d00>,                                              │ │
│ │                              │   │   parse_value=<function coerce_float at              │ │
│ │                              0x104b59da0>,                                              │ │
│ │                              │   │   parse_literal=<function parse_float_literal at     │ │
│ │                              0x104b59e40>,                                              │ │
│ │                              │   │   directives=(),                                     │ │
│ │                              │   │   implementation=<GraphQLScalarType 'Float'>,        │ │
│ │                              │   │   _source_file=None,                                 │ │
│ │                              │   │   _source_line=None                                  │ │
│ │                              │   ),                                                     │ │
│ │                              │   <class 'bool'>: ScalarDefinition(                      │ │
│ │                              │   │   name='Boolean',                                    │ │
│ │                              │   │   description='Boolean',                             │ │
│ │                              │   │   specified_by_url=None,                             │ │
│ │                              │   │   serialize=<function serialize_boolean at           │ │
│ │                              0x104b5a0c0>,                                              │ │
│ │                              │   │   parse_value=<function coerce_boolean at            │ │
│ │                              0x104b5a160>,                                              │ │
│ │                              │   │   parse_literal=<function parse_boolean_literal at   │ │
│ │                              0x104b5a200>,                                              │ │
│ │                              │   │   directives=(),                                     │ │
│ │                              │   │   implementation=<GraphQLScalarType 'Boolean'>,      │ │
│ │                              │   │   _source_file=None,                                 │ │
│ │                              │   │   _source_line=None                                  │ │
│ │                              │   ),                                                     │ │
│ │                              │   strawberry.scalars.ID: ScalarDefinition(               │ │
│ │                              │   │   name='ID',                                         │ │
│ │                              │   │   description='ID',                                  │ │
│ │                              │   │   specified_by_url=None,                             │ │
│ │                              │   │   serialize=<function serialize_id at 0x104b5a2a0>,  │ │
│ │                              │   │   parse_value=<function coerce_id at 0x104b5a340>,   │ │
│ │                              │   │   parse_literal=<function parse_id_literal at        │ │
│ │                              0x104b5a3e0>,                                              │ │
│ │                              │   │   directives=(),                                     │ │
│ │                              │   │   implementation=<GraphQLScalarType 'ID'>,           │ │
│ │                              │   │   _source_file=None,                                 │ │
│ │                              │   │   _source_line=None                                  │ │
│ │                              │   ),                                                     │ │
│ │                              │   <class 'uuid.UUID'>: ScalarDefinition(                 │ │
│ │                              │   │   name='UUID',                                       │ │
│ │                              │   │   description=None,                                  │ │
│ │                              │   │   specified_by_url=None,                             │ │
│ │                              │   │   serialize=<class 'str'>,                           │ │
│ │                              │   │   parse_value=<function wrap_parser.<locals>.inner   │ │
│ │                              at 0x104e97560>,                                           │ │
│ │                              │   │   parse_literal=None,                                │ │
│ │                              │   │   directives=(),                                     │ │
│ │                              │   │   implementation=None,                               │ │
│ │                              │   │                                                      │ │
│ │                              _source_file='/Users/dartt0n/Downloads/strawberry-bug/.ve… │ │
│ │                              │   │   _source_line=63                                    │ │
│ │                              │   ),                                                     │ │
│ │                              │   <strawberry.custom_scalar.ScalarWrapper object at      │ │
│ │                              0x104e0ee40>: ScalarDefinition(                            │ │
│ │                              │   │   name='Upload',                                     │ │
│ │                              │   │   description=None,                                  │ │
│ │                              │   │   specified_by_url=None,                             │ │
│ │                              │   │   serialize=<function identity at 0x10478fec0>,      │ │
│ │                              │   │   parse_value=<function <lambda> at 0x104e13e20>,    │ │
│ │                              │   │   parse_literal=None,                                │ │
│ │                              │   │   directives=(),                                     │ │
│ │                              │   │   implementation=None,                               │ │
│ │                              │   │                                                      │ │
│ │                              _source_file='/Users/dartt0n/Downloads/strawberry-bug/.ve… │ │
│ │                              │   │   _source_line=5                                     │ │
│ │                              │   ),                                                     │ │
│ │                              │   <class 'datetime.date'>: ScalarDefinition(             │ │
│ │                              │   │   name='Date',                                       │ │
│ │                              │   │   description='Date (isoformat)',                    │ │
│ │                              │   │   specified_by_url=None,                             │ │
│ │                              │   │   serialize=operator.methodcaller('isoformat'),      │ │
│ │                              │   │   parse_value=<function wrap_parser.<locals>.inner   │ │
│ │                              at 0x104e97380>,                                           │ │
│ │                              │   │   parse_literal=None,                                │ │
│ │                              │   │   directives=(),                                     │ │
│ │                              │   │   implementation=None,                               │ │
│ │                              │   │                                                      │ │
│ │                              _source_file='/Users/dartt0n/Downloads/strawberry-bug/.ve… │ │
│ │                              │   │   _source_line=33                                    │ │
│ │                              │   ),                                                     │ │
│ │                              │   ... +4                                                 │ │
│ │                              }                                                          │ │
│ │          schema_directives = ()                                                         │ │
│ │                       self = <strawberry.schema.schema.Schema object at 0x10724d910>    │ │
│ │        StrawberryException = <class                                                     │ │
│ │                              'strawberry.exceptions.exception.StrawberryException'>     │ │
│ │               subscription = None                                                       │ │
│ │          subscription_type = None                                                       │ │
│ │                      types = ()                                                         │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                             │
│ /Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-packages/graphql/type/def │
│ inition.py:808 in fields                                                                    │
│                                                                                             │
│    805 │   def fields(self) -> GraphQLFieldMap:                                             │
│    806 │   │   """Get provided fields, wrapping them as GraphQLFields if needed."""         │
│    807 │   │   try:                                                                         │
│ ❱  808 │   │   │   fields = resolve_thunk(self._fields)                                     │
│    809 │   │   except Exception as error:                                                   │
│    810 │   │   │   cls = GraphQLError if isinstance(error, GraphQLError) else TypeError     │
│    811 │   │   │   raise cls(f"{self.name} fields cannot be resolved. {error}") from error  │
│                                                                                             │
│ ╭───────────── locals ──────────────╮                                                       │
│ │  cls = <class 'TypeError'>        │                                                       │
│ │ self = <GraphQLObjectType 'Post'> │                                                       │
│ ╰───────────────────────────────────╯                                                       │
│                                                                                             │
│ /Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-packages/graphql/type/def │
│ inition.py:300 in resolve_thunk                                                             │
│                                                                                             │
│    297 │   Used while defining GraphQL types to allow for circular references in otherwise  │
│    298 │   immutable type definitions.                                                      │
│    299 │   """                                                                              │
│ ❱  300 │   return thunk() if callable(thunk) else thunk                                     │
│    301                                                                                      │
│    302                                                                                      │
│    303 GraphQLScalarSerializer = Callable[[Any], Any]                                       │
│                                                                                             │
│ ╭─────────────────────────────────────── locals ───────────────────────────────────────╮    │
│ │ thunk = <function GraphQLCoreConverter.from_object.<locals>.<lambda> at 0x10729c400> │    │
│ ╰──────────────────────────────────────────────────────────────────────────────────────╯    │
│                                                                                             │
│ /Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-packages/strawberry/schem │
│ a/schema_converter.py:635 in <lambda>                                                       │
│                                                                                             │
│    632 │   │                                                                                │
│    633 │   │   graphql_object_type = GraphQLObjectType(                                     │
│    634 │   │   │   name=object_type_name,                                                   │
│ ❱  635 │   │   │   fields=lambda: self.get_graphql_fields(object_type),                     │
│    636 │   │   │   interfaces=list(map(self.from_interface, object_type.interfaces)),       │
│    637 │   │   │   description=object_type.description,                                     │
│    638 │   │   │   is_type_of=_get_is_type_of(),                                            │
│                                                                                             │
│ ╭──────────────────────────────────────── locals ─────────────────────────────────────────╮ │
│ │ object_type = StrawberryObjectDefinition(                                               │ │
│ │               │   name='Post',                                                          │ │
│ │               │   is_input=False,                                                       │ │
│ │               │   is_interface=False,                                                   │ │
│ │               │   origin=<class 'src.post.Post'>,                                       │ │
│ │               │   description=None,                                                     │ │
│ │               │   interfaces=[],                                                        │ │
│ │               │   extend=False,                                                         │ │
│ │               │   directives=(),                                                        │ │
│ │               │   is_type_of=None,                                                      │ │
│ │               │   resolve_type=None,                                                    │ │
│ │               │   fields=[                                                              │ │
│ │               │   │   Field(name='user',type=<object object at                          │ │
│ │               0x104449090>,default=<dataclasses._MISSING_TYPE object at                 │ │
│ │               0x1045921e0>,default_factory=<dataclasses._MISSING_TYPE object at         │ │
│ │               0x1045921e0>,init=True,repr=True,hash=None,compare=True,metadata=mapping… │ │
│ │               object at 0x1045921e0>,_field_type=None)                                  │ │
│ │               │   ],                                                                    │ │
│ │               │   concrete_of=None,                                                     │ │
│ │               │   type_var_map={}                                                       │ │
│ │               )                                                                         │ │
│ │        self = <strawberry.schema.schema_converter.GraphQLCoreConverter object at        │ │
│ │               0x107282600>                                                              │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                             │
│ /Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-packages/strawberry/schem │
│ a/schema_converter.py:440 in get_graphql_fields                                             │
│                                                                                             │
│    437 │   def get_graphql_fields(                                                          │
│    438 │   │   self, type_definition: StrawberryObjectDefinition                            │
│    439 │   ) -> Dict[str, GraphQLField]:                                                    │
│ ❱  440 │   │   return _get_thunk_mapping(                                                   │
│    441 │   │   │   type_definition=type_definition,                                         │
│    442 │   │   │   name_converter=self.config.name_converter.from_field,                    │
│    443 │   │   │   field_converter=self.from_field,                                         │
│                                                                                             │
│ ╭──────────────────────────────────────── locals ─────────────────────────────────────────╮ │
│ │            self = <strawberry.schema.schema_converter.GraphQLCoreConverter object at    │ │
│ │                   0x107282600>                                                          │ │
│ │ type_definition = StrawberryObjectDefinition(                                           │ │
│ │                   │   name='Post',                                                      │ │
│ │                   │   is_input=False,                                                   │ │
│ │                   │   is_interface=False,                                               │ │
│ │                   │   origin=<class 'src.post.Post'>,                                   │ │
│ │                   │   description=None,                                                 │ │
│ │                   │   interfaces=[],                                                    │ │
│ │                   │   extend=False,                                                     │ │
│ │                   │   directives=(),                                                    │ │
│ │                   │   is_type_of=None,                                                  │ │
│ │                   │   resolve_type=None,                                                │ │
│ │                   │   fields=[                                                          │ │
│ │                   │   │   Field(name='user',type=<object object at                      │ │
│ │                   0x104449090>,default=<dataclasses._MISSING_TYPE object at             │ │
│ │                   0x1045921e0>,default_factory=<dataclasses._MISSING_TYPE object at     │ │
│ │                   0x1045921e0>,init=True,repr=True,hash=None,compare=True,metadata=map… │ │
│ │                   object at 0x1045921e0>,_field_type=None)                              │ │
│ │                   │   ],                                                                │ │
│ │                   │   concrete_of=None,                                                 │ │
│ │                   │   type_var_map={}                                                   │ │
│ │                   )                                                                     │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                             │
│ /Users/dartt0n/Downloads/strawberry-bug/.venv/lib/python3.12/site-packages/strawberry/schem │
│ a/schema_converter.py:135 in _get_thunk_mapping                                             │
│                                                                                             │
│    132 │   │   field_type = field.type                                                      │
│    133 │   │                                                                                │
│    134 │   │   if field_type is UNRESOLVED:                                                 │
│ ❱  135 │   │   │   raise UnresolvedFieldTypeError(type_definition, field)                   │
│    136 │   │                                                                                │
│    137 │   │   if not is_private(field_type):                                               │
│    138 │   │   │   thunk_mapping[name_converter(field)] = field_converter(                  │
│                                                                                             │
│ ╭──────────────────────────────────────── locals ─────────────────────────────────────────╮ │
│ │           field = Field(name='user',type=<object object at                              │ │
│ │                   0x104449090>,default=<dataclasses._MISSING_TYPE object at             │ │
│ │                   0x1045921e0>,default_factory=<dataclasses._MISSING_TYPE object at     │ │
│ │                   0x1045921e0>,init=True,repr=True,hash=None,compare=True,metadata=map… │ │
│ │                   object at 0x1045921e0>,_field_type=None)                              │ │
│ │ field_converter = <bound method GraphQLCoreConverter.from_field of                      │ │
│ │                   <strawberry.schema.schema_converter.GraphQLCoreConverter object at    │ │
│ │                   0x107282600>>                                                         │ │
│ │      field_type = <object object at 0x104449090>                                        │ │
│ │          fields = [                                                                     │ │
│ │                   │   Field(name='user',type=<object object at                          │ │
│ │                   0x104449090>,default=<dataclasses._MISSING_TYPE object at             │ │
│ │                   0x1045921e0>,default_factory=<dataclasses._MISSING_TYPE object at     │ │
│ │                   0x1045921e0>,init=True,repr=True,hash=None,compare=True,metadata=map… │ │
│ │                   object at 0x1045921e0>,_field_type=None)                              │ │
│ │                   ]                                                                     │ │
│ │      get_fields = <bound method Schema.get_fields of <strawberry.schema.schema.Schema   │ │
│ │                   object at 0x10724d910>>                                               │ │
│ │  name_converter = <bound method NameConverter.from_field of                             │ │
│ │                   <strawberry.schema.name_converter.NameConverter object at             │ │
│ │                   0x10722f800>>                                                         │ │
│ │   thunk_mapping = {}                                                                    │ │
│ │ type_definition = StrawberryObjectDefinition(                                           │ │
│ │                   │   name='Post',                                                      │ │
│ │                   │   is_input=False,                                                   │ │
│ │                   │   is_interface=False,                                               │ │
│ │                   │   origin=<class 'src.post.Post'>,                                   │ │
│ │                   │   description=None,                                                 │ │
│ │                   │   interfaces=[],                                                    │ │
│ │                   │   extend=False,                                                     │ │
│ │                   │   directives=(),                                                    │ │
│ │                   │   is_type_of=None,                                                  │ │
│ │                   │   resolve_type=None,                                                │ │
│ │                   │   fields=[                                                          │ │
│ │                   │   │   Field(name='user',type=<object object at                      │ │
│ │                   0x104449090>,default=<dataclasses._MISSING_TYPE object at             │ │
│ │                   0x1045921e0>,default_factory=<dataclasses._MISSING_TYPE object at     │ │
│ │                   0x1045921e0>,init=True,repr=True,hash=None,compare=True,metadata=map… │ │
│ │                   object at 0x1045921e0>,_field_type=None)                              │ │
│ │                   │   ],                                                                │ │
│ │                   │   concrete_of=None,                                                 │ │
│ │                   │   type_var_map={}                                                   │ │
│ │                   )                                                                     │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ │
╰─────────────────────────────────────────────────────────────────────────────────────────────╯
UnresolvedFieldTypeError: Could not resolve the type of 'user'. Check that the class is 
accessible from the global module scope.

If we remove from __future__ import annotations from post.py types are resolved correctly

@dartt0n dartt0n changed the title From future import annotations breaks type resolver From future import annotations breaks lazy types Jul 20, 2024
@hrideshmg
Copy link

I seem to get a similar result when attempting to use from __future__ import annotations when @strawberry.mutations is present in the file, here is the traceback:

  File "/home/hridesh/Coding/repositories/myproj/quiz/graphql/mutations/submission.py", line 165, in MyMutation
    @strawberry.mutation
     ^^^^^^^^^^^^^^^^^^^
  File "/home/hridesh/Coding/repositories/myproj/.venv/lib/python3.12/site-packages/strawberry/field.py", line 520, in field
    return field_(resolver)
           ^^^^^^^^^^^^^^^^
  File "/home/hridesh/Coding/repositories/myproj/.venv/lib/python3.12/site-packages/strawberry/field.py", line 181, in __call__
    for argument in resolver.arguments:
                    ^^^^^^^^^^^^^^^^^^
  File "/home/hridesh/.pyenv/versions/3.12.4/lib/python3.12/functools.py", line 995, in __get__
    val = self.func(instance)
          ^^^^^^^^^^^^^^^^^^^
  File "/home/hridesh/Coding/repositories/myproj/.venv/lib/python3.12/site-packages/strawberry/types/fields/resolver.py", line 226, in arguments
    argument = StrawberryArgument(
               ^^^^^^^^^^^^^^^^^^^
  File "/home/hridesh/Coding/repositories/myproj/.venv/lib/python3.12/site-packages/strawberry/arguments.py", line 123, in __init__
    arg.resolve_forward_ref(first)
  File "/home/hridesh/Coding/repositories/myproj/.venv/lib/python3.12/site-packages/strawberry/lazy_type.py", line 82, in resolve_forward_ref
    return LazyType(forward_ref.__forward_arg__, self.module, self.package)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'LazyType' object has no attribute '__forward_arg__'

Sample code:

    @strawberry.mutation
    def my_function(
        self,
        info,
        question: Annotated[QuestionInput, strawberry.lazy("quiz.graphql.inputs")],
    ) -> Annotated[QuizQuestion, strawberry.lazy("quiz.graphql.types.question")]:

Considering that the PEP behind from __future__ import annotations will be eventually made default in a future release of python, this might break lazy types.

@patrick91
Copy link
Member

Considering that the PEP behind from future import annotations will be eventually made default in a future release of python, this might break lazy types.

That's not the case fortunately 😊

But we should probably find a way to make it work any way 🤔

@hrideshmg
Copy link

That's not the case fortunately 😊

Oh, it does indeed seem like it. I might give this a go (though i have no experience with this stuff) sometime in the future if nobody takes it up

@dartt0n
Copy link
Author

dartt0n commented Jan 7, 2025

Considering that the PEP behind from future import annotations will be eventually made default in a future release of python, this might break lazy types.

That's not the case fortunately 😊

But we should probably find a way to make it work any way 🤔

Seems like this behaviour of forwardref becomes default in python 3.14: https://docs.python.org/3.14/whatsnew/3.14.html

@bellini666
Copy link
Member

Since I've touched this earlier, I'll try to tackle this during the following couple of weeks!

@bellini666 bellini666 self-assigned this Jan 8, 2025
@bellini666
Copy link
Member

I was trying to reproduce this with a code similar to yours @dartt0n , but it always "works for me". I'll try a bit more, but in the mean time, can you tell me which version of python were you using to reproduce this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants