From 9b813a65d9e7d33488ac098c39e82161f1ab40c1 Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Thu, 15 Oct 2026 19:12:57 +0200 Subject: [PATCH] fix(http): pass mypy --strict in middleware options and fix three option bugs Add the missing return types in kiota_http.middleware.options. Part of #722. UserAgentHandlerOption.is_enabled set self._value, so setting it to False did nothing. It now sets self._enabled. UrlReplaceHandlerOption and ParametersNameDecodingHandlerOption used a dict and a list as default arguments. Python builds those once, so every option made with the default shared them, and a change to one showed up in all of them. The defaults are None now, and each option gets its own dict or list. --- .../parameters_name_decoding_handler_option.py | 16 ++++++++++------ .../options/redirect_handler_option.py | 14 +++++++------- .../options/response_handler_option.py | 4 ++-- .../middleware/options/retry_handler_option.py | 2 +- .../options/telemetry_handler_option.py | 2 +- .../middleware/options/url_replace_option.py | 16 ++++++++++------ .../options/user_agent_handler_option.py | 14 +++++++------- .../test_parameters_name_decoding_handler.py | 5 +++++ .../middleware_tests/test_url_replace_handler.py | 5 +++++ .../middleware_tests/test_user_agent_handler.py | 6 ++++++ 10 files changed, 54 insertions(+), 30 deletions(-) diff --git a/packages/http/httpx/kiota_http/middleware/options/parameters_name_decoding_handler_option.py b/packages/http/httpx/kiota_http/middleware/options/parameters_name_decoding_handler_option.py index 9d2624b4..dc7921f2 100644 --- a/packages/http/httpx/kiota_http/middleware/options/parameters_name_decoding_handler_option.py +++ b/packages/http/httpx/kiota_http/middleware/options/parameters_name_decoding_handler_option.py @@ -1,3 +1,5 @@ +from typing import Optional + from kiota_abstractions.request_option import RequestOption @@ -8,7 +10,7 @@ class ParametersNameDecodingHandlerOption(RequestOption): PARAMETERS_NAME_DECODING_HANDLER_OPTION_KEY = "ParametersNameDecodingHandlerOption" def __init__( - self, enable: bool = True, characters_to_decode: list[str] = [".", "-", "~", "$"] + self, enable: bool = True, characters_to_decode: Optional[list[str]] = None ) -> None: """To create an instance of ParametersNameDecodingHandlerOptions @@ -19,25 +21,27 @@ def __init__( Defaults to [".", "-", "~", "$"]. """ self._enable = enable - self._characters_to_decode = characters_to_decode + self._characters_to_decode = ( + [".", "-", "~", "$"] if characters_to_decode is None else characters_to_decode + ) @property - def enabled(self): + def enabled(self) -> bool: """Whether to decode the specified characters in the request query parameters""" return self._enable @enabled.setter - def enabled(self, value: bool): + def enabled(self, value: bool) -> None: self._enable = value @property - def characters_to_decode(self): + def characters_to_decode(self) -> list[str]: """The list of characters to decode in the request query parameters names before executing the request""" return self._characters_to_decode @characters_to_decode.setter - def characters_to_decode(self, value: list[str]): + def characters_to_decode(self, value: list[str]) -> None: self._characters_to_decode = value @staticmethod diff --git a/packages/http/httpx/kiota_http/middleware/options/redirect_handler_option.py b/packages/http/httpx/kiota_http/middleware/options/redirect_handler_option.py index 3d619b19..0fe18c91 100644 --- a/packages/http/httpx/kiota_http/middleware/options/redirect_handler_option.py +++ b/packages/http/httpx/kiota_http/middleware/options/redirect_handler_option.py @@ -69,33 +69,33 @@ def __init__( self._scrub_sensitive_headers = scrub_sensitive_headers or default_scrub_sensitive_headers @property - def max_redirect(self): + def max_redirect(self) -> int: """The maximum number of redirects with a maximum value of 20. This defaults to 5 redirects.""" return self._max_redirect @max_redirect.setter - def max_redirect(self, value: int): + def max_redirect(self, value: int) -> None: if value > self.MAX_MAX_REDIRECT: raise ValueError("MaxLimitExceeded. Maximum value for max_redirect property exceeded") self._max_redirect = value @property - def should_redirect(self): + def should_redirect(self) -> bool: return self._should_redirect @should_redirect.setter - def should_redirect(self, value: bool): + def should_redirect(self, value: bool) -> None: self._should_redirect = value @property - def allow_redirect_on_scheme_change(self): + def allow_redirect_on_scheme_change(self) -> bool: """A boolean value to determine if we redirects are allowed if the scheme changes (e.g. https to http). Defaults to false.""" return self._allow_redirect_on_scheme_change @allow_redirect_on_scheme_change.setter - def allow_redirect_on_scheme_change(self, value: bool): + def allow_redirect_on_scheme_change(self, value: bool) -> None: self._allow_redirect_on_scheme_change = value @property @@ -105,7 +105,7 @@ def scrub_sensitive_headers(self) -> ScrubSensitiveHeadersCallback: return self._scrub_sensitive_headers @scrub_sensitive_headers.setter - def scrub_sensitive_headers(self, value: ScrubSensitiveHeadersCallback): + def scrub_sensitive_headers(self, value: ScrubSensitiveHeadersCallback) -> None: self._scrub_sensitive_headers = value @staticmethod diff --git a/packages/http/httpx/kiota_http/middleware/options/response_handler_option.py b/packages/http/httpx/kiota_http/middleware/options/response_handler_option.py index dd8796b8..35f91764 100644 --- a/packages/http/httpx/kiota_http/middleware/options/response_handler_option.py +++ b/packages/http/httpx/kiota_http/middleware/options/response_handler_option.py @@ -18,10 +18,10 @@ def __init__(self, response_handler: Union[ResponseHandler, None] = None) -> Non self._response_handler = response_handler @property - def response_handler(self): + def response_handler(self) -> Union[ResponseHandler, None]: """Property to return the response handler instance""" return self._response_handler @staticmethod - def get_key(): + def get_key() -> str: return ResponseHandlerOption.RESPONSE_HANDLER_OPTION_KEY diff --git a/packages/http/httpx/kiota_http/middleware/options/retry_handler_option.py b/packages/http/httpx/kiota_http/middleware/options/retry_handler_option.py index 80cf5f39..35b06fb0 100644 --- a/packages/http/httpx/kiota_http/middleware/options/retry_handler_option.py +++ b/packages/http/httpx/kiota_http/middleware/options/retry_handler_option.py @@ -94,5 +94,5 @@ def should_retry(self, value: bool) -> None: self._should_retry = value @staticmethod - def get_key(): + def get_key() -> str: return RetryHandlerOption.RETRY_HANDLER_OPTION_KEY diff --git a/packages/http/httpx/kiota_http/middleware/options/telemetry_handler_option.py b/packages/http/httpx/kiota_http/middleware/options/telemetry_handler_option.py index 7f4d57e4..33395724 100644 --- a/packages/http/httpx/kiota_http/middleware/options/telemetry_handler_option.py +++ b/packages/http/httpx/kiota_http/middleware/options/telemetry_handler_option.py @@ -19,5 +19,5 @@ def telemetry_configurator(self, value: Callable[[], None]) -> None: self._telemetry_configurator = value @staticmethod - def get_key(): + def get_key() -> str: return TelemetryHandlerOption.TELEMETRY_HANDLER_OPTION_KEY diff --git a/packages/http/httpx/kiota_http/middleware/options/url_replace_option.py b/packages/http/httpx/kiota_http/middleware/options/url_replace_option.py index fd47ae2d..501ebd16 100644 --- a/packages/http/httpx/kiota_http/middleware/options/url_replace_option.py +++ b/packages/http/httpx/kiota_http/middleware/options/url_replace_option.py @@ -1,3 +1,5 @@ +from typing import Optional + from kiota_abstractions.request_option import RequestOption @@ -7,7 +9,9 @@ class UrlReplaceHandlerOption(RequestOption): URL_REPLACE_HANDLER_OPTION_KEY = "UrlReplaceHandlerOption" - def __init__(self, enabled: bool = True, replacement_pairs: dict[str, str] = {}) -> None: + def __init__( + self, enabled: bool = True, replacement_pairs: Optional[dict[str, str]] = None + ) -> None: """Creates an instance of url replace option. Args: @@ -17,24 +21,24 @@ def __init__(self, enabled: bool = True, replacement_pairs: dict[str, str] = {}) to replace. Defaults to {}. """ self._enabled = enabled - self._replacement_pairs = replacement_pairs + self._replacement_pairs = {} if replacement_pairs is None else replacement_pairs @property - def is_enabled(self): + def is_enabled(self) -> bool: """Whether the url replace handler is enabled.""" return self._enabled @is_enabled.setter - def is_enabled(self, value: bool): + def is_enabled(self, value: bool) -> None: self._enabled = value @property - def replacement_pairs(self): + def replacement_pairs(self) -> dict[str, str]: """The key value pairs to replace""" return self._replacement_pairs @replacement_pairs.setter - def replacement_pairs(self, value: dict[str, str]): + def replacement_pairs(self, value: dict[str, str]) -> None: self._replacement_pairs = value @staticmethod diff --git a/packages/http/httpx/kiota_http/middleware/options/user_agent_handler_option.py b/packages/http/httpx/kiota_http/middleware/options/user_agent_handler_option.py index 7a023c29..186d4ac0 100644 --- a/packages/http/httpx/kiota_http/middleware/options/user_agent_handler_option.py +++ b/packages/http/httpx/kiota_http/middleware/options/user_agent_handler_option.py @@ -21,34 +21,34 @@ def __init__( self._product_version = product_version @property - def is_enabled(self): + def is_enabled(self) -> bool: """Returns True if the option is allowed.""" return self._enabled @is_enabled.setter - def is_enabled(self, value: bool): + def is_enabled(self, value: bool) -> None: """Sets the option enabled value.""" - self._value = value + self._enabled = value @property - def product_name(self): + def product_name(self) -> str: """Returns kiota-python if the name is not supplied.""" return self._product_name @product_name.setter - def product_name(self, value: str): + def product_name(self, value: str) -> None: """Sets the product name value.""" if not value: raise ValueError("product_name cannot be empty.") self._product_name = value @property - def product_version(self): + def product_version(self) -> str: """Returns VERSION valuerif the name is not supplied.""" return self._product_version @product_version.setter - def product_version(self, value: str): + def product_version(self, value: str) -> None: """Sets the product version value.""" if not value: raise ValueError("product_version cannot be empty.") diff --git a/packages/http/httpx/tests/middleware_tests/test_parameters_name_decoding_handler.py b/packages/http/httpx/tests/middleware_tests/test_parameters_name_decoding_handler.py index 54943d05..88b6d2fe 100644 --- a/packages/http/httpx/tests/middleware_tests/test_parameters_name_decoding_handler.py +++ b/packages/http/httpx/tests/middleware_tests/test_parameters_name_decoding_handler.py @@ -75,3 +75,8 @@ def request_handler(request: httpx.Request): mock_transport = httpx.MockTransport(request_handler) resp = await handler.send(request, mock_transport) assert str(resp.request.url).casefold() == decoded.casefold() + + +def test_default_characters_to_decode_are_not_shared(): + ParametersNameDecodingHandlerOption().characters_to_decode.append("+") + assert ParametersNameDecodingHandlerOption().characters_to_decode == [".", "-", "~", "$"] diff --git a/packages/http/httpx/tests/middleware_tests/test_url_replace_handler.py b/packages/http/httpx/tests/middleware_tests/test_url_replace_handler.py index 8b635117..d6c17186 100644 --- a/packages/http/httpx/tests/middleware_tests/test_url_replace_handler.py +++ b/packages/http/httpx/tests/middleware_tests/test_url_replace_handler.py @@ -48,3 +48,8 @@ def test_replace_url_segment(): assert handler.options.replacement_pairs assert handler.options.get_key() == "UrlReplaceHandlerOption" assert handler.replace_url_segment(ORIGINAL_URL, handler.options) == REPLACED_URL + + +def test_default_replacement_pairs_are_not_shared(): + UrlReplaceHandlerOption().replacement_pairs["/users/user-id-to-replace"] = "/me" + assert UrlReplaceHandlerOption().replacement_pairs == {} diff --git a/packages/http/httpx/tests/middleware_tests/test_user_agent_handler.py b/packages/http/httpx/tests/middleware_tests/test_user_agent_handler.py index c2f0e477..7a4c731d 100644 --- a/packages/http/httpx/tests/middleware_tests/test_user_agent_handler.py +++ b/packages/http/httpx/tests/middleware_tests/test_user_agent_handler.py @@ -21,3 +21,9 @@ def test_custom_config(): options = UserAgentHandlerOption(enabled=False) assert not options.is_enabled + + +def test_is_enabled_setter(): + options = UserAgentHandlerOption() + options.is_enabled = False + assert not options.is_enabled