Opened 4 years ago

Closed 4 years ago

Last modified 2 years ago

#31223 closed New feature (fixed)

Add __class_getitem__ to support runtime type parameters for some classes

Reported by: Sobolev Nikita Owned by: Sobolev Nikita
Component: Utilities Version: dev
Severity: Normal Keywords: types, mypy, django-stubs
Cc: David Foster Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

We (in django-stubs) treat several types as Generics. We provide type parameters to them like so: QuerySet[MyModel]

Currently it is impossible without a monkeypatch from our side, because these classes do not have __class_getitem__ method.
Suggested patch will address this problem for:

  • cached_property
  • Lookup
  • Field
  • QuerySet
  • BaseManager

Implementation detail: __class_getitem__ will be a no-op for django runtime. Since types are only required during mypy check.

django-stubs: https://github.com/typeddjango/django-stubs
monkey-patching: https://github.com/typeddjango/django-stubs/blob/5b3088a17a76a77cb56a9c2241c2ddc6ccc8153a/mypy_django_plugin/django/context.py#L60-L61
Related DEP: https://github.com/django/deps/pull/65

Change History (10)

comment:1 by Ran Benita, 4 years ago

Instead of adding a custom dummy __class_getitem__() implementation, another approach is to actually inherit from typing.Generic. As long as Django doesn't publish its types with a py.typed file, it should not have an effect on type-checking, but it will add the necessary __class_getitem__ at runtime: https://github.com/python/cpython/blob/78c7183f470b60a39ac2dd0ad1a94d49d1e0b062/Lib/typing.py#L876

The reason to do this is that presumably the __class_getitem__ runtime implementation in typing is more correct (certainly seems to do a lot) and more forward compatible than a custom implementation in Django would be.

There might be repercussions I am not considering though, like performance, or side effects of importing typing.

in reply to:  1 comment:2 by Sobolev Nikita, 4 years ago

Replying to Ran Benita:

Yes, this is a best-practice indeed. But.
Inheriting from Generic will also modify __init_subclass__ and __new__ methods. And I am not sure about it.
I guess for now just __class_getitem__ is enough. It has zero possible problems and works for us.

Later (when working on next typing-related things) we would need to return to this question once again.

comment:3 by David Foster, 4 years ago

Cc: David Foster added

comment:4 by David Foster, 4 years ago

Triage Stage: UnreviewedAccepted

Based on one +0 and 2 +1s for this change at https://github.com/django/deps/pull/65 , I'm marking it as Accepted.

comment:5 by David Foster, 4 years ago

PR, by reporter

comment:6 by David Foster, 4 years ago

Has patch: set

comment:7 by Mariusz Felisiak, 4 years ago

Owner: changed from nobody to Sobolev Nikita
Status: newassigned

comment:8 by Carlton Gibson, 4 years ago

Triage Stage: AcceptedReady for checkin

comment:9 by Carlton Gibson <carlton@…>, 4 years ago

Resolution: fixed
Status: assignedclosed

In 578c03b:

Fixed #31223 -- Added class_getitem() to Manager and QuerySet.

comment:10 by GitHub <noreply@…>, 2 years ago

In 0de89b6:

Refs #31223 -- Added class_getitem() to ForeignKey.

Note: See TracTickets for help on using tickets.
Back to Top