From 9d776919bea178785bfa37f301a442693a99bbec Mon Sep 17 00:00:00 2001 From: Pascal Bachor Date: Sun, 8 Jun 2025 07:21:45 +0000 Subject: [PATCH 1/2] python: Read proxies from environment + support no_proxy --- .../resources/python/configuration.mustache | 3 ++ .../src/main/resources/python/rest.mustache | 43 +++++++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python/configuration.mustache b/modules/openapi-generator/src/main/resources/python/configuration.mustache index 0dca8be3583a..66f38beee4d3 100644 --- a/modules/openapi-generator/src/main/resources/python/configuration.mustache +++ b/modules/openapi-generator/src/main/resources/python/configuration.mustache @@ -413,6 +413,9 @@ conf = {{{packageName}}}.Configuration( self.proxy: Optional[str] = None """Proxy URL """ + self.no_proxy: Optional[str] = None + """Hosts for which to bypass the proxy + """ self.proxy_headers = None """Proxy headers """ diff --git a/modules/openapi-generator/src/main/resources/python/rest.mustache b/modules/openapi-generator/src/main/resources/python/rest.mustache index f545066bb677..43de817c72ea 100644 --- a/modules/openapi-generator/src/main/resources/python/rest.mustache +++ b/modules/openapi-generator/src/main/resources/python/rest.mustache @@ -6,6 +6,8 @@ import io import json import re import ssl +from urllib.parse import urlparse +from urllib.request import getproxies, proxy_bypass import urllib3 @@ -89,14 +91,23 @@ class RESTClientObject: # https pool manager self.pool_manager: urllib3.PoolManager - if configuration.proxy: - if is_socks_proxy_url(configuration.proxy): + parsed = urlparse(configuration.host) + proxy = getproxies().get(parsed.scheme) if configuration.proxy is None else configuration.proxy + if proxy: + if configuration.no_proxy is not None: + if _proxy_bypass(parsed.netloc, configuration.no_proxy): + proxy = None + elif proxy_bypass(parsed.netloc): + proxy = None + + if proxy: + if is_socks_proxy_url(proxy): from urllib3.contrib.socks import SOCKSProxyManager - pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_url"] = proxy pool_args["headers"] = configuration.proxy_headers self.pool_manager = SOCKSProxyManager(**pool_args) else: - pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_url"] = proxy pool_args["proxy_headers"] = configuration.proxy_headers self.pool_manager = urllib3.ProxyManager(**pool_args) else: @@ -246,3 +257,27 @@ class RESTClientObject: raise ApiException(status=0, reason=msg) return RESTResponse(r) + +# Adapted from urllib.request.proxy_bypass_environment +def _proxy_bypass(netloc: str, no_proxy: str): + if no_proxy == '*': + return True + + host = netloc.lower() + if match := re.match(r'(.*):([0-9]*)', host): + hostonly, _port = match.groups() + else: + hostonly = host + + for name in no_proxy.split(','): + name = name.strip() + if name: + name = name.lstrip('.') + name = name.lower() + if hostonly == name or host == name: + return True + name = '.' + name + if hostonly.endswith(name) or host.endswith(name): + return True + + return False From e16cd3d47ccb7c3e67415cc9882bc0cd6aaeb9ee Mon Sep 17 00:00:00 2001 From: Pascal Bachor Date: Sun, 8 Jun 2025 07:24:38 +0000 Subject: [PATCH 2/2] python: Update samples --- .../openapi_client/configuration.py | 3 ++ .../openapi_client/rest.py | 43 +++++++++++++++++-- .../python/openapi_client/configuration.py | 3 ++ .../echo_api/python/openapi_client/rest.py | 43 +++++++++++++++++-- .../petstore_api/configuration.py | 3 ++ .../python/petstore_api/configuration.py | 3 ++ .../petstore/python/petstore_api/rest.py | 43 +++++++++++++++++-- 7 files changed, 129 insertions(+), 12 deletions(-) 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 d1ae379ac7b1..273a3283c9ec 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py @@ -309,6 +309,9 @@ def __init__( self.proxy: Optional[str] = None """Proxy URL """ + self.no_proxy: Optional[str] = None + """Hosts for which to bypass the proxy + """ self.proxy_headers = None """Proxy headers """ 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 89600d574a46..85d83705028b 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/rest.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/rest.py @@ -17,6 +17,8 @@ import json import re import ssl +from urllib.parse import urlparse +from urllib.request import getproxies, proxy_bypass import urllib3 @@ -100,14 +102,23 @@ def __init__(self, configuration) -> None: # https pool manager self.pool_manager: urllib3.PoolManager - if configuration.proxy: - if is_socks_proxy_url(configuration.proxy): + parsed = urlparse(configuration.host) + proxy = getproxies().get(parsed.scheme) if configuration.proxy is None else configuration.proxy + if proxy: + if configuration.no_proxy is not None: + if _proxy_bypass(parsed.netloc, configuration.no_proxy): + proxy = None + elif proxy_bypass(parsed.netloc): + proxy = None + + if proxy: + if is_socks_proxy_url(proxy): from urllib3.contrib.socks import SOCKSProxyManager - pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_url"] = proxy pool_args["headers"] = configuration.proxy_headers self.pool_manager = SOCKSProxyManager(**pool_args) else: - pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_url"] = proxy pool_args["proxy_headers"] = configuration.proxy_headers self.pool_manager = urllib3.ProxyManager(**pool_args) else: @@ -257,3 +268,27 @@ def request( raise ApiException(status=0, reason=msg) return RESTResponse(r) + +# Adapted from urllib.request.proxy_bypass_environment +def _proxy_bypass(netloc: str, no_proxy: str): + if no_proxy == '*': + return True + + host = netloc.lower() + if match := re.match(r'(.*):([0-9]*)', host): + hostonly, _port = match.groups() + else: + hostonly = host + + for name in no_proxy.split(','): + name = name.strip() + if name: + name = name.lstrip('.') + name = name.lower() + if hostonly == name or host == name: + return True + name = '.' + name + if hostonly.endswith(name) or host.endswith(name): + return True + + return False diff --git a/samples/client/echo_api/python/openapi_client/configuration.py b/samples/client/echo_api/python/openapi_client/configuration.py index d1ae379ac7b1..273a3283c9ec 100644 --- a/samples/client/echo_api/python/openapi_client/configuration.py +++ b/samples/client/echo_api/python/openapi_client/configuration.py @@ -309,6 +309,9 @@ def __init__( self.proxy: Optional[str] = None """Proxy URL """ + self.no_proxy: Optional[str] = None + """Hosts for which to bypass the proxy + """ self.proxy_headers = None """Proxy headers """ diff --git a/samples/client/echo_api/python/openapi_client/rest.py b/samples/client/echo_api/python/openapi_client/rest.py index d2bd065dc08f..462ad70f1e3a 100644 --- a/samples/client/echo_api/python/openapi_client/rest.py +++ b/samples/client/echo_api/python/openapi_client/rest.py @@ -17,6 +17,8 @@ import json import re import ssl +from urllib.parse import urlparse +from urllib.request import getproxies, proxy_bypass import urllib3 @@ -100,14 +102,23 @@ def __init__(self, configuration) -> None: # https pool manager self.pool_manager: urllib3.PoolManager - if configuration.proxy: - if is_socks_proxy_url(configuration.proxy): + parsed = urlparse(configuration.host) + proxy = getproxies().get(parsed.scheme) if configuration.proxy is None else configuration.proxy + if proxy: + if configuration.no_proxy is not None: + if _proxy_bypass(parsed.netloc, configuration.no_proxy): + proxy = None + elif proxy_bypass(parsed.netloc): + proxy = None + + if proxy: + if is_socks_proxy_url(proxy): from urllib3.contrib.socks import SOCKSProxyManager - pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_url"] = proxy pool_args["headers"] = configuration.proxy_headers self.pool_manager = SOCKSProxyManager(**pool_args) else: - pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_url"] = proxy pool_args["proxy_headers"] = configuration.proxy_headers self.pool_manager = urllib3.ProxyManager(**pool_args) else: @@ -257,3 +268,27 @@ def request( raise ApiException(status=0, reason=msg) return RESTResponse(r) + +# Adapted from urllib.request.proxy_bypass_environment +def _proxy_bypass(netloc: str, no_proxy: str): + if no_proxy == '*': + return True + + host = netloc.lower() + if match := re.match(r'(.*):([0-9]*)', host): + hostonly, _port = match.groups() + else: + hostonly = host + + for name in no_proxy.split(','): + name = name.strip() + if name: + name = name.lstrip('.') + name = name.lower() + if hostonly == name or host == name: + return True + name = '.' + name + if hostonly.endswith(name) or host.endswith(name): + return True + + return False diff --git a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py index 5738e19cf7bc..b471c376ae48 100644 --- a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py @@ -375,6 +375,9 @@ def __init__( self.proxy: Optional[str] = None """Proxy URL """ + self.no_proxy: Optional[str] = None + """Hosts for which to bypass the proxy + """ self.proxy_headers = None """Proxy headers """ diff --git a/samples/openapi3/client/petstore/python/petstore_api/configuration.py b/samples/openapi3/client/petstore/python/petstore_api/configuration.py index cb081f807f50..f387d802591b 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python/petstore_api/configuration.py @@ -379,6 +379,9 @@ def __init__( self.proxy: Optional[str] = None """Proxy URL """ + self.no_proxy: Optional[str] = None + """Hosts for which to bypass the proxy + """ self.proxy_headers = None """Proxy headers """ diff --git a/samples/openapi3/client/petstore/python/petstore_api/rest.py b/samples/openapi3/client/petstore/python/petstore_api/rest.py index abc7aa289384..6a6d31ed2314 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/rest.py +++ b/samples/openapi3/client/petstore/python/petstore_api/rest.py @@ -16,6 +16,8 @@ import json import re import ssl +from urllib.parse import urlparse +from urllib.request import getproxies, proxy_bypass import urllib3 @@ -99,14 +101,23 @@ def __init__(self, configuration) -> None: # https pool manager self.pool_manager: urllib3.PoolManager - if configuration.proxy: - if is_socks_proxy_url(configuration.proxy): + parsed = urlparse(configuration.host) + proxy = getproxies().get(parsed.scheme) if configuration.proxy is None else configuration.proxy + if proxy: + if configuration.no_proxy is not None: + if _proxy_bypass(parsed.netloc, configuration.no_proxy): + proxy = None + elif proxy_bypass(parsed.netloc): + proxy = None + + if proxy: + if is_socks_proxy_url(proxy): from urllib3.contrib.socks import SOCKSProxyManager - pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_url"] = proxy pool_args["headers"] = configuration.proxy_headers self.pool_manager = SOCKSProxyManager(**pool_args) else: - pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_url"] = proxy pool_args["proxy_headers"] = configuration.proxy_headers self.pool_manager = urllib3.ProxyManager(**pool_args) else: @@ -256,3 +267,27 @@ def request( raise ApiException(status=0, reason=msg) return RESTResponse(r) + +# Adapted from urllib.request.proxy_bypass_environment +def _proxy_bypass(netloc: str, no_proxy: str): + if no_proxy == '*': + return True + + host = netloc.lower() + if match := re.match(r'(.*):([0-9]*)', host): + hostonly, _port = match.groups() + else: + hostonly = host + + for name in no_proxy.split(','): + name = name.strip() + if name: + name = name.lstrip('.') + name = name.lower() + if hostonly == name or host == name: + return True + name = '.' + name + if hostonly.endswith(name) or host.endswith(name): + return True + + return False