-
-
Notifications
You must be signed in to change notification settings - Fork 450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: Use PEP 696 defaults for fields #1264
Comments
I think we don't necessarily have to wait for acceptance of the PEP. As long as it's implemented in Once PEP 696 is implemented in mypy itself (python/mypy#14851), maybe we can get rid of this logic in the mypy plugin? Native type constructs tend to be less fragile and better supported in general. |
Thanks for the comment. Generally I would like django-stubs to be a bit more useful for tools like Pyright by default without making life harder for people who benefit from the mypy plugin. |
Would this also provide the ability to have generic fields? For example: class CharField(Field[_ST, _GT]):
_pyi_private_set_type: _ST
_pyi_private_get_type: _GT My use-case: I have a custom field class (a subclass of |
My current approach for custom fields is to cast them like e.g. class SomeModel(models.Model):
currency = cast(
"models.CharField[Currency, Currency]",
CurrencyField(default=None, verbose_name=_("currency")),
) It gets quite verbose though, but at least it works. |
One issue with this is taking into account class Field(Generic[_ST, _GT]):
@overload
def __new__(
cls,
*,
null: Literal[True],
) -> Field[_ST | None, _GT | None]: ...
@overload
def __new__(
cls,
*,
null: Literal[False] = ...,
) -> Field[_ST, _GT]: ... Then field subclasses can be written as: class IntegerField(Field[float | int | str | Combinable, int]):
... Working as expected: from typing import Generic, TypeVar, Literal, overload
_ST = TypeVar("_ST")
_GT = TypeVar("_GT")
class Field(Generic[_ST, _GT]):
@overload
def __new__(
cls,
*,
null: Literal[True],
) -> Field[_ST | None, _GT | None]: ...
@overload
def __new__(
cls,
*,
null: Literal[False] = ...,
) -> Field[_ST, _GT]: ...
def get_type(self) -> _GT: ...
def set_type(self) -> _ST: ...
class IntegerField(Field[float | int | str, int]):
pass
a = IntegerField(null=False)
reveal_type(a.get_type()) # Type of "a.get()" is "int" + None if null=True
reveal_type(a.set_type()) # Type of "a.set()" is "float | int | str" + None if null=True However, this requires two overloads each time a field is defined with a new signature ( Edit: see https://discuss.python.org/t/41483, this is in fact not really possible. |
NOTE: This feature can't be worked on unless PEP 696 is accepted, but given its inclusion in typing_extensions I'd say it's likely it will be.
django-stubs
uses set and get value generic types for fields, defined like so:Specific field types use special attributes that the mypy plugin for django-stubs reads to fill in the get and set types with.
This works for
mypy
, but not for other type checkers, where the generic parameters need to be written manually. To better support different type checkers, we could use the default values from PEP 696 instead.The mypy plugin could read the default values instead of the
_pyi_private*
attributes from before. For other type checkers, the instance values for__get__
and__set__
will then use the generic type defaults if not specified otherwise.The text was updated successfully, but these errors were encountered: