diff --git a/packages/abstractions/kiota_abstractions/request_adapter.py b/packages/abstractions/kiota_abstractions/request_adapter.py index 5fe2eee7..985f1b33 100644 --- a/packages/abstractions/kiota_abstractions/request_adapter.py +++ b/packages/abstractions/kiota_abstractions/request_adapter.py @@ -3,9 +3,11 @@ 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 @@ -13,12 +15,13 @@ 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 +146,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 20cdcda7..a30f7a64 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..111b86ff 100644 --- a/packages/http/httpx/kiota_http/httpx_request_adapter.py +++ b/packages/http/httpx/kiota_http/httpx_request_adapter.py @@ -61,7 +61,7 @@ tracer = trace.get_tracer(ObservabilityOptions.get_tracer_instrumentation_name(), VERSION) -class HttpxRequestAdapter(RequestAdapter): +class HttpxRequestAdapter(RequestAdapter[httpx.Request]): CLAIMS_KEY = "claims" BEARER_AUTHENTICATION_SCHEME = "Bearer" RESPONSE_AUTH_HEADER = "WWW-Authenticate" @@ -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/packages/http/httpx/tests/test_typing.py b/packages/http/httpx/tests/test_typing.py new file mode 100644 index 00000000..70319f46 --- /dev/null +++ b/packages/http/httpx/tests/test_typing.py @@ -0,0 +1,15 @@ +from mypy import api + + +def test_httpx_request_adapter_is_a_request_adapter_of_httpx_request(tmp_path): + snippet = tmp_path / "snippet.py" + snippet.write_text( + "import httpx\n" + "from kiota_abstractions.request_adapter import RequestAdapter\n" + "from kiota_http.httpx_request_adapter import HttpxRequestAdapter\n" + "\n" + "def as_httpx_adapter(adapter: HttpxRequestAdapter) -> RequestAdapter[httpx.Request]:\n" + " return adapter\n" + ) + stdout, _, exit_status = api.run(["--follow-imports=silent", str(snippet)]) + assert exit_status == 0, stdout 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]