From ea9b41c0f5659477399da6bbfb7630b8a8493912 Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Sat, 10 Oct 2026 17:22:26 +0200 Subject: [PATCH] fix(abstractions): default the type params of RequestAdapter and ParsableFactory Generated clients annotate request_adapter: RequestAdapter and dict[str, type[ParsableFactory]] without type arguments, which mypy --strict reports wherever the generated code is checked. That's all 141 strict errors in tests/validation, and msgraph-sdk 1.64.0 has about 26,500 such annotations. Give both type parameters a PEP 696 default at the top of their range. ParsableFactory's U_co defaults to its bound, Parsable, and since it's covariant every ParsableFactory[X] still fits the bare name. RequestAdapter's type parameter is only returned by convert_to_native_async, so it becomes covariant and defaults to object; pylint wants the _co suffix, so it's renamed to RequestType_co. HttpxRequestAdapter.send_collection_async now declares ParsableFactory[ModelType] like the method it overrides, since the bare name no longer means Any. TypeVar only takes a default in the stdlib from 3.13, so it comes from typing_extensions, now a declared dependency of abstractions (it was already installed through opentelemetry-api). tests/validation runs with strict = true so CI catches a regression. Part of #722. --- .../kiota_abstractions/request_adapter.py | 12 +++++++----- .../serialization/parsable_factory.py | 6 ++++-- packages/abstractions/pyproject.toml | 1 + .../http/httpx/kiota_http/httpx_request_adapter.py | 2 +- tests/validation/pyproject.toml | 1 + 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/abstractions/kiota_abstractions/request_adapter.py b/packages/abstractions/kiota_abstractions/request_adapter.py index 5fe2eee7..2baae6be 100644 --- a/packages/abstractions/kiota_abstractions/request_adapter.py +++ b/packages/abstractions/kiota_abstractions/request_adapter.py @@ -3,22 +3,24 @@ from abc import ABC, abstractmethod from datetime import date, datetime, time, timedelta from io import BytesIO -from typing import Generic, Optional, TypeVar, Union +from typing import Generic, Optional, Union from uuid import UUID +from typing_extensions import TypeVar + from .request_information import RequestInformation from .serialization import Parsable, ParsableFactory, SerializationWriterFactory from .store import BackingStoreFactory ResponseType = TypeVar("ResponseType") ModelType = TypeVar("ModelType", bound=Parsable) -RequestType = TypeVar("RequestType") +RequestType_co = TypeVar("RequestType_co", covariant=True, default=object) PrimitiveType = TypeVar( "PrimitiveType", bool, str, int, float, UUID, datetime, timedelta, date, time, bytes ) -class RequestAdapter(ABC, Generic[RequestType]): +class RequestAdapter(ABC, Generic[RequestType_co]): """Service responsible for translating abstract Request Info into concrete native HTTP requests. """ # The base url for every request. @@ -143,13 +145,13 @@ def enable_backing_store(self, backing_store_factory: Optional[BackingStoreFacto pass @abstractmethod - async def convert_to_native_async(self, request_info: RequestInformation) -> RequestType: + async def convert_to_native_async(self, request_info: RequestInformation) -> RequestType_co: """Translates the request information object into a native HTTP client request object. Args: request_info (RequestInformation): request information object to be converted. Returns: - RequestType: the natively typed HTTP request of the client. + RequestType_co: the natively typed HTTP request of the client. """ pass diff --git a/packages/abstractions/kiota_abstractions/serialization/parsable_factory.py b/packages/abstractions/kiota_abstractions/serialization/parsable_factory.py index 139883ed..46c891c8 100644 --- a/packages/abstractions/kiota_abstractions/serialization/parsable_factory.py +++ b/packages/abstractions/kiota_abstractions/serialization/parsable_factory.py @@ -1,10 +1,12 @@ from abc import abstractmethod -from typing import Generic, Optional, Protocol, TypeVar +from typing import Generic, Optional, Protocol + +from typing_extensions import TypeVar from .parsable import Parsable from .parse_node import ParseNode -U_co = TypeVar("U_co", bound="Parsable", covariant=True) +U_co = TypeVar("U_co", bound="Parsable", covariant=True, default="Parsable") class ParsableFactory(Protocol, Generic[U_co]): diff --git a/packages/abstractions/pyproject.toml b/packages/abstractions/pyproject.toml index a34d9f87..c4426146 100644 --- a/packages/abstractions/pyproject.toml +++ b/packages/abstractions/pyproject.toml @@ -24,6 +24,7 @@ dependencies = [ "std-uritemplate>=2.0.0", "opentelemetry-api>=1.27.0", "opentelemetry-sdk>=1.27.0", + "typing-extensions>=4.4.0", ] [project.urls] diff --git a/packages/http/httpx/kiota_http/httpx_request_adapter.py b/packages/http/httpx/kiota_http/httpx_request_adapter.py index 27faeb95..01ae080c 100644 --- a/packages/http/httpx/kiota_http/httpx_request_adapter.py +++ b/packages/http/httpx/kiota_http/httpx_request_adapter.py @@ -215,7 +215,7 @@ async def send_async( async def send_collection_async( self, request_info: RequestInformation, - parsable_factory: ParsableFactory, + parsable_factory: ParsableFactory[ModelType], error_map: Optional[dict[str, type[ParsableFactory]]], ) -> Optional[list[ModelType]]: """Excutes the HTTP request specified by the given RequestInformation and returns the diff --git a/tests/validation/pyproject.toml b/tests/validation/pyproject.toml index 62618ffd..2ae742ba 100644 --- a/tests/validation/pyproject.toml +++ b/tests/validation/pyproject.toml @@ -1,5 +1,6 @@ [tool.mypy] warn_unused_configs = true +strict = true files = "validation" [tool.yapf]