Viicos / django-autotyping

Automatically add type hints for Django powered applications.
https://viicos.github.io/django-autotyping/
MIT License
37 stars 0 forks source link

Infer types for admin.display decorated methods #65

Closed CharString closed 3 months ago

CharString commented 5 months ago
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):

  @admin.display(description="foo")
  def foo(self, obj):
      ...
  reveal_type(foo)  # should be (self: Self@MyModelAdmin, obj: MyModel) -> str

I had to annotate obj but this could be generated in a stub. But maybe this belongs upstream in django-stubs.

Viicos commented 5 months ago

But maybe this belongs upstream in django-stubs.

Probably it does. Here is an implementation that could work:

from typing import Any, Callable, TypeVar
from django.db.models import Model

_ModelT = TypeVar("_ModelT", bound=Model)

def display(
    *,
    description: str | None = ...,
) -> Callable[
        [Callable[[admin.ModelAdmin[_ModelT], Any], Any]],  # Input callable, should be more specific
        Callable[[admin.ModelAdmin[_ModelT], _ModelT], Any]  # Output callable
    ]: ...

@admin.register(Appointment)
class MyModelAdmin(admin.ModelAdmin[Appointment]):

    @display(description="foo")
    def foo(self, obj):
        ...

    reveal_type(foo)  # Type of "foo" is "(ModelAdmin[_ModelT@display], _ModelT@display) -> Any"

but doesn't in its current form as it probably needs more work.

I don't really see the use case of having foo typed without annotating obj? (you rarely call the display methods by hand?).

This could be useful with "forward typing" callables (e.g. in TypeScript, you can do: cosnt myCallable: SomeCallableType = (arg1, arg2) => {...} and arg1/arg2 would be implicitly typed w.r.t. SomeCallableType), but this is not possible in Python.

The best thing to do would be to explicitly annotate obj. The display decorator can typecheck if self is compatible with obj (by checking if the solved ModelAdmin type variable is the same). However, this probably requires HK Type Vars

CharString commented 5 months ago

The use case is existing code bases that don't have annotations, and also the explicit annotation could contradict the required, inferable one, which can result in type errors at runtime.

Viicos commented 5 months ago

The use case is existing code bases that don't have annotations

Hum but still, display methods are rarely called explicitly, so having the right type for reveal_type(foo) (i.e. after the display decorator is applied) isn't really of great use.

However:

and also the explicit annotation could contradict the required

Is valuable, and as I said:

The display decorator can typecheck if self is compatible with obj (by checking if the solved ModelAdmin type variable is the same). However, this probably requires HK Type Vars