Skip to content

feat: Add --no-proxy-env and support --proxy=""#13051

Merged
ichard26 merged 6 commits into
pypa:mainfrom
martinezlc99:feature/add-no-proxy
Jul 7, 2026
Merged

feat: Add --no-proxy-env and support --proxy=""#13051
ichard26 merged 6 commits into
pypa:mainfrom
martinezlc99:feature/add-no-proxy

Conversation

@martinezlc99

Copy link
Copy Markdown
Contributor

Fixes #5378.

This PR was originally done in #12011, which I cancelled due to age and associated pain of rebasing.

Originally this PR stalled in addressing #12011 (comment), but since then I have noticed the --proxy=PROXY option also sets session.trust_env = False as well, so the behavior is consistent.

@martinezlc99

Copy link
Copy Markdown
Contributor Author

Hi everyone - am I missing anything on this PR?

Also, I am thinking about logging a message if both --proxy=<PROXY> and --no-proxy options are simultaneously set.

@notatallshaw

Copy link
Copy Markdown
Member

I'm going to put it on the 25.0 milestone so it doesn't get forgotten, but it will be up to a pip maintainer or release manager to review and decide whether it stays on there.

I don't have a lot of experience reviewing this type of PR but it looks simple and your note about existing use of session.trust_env makes sense to me (though I still think this should be documented somewhere, it at least keeps in line with existing behavior).

@notatallshaw notatallshaw added this to the 25.0 milestone Nov 7, 2024
@jdlangs

jdlangs commented Nov 8, 2024

Copy link
Copy Markdown

@martinezlc99, I just happened to be investigating this behavior today and it was a pleasant surprise to see this was active just yesterday. Thanks for driving this forward!

I did want to ask, wouldn't the ideal behavior be for the --no-proxy flag to take a value similar to the no_proxy env var, instead of turning off proxies entirely? I thought the general use case was people want to provide specific configuration scenarios of which index URLs require proxy use, just without the awkwardness of dynamically changing env vars. It also would be confusing IMO for a no_proxy option to be a boolean given how it's typically used.

Unfortunately, there seems to be buggy behavior in requests that means simple passing on a no_proxy value in session.proxies won't work today but that seems like the ideal behavior for me and my use case.

@notatallshaw

notatallshaw commented Nov 8, 2024

Copy link
Copy Markdown
Member

@jdlangs I think what this PR has going for it is its simplicity. Generally pip should rely on sourcing behavior from the standard or vendored libraries.

I notice that uv has not implemented --proxy and instead points users to environmental variables, which is probably the right call as having these CLI flags means pip needs to make its own choices.

There is no standard definition of what no_proxy or NO_PROXY should do: https://about.gitlab.com/blog/2021/01/27/we-need-to-talk-no-proxy/. So any implementation would break someone's expectations. IMO I think pip should be pointing people towards using http_proxy / HTTP_PROXY / https_proxy / HTTPS_PROXY / no_proxy / NO_PROXY and let the http library pip vendors deal with figuring out how to interpret that.

@jdlangs

jdlangs commented Nov 8, 2024

Copy link
Copy Markdown

Yeah, just using environment variables does seem like the most standard and robust method, but if pip provides a proxy argument, I think being able to configure no_proxy also seems reasonable.

I think what this PR has going for it is its simplicity

The simplest PR would actually be only passing a no_proxy value on to requests, I think, but unfortunately it seems that won't work until it's fixed upstream.

There is no standard definition of what no_proxy or NO_PROXY should do

Point taken, but is there any tool that treats no_proxy as a boolean flag? Maybe for this PR I'm just asking the name be reconsidered, especially if there's any chance in the future it would be reused to be a true no_proxy configuration

@notatallshaw

notatallshaw commented Nov 8, 2024

Copy link
Copy Markdown
Member

Point taken, but is there any tool that treats no_proxy as a boolean flag? Maybe for this PR I'm just asking the name be reconsidered, especially if there's any chance in the future it would be reused to be a true no_proxy configuration

Yeah, I think it's an unfortunate naming collision , maybe --no-proxy-env would be more accurate? I don't want to bikeshed this though, there was discussion in the previous PR #12011, I would personally leave it up to @martinezlc99 to decide, but ultimately a pip maintainer needs to review this.

@martinezlc99

martinezlc99 commented Nov 9, 2024

Copy link
Copy Markdown
Contributor Author

@notatallshaw @jdlangs my initial intent, and my understanding based on the original issue, was to bypass the proxy completely, so the boolean option made sense. But, I agree the --no-proxy option name is counter-intuitive to how the traditional no_proxy environmental variable is used.

I did a quick search to see how other tools handle this situation and found there is not a consensus:

  • curl has a --noproxy option, which appends to the no_proxy environmental variable:

--noproxy <no-proxy-list> List of hosts which do not use proxy

  • Chromium has a --no-proxy-server boolean option, which bypasses the proxy completely:

--no-proxy-server This tells Chrome not to use a Proxy. It overrides any other proxy settings provided.

The Chromium --no-proxy-server option name is at least distinct from the no_proxy environmental variable so this design is noteworthy. Chromium also has a --proxy-bypass-list which "tells chrome to bypass any specified proxy for the given semi-colon-separated list of hosts. This flag must be used (or rather, only has an effect) in tandem with --proxy-server.".

Chromium also supports --proxy-server=direct:// which will cause all connections to not use a proxy.

A nice medium may be adding support for --proxy=direct:// to completely bypass all proxies, and having --no-proxy behave inline with no_proxy environmental variable, with the requests limitation pointed out by @jdlangs .

Open to thoughts/suggestions.

@notatallshaw

notatallshaw commented Nov 9, 2024

Copy link
Copy Markdown
Member

my initial intent, and my understanding based on the original issue, was to bypass the proxy completely, so the boolean option made sense.

But in this implementation you still take the proxy options provided to pip (which I assume can be either CLI or config), so it doesn't bypass the proxy options completely. Which is fine, there is precedence for this in the existing options --no-binary :all: can be overridden with --only-binary <specific package> and vice versa.

I don't know how much other CLIs here are that informative as it's not exactly the same behavior. I would prefer to keep it something simple, but preferably a little more accurate, naming is hard, I'd stick to the current name unless something is obviously better. I really don't think pip should be trying to do it's own emulation of big complex tools, e.g. --proxy=direct://.

@martinezlc99

Copy link
Copy Markdown
Contributor Author

Thanks @notatallshaw - agree with all your points...forgot this implementation will take the proxy from the CLI as well 😎

So I think the name of the option is the only outstanding item. I like your suggestion of --no-proxy-env or even no-proxy-config. I have no preference, so I am fine with --no-proxy-env if its agreed to be the most clear/concise.

@pichuzhkin

This comment was marked as off-topic.

@notatallshaw

This comment was marked as off-topic.

@sbidoul

sbidoul commented Jan 19, 2025

Copy link
Copy Markdown
Member

It looks like the discussion here is still ongoing. So I'll postpone this to the next release.

@sbidoul sbidoul modified the milestones: 25.0, 25.1 Jan 19, 2025
@ichard26

Copy link
Copy Markdown
Member

To restart the discussion on this PR, I'm fine with --no-proxy-env as the name if we're explicitly trying to avoid replicating the "standard" no_proxy envvar behaviour and we still accept --proxy on the CLI.

@pfmoore

pfmoore commented Apr 1, 2025

Copy link
Copy Markdown
Member

@notatallshaw it looks like you have been working on this - do you plan to merge it for 25.1? If not, I suggest we just remove the milestone, and it can go in when it's ready.

@notatallshaw

Copy link
Copy Markdown
Member

I agree with @ichard26 , let's change the name. I'll move it to the next milestone, but will try and review if it gets updated quickly.

@notatallshaw notatallshaw modified the milestones: 25.1, 25.2 Apr 1, 2025
@martinezlc99

Copy link
Copy Markdown
Contributor Author

@notatallshaw - apologies for not tracking this response, been a bit busy. I will update the name ASAP.

@ichard26 ichard26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having come back to review this again, the main wrinkle with this design is that it's not true all proxy configuration set via environment variables will be ignored. All of pip's options can be set via environment variables. PIP_PROXY=myproxy is equivalent to pip --proxy=myproxy

I don't know common ignoring PIP_PROXY would be, but this flag has the potential to be confusing. Thoughts?

Comment thread src/pip/_internal/cli/index_command.py Outdated
Comment thread src/pip/_internal/cli/cmdoptions.py Outdated
Comment thread src/pip/_internal/cli/cmdoptions.py Outdated
Comment thread news/5378.feature.rst Outdated
@martinezlc99

Copy link
Copy Markdown
Contributor Author

Having come back to review this again, the main wrinkle with this design is that it's not true all proxy configuration set via environment variables will be ignored. All of pip's options can be set via environment variables. PIP_PROXY=myproxy is equivalent to pip --proxy=myproxy

I don't know common ignoring PIP_PROXY would be, but this flag has the potential to be confusing. Thoughts?

Thanks @ichard26. From my perspective, overriding PIP_PROXY is ok since my use case was constantly transitioning from my work VPN environment to my home environment without a corporate proxy. Or are you saying PIP_PROXY persists while other environmental variables are overwritten?

The renaming of the option name to include environment seems like it would also cover the PIP_PORXY case as well.

@ichard26

Copy link
Copy Markdown
Member

Or are you saying PIP_PROXY persists while other environmental variables are overwritten?

This, because pip's CLI infrastructure treats PIP_PROXY=myproxy pip install ... as equivalent to pip --proxy myproxy install ...

@martinezlc99

Copy link
Copy Markdown
Contributor Author

Or are you saying PIP_PROXY persists while other environmental variables are overwritten?

This, because pip's CLI infrastructure treats PIP_PROXY=myproxy pip install ... as equivalent to pip --proxy myproxy install ...

@ichard26 - you are correct.

Given this PR allows --proxy=https://proxy.company.com:9090 to be used in conjunction with --no-proxy-env, and for the proxy to be set by --proxy in this case, there is an argument/precedent for the --no-proxy-env to be working as designed when PIP_PROXY is set.

So as to not restart the discussions from scratch, I propose we clarify the documentation to indicate which environmental variables are ignored with this option; however, open to updating to ignore other means of pip setting the proxy as this was the initial intent.

P.S. I had previously set trust_env to False as part of the initial --no-proxy implementation to convince requests to not use the http_proxy, https_proxy, and no_proxy environmental variables. This spawned the discussion on the trust_env implications and hence the rename of the option to --no-proxy-env.

It seems in the timeframe of the initial PR and now, the --proxy option also sets trust_env to False, effectively also ignoring any other requests environmental configurations when this option is set.

I mention this only to state the two converse proxy options are consistent now.

@ichard26 ichard26 mentioned this pull request Jun 22, 2025
@ichard26 ichard26 added the state: up for grabs (PR) Good idea, but needs a new champion as the PR author is busy or unreachable. label Jul 7, 2025
@ichard26

Copy link
Copy Markdown
Member

This PR is stale. I'd like to see it land at some point, but it is too close to feasibly land ahead of the 25.2 deadline. Removing it from the milestone.

@ichard26 ichard26 modified the milestones: 25.2, 25.3 Jul 21, 2025
@notatallshaw notatallshaw removed this from the 25.3 milestone Sep 13, 2025
@notatallshaw

Copy link
Copy Markdown
Member

As this PR is stale I'm removing from the 25.3 milestone, I will try and take time to review before 25.3 if OP or someone else wants to fix this up in the next few weeks.

@notatallshaw notatallshaw added this to the 26.2 milestone Jul 4, 2026
@notatallshaw

Copy link
Copy Markdown
Member

Coming back to this PR! I think it's still good, I made merged in main and made some small tweaks (hope you don't mind), and I think it's ready to merge, I've added it to the milestone.

I'll do one more review pass and if everything is good approve it, and then leave it for a few days for any other maintainers to object before merging.

@ichard26

ichard26 commented Jul 5, 2026

Copy link
Copy Markdown
Member

This seems fine, but I've just realized rereading the earlier discussion that this feature can be achieved via --proxy="" if we simply change

# Handle configured proxies
if options.proxy:
session.proxies = {
"http": options.proxy,
"https": options.proxy,
}
session.trust_env = False
session.pip_proxy = options.proxy

to be gated on if options.proxy is not None

requests handle a blank proxy just fine and we'll set trust_env=False like --no-proxy-env does. The main benefit of adding a new flag is that it's more discoverable and less magical. I would be happy with either approach, but we did say that --proxy="" should work in #5378 (comment).

@notatallshaw

notatallshaw commented Jul 5, 2026

Copy link
Copy Markdown
Member

@ichard26 I am fine with fixing --proxy "" at the same time, I'll prepare a commit. there's a few more lines that need fixing such are carefully passing to the build env suprocess installer. One thing a specific flag can do that --proxy "" can't is setting via an env or config value.

@ichard26

ichard26 commented Jul 6, 2026

Copy link
Copy Markdown
Member

One thing a specific flag can do that --proxy "" can't is setting via an env or config value

Ah ok, then it makes sense to add a new flag. 👍

@ichard26 ichard26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a ton @martinezlc99 and @notatallshaw for pushing this over the line!

(I pushed a commit to reorganise the newly added tests. The build_env proxy unit tests don't belong in test_build_constraints.py and the other tests were moved to their own class since they have a custom session constructor.)

@ichard26 ichard26 changed the title Add --no-proxy Option feat: Add --no-proxy-env and support --proxy="" Jul 7, 2026
@ichard26 ichard26 enabled auto-merge (squash) July 7, 2026 03:35
@ichard26 ichard26 merged commit 131e63d into pypa:main Jul 7, 2026
78 of 80 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:provided state: up for grabs (PR) Good idea, but needs a new champion as the PR author is busy or unreachable.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add option to bypass http proxy

7 participants