forked from strawberry-graphql/strawberry
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(pydantic): Add mypy extension, typing stubs for conversion of py…
…dantic models (strawberry-graphql#1544) * fix(pydantic): Add mypy extension for to_pydantic and from_pydantic for converted models, add stub for IDEs * fix(pydantic): Fix for mypy==0.93.- * fix(pydantic): Backwards compat for mypy < 0.93 * fix(pydantic): Add RELEASE.md * fix(pydantic): Refactor A to become PydanticModel * fix(pydantic): Add type: ignore * fix(pydantic): Rename add_method_to_class to add_static_method_to_class so future developers use it only for static methods * Apply suggestions from code review Co-authored-by: ignormies <bryce.beagle@gmail.com> * fix(pydantic): Use Protocol[PydanticModel] instead of Generic[PydanticModel], use from __future__ import annotations * retrigger checks * fix(compat): import Protocol from typing_extensions instead of typing for Python <= 3.7 compat * fix(codecov): ignore strawberry/ext/mypy_plugin.py in codecov * fix(codecov): ignore setup.py * Edit comment * Update RELEASE.md Co-authored-by: Patrick Arminio <patrick.arminio@gmail.com> * fix(review): Move StrawberryTypeFromPydantic to new file. Add example to RELEASE.md. * fix(codecov): Silence codecov up about moving StrawberryTypeFromPydantic type to new file. * fix(release): Edit RELEASE.md * fix(typehint): fix from_pydantic type hint Co-authored-by: James Chua <james@leadiq.com> Co-authored-by: ignormies <bryce.beagle@gmail.com> Co-authored-by: Patrick Arminio <patrick.arminio@gmail.com>
- Loading branch information
1 parent
b021481
commit 86e9e77
Showing
6 changed files
with
286 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
Release type: minor | ||
|
||
Adds `to_pydantic` and `from_pydantic` type hints for IDE support. | ||
|
||
Adds mypy extension support as well. | ||
|
||
```python | ||
from pydantic import BaseModel | ||
import strawberry | ||
|
||
class UserPydantic(BaseModel): | ||
age: int | ||
|
||
@strawberry.experimental.pydantic.type(UserPydantic) | ||
class UserStrawberry: | ||
age: strawberry.auto | ||
|
||
reveal_type(UserStrawberry(age=123).to_pydantic()) | ||
``` | ||
Mypy will infer the type as "UserPydantic". Previously it would be "Any" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from __future__ import annotations | ||
|
||
from typing import Any, Dict, TypeVar | ||
|
||
from pydantic import BaseModel | ||
from typing_extensions import Protocol | ||
|
||
from strawberry.types.types import TypeDefinition | ||
|
||
|
||
PydanticModel = TypeVar("PydanticModel", bound=BaseModel) | ||
|
||
|
||
class StrawberryTypeFromPydantic(Protocol[PydanticModel]): | ||
"""This class does not exist in runtime. | ||
It only makes the methods below visible for IDEs""" | ||
|
||
def __init__(self, **kwargs): | ||
... | ||
|
||
@staticmethod | ||
def from_pydantic( | ||
instance: PydanticModel, extra: Dict[str, Any] = None | ||
) -> StrawberryTypeFromPydantic[PydanticModel]: | ||
... | ||
|
||
def to_pydantic(self) -> PydanticModel: | ||
... | ||
|
||
@property | ||
def _type_definition(self) -> TypeDefinition: | ||
... | ||
|
||
@property | ||
def _pydantic_type(self) -> PydanticModel: | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
|
||
- case: test_converted_pydantic_init_any_kwargs | ||
main: | | ||
from pydantic import BaseModel | ||
import strawberry | ||
class UserPydantic(BaseModel): | ||
age: int | ||
@strawberry.experimental.pydantic.type(UserPydantic) | ||
class UserStrawberry: | ||
age: strawberry.auto | ||
reveal_type(UserStrawberry) | ||
reveal_type(UserStrawberry(age=123)) | ||
out: | | ||
main:11: note: Revealed type is "def (**kwargs: Any) -> main.UserStrawberry" | ||
main:12: note: Revealed type is "main.UserStrawberry" | ||
- case: test_converted_to_pydantic | ||
main: | | ||
from pydantic import BaseModel | ||
import strawberry | ||
class UserPydantic(BaseModel): | ||
age: int | ||
@strawberry.experimental.pydantic.type(UserPydantic) | ||
class UserStrawberry: | ||
age: strawberry.auto | ||
reveal_type(UserStrawberry(age=123).to_pydantic()) | ||
out: | | ||
main:11: note: Revealed type is "main.UserPydantic" | ||
- case: test_converted_from_pydantic | ||
main: | | ||
from pydantic import BaseModel | ||
import strawberry | ||
class UserPydantic(BaseModel): | ||
age: int | ||
@strawberry.experimental.pydantic.type(UserPydantic) | ||
class UserStrawberry: | ||
age: strawberry.auto | ||
reveal_type(UserStrawberry.from_pydantic(UserPydantic(age=123))) | ||
out: | | ||
main:11: note: Revealed type is "main.UserStrawberry" | ||
- case: test_converted_from_pydantic_raise_error_wrong_instance | ||
main: | | ||
from pydantic import BaseModel | ||
import strawberry | ||
class UserPydantic(BaseModel): | ||
age: int | ||
@strawberry.experimental.pydantic.type(UserPydantic) | ||
class UserStrawberry: | ||
age: strawberry.auto | ||
class AnotherModel(BaseModel): | ||
age: int | ||
UserStrawberry.from_pydantic(AnotherModel(age=123)) | ||
out: | | ||
main:14: error: Argument 1 to "from_pydantic" of "UserStrawberry" has incompatible type "AnotherModel"; expected "UserPydantic" | ||
- case: test_converted_from_pydantic_chained | ||
main: | | ||
from pydantic import BaseModel | ||
import strawberry | ||
class UserPydantic(BaseModel): | ||
age: int | ||
@strawberry.experimental.pydantic.type(UserPydantic) | ||
class UserStrawberry: | ||
age: strawberry.auto | ||
reveal_type(UserStrawberry.from_pydantic(UserPydantic(age=123)).to_pydantic()) | ||
out: | | ||
main:11: note: Revealed type is "main.UserPydantic" |