From 626e85f18240adceeddf3c647a4af45703d5b254 Mon Sep 17 00:00:00 2001 From: Marcel Konrad Date: Wed, 10 Jun 2026 16:34:52 +0200 Subject: [PATCH 1/3] Account for content-type parameters on request preparation --- .../src/main/resources/python/rest.mustache | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python/rest.mustache b/modules/openapi-generator/src/main/resources/python/rest.mustache index 20176e7140f1..f6fcec62dfa5 100644 --- a/modules/openapi-generator/src/main/resources/python/rest.mustache +++ b/modules/openapi-generator/src/main/resources/python/rest.mustache @@ -108,6 +108,10 @@ class RESTClientObject: else: self.pool_manager = urllib3.PoolManager(**pool_args) + def _contenttype_matches(contenttype, maintype, subtype): + pattern = '{type}/(?:[^+;]+\\+)?{subtype}(?:;.*)?'.format(type = re.escape(maintype), subtype = re.escape(subtype)) + return re.fullmatch(pattern, contenttype, re.IGNORECASE) is not None + def request( self, method, @@ -171,7 +175,7 @@ class RESTClientObject: content_type = headers.get('Content-Type') if ( not content_type - or re.search('json', content_type, re.IGNORECASE) + or _contenttype_matches(content_type, 'application', 'json') ): request_body = None if body is not None: @@ -184,7 +188,7 @@ class RESTClientObject: headers=headers, preload_content=False ) - elif content_type == 'application/x-www-form-urlencoded': + elif _contenttype_matches(content_type, 'application', 'x-www-form-urlencoded'): r = self.pool_manager.request( method, url, @@ -194,7 +198,7 @@ class RESTClientObject: headers=headers, preload_content=False ) - elif content_type == 'multipart/form-data': + elif _contenttype_matches(content_type, 'multipart', 'form-data'): # must del headers['Content-Type'], or the correct # Content-Type which generated by urllib3 will be # overwritten. @@ -222,7 +226,7 @@ class RESTClientObject: headers=headers, preload_content=False ) - elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): + elif content_type.startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, From d1c47a50ba71beeacd9864446e694a1a215b4deb Mon Sep 17 00:00:00 2001 From: Marcel Konrad Date: Thu, 11 Jun 2026 10:58:47 +0200 Subject: [PATCH 2/3] Move helper method to outer scope --- .../src/main/resources/python/rest.mustache | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python/rest.mustache b/modules/openapi-generator/src/main/resources/python/rest.mustache index f6fcec62dfa5..99ceb3a2f5eb 100644 --- a/modules/openapi-generator/src/main/resources/python/rest.mustache +++ b/modules/openapi-generator/src/main/resources/python/rest.mustache @@ -25,6 +25,9 @@ def is_socks_proxy_url(url): else: return split_section[0].lower() in SUPPORTED_SOCKS_PROXIES +def contenttype_matches(contenttype, maintype, subtype): + pattern = '{type}/(?:[^+;]+\\+)?{subtype}(?:;.*)?'.format(type = re.escape(maintype), subtype = re.escape(subtype)) + return re.fullmatch(pattern, contenttype, re.IGNORECASE) is not None class RESTResponse(io.IOBase): @@ -108,10 +111,6 @@ class RESTClientObject: else: self.pool_manager = urllib3.PoolManager(**pool_args) - def _contenttype_matches(contenttype, maintype, subtype): - pattern = '{type}/(?:[^+;]+\\+)?{subtype}(?:;.*)?'.format(type = re.escape(maintype), subtype = re.escape(subtype)) - return re.fullmatch(pattern, contenttype, re.IGNORECASE) is not None - def request( self, method, @@ -175,7 +174,7 @@ class RESTClientObject: content_type = headers.get('Content-Type') if ( not content_type - or _contenttype_matches(content_type, 'application', 'json') + or contenttype_matches(content_type, 'application', 'json') ): request_body = None if body is not None: @@ -188,7 +187,7 @@ class RESTClientObject: headers=headers, preload_content=False ) - elif _contenttype_matches(content_type, 'application', 'x-www-form-urlencoded'): + elif contenttype_matches(content_type, 'application', 'x-www-form-urlencoded'): r = self.pool_manager.request( method, url, @@ -198,7 +197,7 @@ class RESTClientObject: headers=headers, preload_content=False ) - elif _contenttype_matches(content_type, 'multipart', 'form-data'): + elif contenttype_matches(content_type, 'multipart', 'form-data'): # must del headers['Content-Type'], or the correct # Content-Type which generated by urllib3 will be # overwritten. From 9485a6d266b4007d12633bbca61add543d0a681d Mon Sep 17 00:00:00 2001 From: Marcel Konrad Date: Thu, 11 Jun 2026 11:02:26 +0200 Subject: [PATCH 3/3] Update examples --- .../openapi_client/rest.py | 11 +++++++---- samples/client/echo_api/python/openapi_client/rest.py | 11 +++++++---- .../petstore/python-lazyImports/petstore_api/rest.py | 11 +++++++---- .../client/petstore/python/petstore_api/rest.py | 11 +++++++---- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/rest.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/rest.py index 4375566a583b..e69a1b10b6c5 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/rest.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/rest.py @@ -35,6 +35,9 @@ def is_socks_proxy_url(url): else: return split_section[0].lower() in SUPPORTED_SOCKS_PROXIES +def contenttype_matches(contenttype, maintype, subtype): + pattern = '{type}/(?:[^+;]+\\+)?{subtype}(?:;.*)?'.format(type = re.escape(maintype), subtype = re.escape(subtype)) + return re.fullmatch(pattern, contenttype, re.IGNORECASE) is not None class RESTResponse(io.IOBase): @@ -181,7 +184,7 @@ def request( content_type = headers.get('Content-Type') if ( not content_type - or re.search('json', content_type, re.IGNORECASE) + or contenttype_matches(content_type, 'application', 'json') ): request_body = None if body is not None: @@ -194,7 +197,7 @@ def request( headers=headers, preload_content=False ) - elif content_type == 'application/x-www-form-urlencoded': + elif contenttype_matches(content_type, 'application', 'x-www-form-urlencoded'): r = self.pool_manager.request( method, url, @@ -204,7 +207,7 @@ def request( headers=headers, preload_content=False ) - elif content_type == 'multipart/form-data': + elif contenttype_matches(content_type, 'multipart', 'form-data'): # must del headers['Content-Type'], or the correct # Content-Type which generated by urllib3 will be # overwritten. @@ -232,7 +235,7 @@ def request( headers=headers, preload_content=False ) - elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): + elif content_type.startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/samples/client/echo_api/python/openapi_client/rest.py b/samples/client/echo_api/python/openapi_client/rest.py index 7f61c8fe4ab0..29171aca8c37 100644 --- a/samples/client/echo_api/python/openapi_client/rest.py +++ b/samples/client/echo_api/python/openapi_client/rest.py @@ -35,6 +35,9 @@ def is_socks_proxy_url(url): else: return split_section[0].lower() in SUPPORTED_SOCKS_PROXIES +def contenttype_matches(contenttype, maintype, subtype): + pattern = '{type}/(?:[^+;]+\\+)?{subtype}(?:;.*)?'.format(type = re.escape(maintype), subtype = re.escape(subtype)) + return re.fullmatch(pattern, contenttype, re.IGNORECASE) is not None class RESTResponse(io.IOBase): @@ -181,7 +184,7 @@ def request( content_type = headers.get('Content-Type') if ( not content_type - or re.search('json', content_type, re.IGNORECASE) + or contenttype_matches(content_type, 'application', 'json') ): request_body = None if body is not None: @@ -194,7 +197,7 @@ def request( headers=headers, preload_content=False ) - elif content_type == 'application/x-www-form-urlencoded': + elif contenttype_matches(content_type, 'application', 'x-www-form-urlencoded'): r = self.pool_manager.request( method, url, @@ -204,7 +207,7 @@ def request( headers=headers, preload_content=False ) - elif content_type == 'multipart/form-data': + elif contenttype_matches(content_type, 'multipart', 'form-data'): # must del headers['Content-Type'], or the correct # Content-Type which generated by urllib3 will be # overwritten. @@ -232,7 +235,7 @@ def request( headers=headers, preload_content=False ) - elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): + elif content_type.startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/rest.py b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/rest.py index 29ce7d04029a..71b21b952ff6 100644 --- a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/rest.py +++ b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/rest.py @@ -34,6 +34,9 @@ def is_socks_proxy_url(url): else: return split_section[0].lower() in SUPPORTED_SOCKS_PROXIES +def contenttype_matches(contenttype, maintype, subtype): + pattern = '{type}/(?:[^+;]+\\+)?{subtype}(?:;.*)?'.format(type = re.escape(maintype), subtype = re.escape(subtype)) + return re.fullmatch(pattern, contenttype, re.IGNORECASE) is not None class RESTResponse(io.IOBase): @@ -180,7 +183,7 @@ def request( content_type = headers.get('Content-Type') if ( not content_type - or re.search('json', content_type, re.IGNORECASE) + or contenttype_matches(content_type, 'application', 'json') ): request_body = None if body is not None: @@ -193,7 +196,7 @@ def request( headers=headers, preload_content=False ) - elif content_type == 'application/x-www-form-urlencoded': + elif contenttype_matches(content_type, 'application', 'x-www-form-urlencoded'): r = self.pool_manager.request( method, url, @@ -203,7 +206,7 @@ def request( headers=headers, preload_content=False ) - elif content_type == 'multipart/form-data': + elif contenttype_matches(content_type, 'multipart', 'form-data'): # must del headers['Content-Type'], or the correct # Content-Type which generated by urllib3 will be # overwritten. @@ -231,7 +234,7 @@ def request( headers=headers, preload_content=False ) - elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): + elif content_type.startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/samples/openapi3/client/petstore/python/petstore_api/rest.py b/samples/openapi3/client/petstore/python/petstore_api/rest.py index 29ce7d04029a..71b21b952ff6 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/rest.py +++ b/samples/openapi3/client/petstore/python/petstore_api/rest.py @@ -34,6 +34,9 @@ def is_socks_proxy_url(url): else: return split_section[0].lower() in SUPPORTED_SOCKS_PROXIES +def contenttype_matches(contenttype, maintype, subtype): + pattern = '{type}/(?:[^+;]+\\+)?{subtype}(?:;.*)?'.format(type = re.escape(maintype), subtype = re.escape(subtype)) + return re.fullmatch(pattern, contenttype, re.IGNORECASE) is not None class RESTResponse(io.IOBase): @@ -180,7 +183,7 @@ def request( content_type = headers.get('Content-Type') if ( not content_type - or re.search('json', content_type, re.IGNORECASE) + or contenttype_matches(content_type, 'application', 'json') ): request_body = None if body is not None: @@ -193,7 +196,7 @@ def request( headers=headers, preload_content=False ) - elif content_type == 'application/x-www-form-urlencoded': + elif contenttype_matches(content_type, 'application', 'x-www-form-urlencoded'): r = self.pool_manager.request( method, url, @@ -203,7 +206,7 @@ def request( headers=headers, preload_content=False ) - elif content_type == 'multipart/form-data': + elif contenttype_matches(content_type, 'multipart', 'form-data'): # must del headers['Content-Type'], or the correct # Content-Type which generated by urllib3 will be # overwritten. @@ -231,7 +234,7 @@ def request( headers=headers, preload_content=False ) - elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): + elif content_type.startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method,