From 478288fbd56a259e3775ee5067ab9979500e4379 Mon Sep 17 00:00:00 2001 From: emmanuel-adu Date: Fri, 31 Jul 2026 07:37:04 -0700 Subject: [PATCH 1/3] feat(python): support proxy_ssl_context for the urllib3-based client Adds an optional Configuration.proxy_ssl_context so callers can supply a distinct SSL context for the TLS handshake with an HTTPS proxy, separate from the destination (API server) TLS settings, per urllib3's proxy_ssl_context support. Defaults to None (no behavior change). Applies to the python (urllib3 library) and python-pydantic-v1 generators. Not applicable to the SOCKS proxy path (no TLS handshake with a SOCKS proxy) or to the aiohttp-based async client (does not use urllib3's ProxyManager). --- .../python-pydantic-v1/configuration.mustache | 5 +++++ .../resources/python-pydantic-v1/rest.mustache | 2 ++ .../main/resources/python/configuration.mustache | 14 ++++++++++++++ .../src/main/resources/python/rest.mustache | 2 ++ .../openapi_client/configuration.py | 8 ++++++++ .../openapi_client/rest.py | 2 ++ .../openapi_client/configuration.py | 5 +++++ .../python-pydantic-v1/openapi_client/rest.py | 2 ++ .../python/openapi_client/configuration.py | 8 ++++++++ .../client/echo_api/python/openapi_client/rest.py | 2 ++ .../legacy_model_dict_client/configuration.py | 8 ++++++++ .../legacy_model_dict_client/rest.py | 2 ++ .../petstore_api/configuration.py | 8 ++++++++ .../python-lazyImports/petstore_api/rest.py | 2 ++ .../petstore_api/configuration.py | 5 +++++ .../petstore_api/configuration.py | 5 +++++ .../python-pydantic-v1/petstore_api/rest.py | 2 ++ .../petstore/python/petstore_api/configuration.py | 8 ++++++++ .../client/petstore/python/petstore_api/rest.py | 2 ++ 19 files changed, 92 insertions(+) diff --git a/modules/openapi-generator/src/main/resources/python-pydantic-v1/configuration.mustache b/modules/openapi-generator/src/main/resources/python-pydantic-v1/configuration.mustache index b69d90153301..45a9c84aea5e 100644 --- a/modules/openapi-generator/src/main/resources/python-pydantic-v1/configuration.mustache +++ b/modules/openapi-generator/src/main/resources/python-pydantic-v1/configuration.mustache @@ -259,6 +259,11 @@ conf = {{{packageName}}}.Configuration( self.proxy_headers = None """Proxy headers """ + self.proxy_ssl_context = None + """SSL context used only for the TLS handshake with the proxy itself + (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS + settings above. + """ self.safe_chars_for_path_param = '' """Safe chars for path_param """ diff --git a/modules/openapi-generator/src/main/resources/python-pydantic-v1/rest.mustache b/modules/openapi-generator/src/main/resources/python-pydantic-v1/rest.mustache index f02f28cf2128..9ec8e7d4f549 100644 --- a/modules/openapi-generator/src/main/resources/python-pydantic-v1/rest.mustache +++ b/modules/openapi-generator/src/main/resources/python-pydantic-v1/rest.mustache @@ -96,6 +96,8 @@ class RESTClientObject: **addition_pool_args ) else: + if configuration.proxy_ssl_context is not None: + addition_pool_args['proxy_ssl_context'] = configuration.proxy_ssl_context self.pool_manager = urllib3.ProxyManager( num_pools=pools_size, maxsize=maxsize, diff --git a/modules/openapi-generator/src/main/resources/python/configuration.mustache b/modules/openapi-generator/src/main/resources/python/configuration.mustache index db0afd15517c..a8aab8e2f9ab 100644 --- a/modules/openapi-generator/src/main/resources/python/configuration.mustache +++ b/modules/openapi-generator/src/main/resources/python/configuration.mustache @@ -13,6 +13,7 @@ import logging from logging import FileHandler {{^async}} import multiprocessing +import ssl {{/async}} import sys from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union @@ -227,6 +228,9 @@ class Configuration: :param no_proxy: Comma-separated hosts that bypass the proxy. {{/async}} :param proxy_headers: Proxy headers. +{{^async}} + :param proxy_ssl_context: SSL context used only for the TLS handshake with the proxy itself, independent of the destination TLS settings. +{{/async}} :param safe_chars_for_path_param: Safe characters for path parameter encoding. :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. @@ -361,6 +365,9 @@ conf = {{{packageName}}}.Configuration( no_proxy: Optional[str]=None, {{/async}} proxy_headers: Optional[Any]=None, +{{^async}} + proxy_ssl_context: Optional[ssl.SSLContext]=None, +{{/async}} safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, @@ -505,6 +512,13 @@ conf = {{{packageName}}}.Configuration( self.proxy_headers = proxy_headers """Proxy headers """ +{{^async}} + self.proxy_ssl_context = proxy_ssl_context + """SSL context used only for the TLS handshake with the proxy itself + (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS + settings above. + """ +{{/async}} self.safe_chars_for_path_param = safe_chars_for_path_param """Safe chars for path_param """ diff --git a/modules/openapi-generator/src/main/resources/python/rest.mustache b/modules/openapi-generator/src/main/resources/python/rest.mustache index fcccd6afd820..5f56a2d60b32 100644 --- a/modules/openapi-generator/src/main/resources/python/rest.mustache +++ b/modules/openapi-generator/src/main/resources/python/rest.mustache @@ -161,6 +161,8 @@ class RESTClientObject: else: pool_args["proxy_url"] = configuration.proxy pool_args["proxy_headers"] = configuration.proxy_headers + if configuration.proxy_ssl_context is not None: + pool_args["proxy_ssl_context"] = configuration.proxy_ssl_context self.pool_manager = urllib3.ProxyManager(**pool_args) else: self.pool_manager = urllib3.PoolManager(**pool_args) diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py index 848539a45392..13f948249b0a 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py @@ -16,6 +16,7 @@ import logging from logging import FileHandler import multiprocessing +import ssl import sys from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union from urllib.parse import urlparse @@ -175,6 +176,7 @@ class Configuration: :param proxy: Proxy URL. :param no_proxy: Comma-separated hosts that bypass the proxy. :param proxy_headers: Proxy headers. + :param proxy_ssl_context: SSL context used only for the TLS handshake with the proxy itself, independent of the destination TLS settings. :param safe_chars_for_path_param: Safe characters for path parameter encoding. :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. @@ -227,6 +229,7 @@ def __init__( proxy: Optional[str]=None, no_proxy: Optional[str]=None, proxy_headers: Optional[Any]=None, + proxy_ssl_context: Optional[ssl.SSLContext]=None, safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, @@ -350,6 +353,11 @@ def __init__( self.proxy_headers = proxy_headers """Proxy headers """ + self.proxy_ssl_context = proxy_ssl_context + """SSL context used only for the TLS handshake with the proxy itself + (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS + settings above. + """ self.safe_chars_for_path_param = safe_chars_for_path_param """Safe chars for path_param """ 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 ef3ed39f4679..9a0c6d4de785 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/rest.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/rest.py @@ -171,6 +171,8 @@ def __init__(self, configuration) -> None: else: pool_args["proxy_url"] = configuration.proxy pool_args["proxy_headers"] = configuration.proxy_headers + if configuration.proxy_ssl_context is not None: + pool_args["proxy_ssl_context"] = configuration.proxy_ssl_context self.pool_manager = urllib3.ProxyManager(**pool_args) else: self.pool_manager = urllib3.PoolManager(**pool_args) diff --git a/samples/client/echo_api/python-pydantic-v1/openapi_client/configuration.py b/samples/client/echo_api/python-pydantic-v1/openapi_client/configuration.py index 40a30ca4ca90..3dd46b44b772 100644 --- a/samples/client/echo_api/python-pydantic-v1/openapi_client/configuration.py +++ b/samples/client/echo_api/python-pydantic-v1/openapi_client/configuration.py @@ -179,6 +179,11 @@ def __init__(self, host=None, self.proxy_headers = None """Proxy headers """ + self.proxy_ssl_context = None + """SSL context used only for the TLS handshake with the proxy itself + (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS + settings above. + """ self.safe_chars_for_path_param = '' """Safe chars for path_param """ diff --git a/samples/client/echo_api/python-pydantic-v1/openapi_client/rest.py b/samples/client/echo_api/python-pydantic-v1/openapi_client/rest.py index 7600e9d54cc7..e1c59ddf82f5 100644 --- a/samples/client/echo_api/python-pydantic-v1/openapi_client/rest.py +++ b/samples/client/echo_api/python-pydantic-v1/openapi_client/rest.py @@ -106,6 +106,8 @@ def __init__(self, configuration, pools_size=4, maxsize=None) -> None: **addition_pool_args ) else: + if configuration.proxy_ssl_context is not None: + addition_pool_args['proxy_ssl_context'] = configuration.proxy_ssl_context self.pool_manager = urllib3.ProxyManager( num_pools=pools_size, maxsize=maxsize, diff --git a/samples/client/echo_api/python/openapi_client/configuration.py b/samples/client/echo_api/python/openapi_client/configuration.py index 848539a45392..13f948249b0a 100644 --- a/samples/client/echo_api/python/openapi_client/configuration.py +++ b/samples/client/echo_api/python/openapi_client/configuration.py @@ -16,6 +16,7 @@ import logging from logging import FileHandler import multiprocessing +import ssl import sys from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union from urllib.parse import urlparse @@ -175,6 +176,7 @@ class Configuration: :param proxy: Proxy URL. :param no_proxy: Comma-separated hosts that bypass the proxy. :param proxy_headers: Proxy headers. + :param proxy_ssl_context: SSL context used only for the TLS handshake with the proxy itself, independent of the destination TLS settings. :param safe_chars_for_path_param: Safe characters for path parameter encoding. :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. @@ -227,6 +229,7 @@ def __init__( proxy: Optional[str]=None, no_proxy: Optional[str]=None, proxy_headers: Optional[Any]=None, + proxy_ssl_context: Optional[ssl.SSLContext]=None, safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, @@ -350,6 +353,11 @@ def __init__( self.proxy_headers = proxy_headers """Proxy headers """ + self.proxy_ssl_context = proxy_ssl_context + """SSL context used only for the TLS handshake with the proxy itself + (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS + settings above. + """ self.safe_chars_for_path_param = safe_chars_for_path_param """Safe chars for path_param """ diff --git a/samples/client/echo_api/python/openapi_client/rest.py b/samples/client/echo_api/python/openapi_client/rest.py index 5bd90b34957e..77b4fe56053a 100644 --- a/samples/client/echo_api/python/openapi_client/rest.py +++ b/samples/client/echo_api/python/openapi_client/rest.py @@ -171,6 +171,8 @@ def __init__(self, configuration) -> None: else: pool_args["proxy_url"] = configuration.proxy pool_args["proxy_headers"] = configuration.proxy_headers + if configuration.proxy_ssl_context is not None: + pool_args["proxy_ssl_context"] = configuration.proxy_ssl_context self.pool_manager = urllib3.ProxyManager(**pool_args) else: self.pool_manager = urllib3.PoolManager(**pool_args) diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py index 96f087a0c127..ec7a4beaba82 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py @@ -15,6 +15,7 @@ import logging from logging import FileHandler import multiprocessing +import ssl import sys from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union from urllib.parse import urlparse @@ -172,6 +173,7 @@ class Configuration: :param proxy: Proxy URL. :param no_proxy: Comma-separated hosts that bypass the proxy. :param proxy_headers: Proxy headers. + :param proxy_ssl_context: SSL context used only for the TLS handshake with the proxy itself, independent of the destination TLS settings. :param safe_chars_for_path_param: Safe characters for path parameter encoding. :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. @@ -207,6 +209,7 @@ def __init__( proxy: Optional[str]=None, no_proxy: Optional[str]=None, proxy_headers: Optional[Any]=None, + proxy_ssl_context: Optional[ssl.SSLContext]=None, safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, @@ -330,6 +333,11 @@ def __init__( self.proxy_headers = proxy_headers """Proxy headers """ + self.proxy_ssl_context = proxy_ssl_context + """SSL context used only for the TLS handshake with the proxy itself + (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS + settings above. + """ self.safe_chars_for_path_param = safe_chars_for_path_param """Safe chars for path_param """ diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/rest.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/rest.py index 0e0bdcc507a0..c6da043e386b 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/rest.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/rest.py @@ -170,6 +170,8 @@ def __init__(self, configuration) -> None: else: pool_args["proxy_url"] = configuration.proxy pool_args["proxy_headers"] = configuration.proxy_headers + if configuration.proxy_ssl_context is not None: + pool_args["proxy_ssl_context"] = configuration.proxy_ssl_context self.pool_manager = urllib3.ProxyManager(**pool_args) else: self.pool_manager = urllib3.PoolManager(**pool_args) diff --git a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/configuration.py index f38713f1cfc0..80c24c59491f 100644 --- a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/configuration.py @@ -15,6 +15,7 @@ import logging from logging import FileHandler import multiprocessing +import ssl import sys from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union from urllib.parse import urlparse @@ -181,6 +182,7 @@ class Configuration: :param proxy: Proxy URL. :param no_proxy: Comma-separated hosts that bypass the proxy. :param proxy_headers: Proxy headers. + :param proxy_ssl_context: SSL context used only for the TLS handshake with the proxy itself, independent of the destination TLS settings. :param safe_chars_for_path_param: Safe characters for path parameter encoding. :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. @@ -292,6 +294,7 @@ def __init__( proxy: Optional[str]=None, no_proxy: Optional[str]=None, proxy_headers: Optional[Any]=None, + proxy_ssl_context: Optional[ssl.SSLContext]=None, safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, @@ -420,6 +423,11 @@ def __init__( self.proxy_headers = proxy_headers """Proxy headers """ + self.proxy_ssl_context = proxy_ssl_context + """SSL context used only for the TLS handshake with the proxy itself + (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS + settings above. + """ self.safe_chars_for_path_param = safe_chars_for_path_param """Safe chars for path_param """ 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 1344bf560901..8affe12ad0a2 100644 --- a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/rest.py +++ b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/rest.py @@ -170,6 +170,8 @@ def __init__(self, configuration) -> None: else: pool_args["proxy_url"] = configuration.proxy pool_args["proxy_headers"] = configuration.proxy_headers + if configuration.proxy_ssl_context is not None: + pool_args["proxy_ssl_context"] = configuration.proxy_ssl_context self.pool_manager = urllib3.ProxyManager(**pool_args) else: self.pool_manager = urllib3.PoolManager(**pool_args) diff --git a/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/petstore_api/configuration.py index 01aff11e2adb..87101cafeed3 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/petstore_api/configuration.py @@ -240,6 +240,11 @@ def __init__(self, host=None, self.proxy_headers = None """Proxy headers """ + self.proxy_ssl_context = None + """SSL context used only for the TLS handshake with the proxy itself + (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS + settings above. + """ self.safe_chars_for_path_param = '' """Safe chars for path_param """ diff --git a/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/configuration.py index 4bfa3e213b57..67bf8b8fb740 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/configuration.py @@ -244,6 +244,11 @@ def __init__(self, host=None, self.proxy_headers = None """Proxy headers """ + self.proxy_ssl_context = None + """SSL context used only for the TLS handshake with the proxy itself + (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS + settings above. + """ self.safe_chars_for_path_param = '' """Safe chars for path_param """ diff --git a/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/rest.py b/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/rest.py index d677d53b40fc..16d3c8490523 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/rest.py +++ b/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/rest.py @@ -105,6 +105,8 @@ def __init__(self, configuration, pools_size=4, maxsize=None) -> None: **addition_pool_args ) else: + if configuration.proxy_ssl_context is not None: + addition_pool_args['proxy_ssl_context'] = configuration.proxy_ssl_context self.pool_manager = urllib3.ProxyManager( num_pools=pools_size, maxsize=maxsize, diff --git a/samples/openapi3/client/petstore/python/petstore_api/configuration.py b/samples/openapi3/client/petstore/python/petstore_api/configuration.py index 8e3b6590b385..67d8edaf3145 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python/petstore_api/configuration.py @@ -15,6 +15,7 @@ import logging from logging import FileHandler import multiprocessing +import ssl import sys from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union from urllib.parse import urlparse @@ -181,6 +182,7 @@ class Configuration: :param proxy: Proxy URL. :param no_proxy: Comma-separated hosts that bypass the proxy. :param proxy_headers: Proxy headers. + :param proxy_ssl_context: SSL context used only for the TLS handshake with the proxy itself, independent of the destination TLS settings. :param safe_chars_for_path_param: Safe characters for path parameter encoding. :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. @@ -292,6 +294,7 @@ def __init__( proxy: Optional[str]=None, no_proxy: Optional[str]=None, proxy_headers: Optional[Any]=None, + proxy_ssl_context: Optional[ssl.SSLContext]=None, safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, @@ -420,6 +423,11 @@ def __init__( self.proxy_headers = proxy_headers """Proxy headers """ + self.proxy_ssl_context = proxy_ssl_context + """SSL context used only for the TLS handshake with the proxy itself + (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS + settings above. + """ self.safe_chars_for_path_param = safe_chars_for_path_param """Safe chars for path_param """ diff --git a/samples/openapi3/client/petstore/python/petstore_api/rest.py b/samples/openapi3/client/petstore/python/petstore_api/rest.py index 075dca30faee..a265bee3515c 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/rest.py +++ b/samples/openapi3/client/petstore/python/petstore_api/rest.py @@ -170,6 +170,8 @@ def __init__(self, configuration) -> None: else: pool_args["proxy_url"] = configuration.proxy pool_args["proxy_headers"] = configuration.proxy_headers + if configuration.proxy_ssl_context is not None: + pool_args["proxy_ssl_context"] = configuration.proxy_ssl_context self.pool_manager = urllib3.ProxyManager(**pool_args) else: self.pool_manager = urllib3.PoolManager(**pool_args) From 2a3061745bbd6d0cdec62d3a803744b3a5670dd3 Mon Sep 17 00:00:00 2001 From: emmanuel-adu Date: Fri, 31 Jul 2026 08:10:18 -0700 Subject: [PATCH 2/3] fix: address cubic review on proxy_ssl_context PR - Configuration.__deepcopy__ special-cases proxy_ssl_context (like the existing retries/proxy_headers handling), since ssl.SSLContext cannot be deep-copied and previously raised TypeError. - Gate proxy_ssl_context to the true urllib3 library variant only (not asyncio/aiohttp, not the deprecated tornado library), since neither of those REST clients read the option. - Raise python-pydantic-v1's generated urllib3 floor from 1.25.3 to 1.26.0, the version that added ProxyManager's proxy_ssl_context kwarg, so setting the option can't crash under an allowed-but-too-old urllib3. --- .../README_onlypackage.mustache | 2 +- .../python-pydantic-v1/configuration.mustache | 17 ++++++++-- .../python-pydantic-v1/pyproject.mustache | 2 +- .../python-pydantic-v1/requirements.mustache | 2 +- .../python-pydantic-v1/setup.mustache | 2 +- .../resources/python/configuration.mustache | 31 +++++++++++++++++-- .../openapi_client/configuration.py | 9 ++++-- .../openapi_client/configuration.py | 9 ++++-- .../python-pydantic-v1/pyproject.toml | 2 +- .../python-pydantic-v1/requirements.txt | 2 +- .../echo_api/python-pydantic-v1/setup.py | 2 +- .../python/openapi_client/configuration.py | 9 ++++-- .../legacy_model_dict_client/configuration.py | 9 ++++-- .../petstore_api/configuration.py | 5 +-- .../petstore_api/configuration.py | 5 +-- .../petstore_api/configuration.py | 4 +++ .../petstore_api/configuration.py | 10 ++---- .../python-pydantic-v1-aiohttp/pyproject.toml | 2 +- .../requirements.txt | 2 +- .../python-pydantic-v1-aiohttp/setup.py | 2 +- .../petstore_api/configuration.py | 9 ++++-- .../python-pydantic-v1/pyproject.toml | 2 +- .../python-pydantic-v1/requirements.txt | 2 +- .../petstore/python-pydantic-v1/setup.py | 2 +- .../python/petstore_api/configuration.py | 9 ++++-- 25 files changed, 112 insertions(+), 40 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python-pydantic-v1/README_onlypackage.mustache b/modules/openapi-generator/src/main/resources/python-pydantic-v1/README_onlypackage.mustache index e9bedf610cb3..2fb2c65af442 100644 --- a/modules/openapi-generator/src/main/resources/python-pydantic-v1/README_onlypackage.mustache +++ b/modules/openapi-generator/src/main/resources/python-pydantic-v1/README_onlypackage.mustache @@ -26,7 +26,7 @@ This python library package is generated without supporting files like setup.py To be able to use it, you will need these dependencies in your own package that uses this library: -* urllib3 >= 1.25.3 +* urllib3 >= 1.26.0 * python-dateutil {{#asyncio}} * aiohttp diff --git a/modules/openapi-generator/src/main/resources/python-pydantic-v1/configuration.mustache b/modules/openapi-generator/src/main/resources/python-pydantic-v1/configuration.mustache index 45a9c84aea5e..bb2e39920af8 100644 --- a/modules/openapi-generator/src/main/resources/python-pydantic-v1/configuration.mustache +++ b/modules/openapi-generator/src/main/resources/python-pydantic-v1/configuration.mustache @@ -259,11 +259,15 @@ conf = {{{packageName}}}.Configuration( self.proxy_headers = None """Proxy headers """ +{{^asyncio}} +{{^tornado}} self.proxy_ssl_context = None """SSL context used only for the TLS handshake with the proxy itself (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS settings above. """ +{{/tornado}} +{{/asyncio}} self.safe_chars_for_path_param = '' """Safe chars for path_param """ @@ -290,8 +294,17 @@ conf = {{{packageName}}}.Configuration( result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k not in ('logger', 'logger_file_handler'): - setattr(result, k, copy.deepcopy(v, memo)) + if k in ('logger', 'logger_file_handler'): + continue +{{^asyncio}} +{{^tornado}} + if k == 'proxy_ssl_context': + # ssl.SSLContext holds unpicklable C state and can't be deepcopied. + setattr(result, k, v) + continue +{{/tornado}} +{{/asyncio}} + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/modules/openapi-generator/src/main/resources/python-pydantic-v1/pyproject.mustache b/modules/openapi-generator/src/main/resources/python-pydantic-v1/pyproject.mustache index 8892d1566f32..5b8f45a9827f 100644 --- a/modules/openapi-generator/src/main/resources/python-pydantic-v1/pyproject.mustache +++ b/modules/openapi-generator/src/main/resources/python-pydantic-v1/pyproject.mustache @@ -12,7 +12,7 @@ include = ["{{packageName}}/py.typed"] [tool.poetry.dependencies] python = "^3.8" -urllib3 = ">= 1.25.3" +urllib3 = ">= 1.26.0" python-dateutil = ">=2.8.2" {{#asyncio}} aiohttp = ">= 3.8.4" diff --git a/modules/openapi-generator/src/main/resources/python-pydantic-v1/requirements.mustache b/modules/openapi-generator/src/main/resources/python-pydantic-v1/requirements.mustache index 8add30ffd46a..0724c06b0748 100644 --- a/modules/openapi-generator/src/main/resources/python-pydantic-v1/requirements.mustache +++ b/modules/openapi-generator/src/main/resources/python-pydantic-v1/requirements.mustache @@ -1,6 +1,6 @@ python_dateutil >= 2.5.3 setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 3.0.0 +urllib3 >= 1.26.0, < 3.0.0 pydantic >= 1.10.5, < 2 aenum >= 3.1.11 {{#asyncio}} diff --git a/modules/openapi-generator/src/main/resources/python-pydantic-v1/setup.mustache b/modules/openapi-generator/src/main/resources/python-pydantic-v1/setup.mustache index fed7c0b3eecd..3cd0e9c82946 100644 --- a/modules/openapi-generator/src/main/resources/python-pydantic-v1/setup.mustache +++ b/modules/openapi-generator/src/main/resources/python-pydantic-v1/setup.mustache @@ -18,7 +18,7 @@ PYTHON_REQUIRES = ">=3.7" {{#apis}} {{#-last}} REQUIRES = [ - "urllib3 >= 1.25.3, < 3.0.0", + "urllib3 >= 1.26.0, < 3.0.0", "python-dateutil", {{#asyncio}} "aiohttp >= 3.0.0", diff --git a/modules/openapi-generator/src/main/resources/python/configuration.mustache b/modules/openapi-generator/src/main/resources/python/configuration.mustache index a8aab8e2f9ab..04b8b11fa9ff 100644 --- a/modules/openapi-generator/src/main/resources/python/configuration.mustache +++ b/modules/openapi-generator/src/main/resources/python/configuration.mustache @@ -13,7 +13,11 @@ import logging from logging import FileHandler {{^async}} import multiprocessing +{{/async}} +{{^async}} +{{^tornado}} import ssl +{{/tornado}} {{/async}} import sys from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union @@ -229,7 +233,9 @@ class Configuration: {{/async}} :param proxy_headers: Proxy headers. {{^async}} +{{^tornado}} :param proxy_ssl_context: SSL context used only for the TLS handshake with the proxy itself, independent of the destination TLS settings. +{{/tornado}} {{/async}} :param safe_chars_for_path_param: Safe characters for path parameter encoding. :param client_side_validation: Enable client-side validation. Default True. @@ -366,7 +372,9 @@ conf = {{{packageName}}}.Configuration( {{/async}} proxy_headers: Optional[Any]=None, {{^async}} +{{^tornado}} proxy_ssl_context: Optional[ssl.SSLContext]=None, +{{/tornado}} {{/async}} safe_chars_for_path_param: str='', client_side_validation: bool=True, @@ -513,11 +521,13 @@ conf = {{{packageName}}}.Configuration( """Proxy headers """ {{^async}} +{{^tornado}} self.proxy_ssl_context = proxy_ssl_context """SSL context used only for the TLS handshake with the proxy itself (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS settings above. """ +{{/tornado}} {{/async}} self.safe_chars_for_path_param = safe_chars_for_path_param """Safe chars for path_param @@ -571,6 +581,14 @@ conf = {{{packageName}}}.Configuration( if callable(copy_method): setattr(result, k, copy_method()) continue +{{^async}} +{{^tornado}} + if k == 'proxy_ssl_context': + # ssl.SSLContext holds unpicklable C state and can't be deepcopied. + setattr(result, k, v) + continue +{{/tornado}} +{{/async}} {{#asyncio}} if k in ('client_session_kwargs', 'trace_configs'): setattr(result, k, copy.copy(v)) @@ -592,8 +610,17 @@ conf = {{{packageName}}}.Configuration( result.logger_stream_handler = self.logger_stream_handler {{/useIndependentImplicitClients}} {{^useIndependentImplicitClients}} - if k not in ('logger', 'logger_file_handler'): - setattr(result, k, copy.deepcopy(v, memo)) + if k in ('logger', 'logger_file_handler'): + continue +{{^async}} +{{^tornado}} + if k == 'proxy_ssl_context': + # ssl.SSLContext holds unpicklable C state and can't be deepcopied. + setattr(result, k, v) + continue +{{/tornado}} +{{/async}} + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py index 13f948249b0a..515cb3b8e03c 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py @@ -384,8 +384,13 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k not in ('logger', 'logger_file_handler'): - setattr(result, k, copy.deepcopy(v, memo)) + if k in ('logger', 'logger_file_handler'): + continue + if k == 'proxy_ssl_context': + # ssl.SSLContext holds unpicklable C state and can't be deepcopied. + setattr(result, k, v) + continue + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/client/echo_api/python-pydantic-v1/openapi_client/configuration.py b/samples/client/echo_api/python-pydantic-v1/openapi_client/configuration.py index 3dd46b44b772..b5a898037a35 100644 --- a/samples/client/echo_api/python-pydantic-v1/openapi_client/configuration.py +++ b/samples/client/echo_api/python-pydantic-v1/openapi_client/configuration.py @@ -210,8 +210,13 @@ def __deepcopy__(self, memo): result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k not in ('logger', 'logger_file_handler'): - setattr(result, k, copy.deepcopy(v, memo)) + if k in ('logger', 'logger_file_handler'): + continue + if k == 'proxy_ssl_context': + # ssl.SSLContext holds unpicklable C state and can't be deepcopied. + setattr(result, k, v) + continue + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/client/echo_api/python-pydantic-v1/pyproject.toml b/samples/client/echo_api/python-pydantic-v1/pyproject.toml index 192e7c548361..ff54392bbebb 100644 --- a/samples/client/echo_api/python-pydantic-v1/pyproject.toml +++ b/samples/client/echo_api/python-pydantic-v1/pyproject.toml @@ -12,7 +12,7 @@ include = ["openapi_client/py.typed"] [tool.poetry.dependencies] python = "^3.8" -urllib3 = ">= 1.25.3" +urllib3 = ">= 1.26.0" python-dateutil = ">=2.8.2" pydantic = "^1.10.5, <2" aenum = ">=3.1.11" diff --git a/samples/client/echo_api/python-pydantic-v1/requirements.txt b/samples/client/echo_api/python-pydantic-v1/requirements.txt index 0a8bf96cadf2..39ac48267898 100644 --- a/samples/client/echo_api/python-pydantic-v1/requirements.txt +++ b/samples/client/echo_api/python-pydantic-v1/requirements.txt @@ -1,5 +1,5 @@ python_dateutil >= 2.5.3 setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 3.0.0 +urllib3 >= 1.26.0, < 3.0.0 pydantic >= 1.10.5, < 2 aenum >= 3.1.11 diff --git a/samples/client/echo_api/python-pydantic-v1/setup.py b/samples/client/echo_api/python-pydantic-v1/setup.py index d91b9d9f069e..7551181347d1 100644 --- a/samples/client/echo_api/python-pydantic-v1/setup.py +++ b/samples/client/echo_api/python-pydantic-v1/setup.py @@ -25,7 +25,7 @@ VERSION = "1.0.0" PYTHON_REQUIRES = ">=3.7" REQUIRES = [ - "urllib3 >= 1.25.3, < 3.0.0", + "urllib3 >= 1.26.0, < 3.0.0", "python-dateutil", "pydantic >= 1.10.5, < 2", "aenum" diff --git a/samples/client/echo_api/python/openapi_client/configuration.py b/samples/client/echo_api/python/openapi_client/configuration.py index 13f948249b0a..515cb3b8e03c 100644 --- a/samples/client/echo_api/python/openapi_client/configuration.py +++ b/samples/client/echo_api/python/openapi_client/configuration.py @@ -384,8 +384,13 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k not in ('logger', 'logger_file_handler'): - setattr(result, k, copy.deepcopy(v, memo)) + if k in ('logger', 'logger_file_handler'): + continue + if k == 'proxy_ssl_context': + # ssl.SSLContext holds unpicklable C state and can't be deepcopied. + setattr(result, k, v) + continue + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py index ec7a4beaba82..4c2cefdb40b0 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py @@ -364,8 +364,13 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k not in ('logger', 'logger_file_handler'): - setattr(result, k, copy.deepcopy(v, memo)) + if k in ('logger', 'logger_file_handler'): + continue + if k == 'proxy_ssl_context': + # ssl.SSLContext holds unpicklable C state and can't be deepcopied. + setattr(result, k, v) + continue + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/configuration.py index cefa6fa3a1f9..1d31fbc4eae5 100644 --- a/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/configuration.py @@ -428,8 +428,9 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k not in ('logger', 'logger_file_handler'): - setattr(result, k, copy.deepcopy(v, memo)) + if k in ('logger', 'logger_file_handler'): + continue + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/openapi3/client/petstore/python-httpx/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-httpx/petstore_api/configuration.py index cefa6fa3a1f9..1d31fbc4eae5 100644 --- a/samples/openapi3/client/petstore/python-httpx/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-httpx/petstore_api/configuration.py @@ -428,8 +428,9 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k not in ('logger', 'logger_file_handler'): - setattr(result, k, copy.deepcopy(v, memo)) + if k in ('logger', 'logger_file_handler'): + continue + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/configuration.py index 80c24c59491f..8f0b80ef4aed 100644 --- a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/configuration.py @@ -464,6 +464,10 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: if callable(copy_method): setattr(result, k, copy_method()) continue + if k == 'proxy_ssl_context': + # ssl.SSLContext holds unpicklable C state and can't be deepcopied. + setattr(result, k, v) + continue setattr(result, k, copy.deepcopy(v, memo)) # Loggers and their handlers are process-global. diff --git a/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/petstore_api/configuration.py index 87101cafeed3..5dea0d26c227 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/petstore_api/configuration.py @@ -240,11 +240,6 @@ def __init__(self, host=None, self.proxy_headers = None """Proxy headers """ - self.proxy_ssl_context = None - """SSL context used only for the TLS handshake with the proxy itself - (e.g. an HTTPS CONNECT tunnel), independent of the destination TLS - settings above. - """ self.safe_chars_for_path_param = '' """Safe chars for path_param """ @@ -271,8 +266,9 @@ def __deepcopy__(self, memo): result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k not in ('logger', 'logger_file_handler'): - setattr(result, k, copy.deepcopy(v, memo)) + if k in ('logger', 'logger_file_handler'): + continue + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/pyproject.toml b/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/pyproject.toml index d65781e4a8a8..99cb8cdef767 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/pyproject.toml +++ b/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/pyproject.toml @@ -12,7 +12,7 @@ include = ["petstore_api/py.typed"] [tool.poetry.dependencies] python = "^3.8" -urllib3 = ">= 1.25.3" +urllib3 = ">= 1.26.0" python-dateutil = ">=2.8.2" aiohttp = ">= 3.8.4" pem = ">= 19.3.0" diff --git a/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/requirements.txt b/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/requirements.txt index c8ee56b4876d..6f8a93445cf3 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/requirements.txt +++ b/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/requirements.txt @@ -1,6 +1,6 @@ python_dateutil >= 2.5.3 setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 3.0.0 +urllib3 >= 1.26.0, < 3.0.0 pydantic >= 1.10.5, < 2 aenum >= 3.1.11 aiohttp >= 3.0.0 diff --git a/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/setup.py b/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/setup.py index 6c3c289d34cc..3f90b0e52605 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/setup.py +++ b/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/setup.py @@ -24,7 +24,7 @@ VERSION = "1.0.0" PYTHON_REQUIRES = ">=3.7" REQUIRES = [ - "urllib3 >= 1.25.3, < 3.0.0", + "urllib3 >= 1.26.0, < 3.0.0", "python-dateutil", "aiohttp >= 3.0.0", "pem>=19.3.0", diff --git a/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/configuration.py index 67bf8b8fb740..b2de668e5660 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/configuration.py @@ -275,8 +275,13 @@ def __deepcopy__(self, memo): result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k not in ('logger', 'logger_file_handler'): - setattr(result, k, copy.deepcopy(v, memo)) + if k in ('logger', 'logger_file_handler'): + continue + if k == 'proxy_ssl_context': + # ssl.SSLContext holds unpicklable C state and can't be deepcopied. + setattr(result, k, v) + continue + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/openapi3/client/petstore/python-pydantic-v1/pyproject.toml b/samples/openapi3/client/petstore/python-pydantic-v1/pyproject.toml index d67ebb4ca8e2..1065ebed888c 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1/pyproject.toml +++ b/samples/openapi3/client/petstore/python-pydantic-v1/pyproject.toml @@ -12,7 +12,7 @@ include = ["petstore_api/py.typed"] [tool.poetry.dependencies] python = "^3.8" -urllib3 = ">= 1.25.3" +urllib3 = ">= 1.26.0" python-dateutil = ">=2.8.2" pem = ">= 19.3.0" pycryptodome = ">= 3.9.0" diff --git a/samples/openapi3/client/petstore/python-pydantic-v1/requirements.txt b/samples/openapi3/client/petstore/python-pydantic-v1/requirements.txt index 2a3de4f163ef..4ac6bb3d1137 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1/requirements.txt +++ b/samples/openapi3/client/petstore/python-pydantic-v1/requirements.txt @@ -1,6 +1,6 @@ python_dateutil >= 2.5.3 setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 3.0.0 +urllib3 >= 1.26.0, < 3.0.0 pydantic >= 1.10.5, < 2 aenum >= 3.1.11 pycryptodome >= 3.9.0 diff --git a/samples/openapi3/client/petstore/python-pydantic-v1/setup.py b/samples/openapi3/client/petstore/python-pydantic-v1/setup.py index 6af2c4f9a0be..40ca1c9a4bf6 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1/setup.py +++ b/samples/openapi3/client/petstore/python-pydantic-v1/setup.py @@ -24,7 +24,7 @@ VERSION = "1.0.0" PYTHON_REQUIRES = ">=3.7" REQUIRES = [ - "urllib3 >= 1.25.3, < 3.0.0", + "urllib3 >= 1.26.0, < 3.0.0", "python-dateutil", "pem>=19.3.0", "pycryptodome>=3.9.0", diff --git a/samples/openapi3/client/petstore/python/petstore_api/configuration.py b/samples/openapi3/client/petstore/python/petstore_api/configuration.py index 67d8edaf3145..60cd34fe69d7 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python/petstore_api/configuration.py @@ -454,8 +454,13 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k not in ('logger', 'logger_file_handler'): - setattr(result, k, copy.deepcopy(v, memo)) + if k in ('logger', 'logger_file_handler'): + continue + if k == 'proxy_ssl_context': + # ssl.SSLContext holds unpicklable C state and can't be deepcopied. + setattr(result, k, v) + continue + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) From 7eb0816b84160a6e2e935581d8ef854f75865981 Mon Sep 17 00:00:00 2001 From: emmanuel-adu Date: Fri, 31 Jul 2026 12:11:43 -0700 Subject: [PATCH 3/3] fix: restore exact deepcopy line asserted by PythonClientCodegenTest My previous restructuring of the non-useIndependentImplicitClients __deepcopy__ branch (if k in (...): continue / setattr(...)) changed the exact generated line if k not in ('logger', 'logger_file_handler'): that PythonClientCodegenTest.testIndependentImplicitClientsPreserveDefaultsWhenDisabled asserts on verbatim, breaking CI on all 3 Java build jobs. Restore that literal line unchanged and instead insert the proxy_ssl_context special-case as an early continue before it, which is behavior-identical and a smaller diff. Verified locally: the previously-failing PythonClientCodegenTest now passes (62/62), and the proxy_ssl_context deepcopy fix still works end-to-end. --- .../main/resources/python-pydantic-v1/configuration.mustache | 5 ++--- .../src/main/resources/python/configuration.mustache | 5 ++--- .../openapi_client/configuration.py | 5 ++--- .../python-pydantic-v1/openapi_client/configuration.py | 5 ++--- .../client/echo_api/python/openapi_client/configuration.py | 5 ++--- .../legacy_model_dict_client/configuration.py | 5 ++--- .../petstore/python-httpx-sync/petstore_api/configuration.py | 5 ++--- .../petstore/python-httpx/petstore_api/configuration.py | 5 ++--- .../python-pydantic-v1-aiohttp/petstore_api/configuration.py | 5 ++--- .../python-pydantic-v1/petstore_api/configuration.py | 5 ++--- .../client/petstore/python/petstore_api/configuration.py | 5 ++--- 11 files changed, 22 insertions(+), 33 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python-pydantic-v1/configuration.mustache b/modules/openapi-generator/src/main/resources/python-pydantic-v1/configuration.mustache index bb2e39920af8..e77d3413edc2 100644 --- a/modules/openapi-generator/src/main/resources/python-pydantic-v1/configuration.mustache +++ b/modules/openapi-generator/src/main/resources/python-pydantic-v1/configuration.mustache @@ -294,8 +294,6 @@ conf = {{{packageName}}}.Configuration( result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k in ('logger', 'logger_file_handler'): - continue {{^asyncio}} {{^tornado}} if k == 'proxy_ssl_context': @@ -304,7 +302,8 @@ conf = {{{packageName}}}.Configuration( continue {{/tornado}} {{/asyncio}} - setattr(result, k, copy.deepcopy(v, memo)) + if k not in ('logger', 'logger_file_handler'): + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/modules/openapi-generator/src/main/resources/python/configuration.mustache b/modules/openapi-generator/src/main/resources/python/configuration.mustache index 04b8b11fa9ff..2d40eb8cb826 100644 --- a/modules/openapi-generator/src/main/resources/python/configuration.mustache +++ b/modules/openapi-generator/src/main/resources/python/configuration.mustache @@ -610,8 +610,6 @@ conf = {{{packageName}}}.Configuration( result.logger_stream_handler = self.logger_stream_handler {{/useIndependentImplicitClients}} {{^useIndependentImplicitClients}} - if k in ('logger', 'logger_file_handler'): - continue {{^async}} {{^tornado}} if k == 'proxy_ssl_context': @@ -620,7 +618,8 @@ conf = {{{packageName}}}.Configuration( continue {{/tornado}} {{/async}} - setattr(result, k, copy.deepcopy(v, memo)) + if k not in ('logger', 'logger_file_handler'): + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py index 515cb3b8e03c..2bbf005e307a 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py @@ -384,13 +384,12 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k in ('logger', 'logger_file_handler'): - continue if k == 'proxy_ssl_context': # ssl.SSLContext holds unpicklable C state and can't be deepcopied. setattr(result, k, v) continue - setattr(result, k, copy.deepcopy(v, memo)) + if k not in ('logger', 'logger_file_handler'): + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/client/echo_api/python-pydantic-v1/openapi_client/configuration.py b/samples/client/echo_api/python-pydantic-v1/openapi_client/configuration.py index b5a898037a35..a618cee7e10a 100644 --- a/samples/client/echo_api/python-pydantic-v1/openapi_client/configuration.py +++ b/samples/client/echo_api/python-pydantic-v1/openapi_client/configuration.py @@ -210,13 +210,12 @@ def __deepcopy__(self, memo): result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k in ('logger', 'logger_file_handler'): - continue if k == 'proxy_ssl_context': # ssl.SSLContext holds unpicklable C state and can't be deepcopied. setattr(result, k, v) continue - setattr(result, k, copy.deepcopy(v, memo)) + if k not in ('logger', 'logger_file_handler'): + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/client/echo_api/python/openapi_client/configuration.py b/samples/client/echo_api/python/openapi_client/configuration.py index 515cb3b8e03c..2bbf005e307a 100644 --- a/samples/client/echo_api/python/openapi_client/configuration.py +++ b/samples/client/echo_api/python/openapi_client/configuration.py @@ -384,13 +384,12 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k in ('logger', 'logger_file_handler'): - continue if k == 'proxy_ssl_context': # ssl.SSLContext holds unpicklable C state and can't be deepcopied. setattr(result, k, v) continue - setattr(result, k, copy.deepcopy(v, memo)) + if k not in ('logger', 'logger_file_handler'): + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py index 4c2cefdb40b0..8e689e45eb90 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py @@ -364,13 +364,12 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k in ('logger', 'logger_file_handler'): - continue if k == 'proxy_ssl_context': # ssl.SSLContext holds unpicklable C state and can't be deepcopied. setattr(result, k, v) continue - setattr(result, k, copy.deepcopy(v, memo)) + if k not in ('logger', 'logger_file_handler'): + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/configuration.py index 1d31fbc4eae5..cefa6fa3a1f9 100644 --- a/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/configuration.py @@ -428,9 +428,8 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k in ('logger', 'logger_file_handler'): - continue - setattr(result, k, copy.deepcopy(v, memo)) + if k not in ('logger', 'logger_file_handler'): + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/openapi3/client/petstore/python-httpx/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-httpx/petstore_api/configuration.py index 1d31fbc4eae5..cefa6fa3a1f9 100644 --- a/samples/openapi3/client/petstore/python-httpx/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-httpx/petstore_api/configuration.py @@ -428,9 +428,8 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k in ('logger', 'logger_file_handler'): - continue - setattr(result, k, copy.deepcopy(v, memo)) + if k not in ('logger', 'logger_file_handler'): + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/petstore_api/configuration.py index 5dea0d26c227..01aff11e2adb 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-pydantic-v1-aiohttp/petstore_api/configuration.py @@ -266,9 +266,8 @@ def __deepcopy__(self, memo): result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k in ('logger', 'logger_file_handler'): - continue - setattr(result, k, copy.deepcopy(v, memo)) + if k not in ('logger', 'logger_file_handler'): + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/configuration.py index b2de668e5660..94b30a8c6fd9 100644 --- a/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-pydantic-v1/petstore_api/configuration.py @@ -275,13 +275,12 @@ def __deepcopy__(self, memo): result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k in ('logger', 'logger_file_handler'): - continue if k == 'proxy_ssl_context': # ssl.SSLContext holds unpicklable C state and can't be deepcopied. setattr(result, k, v) continue - setattr(result, k, copy.deepcopy(v, memo)) + if k not in ('logger', 'logger_file_handler'): + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy) diff --git a/samples/openapi3/client/petstore/python/petstore_api/configuration.py b/samples/openapi3/client/petstore/python/petstore_api/configuration.py index 60cd34fe69d7..fcbc987747b6 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python/petstore_api/configuration.py @@ -454,13 +454,12 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> Self: result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k in ('logger', 'logger_file_handler'): - continue if k == 'proxy_ssl_context': # ssl.SSLContext holds unpicklable C state and can't be deepcopied. setattr(result, k, v) continue - setattr(result, k, copy.deepcopy(v, memo)) + if k not in ('logger', 'logger_file_handler'): + setattr(result, k, copy.deepcopy(v, memo)) # shallow copy of loggers result.logger = copy.copy(self.logger) # use setter to re-create the file handler (excluded from __dict__ copy)