from typing import Type, Optional, Self, override from rest_framework.viewsets import ViewSetMixin # type: ignore from rest_framework.routers import DefaultRouter # type: ignore class TypedRouter(DefaultRouter): """ A subclass of DRF's `rest_framework.routers.DefaultRouter` that adds proper static type annotations to certain methods — particularly the `register` method. This resolves issues with static analysis tools such as MyPy and Pyright, which normally raise warnings or require `# type: ignore` comments due to the original method's lack of strict typing. Benefits: - Eliminates the need to use `# type: ignore` when calling `.register(...)` - Improves type safety by enforcing that only subclasses of `ViewSetMixin` are passed - Enhances developer experience (DX) in statically typed projects - Promotes DRY principles by reducing repetitive ignores across the codebase This class does not modify any runtime behavior of `DefaultRouter`. It is purely a DX and tooling improvement for typed Python projects using Django REST Framework (DRF). Example: from my_project.routers import TypedRouter from my_app.api import UserViewSet router = TypedRouter() router.register("users", UserViewSet, basename="user") """ @override def register( # type: ignore self, prefix: str, viewset: Type[ViewSetMixin], basename: Optional[str] = None, **kwargs: object ) -> Self: """ Registers a viewset with a given URL prefix and optional basename, with proper type hints to improve static analysis (e.g., with MyPy or Pyright) when using DRF's DefaultRouter. This method overrides `DefaultRouter.register()` to annotate the expected `viewset` type as a subclass of `ViewSetMixin`, which reflects how DRF expects viewsets to behave. Useful for eliminating `# type: ignore` comments and improving autocompletion. See also: - DRF Router documentation: https://www.django-rest-framework.org/api-guide/routers/ """ super().register(prefix=prefix, viewset=viewset, basename=basename, **kwargs) # type: ignore return self