From 0205e2e7a18156972ca975baa404a01387123895 Mon Sep 17 00:00:00 2001 From: Joshua Pedrick Date: Tue, 13 Jun 2023 00:29:56 +0800 Subject: [PATCH] Add auth_override_provider mechanism pyapa/pip#4475 --- src/pip/_internal/cli/cmdoptions.py | 16 +++++++++++++++ src/pip/_internal/network/session.py | 13 +++++++++++- tests/lib/auth_override_provider_dummy.py | 24 +++++++++++++++++++++++ tests/unit/test_network_session.py | 8 ++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 tests/lib/auth_override_provider_dummy.py diff --git a/src/pip/_internal/cli/cmdoptions.py b/src/pip/_internal/cli/cmdoptions.py index 02ba6082793..a39aa521801 100644 --- a/src/pip/_internal/cli/cmdoptions.py +++ b/src/pip/_internal/cli/cmdoptions.py @@ -265,6 +265,21 @@ class PipOption(Option): ), ) +auth_override_provider: Callable[..., Option] = partial( + Option, + "--auth-override-provider", + dest="auth_override_provider", + type="str", + default=None, + help=( + "Python module which can replace MultiDomainBasicAuth." + "The module will be imported using importlib.import_module" + " expects a python file, with a function: " + " create_auth_override_provider(auth_module, index_urls)." + " (default: None)" + ), +) + proxy: Callable[..., Option] = partial( Option, "--proxy", @@ -1060,6 +1075,7 @@ def check_list_path_option(options: Values) -> None: no_python_version_warning, use_new_feature, use_deprecated_feature, + auth_override_provider, ], } diff --git a/src/pip/_internal/network/session.py b/src/pip/_internal/network/session.py index 6c40ade1595..40878d0c7f4 100644 --- a/src/pip/_internal/network/session.py +++ b/src/pip/_internal/network/session.py @@ -3,6 +3,7 @@ """ import email.utils +import importlib import io import ipaddress import json @@ -326,6 +327,7 @@ def __init__( trusted_hosts: Sequence[str] = (), index_urls: Optional[List[str]] = None, ssl_context: Optional["SSLContext"] = None, + auth_override_provider = None, **kwargs: Any, ) -> None: """ @@ -342,7 +344,16 @@ def __init__( self.headers["User-Agent"] = user_agent() # Attach our Authentication handler to the session - self.auth = MultiDomainBasicAuth(index_urls=index_urls) + if auth_override_provider: + import pip._internal.network.auth + m = importlib.import_module(auth_override_provider) + # pass the module so users can implement AuthBase and/or + # provide fallback to MultiDomainBasicAuth + self.auth = m.create_auth_override_provider( + index_urls=index_urls, + auth_module=pip._internal.network.auth) + else: + self.auth = MultiDomainBasicAuth(index_urls=index_urls) # Create our urllib3.Retry instance which will allow us to customize # how we handle retries. diff --git a/tests/lib/auth_override_provider_dummy.py b/tests/lib/auth_override_provider_dummy.py new file mode 100644 index 00000000000..2fde3e97f08 --- /dev/null +++ b/tests/lib/auth_override_provider_dummy.py @@ -0,0 +1,24 @@ + + +def create_auth_override_provider(auth_module, index_urls): + class DummyAuthOverrideProvider(auth_module.AuthBase): + def __init__(self, index_urls): + self.multi_domain_basic_auth = auth_module.MultiDomainBasicAuth( + index_urls=index_urls) + + + @property + def index_urls(self): + return self.multi_domain_basic_auth.index_urls + + + @index_urls.setter + def set_index_urls(self, index_urls): + self.multi_domain_basic_auth.index_urls = index_urls + + + def __call__(self, r): + return self.multi_domain_basic_auth(r) + + + return DummyAuthOverrideProvider(index_urls=index_urls) diff --git a/tests/unit/test_network_session.py b/tests/unit/test_network_session.py index 2bb9317b762..b78e99d4e61 100644 --- a/tests/unit/test_network_session.py +++ b/tests/unit/test_network_session.py @@ -76,6 +76,14 @@ def test_cache_is_enabled(self, tmpdir: Path) -> None: assert session.adapters["https://"].cache.directory == cache_directory + def test_auth_override_provider(self, tmpdir: Path) -> None: + cache_directory = os.fspath(tmpdir.joinpath("test-cache")) + session = PipSession( + cache=cache_directory, + auth_override_provider='tests.lib.auth_override_provider_dummy') + + assert session.auth.__class__.__name__ == "DummyAuthOverrideProvider" + def test_http_cache_is_not_enabled(self, tmpdir: Path) -> None: session = PipSession(cache=os.fspath(tmpdir.joinpath("test-cache")))