From c99d699d18ddfd6bec852edbbbc7ad0eb6ba40ea Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Thu, 16 Jul 2026 10:11:34 -0700 Subject: [PATCH] fix(typing): give Application.include_router a fully-known signature reportUnknownMemberType fired at every include_router call site because the method's **kwargs and return type were unannotated, so pyright/ basedpyright inferred an "Unknown"-tainted signature for it. The underlying FastAPI.include_router() itself is fully typed, so the leak was entirely in our own wrapper. Type the accepted kwargs with an IncludeRouterOptions TypedDict mirroring FastAPI's own include_router() parameters (mirrors the existing RouterOptions/RouteOptions pattern in fastapi/routers/router.py) and add an explicit "Application[TConfig]" return annotation. Types that require fastapi/starlette are referenced as quoted forward refs, consistent with the rest of this file, so importing fastapi_startkit.application still does not require the fastapi extra to be installed. --- .../src/fastapi_startkit/application.py | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/fastapi_startkit/src/fastapi_startkit/application.py b/fastapi_startkit/src/fastapi_startkit/application.py index 4cd1d14c..5fa23975 100644 --- a/fastapi_startkit/src/fastapi_startkit/application.py +++ b/fastapi_startkit/src/fastapi_startkit/application.py @@ -1,9 +1,12 @@ import os import shlex +from enum import Enum from fastapi_startkit.foundation.app_provider import AppProvider from pathlib import Path from typing import TYPE_CHECKING, Optional -from typing import Type, Callable, Any, List, TypeVar, Generic +from typing import Type, Callable, Any, Dict, List, Sequence, TypeVar, Union, Generic + +from typing_extensions import TypedDict, Unpack from .config import AppConfig from .configuration.providers import ConfigurationProvider @@ -11,8 +14,11 @@ from .environment.environment import Environment if TYPE_CHECKING: - from fastapi import FastAPI, APIRouter + from fastapi import FastAPI, APIRouter, params + from fastapi.routing import APIRoute from starlette.middleware.base import BaseHTTPMiddleware + from starlette.responses import Response + from starlette.routing import BaseRoute from fastapi_startkit.exceptions import ExceptionHandler @@ -24,6 +30,20 @@ def app() -> "Container": TConfig = TypeVar("TConfig", bound=AppConfig) +class IncludeRouterOptions(TypedDict, total=False): + """Keyword arguments accepted by `FastAPI.include_router()`.""" + + prefix: str + tags: Optional[List[Union[str, Enum]]] + dependencies: "Optional[Sequence[params.Depends]]" + responses: Optional[Dict[Union[int, str], Dict[str, Any]]] + deprecated: Optional[bool] + include_in_schema: bool + default_response_class: "Type[Response]" + callbacks: "Optional[List[BaseRoute]]" + generate_unique_id_function: "Callable[[APIRoute], str]" + + class Application(Container, Generic[TConfig]): DEFAULT_PROVIDERS = [ ConfigurationProvider, @@ -142,7 +162,7 @@ def trace(self, path: str, **kwargs) -> Callable: return self._fastapi.trace(path, **kwargs) # Include routers - def include_router(self, router: "APIRouter", **kwargs): + def include_router(self, router: "APIRouter", **kwargs: Unpack[IncludeRouterOptions]) -> "Application[TConfig]": self.fastapi.include_router(router, **kwargs) return self