diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000000..3215667110 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,21 @@ +release type: patch + +This release fixes a long standing typing issue where mypy would +return the following error: + +```text +main:14: error: Untyped decorator makes function "e" untyped [misc] (diff) +``` + +When using the following code: + +```python +import strawberry + + +@strawberry.type +class Query: + @strawberry.field(description="Get the last user") + def last_user_v2(self) -> str: + return "Hello" +``` diff --git a/strawberry/federation/field.py b/strawberry/federation/field.py index 9fbe875505..6e8d1ece6a 100644 --- a/strawberry/federation/field.py +++ b/strawberry/federation/field.py @@ -118,7 +118,7 @@ def field( directives: Optional[Sequence[object]] = (), extensions: Optional[list[FieldExtension]] = None, graphql_type: Optional[Any] = None, -) -> Any: ... +) -> StrawberryField: ... @overload diff --git a/strawberry/types/field.py b/strawberry/types/field.py index 02d90ab818..e119d6acd9 100644 --- a/strawberry/types/field.py +++ b/strawberry/types/field.py @@ -475,7 +475,7 @@ def field( directives: Optional[Sequence[object]] = (), extensions: Optional[list[FieldExtension]] = None, graphql_type: Optional[Any] = None, -) -> Any: ... +) -> StrawberryField: ... @overload @@ -515,23 +515,23 @@ def field( def field( - resolver: Optional[_RESOLVER_TYPE[Any]] = None, + resolver=None, *, - name: Optional[str] = None, - is_subscription: bool = False, - description: Optional[str] = None, - permission_classes: Optional[list[type[BasePermission]]] = None, - deprecation_reason: Optional[str] = None, - default: Any = dataclasses.MISSING, - default_factory: Union[Callable[..., object], object] = dataclasses.MISSING, - metadata: Optional[Mapping[Any, Any]] = None, - directives: Optional[Sequence[object]] = (), - extensions: Optional[list[FieldExtension]] = None, - graphql_type: Optional[Any] = None, + name=None, + is_subscription=False, + description=None, + permission_classes=None, + deprecation_reason=None, + default=dataclasses.MISSING, + default_factory=dataclasses.MISSING, + metadata=None, + directives=(), + extensions=None, + graphql_type=None, # This init parameter is used by PyRight to determine whether this field # is added in the constructor or not. It is not used to change # any behavior at the moment. - init: Literal[True, False, None] = None, + init=None, ) -> Any: """Annotates a method or property as a GraphQL field. diff --git a/tests/typecheckers/test_fields_with_arguments.py b/tests/typecheckers/test_fields_with_arguments.py new file mode 100644 index 0000000000..ec401f9a0f --- /dev/null +++ b/tests/typecheckers/test_fields_with_arguments.py @@ -0,0 +1,31 @@ +from inline_snapshot import snapshot + +from .utils.marks import requires_mypy, requires_pyright, skip_on_windows +from .utils.typecheck import typecheck + +pytestmark = [skip_on_windows, requires_pyright, requires_mypy] + + +CODE = """ +import strawberry + + +@strawberry.type +class Query: + @strawberry.field(description="Get the last user") + def last_user_v2(self) -> str: + return "Hello" + +@strawberry.federation.type +class FederatedQuery: + @strawberry.federation.field(description="Get the last user") + def last_user_v2(self) -> str: + return "Hello" +""" + + +def test(): + results = typecheck(CODE) + + assert results.pyright == snapshot([]) + assert results.mypy == snapshot([]) diff --git a/tests/typecheckers/utils/mypy.py b/tests/typecheckers/utils/mypy.py index 8fc44ad230..84c431d3e2 100644 --- a/tests/typecheckers/utils/mypy.py +++ b/tests/typecheckers/utils/mypy.py @@ -62,6 +62,10 @@ def run_mypy(code: str, strict: bool = True) -> list[Result]: ) full_output = full_output.strip() + if not full_output: + assert process_result.returncode == 0 + return [] + results: list[Result] = [] try: