-
Notifications
You must be signed in to change notification settings - Fork 63
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
Support Type Hints #354
base: master
Are you sure you want to change the base?
Support Type Hints #354
Conversation
So this is part of a little proof of concept that I'm working on: Can you leverage mypy to detect errors in your mongo queries? For exemple, with my current code I can detect this: from umongo import Document
from umongo.fields import StrField
class MyDocument(Document):
known_field = StrField(required=True)
cursor = MyDocument.find({"known_field": 123, "unknown_field": "string"}) # E: main.MyDocument has no field "unknown_field" [misc] So right now I just implemented the bare minimum to get my code working and I'm testing manually, but my question is: How can we test type hints automatically?
I'm open to suggestions. |
EDIT: My bad I just didn't have the dependencies in my The list of packages missing type hints (after installing
|
With some tweaks so `mypy umongo/` runs without errors. Those are only basic stubs they should be changed to appropriate types later
And steal some signatures from marshmallow's source code
Ok, so, now that I have a more complete set of stubs I'm hitting what @talwrii warned about. That is: metaprogramming. I.e. my previous example was incorrect: without registering my Here is an updated example (note the from umongo import Document
from umongo.fields import StrField
from umongo.frameworks import MotorAsyncIOInstance
instance = MotorAsyncIOInstance()
@instance.register # Changes the parent type to MotorAsyncIODocument
class MyDocument(Document):
known_field = StrField(required=True)
MyDocument.find() # With motor, this isn't a cursor, but a coroutine that returns a cursor, and this is where mypy can remind us to await it. Naively, this shouldn't be too hard to type correctly. A decorator boils down to a function that takes a function/class definition and returns an other function/class definition. So typing the decorator properly should be enough for mypy to work its magic, right? This is what I tried: # umongo/frameworks/motor_asyncio.pyi
...
class MotorAsyncIOInstance(Instance):
...
def register(self, template: Type[DocumentTemplate]) -> Type[MotorAsyncIODocument]: ... Except that
and here is what I get from mypy when checking the previous code:
Which is true for a I suppose a mypy plugin could work that out and fix the situation, but that feels a bit dirty. |
I originally planned to write a mypy plugin that could lint pymongo queries on several ODMs (not only This is what it is currently able to do: from umongo import Document
from umongo.fields import StrField
from umongo.frameworks import PyMongoInstance
instance = PyMongoInstance()
@instance.register
class MyDocument(Document):
known_field = StrField(required=True)
cursor = MyDocument.find({"known_field": 123, "unknown_field": "string"}) # E: main.MyDocument has no field "unknown_field" [misc]
reveal_type(cursor) # N: Revealed type is "umongo.frameworks.pymongo.WrappedCursor[main.MyDocument*]" Note that with only the type stubs I wrote in this PR (so, without the plugin), this is what mypy will yield: from umongo import Document
from umongo.fields import StrField
from umongo.frameworks import PyMongoInstance
instance = PyMongoInstance()
@instance.register
class MyDocument(Document):
known_field = StrField(required=True)
cursor = MyDocument.find({"known_field": 123, "unknown_field": "string"}) # E: "Type[MyDocument]" has no attribute "find" [attr-defined]
reveal_type(cursor) # N: Revealed type is "Any" That's because of a limitation of mypy in how it handles class decorators. So this PR is effectively useless without this plugin... So because this plugin has somewhat shifted in scope towards being more I'm thinking I should move it over here and merge it to this PR, maybe in a folder called |
any progress on this? we are using fastapi and we are searching for an async pydantic-mongo-odb. |
I have since changed jobs and this is no longer relevant to my current job, so I'm sorry but I won't be working on it anymore (however anyone is welcome to pick up where I left off, and ask for information if there's something I overlooked). If you are looking for a Pydantic<->Mongo ODM I think you should look into |
@ThibaultLemaire I think this ODM is better than pydantic-odm, what do you think? |
Indeed. I wish it had existed back when I was making my own search. |
Closes #233