Skip to content

Commit

Permalink
add --no-proxy option
Browse files Browse the repository at this point in the history
  • Loading branch information
martinezlc99 committed Oct 27, 2024
1 parent 4204359 commit e7abbd8
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 1 deletion.
1 change: 1 addition & 0 deletions news/5378.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add ``--no-proxy`` option to bypass http proxy. Using this option will ignore any configured http proxies, including any environmental variables
10 changes: 10 additions & 0 deletions src/pip/_internal/cli/cmdoptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,15 @@ class PipOption(Option):
help="Specify a proxy in the form scheme://[user:passwd@]proxy.server:port.",
)

no_proxy: Callable[..., Option] = partial(
Option,
"--no-proxy",
dest="no_proxy",
action="store_true",
default=False,
help="Ignore all configured proxy settings, including environmental variables.",
)

retries: Callable[..., Option] = partial(
Option,
"--retries",
Expand Down Expand Up @@ -1048,6 +1057,7 @@ def check_list_path_option(options: Values) -> None:
no_input,
keyring_provider,
proxy,
no_proxy,
retries,
timeout,
exists_action,
Expand Down
13 changes: 13 additions & 0 deletions src/pip/_internal/cli/index_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,19 @@ def _build_session(
}
session.trust_env = False

# Handle no proxy option
if options.no_proxy:
# Handle case of both --no-proxy being set along with --proxy=<proxy>.
# In this case, the proxies from the environmental variables will be
# ignored, but the command line proxy will be used.
http_proxy = options.proxy if options.proxy else None
https_proxy = options.proxy if options.proxy else None
session.proxies = {
"http": http_proxy,
"https": https_proxy,
}
session.trust_env = False

# Determine if we can prompt the user for authentication or not
session.auth.prompting = not options.no_input
session.auth.keyring_provider = options.keyring_provider
Expand Down
6 changes: 6 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ def pytest_addoption(parser: Parser) -> None:
default=None,
help="use given proxy in session network tests",
)
parser.addoption(
"--no-proxy",
action="store_true",
default=False,
help="ignore any configured proxies in session network tests",
)
parser.addoption(
"--use-zipapp",
action="store_true",
Expand Down
38 changes: 37 additions & 1 deletion tests/unit/test_network_session.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
import os
from pathlib import Path
from typing import Any, List, Optional
from typing import Any, List, Optional, Union
from urllib.parse import urlparse
from urllib.request import getproxies

Expand Down Expand Up @@ -282,3 +282,39 @@ def test_proxy(self, proxy: Optional[str]) -> None:
f"Invalid proxy {proxy} or session.proxies: "
f"{session.proxies} is not correctly passed to session.request."
)

@pytest.mark.network
def test_no_proxy(self) -> None:
def _set_no_proxy(session: PipSession) -> PipSession:
"""Mimic logic for command line `no_proxy` option"""
session.trust_env = False
session.proxies = {
"http": None,
"https": None,
}
return session

session = PipSession(trusted_hosts=[])

connection_error_http: Union[requests.exceptions.RequestException, None] = None
# setup with known bad (hopefully) http proxy, and then test connection
# expecting a failure if the proxy is used
with requests.utils.set_environ("http_proxy", "http://127.0.0.1:88888"):
try:
session = _set_no_proxy(session)
session.request("GET", "https://pypi.org", timeout=1)
except requests.exceptions.ConnectionError as e:
connection_error_http = e

connection_error_https: Union[requests.exceptions.RequestException, None] = None
# setup with known bad (hopefully) https proxy, and then test connection
# expecting a failure if the proxy is used
with requests.utils.set_environ("https_proxy", "http://127.0.0.1:65534"):
try:
session = _set_no_proxy(session)
session.request("GET", "https://pypi.org", timeout=1)
except requests.exceptions.ConnectionError as e:
connection_error_https = e

assert connection_error_http is None, "Unexpected use of http proxy"
assert connection_error_https is None, "Unexpected use of https proxy"
7 changes: 7 additions & 0 deletions tests/unit/test_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,13 @@ def test_proxy(self) -> None:
)
assert options1.proxy == options2.proxy == "path"

def test_no_proxy(self) -> None:
# FakeCommand intentionally returns the wrong type.
options1, _ = cast(Tuple[Values, List[str]], main(["--no-proxy", "fake"]))
options2, _ = cast(Tuple[Values, List[str]], main(["fake", "--no-proxy"]))
assert options1.no_proxy
assert options2.no_proxy

def test_retries(self) -> None:
# FakeCommand intentionally returns the wrong type.
options1, args1 = cast(
Expand Down

0 comments on commit e7abbd8

Please sign in to comment.