Skip to content
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

Export types from a plugin as pyi #17315

Closed
last-partizan opened this issue Jun 3, 2024 · 2 comments
Closed

Export types from a plugin as pyi #17315

last-partizan opened this issue Jun 3, 2024 · 2 comments
Labels

Comments

@last-partizan
Copy link

Feature

Add a way to export generated types from a plugin (like mypy_django_plugin) as pyi. So they can be used by other type checkers.

Pitch

Few days ago i started an effort to migrate types from mongo-types into core mongoengine, and i need to solve a problem:

Each field can accept and return either T or T | None, depending on the required property.

In the mongo-types it was solved by adding __new__ overloads for each field, and it works well, but clutters the codebase.
Similar problem exists for Django, and django-stubs are solving this by writing a mypy plugin, that changes __set__ and __get__ descriptors for a field, depending on the init argumens.

Can this type information be exported? For example, for a django app/models.py plugin would generate typings/mypy/app/models.pyi with all the added types. I would run it like mypy export-plugin-types or something similar, when my code changes.

Other options

If there's another way to solve this problem, please help me.

My last attempt looks like this (but it returns BaseField, and not the child class like StringField. And when init arguments are changing, i need to redefine those overloads for a field specifically):

from typing import Literal, Optional, TypeVar, Union, overload

from typing import Any, Callable, Generic

_ST = TypeVar("_ST")
_GT = TypeVar("_GT")

class BaseField(Generic[_ST, _GT]):
    @overload
    def __new__(
        cls,
        *args: Any,
        required: Literal[False] = ...,
        default: None = ...,
        **kwargs: Any,
    ) -> BaseField[Optional[_ST], Optional[_GT]]: ...
    # BaseField()
    @overload
    def __new__(
        cls,
        *args: Any,
        required: Literal[False] = ...,
        default: Union[str, Callable[[], str]],
        **kwargs: Any,
    ) -> BaseField[Optional[_ST], _GT]: ...
    # BaseField(required=False, default="foo")
    @overload
    def __new__(
        cls,
        *args: Any,
        **kwargs: Any,
    ) -> BaseField[_ST, _GT]: ...
    # BaseField(required=True)
    def __set__(self, instance: Any, value: _ST) -> None: ...
    def __get__(self, instance: Any, owner: Any) -> _GT: ...
@Viicos
Copy link
Contributor

Viicos commented Nov 26, 2024

@last-partizan, I did something really similar for django with https://github.com/Viicos/django-autotyping/. The library provides a CLI to dynamically generate django stubs definitions matching your project and you can then configure your type checker to use the generate stubs as a source of truth for types. I don't think such a feature should live in mypy. Generating code can be hard, and there's many ways to do so.

@last-partizan
Copy link
Author

Oh, that looks really promising.

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants