django-stubs
django-stubs copied to clipboard
Django QuerySet does not implement `__contains__` but Stubs does
What's wrong
Stubs implement __contains__
for QuerySet
but Django does not.
How is that should be
Django does not implement __contains__
for QuerySet
. It relies on the fallback described in the docs at https://docs.python.org/3/reference/expressions.html#membership-test-details. I do not know why this was introduced in https://github.com/typeddjango/django-stubs/pull/33. It is not mentioned there.
class Example:
def __iter__(self):
return self
def __next__(self):
raise StopIteration
print(42 in Example())
This Minimal example proves that this is not necessary to type it that way.
Example
does not implement __contains__
but in
is usable. So 42 in myQuerySet
will work but myQuerySet.__contains__(42)
not, because it is not defined (you can check with dir
).
QuerySet
will be type checked correctly by mypy but will not have the same behavior at Runtime because QuerySet
does not implement __contains__
. A Django QuerySet
is not a container because it does not implement __contains__
as described at
https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes and https://mypy.readthedocs.io/en/stable/protocols.html#container-t. The docs are clear there. No __contains__
no Container
. A static type checker will think that a Django Stubs QuerySet
is a Container
but a runtime type checker will not recognize a Django QuerySet
as a Container. Also, using __contains__(42)
will be allowed by Django Stubs but fail on Django at runtime.
Why __contains__
is not implemented with contains
for QuerySet
in Django, I do not know. But since this project is for typing Django, this is on their site to do. I am planning to open an issue there as well.
System information
- OS:
-
python
: 3.10 -
django
: 4.2.7 -
mypy
: 1.8 -
django-stubs
: 4.2.6 -
django-stubs-ext
: None
PR is welcome!