strawberry-graphql / strawberry

A GraphQL library for Python that leverages type annotations 🍓
https://strawberry.rocks
MIT License
4.01k stars 533 forks source link

@strawberry.field(args...) decorator gives 'untyped decorator makes function .. untyped' #1929

Open huonw opened 2 years ago

huonw commented 2 years ago

Describe the Bug

Using @strawberry.field as a decorator is nifty, but it seems like its type annotations only work great if it's called without arguments. If it's called like @strawberry.field(name="whatever"), mypy considers the decorator untyped and thus gives 'untyped decorator makes function .. untyped' errors in strict mode.

For instance, adjust test_all_field_usage in test_fields.yml to use strict mode:

modified   tests/mypy/test_fields.yml
@@ -40,6 +40,8 @@
     reveal_type(Example.d)
     reveal_type(Example.e)
     reveal_type(Example.f_resolver)
+  mypy_config: |
+    strict = true
   out: |
     main:22: note: Revealed type is "builtins.str"
     main:23: note: Revealed type is "builtins.str"

There's a whole much of output, but the key lines are towards the end (just before the real Revealed type output):

E     main:14: error: Untyped decorator makes function "e" untyped  [misc] (diff)
...
E     main:18: error: Untyped decorator makes function "f_resolver" untyped  [misc] (diff)
...

This is easily squashed by # type: ignore[misc] annotations, but it'd be neat if we could avoid them 😄

If the test is additionally edited to remove the arguments to field, there's no complains about untyped decorators:

modified   tests/mypy/test_fields.yml
@@ -26,11 +26,11 @@
         c: str = strawberry.field(name="c", resolver=some_resolver)
         d: str = strawberry.field(resolver=some_resolver)

-        @strawberry.field(description="ABC")
+        @strawberry.field
         def e(self, info: Info) -> str:
             return ""

-        @strawberry.field(name="f")
+        @strawberry.field
         def f_resolver(self, info) -> str:
             return ""

System Information

Additional Context

As always, thanks for strawberry! 🍓

Upvote & Fund

Fund with Polar

sirrus233 commented 2 years ago

The same issue affects @strawberry.mutation

harrykao commented 1 year ago

@patrick91 Should this line return a StrawberryField instead of Any?

https://github.com/strawberry-graphql/strawberry/blob/2986600d0ab0cfcc229b97453091badf3cea05db/strawberry/field.py#L444

patrick91 commented 1 year ago

@patrick91 Should this line return a StrawberryField instead of Any?

https://github.com/strawberry-graphql/strawberry/blob/2986600d0ab0cfcc229b97453091badf3cea05db/strawberry/field.py#L444

I think any makes it work with the dataclass transform decorator, but maybe that was only true when we used our own implementation of it 🤔

harrykao commented 1 year ago

Hmm. I'm new here so I know almost nothing. :)

field() returns a StrawberryField if a resolver isn't provided so it seems like using StrawberryField as a return type is more correct than Any. I'm not sure what downstream effects that would have, but what do you think of making the type hint more accurate here and making adjustments elsewhere (maybe by casting to Any) if needed?

harrykao commented 1 year ago

field() returns a StrawberryField if a resolver isn't provided

Oh, actually it returns a StrawberryField no matter what, right?

pm-incyan commented 8 months ago

I've just hit the same issue with strawberry_django.input_mutation it's fine when there are no args, but as soon as I add a description I see the mypy error error: Untyped decorator makes function "foo" untyped [misc]

thearchitector commented 2 months ago

I'm observing this issue as well