https://github.com/sbdchd/mongo-types
:fallen_leaf: Type stubs for mongoengine, pymongo, and bson
https://github.com/sbdchd/mongo-types
mongoengine mypy mypy-stubs stubs type-stubs
Last synced: 5 months ago
JSON representation
:fallen_leaf: Type stubs for mongoengine, pymongo, and bson
- Host: GitHub
- URL: https://github.com/sbdchd/mongo-types
- Owner: sbdchd
- License: apache-2.0
- Created: 2020-11-16T01:06:45.000Z (about 5 years ago)
- Default Branch: main
- Last Pushed: 2023-11-24T23:16:31.000Z (about 2 years ago)
- Last Synced: 2025-06-20T19:27:08.602Z (6 months ago)
- Topics: mongoengine, mypy, mypy-stubs, stubs, type-stubs
- Language: Python
- Homepage:
- Size: 133 KB
- Stars: 20
- Watchers: 3
- Forks: 8
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# mongo-types [](https://pypi.org/project/mongo-types/)
Type stubs for [`mongoengine`][0].
Allows for autocomplete and static typing.
## install
```shell
pip install mongo-types
```
Monkey patch mongoengine's `QuerySet` so we can type it with a generic
argument at runtime:
```python
import types
from mongoengine.queryset.queryset import QuerySet
def no_op(self, x):
return self
QuerySet.__class_getitem__ = types.MethodType(no_op, QuerySet)
```
## usage
After installing and monkey patching, the types should work for the most
part,
but you'll probably need to change how you write some things.
### getting `objects` to work
By default, the base document is typed to not have an `objects` property so
that each document can type it properly.
Here's a helper class that's useful for simple cases which don't modify the
`QuerySet`.
```python
from typing import Generic, Type, TypeVar
from mongoengine import QuerySet, Document
U = TypeVar("U", bound=Document)
class QuerySetManager(Generic[U]):
def __get__(self, instance: object, cls: Type[U]) -> QuerySet[U]:
return QuerySet(cls, cls._get_collection())
class Page(Document):
meta = {
"collection": "pages",
}
objects = QuerySetManager["Page"]()
organization = fields.StringField()
```
### replacing usages of `queryset_class`
before:
```python
from typing import Type
from mongoengine import QuerySet, Document
class PostQuerySet(QuerySet):
def for_org(self, *, org: str) -> QuerySet:
return self.filter(organization=org)
def exists(self) -> bool:
return self.count() > 0
class Post(Document):
meta = {
"collection": "posts",
"queryset_class": SMSLogQuerySet,
}
organization = fields.StringField()
# --snip--
```
after:
```python
from typing import Type
from mongoengine import QuerySet, Document
class PostQuerySet(QuerySet["Post"]):
def for_org(self, *, org: str) -> QuerySet["Post"]:
return self.filter(organization=org)
def exists(self) -> bool:
return self.count() > 0
class QuerySetManager:
def __get__(self, instance: object, cls: Type[Post]) -> PostQuerySet:
return PostQuerySet(cls, cls._get_collection())
class Post(Document):
meta = {
"collection": "posts",
}
objects = QuerySetManager()
organization = fields.StringField()
# --snip--
```
### replicating `@queryset_manager` behavior
before:
```python
from mongoengine import Document, QuerySet, queryset_manager, fields
class UserQuerySet(QuerySet):
def for_org(self, *, org: str) -> QuerySet:
return self.filter(organization=org)
class User(Document):
meta = {
"collection": "users",
"queryset_class": UserQuerySet,
}
is_active = fields.BooleanField()
# --snip--
@queryset_manager
def objects(self, queryset: QuerySet) -> QuerySet:
return queryset.filter(is_active=True)
@queryset_manager
def all_objects(self, queryset: QuerySet) -> QuerySet:
return queryset
maybe_user = User.all_objects.first()
```
after:
```python
from __future__ import annotations
from typing import Type
from mongoengine import QuerySet, Document
class UserQuerySet(QuerySet["User"]):
def for_org(self, *, org: str) -> UserQuerySet:
return self.filter(organization=org)
class QuerySetManager:
def __get__(self, instance: object, cls: Type[User]) -> UserQuerySet:
return UserQuerySet(cls, cls._get_collection()).filter(is_active=True)
class User(Document):
meta = {
"collection": "users",
}
is_active = fields.BooleanField()
# --snip--
objects = QuerySetManager()
@classmethod
def all_objects(cls) -> UserQuerySet:
return UserQuerySet(cls, cls._get_collection())
maybe_user = User.all_objects().first()
```
### fixing "Model" has no attribute "id"
Mongoengine will define an `id` field for you automatically.
Mongo-types require you specify your `id` explicitly so that
the types can be more strict.
```python
class User(Document):
meta = {
"collection": "users",
}
# becomes
class User(Document):
meta = {
"collection": "users",
}
id = fields.StringField(db_field="_id", primary_key=True, default=default_id)
# or if you prefer ObjectIds
class User(Document):
meta = {
"collection": "users",
}
id = fields.ObjectIdField(db_field="_id", primary_key=True, default=ObjectId)
```
## dev
```shell
poetry install
# run formatting, linting, and typechecking
s/lint
# build
poetry build -f wheel
# build and publish
poetry publish --build
```
[0]: https://github.com/MongoEngine/mongoengine
## related
-
-
-
-