From 9cab6a109460e4c80e9c9ec41f034e3f0b9ea856 Mon Sep 17 00:00:00 2001 From: Quentin Pradet Date: Wed, 12 Mar 2025 09:25:34 +0400 Subject: [PATCH] Remove deprecated http_auth parameter (#2839) (cherry picked from commit 74387d0a3f42517e2a5805c9bb0aec57511b6e15) --- elasticsearch/_async/client/__init__.py | 21 ----- elasticsearch/_async/client/_base.py | 26 ------ elasticsearch/_async/client/utils.py | 4 - elasticsearch/_async/helpers.py | 7 +- elasticsearch/_sync/client/__init__.py | 21 ----- elasticsearch/_sync/client/_base.py | 26 ------ elasticsearch/_sync/client/utils.py | 35 -------- elasticsearch/helpers/actions.py | 6 +- .../test_async/test_server/test_helpers.py | 6 +- .../test_client/test_deprecated_options.py | 26 ------ .../test_client/test_requests_auth.py | 84 ------------------- .../test_client/test_rewrite_parameters.py | 4 +- .../test_server/test_helpers.py | 7 +- 13 files changed, 8 insertions(+), 265 deletions(-) delete mode 100644 test_elasticsearch/test_client/test_requests_auth.py diff --git a/elasticsearch/_async/client/__init__.py b/elasticsearch/_async/client/__init__.py index 4eab35bb0..14ada0e22 100644 --- a/elasticsearch/_async/client/__init__.py +++ b/elasticsearch/_async/client/__init__.py @@ -88,8 +88,6 @@ _rewrite_parameters, _stability_warning, client_node_configs, - is_requests_http_auth, - is_requests_node_class, ) from .watcher import WatcherClient from .xpack import XPackClient @@ -191,7 +189,6 @@ def __init__( ] = None, sniffer_timeout: t.Union[DefaultType, None, float] = DEFAULT, sniff_on_connection_fail: t.Union[DefaultType, bool] = DEFAULT, - http_auth: t.Union[DefaultType, t.Any] = DEFAULT, maxsize: t.Union[DefaultType, int] = DEFAULT, # Internal use only _transport: t.Optional[AsyncTransport] = None, @@ -320,26 +317,9 @@ def __init__( sniff_callback = default_sniff_callback if _transport is None: - requests_session_auth = None - if http_auth is not None and http_auth is not DEFAULT: - if is_requests_http_auth(http_auth): - # If we're using custom requests authentication - # then we need to alert the user that they also - # need to use 'node_class=requests'. - if not is_requests_node_class(node_class): - raise ValueError( - "Using a custom 'requests.auth.AuthBase' class for " - "'http_auth' must be used with node_class='requests'" - ) - - # Reset 'http_auth' to DEFAULT so it's not consumed below. - requests_session_auth = http_auth - http_auth = DEFAULT - node_configs = client_node_configs( hosts, cloud_id=cloud_id, - requests_session_auth=requests_session_auth, connections_per_node=connections_per_node, http_compress=http_compress, verify_certs=verify_certs, @@ -426,7 +406,6 @@ def __init__( self._headers["x-opaque-id"] = opaque_id self._headers = resolve_auth_headers( self._headers, - http_auth=http_auth, api_key=api_key, basic_auth=basic_auth, bearer_auth=bearer_auth, diff --git a/elasticsearch/_async/client/_base.py b/elasticsearch/_async/client/_base.py index cc090671c..3907cfd84 100644 --- a/elasticsearch/_async/client/_base.py +++ b/elasticsearch/_async/client/_base.py @@ -68,7 +68,6 @@ def resolve_auth_headers( headers: Optional[Mapping[str, str]], - http_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, api_key: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, basic_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, bearer_auth: Union[DefaultType, None, str] = DEFAULT, @@ -78,32 +77,7 @@ def resolve_auth_headers( elif not isinstance(headers, HttpHeaders): headers = HttpHeaders(headers) - resolved_http_auth = http_auth if http_auth is not DEFAULT else None resolved_basic_auth = basic_auth if basic_auth is not DEFAULT else None - if resolved_http_auth is not None: - if resolved_basic_auth is not None: - raise ValueError( - "Can't specify both 'http_auth' and 'basic_auth', " - "instead only specify 'basic_auth'" - ) - if isinstance(http_auth, str) or ( - isinstance(resolved_http_auth, (list, tuple)) - and all(isinstance(x, str) for x in resolved_http_auth) - ): - resolved_basic_auth = resolved_http_auth - else: - raise TypeError( - "The deprecated 'http_auth' parameter must be either 'Tuple[str, str]' or 'str'. " - "Use either the 'basic_auth' parameter instead" - ) - - warnings.warn( - "The 'http_auth' parameter is deprecated. " - "Use 'basic_auth' or 'bearer_auth' parameters instead", - category=DeprecationWarning, - stacklevel=warn_stacklevel(), - ) - resolved_api_key = api_key if api_key is not DEFAULT else None resolved_bearer_auth = bearer_auth if bearer_auth is not DEFAULT else None if resolved_api_key or resolved_basic_auth or resolved_bearer_auth: diff --git a/elasticsearch/_async/client/utils.py b/elasticsearch/_async/client/utils.py index 97918d9e4..ac7a35062 100644 --- a/elasticsearch/_async/client/utils.py +++ b/elasticsearch/_async/client/utils.py @@ -27,8 +27,6 @@ _rewrite_parameters, _stability_warning, client_node_configs, - is_requests_http_auth, - is_requests_node_class, ) __all__ = [ @@ -43,6 +41,4 @@ "client_node_configs", "_rewrite_parameters", "_stability_warning", - "is_requests_http_auth", - "is_requests_node_class", ] diff --git a/elasticsearch/_async/helpers.py b/elasticsearch/_async/helpers.py index e4d5e6bc5..8b5d3d0d2 100644 --- a/elasticsearch/_async/helpers.py +++ b/elasticsearch/_async/helpers.py @@ -418,12 +418,9 @@ def pop_transport_kwargs(kw: MutableMapping[str, Any]) -> MutableMapping[str, An # Grab options that should be propagated to every # API call within this helper instead of just 'search()' transport_kwargs = {} - for key in ("headers", "api_key", "http_auth", "basic_auth", "bearer_auth"): + for key in ("headers", "api_key", "basic_auth", "bearer_auth"): try: - value = kw.pop(key) - if key == "http_auth": - key = "basic_auth" - transport_kwargs[key] = value + transport_kwargs[key] = kw.pop(key) except KeyError: pass return transport_kwargs diff --git a/elasticsearch/_sync/client/__init__.py b/elasticsearch/_sync/client/__init__.py index d4082ceb1..46484630a 100644 --- a/elasticsearch/_sync/client/__init__.py +++ b/elasticsearch/_sync/client/__init__.py @@ -88,8 +88,6 @@ _rewrite_parameters, _stability_warning, client_node_configs, - is_requests_http_auth, - is_requests_node_class, ) from .watcher import WatcherClient from .xpack import XPackClient @@ -191,7 +189,6 @@ def __init__( ] = None, sniffer_timeout: t.Union[DefaultType, None, float] = DEFAULT, sniff_on_connection_fail: t.Union[DefaultType, bool] = DEFAULT, - http_auth: t.Union[DefaultType, t.Any] = DEFAULT, maxsize: t.Union[DefaultType, int] = DEFAULT, # Internal use only _transport: t.Optional[Transport] = None, @@ -320,26 +317,9 @@ def __init__( sniff_callback = default_sniff_callback if _transport is None: - requests_session_auth = None - if http_auth is not None and http_auth is not DEFAULT: - if is_requests_http_auth(http_auth): - # If we're using custom requests authentication - # then we need to alert the user that they also - # need to use 'node_class=requests'. - if not is_requests_node_class(node_class): - raise ValueError( - "Using a custom 'requests.auth.AuthBase' class for " - "'http_auth' must be used with node_class='requests'" - ) - - # Reset 'http_auth' to DEFAULT so it's not consumed below. - requests_session_auth = http_auth - http_auth = DEFAULT - node_configs = client_node_configs( hosts, cloud_id=cloud_id, - requests_session_auth=requests_session_auth, connections_per_node=connections_per_node, http_compress=http_compress, verify_certs=verify_certs, @@ -426,7 +406,6 @@ def __init__( self._headers["x-opaque-id"] = opaque_id self._headers = resolve_auth_headers( self._headers, - http_auth=http_auth, api_key=api_key, basic_auth=basic_auth, bearer_auth=bearer_auth, diff --git a/elasticsearch/_sync/client/_base.py b/elasticsearch/_sync/client/_base.py index 868b71073..64abdc250 100644 --- a/elasticsearch/_sync/client/_base.py +++ b/elasticsearch/_sync/client/_base.py @@ -68,7 +68,6 @@ def resolve_auth_headers( headers: Optional[Mapping[str, str]], - http_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, api_key: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, basic_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, bearer_auth: Union[DefaultType, None, str] = DEFAULT, @@ -78,32 +77,7 @@ def resolve_auth_headers( elif not isinstance(headers, HttpHeaders): headers = HttpHeaders(headers) - resolved_http_auth = http_auth if http_auth is not DEFAULT else None resolved_basic_auth = basic_auth if basic_auth is not DEFAULT else None - if resolved_http_auth is not None: - if resolved_basic_auth is not None: - raise ValueError( - "Can't specify both 'http_auth' and 'basic_auth', " - "instead only specify 'basic_auth'" - ) - if isinstance(http_auth, str) or ( - isinstance(resolved_http_auth, (list, tuple)) - and all(isinstance(x, str) for x in resolved_http_auth) - ): - resolved_basic_auth = resolved_http_auth - else: - raise TypeError( - "The deprecated 'http_auth' parameter must be either 'Tuple[str, str]' or 'str'. " - "Use either the 'basic_auth' parameter instead" - ) - - warnings.warn( - "The 'http_auth' parameter is deprecated. " - "Use 'basic_auth' or 'bearer_auth' parameters instead", - category=DeprecationWarning, - stacklevel=warn_stacklevel(), - ) - resolved_api_key = api_key if api_key is not DEFAULT else None resolved_bearer_auth = bearer_auth if bearer_auth is not DEFAULT else None if resolved_api_key or resolved_basic_auth or resolved_bearer_auth: diff --git a/elasticsearch/_sync/client/utils.py b/elasticsearch/_sync/client/utils.py index 48ebcb217..3293e356e 100644 --- a/elasticsearch/_sync/client/utils.py +++ b/elasticsearch/_sync/client/utils.py @@ -16,7 +16,6 @@ # under the License. import base64 -import inspect import urllib.parse import warnings from datetime import date, datetime @@ -44,7 +43,6 @@ AsyncTransport, HttpHeaders, NodeConfig, - RequestsHttpNode, SniffOptions, Transport, ) @@ -92,7 +90,6 @@ class Stability(Enum): _TRANSPORT_OPTIONS = { "api_key", - "http_auth", "request_timeout", "opaque_id", "headers", @@ -105,7 +102,6 @@ class Stability(Enum): def client_node_configs( hosts: Optional[_TYPE_HOSTS], cloud_id: Optional[str], - requests_session_auth: Optional[Any] = None, **kwargs: Any, ) -> List[NodeConfig]: if cloud_id is not None: @@ -126,12 +122,6 @@ def client_node_configs( headers.setdefault("user-agent", USER_AGENT) node_options["headers"] = headers - # If a custom Requests AuthBase is passed we set that via '_extras'. - if requests_session_auth is not None: - node_options.setdefault("_extras", {})[ - "requests.session.auth" - ] = requests_session_auth - def apply_node_options(node_config: NodeConfig) -> NodeConfig: """Needs special handling of headers since .replace() wipes out existing headers""" headers = node_config.headers.copy() # type: ignore[attr-defined] @@ -448,28 +438,3 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: return wrapped # type: ignore[return-value] return wrapper - - -def is_requests_http_auth(http_auth: Any) -> bool: - """Detect if an http_auth value is a custom Requests auth object""" - try: - from requests.auth import AuthBase - - return isinstance(http_auth, AuthBase) - except ImportError: - pass - return False - - -def is_requests_node_class(node_class: Any) -> bool: - """Detect if 'RequestsHttpNode' would be used given the setting of 'node_class'""" - return ( - node_class is not None - and node_class is not DEFAULT - and ( - node_class == "requests" - or ( - inspect.isclass(node_class) and issubclass(node_class, RequestsHttpNode) - ) - ) - ) diff --git a/elasticsearch/helpers/actions.py b/elasticsearch/helpers/actions.py index d1a43a8dc..25c21cdd4 100644 --- a/elasticsearch/helpers/actions.py +++ b/elasticsearch/helpers/actions.py @@ -698,16 +698,12 @@ def pop_transport_kwargs(kw: MutableMapping[str, Any]) -> Dict[str, Any]: for key in ( "headers", "api_key", - "http_auth", "basic_auth", "bearer_auth", "opaque_id", ): try: - value = kw.pop(key) - if key == "http_auth": - key = "basic_auth" - transport_kwargs[key] = value + transport_kwargs[key] = kw.pop(key) except KeyError: pass return transport_kwargs diff --git a/test_elasticsearch/test_async/test_server/test_helpers.py b/test_elasticsearch/test_async/test_server/test_helpers.py index 0bb781304..86439b487 100644 --- a/test_elasticsearch/test_async/test_server/test_helpers.py +++ b/test_elasticsearch/test_async/test_server/test_helpers.py @@ -741,7 +741,8 @@ async def test_clear_scroll(self, async_client, scan_teardown): "kwargs", [ {"api_key": ("name", "value")}, - {"http_auth": ("username", "password")}, + {"basic_auth": ("username", "password")}, + {"bearer_auth": "token"}, {"headers": {"custom", "header"}}, ], ) @@ -790,9 +791,6 @@ async def test_scan_auth_kwargs_forwarded( assert data == [{"search_data": 1}] - if "http_auth" in kwargs: - kwargs = {"basic_auth": kwargs.pop("http_auth")} - assert options.call_args_list == [ call(request_timeout=None, **kwargs), call(ignore_status=404), diff --git a/test_elasticsearch/test_client/test_deprecated_options.py b/test_elasticsearch/test_client/test_deprecated_options.py index 3b4e0b9ed..a4db1fbb7 100644 --- a/test_elasticsearch/test_client/test_deprecated_options.py +++ b/test_elasticsearch/test_client/test_deprecated_options.py @@ -100,32 +100,6 @@ def test_randomize_hosts(): ) -def test_http_auth(): - with warnings.catch_warnings(record=True) as w: - client = Elasticsearch( - "http://localhost:9200", http_auth=("username", "password") - ) - - assert len(w) == 1 - assert w[0].category == DeprecationWarning - assert ( - str(w[0].message) - == "The 'http_auth' parameter is deprecated. Use 'basic_auth' or 'bearer_auth' parameters instead" - ) - assert client._headers["Authorization"] == "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" - - with pytest.raises(ValueError) as e: - Elasticsearch( - "http://localhost:9200", - http_auth=("username", "password"), - basic_auth=("username", "password"), - ) - assert ( - str(e.value) - == "Can't specify both 'http_auth' and 'basic_auth', instead only specify 'basic_auth'" - ) - - def test_serializer_and_serializers(): with pytest.raises(ValueError) as e: Elasticsearch( diff --git a/test_elasticsearch/test_client/test_requests_auth.py b/test_elasticsearch/test_client/test_requests_auth.py deleted file mode 100644 index 2eb656f5d..000000000 --- a/test_elasticsearch/test_client/test_requests_auth.py +++ /dev/null @@ -1,84 +0,0 @@ -# Licensed to Elasticsearch B.V. under one or more contributor -# license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright -# ownership. Elasticsearch B.V. licenses this file to you under -# the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -import warnings - -import pytest -import requests -from elastic_transport import RequestsHttpNode, Urllib3HttpNode -from elastic_transport.client_utils import DEFAULT -from requests.auth import HTTPBasicAuth - -from elasticsearch import AsyncElasticsearch, Elasticsearch - - -class CustomRequestHttpNode(RequestsHttpNode): - pass - - -class CustomUrllib3HttpNode(Urllib3HttpNode): - pass - - -@pytest.mark.parametrize( - "node_class", ["requests", RequestsHttpNode, CustomRequestHttpNode] -) -def test_requests_auth(node_class): - http_auth = HTTPBasicAuth("username", "password") - - with warnings.catch_warnings(record=True) as w: - client = Elasticsearch( - "http://localhost:9200", http_auth=http_auth, node_class=node_class - ) - - # http_auth is deprecated for all other cases except this one. - assert len(w) == 0 - - # Instance should be forwarded directly to requests.Session.auth. - node = client.transport.node_pool.get() - assert isinstance(node, RequestsHttpNode) - assert isinstance(node.session, requests.Session) - assert node.session.auth is http_auth - - -@pytest.mark.parametrize("client_class", [Elasticsearch, AsyncElasticsearch]) -@pytest.mark.parametrize( - "node_class", ["urllib3", "aiohttp", None, DEFAULT, CustomUrllib3HttpNode] -) -def test_error_for_requests_auth_node_class(client_class, node_class): - http_auth = HTTPBasicAuth("username", "password") - - with pytest.raises(ValueError) as e: - client_class( - "http://localhost:9200", http_auth=http_auth, node_class=node_class - ) - assert str(e.value) == ( - "Using a custom 'requests.auth.AuthBase' class for " - "'http_auth' must be used with node_class='requests'" - ) - - -def test_error_for_requests_auth_async(): - http_auth = HTTPBasicAuth("username", "password") - - with pytest.raises(ValueError) as e: - AsyncElasticsearch( - "http://localhost:9200", http_auth=http_auth, node_class="requests" - ) - assert str(e.value) == ( - "Specified 'node_class' is not async, should be async instead" - ) diff --git a/test_elasticsearch/test_client/test_rewrite_parameters.py b/test_elasticsearch/test_client/test_rewrite_parameters.py index 50a232563..f933cfd51 100644 --- a/test_elasticsearch/test_client/test_rewrite_parameters.py +++ b/test_elasticsearch/test_client/test_rewrite_parameters.py @@ -208,7 +208,7 @@ def test_ignore_deprecated_options(self): body={"query": {"match_all": {}}}, params={"key": "value"}, param=1, - http_auth=("key", "value"), + request_timeout=10, ) assert len(w) == 1 @@ -219,7 +219,7 @@ def test_ignore_deprecated_options(self): ) assert self.calls == [ - ((), {"http_auth": ("key", "value")}), + ((), {"request_timeout": 10}), ( (), { diff --git a/test_elasticsearch/test_server/test_helpers.py b/test_elasticsearch/test_server/test_helpers.py index 6ed43e2af..361a98ae2 100644 --- a/test_elasticsearch/test_server/test_helpers.py +++ b/test_elasticsearch/test_server/test_helpers.py @@ -626,7 +626,6 @@ def test_no_scroll_id_fast_route(sync_client): "kwargs", [ {"api_key": ("name", "value")}, - {"http_auth": ("username", "password")}, {"basic_auth": ("username", "password")}, {"bearer_auth": "token"}, {"headers": {"custom", "header"}}, @@ -634,8 +633,6 @@ def test_no_scroll_id_fast_route(sync_client): ) @pytest.mark.usefixtures("scan_teardown") def test_scan_auth_kwargs_forwarded(sync_client, kwargs): - ((key, val),) = kwargs.items() - with patch.object( sync_client, "options", return_value=sync_client ) as options, patch.object( @@ -668,9 +665,7 @@ def test_scan_auth_kwargs_forwarded(sync_client, kwargs): assert data == [{"search_data": 1}] assert options.call_args_list == [ - call( - request_timeout=None, **{key if key != "http_auth" else "basic_auth": val} - ), + call(request_timeout=None, **kwargs), call(ignore_status=404), ]