-
Notifications
You must be signed in to change notification settings - Fork 219
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
[BUG] Incorrect type annotations for Document's insert
, save
and replace
#679
Comments
Was baffled by the error as well. |
Hi, I'm also facing the same issue with pylance for Whenever I try to assign a value to a Link[Document] with a new Document instance it triggers an error. To reproduce:
|
I have the same issues |
It seems to be due to the decorator conventions in this project. For example this decorator used in save def validate_self_before(f: Callable):
@wraps(f)
async def wrapper(self: "DocType", *args, **kwargs):
await self.validate_self(*args, **kwargs)
return await f(self, *args, **kwargs)
return wrapper Because this The way to make this work better with other linters is like this def validate_self_before(f: Callable):
@wraps(f)
async def wrapper(*args, **kwargs):
self = args[0]
await self.validate_self(args[1:], **kwargs)
return await f(*args, **kwargs)
return wrapper I'd be more than happy to see the clean linter results from my IDEs too, but not sure if this is what the maintainers would like to do. UPDATE: I guess this is something that the type checking/linting tools should update and reported it to pyright: microsoft/pyright#6472 |
@jbkoh tried following along with the explanation in microsoft/pyright#6472, but what did you mean in this question? Just asking for clarification. |
When you invoke |
To close the conversation, pyright folks said that we should annotate the arguments better as described here |
I had a go at this and it does seem to work. I'm not sure it's 100% correct still, but at least it resolves the I changed: from typing import ParamSpec, TypeVar, Concatenate
P = ParamSpec("P")
R = TypeVar("R")
S = TypeVar("S")
def wrap_with_actions(event_type: EventTypes):
def decorator(f: Callable[Concatenate[S, P], R]) -> Callable[Concatenate[S, P], R]:
@wraps(f)
async def wrapper(
self: S,
*args: P.args,
skip_actions: Optional[List[Union[ActionDirections, str]]] = None,
**kwargs: P.kwargs,
):
# the rest is the same Then from functools import wraps
from typing import TYPE_CHECKING, Callable, ParamSpec, TypeVar, Concatenate
if TYPE_CHECKING:
from beanie.odm.documents import DocType
P = ParamSpec("P")
R = TypeVar("R")
def validate_self_before(f: Callable[Concatenate["DocType", P], R]) -> Callable[Concatenate["DocType", P], R]:
@wraps(f)
async def wrapper(self: "DocType", *args: P.args, **kwargs: P.kwargs):
await self.validate_self(*args, **kwargs)
return await f(self, *args, **kwargs)
return wrapper and finally from typing import ParamSpec, TypeVar, Concatenate
P = ParamSpec("P")
R = TypeVar("R")
def save_state_after(f: Callable[Concatenate["DocType", P], R]) -> Callable[Concatenate["DocType", P], R]:
@wraps(f)
async def wrapper(self: "DocType", *args: P.args, **kwargs: P.kwargs):
result = await f(self, *args, **kwargs)
self._save_state()
return result
return wrapper Now I can do something like this, and there's no I think it's still not perfect, because if I hover over
So it's not got the type info for the parameters of the method being wrapped. But it's still a lot better than it was before! Anyone got any comments on this? Otherwise I might PR it as it is now |
Of course a big issue with the above is that |
I'm tinkering with this a bit as well. I'm also trying to replace UPD2 Nevermind, I did a stupid thing
Everything below is wrong. I found an error in my code and now all works as expected! but it seems I found a bug in pyright because when type checking this class Document(...):
...
@wrap_with_actions(EventTypes.INSERT)
@save_state_after
@validate_self_before
async def insert(
self: Self,
*,
link_rule: WriteRules = WriteRules.DO_NOTHING,
session: Optional[ClientSession] = None,
skip_actions: Optional[List[Union[ActionDirections, str]]] = None,
) -> Self:
...
async def create(
self: Self,
session: Optional[ClientSession] = None,
) -> Self:
"""
The same as self.insert()
:return: Document
"""
reveal_type(self)
reveal_type(self.insert)
reveal_type(self.insert(session=session))
reveal_type(await self.insert(session=session))
return await self.insert(session=session) I get this /Users/bedlamzd/Repositories/beanie/beanie/odm/documents.py:372:21 - information: Type of "self" is "Self@Document"
/Users/bedlamzd/Repositories/beanie/beanie/odm/documents.py:373:21 - information: Type of "self.insert" is "(*, link_rule: WriteRules = WriteRules.DO_NOTHING, session: ClientSession | None = None, skip_actions: List[ActionDirections | str] | None = None) -> Coroutine[Any, Any, Document]"
/Users/bedlamzd/Repositories/beanie/beanie/odm/documents.py:374:21 - information: Type of "self.insert(session=session)" is "Coroutine[Any, Any, Document]"
/Users/bedlamzd/Repositories/beanie/beanie/odm/documents.py:375:21 - information: Type of "await self.insert(session=session)" is "Document"
/Users/bedlamzd/Repositories/beanie/beanie/odm/documents.py:376:16 - error: Expression of type "Document" cannot be assigned to return type "Self@Document"
Type "Document" cannot be assigned to type "Self@Document" (reportReturnType)
I don't see a reason why pyright thinks UPD1: More on `Self` type erasure
reveal_type(type(self))
reveal_type(type(self).insert) outputs /Users/bedlamzd/Repositories/beanie/beanie/odm/documents.py:371:21 - information: Type of "type(self)" is "type[Self@Document]"
/Users/bedlamzd/Repositories/beanie/beanie/odm/documents.py:372:21 - information: Type of "type(self).insert" is "(Document, *, link_rule: WriteRules = WriteRules.DO_NOTHING, session: ClientSession | None = None, skip_actions: List[ActionDirections | str] | None = None) -> Coroutine[Any, Any, Document]" So when accessing methods pyright for some reason resolves the class type |
Oh yes, great point! I forgot about that. So are you already working on a PR for this? I won't do one if you already have one you're working on. |
I don't have a PR for this, so you can go ahead if you have something ready. I just stumbled upon this yesterday and thought it'd be interesting to look around. But I can start working on a PR, I think I'm almost done with the decorators. The only thing left is to annotate async cases properly |
Type checkers were complaining about missing `self` argument in decorated `Document` methods. This was caused by incomplete annotations of used decorators.
Type checkers were complaining about missing `self` argument in decorated `Document` methods. This was caused by incomplete annotations of used decorators.
FYI I've opened a PR for this issue #886 Sorry it took few days, got distracted |
Removed sync/async overload in favour of ignoring errors in wrappers because mypy confused them and always expected async function.
Type checkers were complaining about missing `self` argument in decorated `Document` methods. This was caused by incomplete annotations of used decorators.
Removed sync/async overload in favour of ignoring errors in wrappers because mypy confused them and always expected async function.
Removed sync/async overload in favour of ignoring errors in wrappers because mypy confused them and always expected async function.
Removed sync/async overload in favour of ignoring errors in wrappers because mypy confused them and always expected async function.
Removed sync/async overload in favour of ignoring errors in wrappers because mypy confused them and always expected async function.
* Annotate decorators that wrap `Document` methods (#679) Type checkers were complaining about missing `self` argument in decorated `Document` methods. This was caused by incomplete annotations of used decorators. * fixup! Annotate decorators that wrap `Document` methods (#679) Removed sync/async overload in favour of ignoring errors in wrappers because mypy confused them and always expected async function. --------- Co-authored-by: Maxim Borisov <maksimb@airg.com>
In general, some of the issues have been fixed in Beanie 1.27.0 (upcoming release). |
Describe the bug
when using Document.insert, save or replace
vscode pylance report an error like this:
I found that it was due to the incorrect type annotation of the decorator, such as
wrap_with_actions
,save_state_after
decorator.If I remove its type comment, it's correct.
For example:
https://github.com/roman-right/beanie/blob/main/beanie/odm/utils/state.py#L63C31
This is probably the easiest way. If we want to use annotations, I guess we need to use
ParamSpec
andTypeVar
for more detailed annotations. For example:To Reproduce
Expected behavior
no error report
Additional context
The text was updated successfully, but these errors were encountered: