From 4fd60dbb788f520b0609fd9f7e0df92f760e7ad9 Mon Sep 17 00:00:00 2001 From: Libba Lawrence Date: Fri, 10 Jul 2026 10:10:46 -0700 Subject: [PATCH] fix(http-client-python): honor models-mode=none passed to OptionsDict constructor Route constructor-supplied options through _validate_and_transform so models-mode=none normalizes to falsy False, matching __setitem__. Fixes crash where MsrestModelSerializer entered the model-writing path. Fixes #11046 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- ...-mode-none-constructor-2026-7-10-9-46-0.md | 7 +++++ .../generator/pygen/__init__.py | 5 +++- .../tests/unit/test_options_dict.py | 27 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 .chronus/changes/fix-models-mode-none-constructor-2026-7-10-9-46-0.md create mode 100644 packages/http-client-python/tests/unit/test_options_dict.py diff --git a/.chronus/changes/fix-models-mode-none-constructor-2026-7-10-9-46-0.md b/.chronus/changes/fix-models-mode-none-constructor-2026-7-10-9-46-0.md new file mode 100644 index 00000000000..099a85bb66d --- /dev/null +++ b/.chronus/changes/fix-models-mode-none-constructor-2026-7-10-9-46-0.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-client-python" +--- + +Fix crash when generating with `models-mode=none`. Options passed to the `OptionsDict` constructor are now normalized through the same validation/transform path as `__setitem__`, so `models-mode=none` is correctly treated as falsy and a modelless client is produced instead of crashing. diff --git a/packages/http-client-python/generator/pygen/__init__.py b/packages/http-client-python/generator/pygen/__init__.py index b8841e4fc1a..d09e368dd18 100644 --- a/packages/http-client-python/generator/pygen/__init__.py +++ b/packages/http-client-python/generator/pygen/__init__.py @@ -44,7 +44,10 @@ class OptionsDict(MutableMapping): } def __init__(self, options: Optional[dict[str, Any]] = None) -> None: - self._data = options.copy() if options else {} + self._data = {} + if options: + for key, value in options.items(): + self._data[key] = self._validate_and_transform(key, value) self._validate_combinations() def __getitem__(self, key: str) -> Any: # pylint: disable=too-many-return-statements diff --git a/packages/http-client-python/tests/unit/test_options_dict.py b/packages/http-client-python/tests/unit/test_options_dict.py new file mode 100644 index 00000000000..1fa11d3bd90 --- /dev/null +++ b/packages/http-client-python/tests/unit/test_options_dict.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from pygen import OptionsDict + + +def test_models_mode_none_normalized_via_constructor(): + # models-mode=none must be normalized to falsy False, even when passed + # through the constructor (not just __setitem__). + assert OptionsDict({"models-mode": "none"})["models-mode"] is False + + +def test_models_mode_none_normalized_via_setitem(): + options = OptionsDict() + options["models-mode"] = "none" + assert options["models-mode"] is False + + +def test_constructor_and_setitem_agree(): + via_ctor = OptionsDict({"models-mode": "none"})["models-mode"] + options = OptionsDict() + options["models-mode"] = "none" + via_setitem = options["models-mode"] + assert via_ctor == via_setitem