mirror of https://github.com/zulip/zulip.git
docs: Add a section on django-stubs.
This adds examples for QuerySet, ValuesQuerySet, TestHttpResponse, which are some common examples that need a bit of extra care when typing. Signed-off-by: Zixuan James Li <p359101898@gmail.com>
This commit is contained in:
parent
8e472402fe
commit
dd1f8c6bfb
|
@ -107,6 +107,88 @@ everything in the third-party module as an `Any`, which is the right
|
|||
model (one certainly wouldn't want to need stubs for everything just
|
||||
to use `mypy`!), but means the code can't be fully type-checked.
|
||||
|
||||
## Working with types from django-stubs
|
||||
|
||||
For features that are difficult to be expressed with static type
|
||||
annotations, type analysis is supplemented with mypy plugins. Zulip's
|
||||
Python codebases uses the Django web framework, and such a plugin is
|
||||
required in order for `mypy` to correctly infer the types of most code
|
||||
interacting with Django model classes (i.e. code that accesses the
|
||||
database).
|
||||
|
||||
We use the `mypy_django_plugin` plugin from the
|
||||
[django-stubs](https://github.com/typeddjango/django-stubs) project,
|
||||
which supports accurate type inference for classes like
|
||||
`QuerySet`. For example, `Stream.objects.filter(realm=realm)` is
|
||||
simple Django code to fetch all the streams in a realm. With this
|
||||
plugin, mypy will correctly determine its type is `QuerySet[Stream]`,
|
||||
aka a standard, lazily evaluated Django query object that can be
|
||||
iterated through to access `Stream` objects, without the developer
|
||||
needing to do an explicit annotation.
|
||||
|
||||
When declaring the types for functions that accept a `QuerySet`
|
||||
object, you should always supply the model type that it accepts as the
|
||||
type parameter.
|
||||
|
||||
```python
|
||||
def foo(user: QuerySet[UserProfile]) -> None:
|
||||
...
|
||||
```
|
||||
|
||||
In cases where you need to type the return value from `.values_list`
|
||||
or `.values` on a `QuerySet`, you can use the special
|
||||
`django_stubs_ext.ValuesQuerySet` type.
|
||||
|
||||
For `.values_list`, the second type parameter will be the type of the
|
||||
column.
|
||||
|
||||
```python
|
||||
from django_stubs_ext import ValuesQuerySet
|
||||
|
||||
def get_book_page_counts() -> ValuesQuerySet[Book, int]:
|
||||
return Book.objects.filter().values_list("page_count", flat=True)
|
||||
```
|
||||
|
||||
For `.values`, we prefer to define a `TypedDict` containing the
|
||||
key-value pairs for the columns.
|
||||
|
||||
```python
|
||||
from django_stubs_ext import ValuesQuerySet
|
||||
|
||||
class BookMetadata(TypedDict):
|
||||
id: int
|
||||
name: str
|
||||
|
||||
def get_book_meta_data(
|
||||
book_ids: List[int],
|
||||
) -> ValuesQuerySet[Book, BookMetadata]:
|
||||
return Book.objects.filter(id__in=book_ids).values("name", "id")
|
||||
```
|
||||
|
||||
When writing a helper function ehat returns the response from a test
|
||||
client, it should be typed as `TestHttpResponse` instead of
|
||||
`HttpResponse`. This type is only defined in the Django stubs, so it
|
||||
has to be conditionally imported only when type
|
||||
checking. Conventionally, we alias it as `TestHttpResponse`, which is
|
||||
internally named `_MonkeyPatchedWSGIResponse` within django-stubs.
|
||||
|
||||
```python
|
||||
from typing import TYPE_CHECKING
|
||||
from zerver.lib.test_classes import ZulipTestCase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from django.test.client import _MonkeyPatchedWSGIResponse as TestHttpResponse
|
||||
|
||||
class FooTestCase(ZulipTestCase):
|
||||
def helper(self) -> "TestHttpResponse":
|
||||
return self.client_get("/bar")
|
||||
```
|
||||
|
||||
We sometimes encounter innaccurate type annotations in the Django
|
||||
stubs project. We prefer to address these by [submiting a pull
|
||||
request](https://github.com/typeddjango/django-stubs/pulls) to fix the
|
||||
issue in the upstream project, just like we do with `typeshed` bugs.
|
||||
|
||||
## Using @overload to accurately describe variations
|
||||
|
||||
Sometimes, a function's type is most precisely expressed as a few
|
||||
|
|
Loading…
Reference in New Issue