[python] re-resolve the environment proxy when the host is assigned - #24716
Merged
Conversation
The scheme-specific proxy is read in __init__ from self.host, which is empty for specs without a server URL until the caller assigns one. A host set after construction therefore never matched HTTP_PROXY or HTTPS_PROXY and requests went direct; only ALL_PROXY worked. Re-resolve in the host setter when the proxy came from the environment. An assigned proxy still wins.
Contributor
There was a problem hiding this comment.
All reported issues were addressed across 7 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
The scheme lookup and the ALL_PROXY fallback were spelled out both in __init__ and in the host setter. Keep the rule in one place so the two cannot drift.
Contributor
Author
|
Incidentally closed, re-opening |
This was referenced Aug 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Configuration.__init__picks the environment proxy by the scheme ofself.host:hostis a property, not the constructor argument, andserver_indexfalls back to0when nohostis given. For a spec with no server URL that makeshostan empty string, sourlparse("").schemeis"",proxies.get("")misses, and only theproxies.get("all")fallback can match. Clients that constructConfiguration()and assign the host afterwards never seeHTTP_PROXYorHTTPS_PROXY, and requests go direct with no warning.ALL_PROXYis the only variable that works, which is a confusing thing to have to discover.The host is simply not known at construction time in that pattern, so no reordering inside
__init__can fix it. This re-resolves the proxy in thehostsetter, which is the point at which the scheme first becomes known.Construction is unchanged — same code, same order, same result — so nothing that works today behaves differently. The only addition is that assigning a host refreshes a proxy that came from the environment. An explicitly provided proxy is never touched: the property setter clears the "came from the environment" flag, so
config.proxy = Xsurvives a laterconfig.host = Y, andconfig.proxy = Nonestill means no proxy.I first tried resolving lazily on every read of
proxy. That also fixes the bug but makes the value re-read the environment on each access, and it broketest_proxy_settings_default_from_environment, which constructs insidepatch(getproxies)and asserts outside it. Re-resolving on host assignment keeps that test passing unmodified, which seemed like the better signal.Scoped to the urllib3 client with
{{^async}}, matching the existing guards on thegetproxies/urlparseimports and onno_proxy, and consistent with #24082 leaving the async backends to their own proxy handling. Five urllib3 samples change; the httpx and aiohttp samples never had the block.Tests: the three existing proxy tests pass unmodified, and five are added covering a host assigned after construction (both schemes), a host unknown at construction, an assigned proxy surviving a later host change, an assigned
None, and theALL_PROXYfallback.tests/test_configuration.pyis 18 passed; the rest of the petstore suite is unchanged apart from the usual failures that need a live server.Reported downstream at kubernetes-client/python#2681, where
load_kube_config()builds the configuration with no host and sets the server afterwards. Verified there by patching the generated file: withHTTPS_PROXYset and a kubeconfig pointing at a name that does not resolve, the client goes fromproxy=Noneand a DNS failure to aProxyManagerand the proxy loggingCONNECT.Follows #24082. Related to #20226.
PR checklist
@cbornet @tomplus @krjakbrjak @fa0311
Summary by cubic
Re-resolves environment proxies when
Configuration.hostis assigned so scheme-specific proxies apply. Previously, assigninghostafter construction skippedHTTP_PROXY/HTTPS_PROXYand sent requests direct unlessALL_PROXYwas set; now host assignment refreshes env-derived proxies while explicit proxies remain unchanged.pythongenerator forurllib3only;httpxandaiohttpunchanged._proxy_from_env; store_proxybehind aproxyproperty whose setter disables re-resolution; re-resolve in thehostsetter using extracted_env_proxy(proxies, host)withALL_PROXYfallback;no_proxyhandling unchanged.Nonesurviving host changes, andALL_PROXYfallback.config.hostafter construction now pick upHTTP_PROXY/HTTPS_PROXY; explicitconfig.proxystill overrides andNonedisables proxies.Written for commit 2437d2f. Summary will update on new commits.