Skip to content

Commit

Permalink
django-stubs-ext: Export RelatedManager, ManyRelatedManager stub-…
Browse files Browse the repository at this point in the history
…only classes (typeddjango#1834)

RelatedManager, ManyRelatedManager classes are sometimes useful for type hinting.
But these classes don't exist as is at Django runtime, rather they are defined inside function bodies.

* When `TYPE_CHECKING`, we re-export django-stubs fake classes.
* At runtime, we define these as `Protocol[_T]`.
  This has the advantage that Python prevents them being used with isinstance().

Usage before:

```python
if TYPE_CHECKING:
    from django.db.models.manager import RelatedManager  # before PR typeddjango#1814

def get_manager() -> "RelatedManager[MyModel]": ...
```

Usage after:

```python
from django_stubs_ext.db.models.manager import RelatedManager

def get_manager() -> RelatedManager[MyModel]: ...
```
  • Loading branch information
intgr authored Nov 9, 2023
1 parent 965d88a commit 997ac44
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 0 deletions.
File renamed without changes.
23 changes: 23 additions & 0 deletions ext/django_stubs_ext/db/models/manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from typing import TYPE_CHECKING

# Re-export stubs-only classes RelatedManger and ManyRelatedManager.
# These are fake, Django defines these inside function body.
if TYPE_CHECKING:
# noinspection PyUnresolvedReferences
from django.db.models.fields.related_descriptors import ManyRelatedManager as ManyRelatedManager

# noinspection PyUnresolvedReferences
from django.db.models.fields.related_descriptors import RelatedManager as RelatedManager

else:
from typing import Protocol, TypeVar

_T = TypeVar("_T")

# Define as `Protocol` to prevent them being used with `isinstance()`.
# These actually inherit from `BaseManager`.
class RelatedManager(Protocol[_T]):
pass

class ManyRelatedManager(Protocol[_T]):
pass

0 comments on commit 997ac44

Please sign in to comment.