From dd4647873f52dc1da8476f29734e9a91b6dd1454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=81=81?= Date: Mon, 20 Jul 2026 06:59:54 +0000 Subject: [PATCH 1/3] [python] serialize booleans as lowercase in all parameter styles parameters_to_url_query lowercased a top-level boolean query value, but booleans inside collections went through str() and ended up as True/False on the wire (?flags=True,False). Path, header and form parameters had no boolean handling at all, producing /pets/True style urls. Lowercase them in parameters_to_tuples and in the collection branches of parameters_to_url_query as well. --- .../main/resources/python/api_client.mustache | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python/api_client.mustache b/modules/openapi-generator/src/main/resources/python/api_client.mustache index 71392d82e126..7d8d58f79721 100644 --- a/modules/openapi-generator/src/main/resources/python/api_client.mustache +++ b/modules/openapi-generator/src/main/resources/python/api_client.mustache @@ -646,10 +646,15 @@ https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: + if isinstance(v, bool): + v = str(v).lower() if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend( + (k, str(value).lower() if isinstance(value, bool) else value) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -660,7 +665,9 @@ https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(str(value) for value in v))) + (k, delimiter.join( + str(value).lower() if isinstance(value, bool) else str(value) + for value in v))) else: new_params.append((k, v)) return new_params @@ -686,7 +693,10 @@ https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, quote(str(value))) for value in v) + new_params.extend( + (k, quote(str(value).lower() if isinstance(value, bool) else str(value))) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -697,7 +707,9 @@ https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(quote(str(value)) for value in v)) + (k, delimiter.join( + quote(str(value).lower() if isinstance(value, bool) else str(value)) + for value in v)) ) else: new_params.append((k, quote(str(v)))) From b6b1894877e7c501146db298bd63fbd4b6a9e317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=81=81?= Date: Mon, 20 Jul 2026 06:59:55 +0000 Subject: [PATCH 2/3] update samples --- .../openapi_client/api_client.py | 20 +++++++++++++++---- .../python/openapi_client/api_client.py | 20 +++++++++++++++---- .../legacy_model_dict_client/api_client.py | 20 +++++++++++++++---- .../python-aiohttp/petstore_api/api_client.py | 20 +++++++++++++++---- .../petstore_api/api_client.py | 20 +++++++++++++++---- .../python-httpx/petstore_api/api_client.py | 20 +++++++++++++++---- .../petstore_api/api_client.py | 20 +++++++++++++++---- .../python/petstore_api/api_client.py | 20 +++++++++++++++---- 8 files changed, 128 insertions(+), 32 deletions(-) diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py index 594ec0e5a703..2b8dbc627dab 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py @@ -489,10 +489,15 @@ def parameters_to_tuples(self, params, collection_formats): if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: + if isinstance(v, bool): + v = str(v).lower() if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend( + (k, str(value).lower() if isinstance(value, bool) else value) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -503,7 +508,9 @@ def parameters_to_tuples(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(str(value) for value in v))) + (k, delimiter.join( + str(value).lower() if isinstance(value, bool) else str(value) + for value in v))) else: new_params.append((k, v)) return new_params @@ -529,7 +536,10 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, quote(str(value))) for value in v) + new_params.extend( + (k, quote(str(value).lower() if isinstance(value, bool) else str(value))) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -540,7 +550,9 @@ def parameters_to_url_query(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(quote(str(value)) for value in v)) + (k, delimiter.join( + quote(str(value).lower() if isinstance(value, bool) else str(value)) + for value in v)) ) else: new_params.append((k, quote(str(v)))) diff --git a/samples/client/echo_api/python/openapi_client/api_client.py b/samples/client/echo_api/python/openapi_client/api_client.py index 594ec0e5a703..2b8dbc627dab 100644 --- a/samples/client/echo_api/python/openapi_client/api_client.py +++ b/samples/client/echo_api/python/openapi_client/api_client.py @@ -489,10 +489,15 @@ def parameters_to_tuples(self, params, collection_formats): if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: + if isinstance(v, bool): + v = str(v).lower() if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend( + (k, str(value).lower() if isinstance(value, bool) else value) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -503,7 +508,9 @@ def parameters_to_tuples(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(str(value) for value in v))) + (k, delimiter.join( + str(value).lower() if isinstance(value, bool) else str(value) + for value in v))) else: new_params.append((k, v)) return new_params @@ -529,7 +536,10 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, quote(str(value))) for value in v) + new_params.extend( + (k, quote(str(value).lower() if isinstance(value, bool) else str(value))) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -540,7 +550,9 @@ def parameters_to_url_query(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(quote(str(value)) for value in v)) + (k, delimiter.join( + quote(str(value).lower() if isinstance(value, bool) else str(value)) + for value in v)) ) else: new_params.append((k, quote(str(v)))) diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/api_client.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/api_client.py index 37ab9efc5d92..bf9b93c745f6 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/api_client.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/api_client.py @@ -597,10 +597,15 @@ def parameters_to_tuples(self, params, collection_formats): if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: + if isinstance(v, bool): + v = str(v).lower() if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend( + (k, str(value).lower() if isinstance(value, bool) else value) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -611,7 +616,9 @@ def parameters_to_tuples(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(str(value) for value in v))) + (k, delimiter.join( + str(value).lower() if isinstance(value, bool) else str(value) + for value in v))) else: new_params.append((k, v)) return new_params @@ -637,7 +644,10 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, quote(str(value))) for value in v) + new_params.extend( + (k, quote(str(value).lower() if isinstance(value, bool) else str(value))) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -648,7 +658,9 @@ def parameters_to_url_query(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(quote(str(value)) for value in v)) + (k, delimiter.join( + quote(str(value).lower() if isinstance(value, bool) else str(value)) + for value in v)) ) else: new_params.append((k, quote(str(v)))) diff --git a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py index f90151f6105b..9b4ecfe9b20b 100644 --- a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py @@ -488,10 +488,15 @@ def parameters_to_tuples(self, params, collection_formats): if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: + if isinstance(v, bool): + v = str(v).lower() if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend( + (k, str(value).lower() if isinstance(value, bool) else value) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -502,7 +507,9 @@ def parameters_to_tuples(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(str(value) for value in v))) + (k, delimiter.join( + str(value).lower() if isinstance(value, bool) else str(value) + for value in v))) else: new_params.append((k, v)) return new_params @@ -528,7 +535,10 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, quote(str(value))) for value in v) + new_params.extend( + (k, quote(str(value).lower() if isinstance(value, bool) else str(value))) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -539,7 +549,9 @@ def parameters_to_url_query(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(quote(str(value)) for value in v)) + (k, delimiter.join( + quote(str(value).lower() if isinstance(value, bool) else str(value)) + for value in v)) ) else: new_params.append((k, quote(str(v)))) diff --git a/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/api_client.py b/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/api_client.py index 5fb082d86bc9..8e7f65530e12 100644 --- a/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/api_client.py @@ -491,10 +491,15 @@ def parameters_to_tuples(self, params, collection_formats): if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: + if isinstance(v, bool): + v = str(v).lower() if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend( + (k, str(value).lower() if isinstance(value, bool) else value) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -505,7 +510,9 @@ def parameters_to_tuples(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(str(value) for value in v))) + (k, delimiter.join( + str(value).lower() if isinstance(value, bool) else str(value) + for value in v))) else: new_params.append((k, v)) return new_params @@ -531,7 +538,10 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, quote(str(value))) for value in v) + new_params.extend( + (k, quote(str(value).lower() if isinstance(value, bool) else str(value))) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -542,7 +552,9 @@ def parameters_to_url_query(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(quote(str(value)) for value in v)) + (k, delimiter.join( + quote(str(value).lower() if isinstance(value, bool) else str(value)) + for value in v)) ) else: new_params.append((k, quote(str(v)))) diff --git a/samples/openapi3/client/petstore/python-httpx/petstore_api/api_client.py b/samples/openapi3/client/petstore/python-httpx/petstore_api/api_client.py index 5fb082d86bc9..8e7f65530e12 100644 --- a/samples/openapi3/client/petstore/python-httpx/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python-httpx/petstore_api/api_client.py @@ -491,10 +491,15 @@ def parameters_to_tuples(self, params, collection_formats): if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: + if isinstance(v, bool): + v = str(v).lower() if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend( + (k, str(value).lower() if isinstance(value, bool) else value) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -505,7 +510,9 @@ def parameters_to_tuples(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(str(value) for value in v))) + (k, delimiter.join( + str(value).lower() if isinstance(value, bool) else str(value) + for value in v))) else: new_params.append((k, v)) return new_params @@ -531,7 +538,10 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, quote(str(value))) for value in v) + new_params.extend( + (k, quote(str(value).lower() if isinstance(value, bool) else str(value))) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -542,7 +552,9 @@ def parameters_to_url_query(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(quote(str(value)) for value in v)) + (k, delimiter.join( + quote(str(value).lower() if isinstance(value, bool) else str(value)) + for value in v)) ) else: new_params.append((k, quote(str(v)))) diff --git a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/api_client.py b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/api_client.py index a26ad3c644a2..9e14d8b2debf 100644 --- a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/api_client.py @@ -488,10 +488,15 @@ def parameters_to_tuples(self, params, collection_formats): if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: + if isinstance(v, bool): + v = str(v).lower() if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend( + (k, str(value).lower() if isinstance(value, bool) else value) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -502,7 +507,9 @@ def parameters_to_tuples(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(str(value) for value in v))) + (k, delimiter.join( + str(value).lower() if isinstance(value, bool) else str(value) + for value in v))) else: new_params.append((k, v)) return new_params @@ -528,7 +535,10 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, quote(str(value))) for value in v) + new_params.extend( + (k, quote(str(value).lower() if isinstance(value, bool) else str(value))) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -539,7 +549,9 @@ def parameters_to_url_query(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(quote(str(value)) for value in v)) + (k, delimiter.join( + quote(str(value).lower() if isinstance(value, bool) else str(value)) + for value in v)) ) else: new_params.append((k, quote(str(v)))) diff --git a/samples/openapi3/client/petstore/python/petstore_api/api_client.py b/samples/openapi3/client/petstore/python/petstore_api/api_client.py index 4a91fbc24248..9abc7d7dabfd 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python/petstore_api/api_client.py @@ -488,10 +488,15 @@ def parameters_to_tuples(self, params, collection_formats): if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: + if isinstance(v, bool): + v = str(v).lower() if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend( + (k, str(value).lower() if isinstance(value, bool) else value) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -502,7 +507,9 @@ def parameters_to_tuples(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(str(value) for value in v))) + (k, delimiter.join( + str(value).lower() if isinstance(value, bool) else str(value) + for value in v))) else: new_params.append((k, v)) return new_params @@ -528,7 +535,10 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, quote(str(value))) for value in v) + new_params.extend( + (k, quote(str(value).lower() if isinstance(value, bool) else str(value))) + for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -539,7 +549,9 @@ def parameters_to_url_query(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(quote(str(value)) for value in v)) + (k, delimiter.join( + quote(str(value).lower() if isinstance(value, bool) else str(value)) + for value in v)) ) else: new_params.append((k, quote(str(v)))) From b2e9e746338c7195ed73d94517e919cd8367a536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=81=81?= Date: Mon, 20 Jul 2026 07:29:04 +0000 Subject: [PATCH 3/3] [python] update echo_api header test for lowercase boolean The manual header test asserted the old buggy 'True'; with booleans now serialized as 'true' the echo server reflects 'true'. --- samples/client/echo_api/python/tests/test_manual.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/client/echo_api/python/tests/test_manual.py b/samples/client/echo_api/python/tests/test_manual.py index 8572845b9ab8..b63f5b36dcb1 100644 --- a/samples/client/echo_api/python/tests/test_manual.py +++ b/samples/client/echo_api/python/tests/test_manual.py @@ -61,7 +61,7 @@ def testHeaderParameters(self): e = EchoServerResponseParser(api_response) expected_header = dict( integer_header="123", - boolean_header="True", + boolean_header="true", string_header="string_value", enum_nonref_string_header="success", enum_ref_string_header="failure",