Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-elastic-transport for 
openSUSE:Factory checked in at 2024-05-24 19:50:02
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-elastic-transport (Old)
 and      /work/SRC/openSUSE:Factory/.python-elastic-transport.new.24587 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-elastic-transport"

Fri May 24 19:50:02 2024 rev:9 rq:1176152 version:8.13.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-elastic-transport/python-elastic-transport.changes
        2024-01-21 23:07:17.955193639 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-elastic-transport.new.24587/python-elastic-transport.changes
     2024-05-24 19:50:04.283167292 +0200
@@ -1,0 +2,12 @@
+Thu May 23 08:17:35 UTC 2024 - Markéta Machová <[email protected]>
+
+- Add requests232.patch to fix compatibility with new requests
+
+-------------------------------------------------------------------
+Fri May 17 13:29:03 UTC 2024 - Markéta Machová <[email protected]>
+
+- update to 8.13.0
+  * Support the HTTPX client with asyncio
+  * Added optional orjson serializer support
+
+-------------------------------------------------------------------

Old:
----
  elastic-transport-python-8.12.0.tar.gz

New:
----
  elastic-transport-python-8.13.0.tar.gz
  requests232.patch

BETA DEBUG BEGIN:
  New:
- Add requests232.patch to fix compatibility with new requests
BETA DEBUG END:

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-elastic-transport.spec ++++++
--- /var/tmp/diff_new_pack.nuittB/_old  2024-05-24 19:50:05.131198258 +0200
+++ /var/tmp/diff_new_pack.nuittB/_new  2024-05-24 19:50:05.135198404 +0200
@@ -18,12 +18,14 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-elastic-transport
-Version:        8.12.0
+Version:        8.13.0
 Release:        0
 Summary:        Transport classes and utilities shared among Python Elastic 
client libraries
 License:        Apache-2.0
 URL:            https://github.com/elastic/elastic-transport-python
 Source:         
https://github.com/elastic/elastic-transport-python/archive/refs/tags/v%{version}.tar.gz#/elastic-transport-python-%{version}.tar.gz
+# PATCH-FIX-UPSTREAM 
https://github.com/elastic/elastic-transport-python/pull/164 Fix requests 2.32 
compatibility
+Patch:          requests232.patch
 BuildRequires:  %{python_module base >= 3.7}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
@@ -31,18 +33,19 @@
 Requires:       python-certifi
 Requires:       python-urllib3
 BuildArch:      noarch
-%if 0%{python_version_nodots} < 37
-Requires:       python-dataclasses
-%endif
 # SECTION test requirements
 BuildRequires:  %{python_module aiohttp}
 BuildRequires:  %{python_module certifi}
-BuildRequires:  %{python_module dataclasses if %python-base < 3.7}
+BuildRequires:  %{python_module httpx}
+BuildRequires:  %{python_module opentelemetry-api}
+BuildRequires:  %{python_module opentelemetry-sdk}
+BuildRequires:  %{python_module orjson}
 BuildRequires:  %{python_module pytest-asyncio}
 BuildRequires:  %{python_module pytest-httpserver}
 BuildRequires:  %{python_module pytest-mock}
 BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module requests}
+BuildRequires:  %{python_module respx}
 BuildRequires:  %{python_module trustme}
 BuildRequires:  %{python_module urllib3}
 # /SECTION
@@ -52,7 +55,7 @@
 Transport classes and utilities shared among Python Elastic client libraries
 
 %prep
-%setup -q -n elastic-transport-python-%{version}
+%autosetup -p1 -n elastic-transport-python-%{version}
 sed -i '/addopts/d' setup.cfg
 sed -i 's/from mock/from unittest.mock/' tests/node/test_http_*.py
 
@@ -68,6 +71,7 @@
 donttest="(test_http_aiohttp and not TestAiohttpHttpNode)"
 donttest="$donttest or test_tls_versions"
 donttest="$donttest or test_assert_fingerprint_in_cert_chain"
+donttest="$donttest or (test_ssl_assert_fingerprint and httpx)"
 # gh#elastic/elastic-transport-python#96
 donttest="$donttest or 
test_url_to_node_config[https://[::1]:0/-https://[::1]:0-]";
 %pytest -k "not ($donttest)"

++++++ elastic-transport-python-8.12.0.tar.gz -> 
elastic-transport-python-8.13.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elastic-transport-python-8.12.0/CHANGELOG.md 
new/elastic-transport-python-8.13.0/CHANGELOG.md
--- old/elastic-transport-python-8.12.0/CHANGELOG.md    2024-01-19 
09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/CHANGELOG.md    2024-03-27 
07:15:44.000000000 +0100
@@ -1,5 +1,10 @@
 # Changelog
 
+## 8.13.0
+
+- Support the HTTPX client with asyncio (#137, contributed by @b4sus)
+- Added optional orjson serializer support (#152)
+
 ## 8.12.0
 
 - Fix basic auth built from percent-encoded URLs (#143)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elastic-transport-python-8.12.0/README.md 
new/elastic-transport-python-8.13.0/README.md
--- old/elastic-transport-python-8.12.0/README.md       2024-01-19 
09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/README.md       2024-03-27 
07:15:44.000000000 +0100
@@ -3,7 +3,7 @@
 
[![PyPI](https://img.shields.io/pypi/v/elastic-transport)](https://pypi.org/elastic-transport)
 [![Python 
Versions](https://img.shields.io/pypi/pyversions/elastic-transport)](https://pypi.org/elastic-transport)
 [![PyPI 
Downloads](https://static.pepy.tech/badge/elastic-transport)](https://pepy.tech/project/elastic-transport)
-[![CI 
Status](https://img.shields.io/github/workflow/status/elastic/elastic-transport-python/CI/main)](https://github.com/elastic/elastic-transport-python/actions)
+[![CI 
Status](https://img.shields.io/github/actions/workflow/status/elastic/elastic-transport-python/ci.yml)](https://github.com/elastic/elastic-transport-python/actions)
 
 Transport classes and utilities shared among Python Elastic client libraries
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/docs/sphinx/installation.rst 
new/elastic-transport-python-8.13.0/docs/sphinx/installation.rst
--- old/elastic-transport-python-8.12.0/docs/sphinx/installation.rst    
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/docs/sphinx/installation.rst    
2024-03-27 07:15:44.000000000 +0100
@@ -10,3 +10,5 @@
 Install the ``requests`` package to use 
:class:`elastic_transport.RequestsHttpNode`.
 
 Install the ``aiohttp`` package to use 
:class:`elastic_transport.AiohttpHttpNode`.
+
+Install the ``httpx`` package to use 
:class:`elastic_transport.HttpxAsyncHttpNode`.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/docs/sphinx/nodes.rst 
new/elastic-transport-python-8.13.0/docs/sphinx/nodes.rst
--- old/elastic-transport-python-8.12.0/docs/sphinx/nodes.rst   2024-01-19 
09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/docs/sphinx/nodes.rst   2024-03-27 
07:15:44.000000000 +0100
@@ -22,6 +22,9 @@
 .. autoclass:: AiohttpHttpNode
    :members:
 
+.. autoclass:: HttpxAsyncHttpNode
+   :members:
+
 Custom node classes
 -------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/docs/sphinx/serializers.rst 
new/elastic-transport-python-8.13.0/docs/sphinx/serializers.rst
--- old/elastic-transport-python-8.12.0/docs/sphinx/serializers.rst     
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/docs/sphinx/serializers.rst     
2024-03-27 07:15:44.000000000 +0100
@@ -9,6 +9,9 @@
 .. autoclass:: JsonSerializer
    :members:
 
+.. autoclass:: OrjsonSerializer
+   :members:
+
 .. autoclass:: TextSerializer
    :members:
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/__init__.py 
new/elastic-transport-python-8.13.0/elastic_transport/__init__.py
--- old/elastic-transport-python-8.12.0/elastic_transport/__init__.py   
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/elastic_transport/__init__.py   
2024-03-27 07:15:44.000000000 +0100
@@ -36,10 +36,12 @@
     AiohttpHttpNode,
     BaseAsyncNode,
     BaseNode,
+    HttpxAsyncHttpNode,
     RequestsHttpNode,
     Urllib3HttpNode,
 )
 from ._node_pool import NodePool, NodeSelector, RandomSelector, 
RoundRobinSelector
+from ._otel import OpenTelemetrySpan
 from ._response import ApiResponse as ApiResponse
 from ._response import BinaryApiResponse as BinaryApiResponse
 from ._response import HeadApiResponse as HeadApiResponse
@@ -70,6 +72,7 @@
     "ConnectionTimeout",
     "HeadApiResponse",
     "HttpHeaders",
+    "HttpxAsyncHttpNode",
     "JsonSerializer",
     "ListApiResponse",
     "NdjsonSerializer",
@@ -77,6 +80,7 @@
     "NodePool",
     "NodeSelector",
     "ObjectApiResponse",
+    "OpenTelemetrySpan",
     "RandomSelector",
     "RequestsHttpNode",
     "RoundRobinSelector",
@@ -95,6 +99,13 @@
     "Urllib3HttpNode",
 ]
 
+try:
+    from elastic_transport._serializer import OrjsonSerializer  # noqa: F401
+
+    __all__.append("OrjsonSerializer")
+except ImportError:
+    pass
+
 _logger = logging.getLogger("elastic_transport")
 _logger.addHandler(logging.NullHandler())
 del _logger
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_async_transport.py 
new/elastic-transport-python-8.13.0/elastic_transport/_async_transport.py
--- old/elastic-transport-python-8.12.0/elastic_transport/_async_transport.py   
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/elastic_transport/_async_transport.py   
2024-03-27 07:15:44.000000000 +0100
@@ -30,7 +30,7 @@
     Union,
 )
 
-from ._compat import await_if_coro, get_running_loop
+from ._compat import await_if_coro
 from ._exceptions import (
     ConnectionError,
     ConnectionTimeout,
@@ -40,6 +40,7 @@
 from ._models import DEFAULT, DefaultType, HttpHeaders, NodeConfig, 
SniffOptions
 from ._node import AiohttpHttpNode, BaseAsyncNode
 from ._node_pool import NodePool, NodeSelector
+from ._otel import OpenTelemetrySpan
 from ._serializer import Serializer
 from ._transport import (
     DEFAULT_CLIENT_META_SERVICE,
@@ -173,7 +174,7 @@
         # sniffing. Uses '_sniffing_task' instead.
         self._sniffing_lock = None  # type: ignore[assignment]
 
-    async def perform_request(  # type: ignore[override,return]
+    async def perform_request(  # type: ignore[override, return]
         self,
         method: str,
         target: str,
@@ -185,6 +186,7 @@
         retry_on_timeout: Union[bool, DefaultType] = DEFAULT,
         request_timeout: Union[Optional[float], DefaultType] = DEFAULT,
         client_meta: Union[Tuple[Tuple[str, str], ...], DefaultType] = DEFAULT,
+        otel_span: Union[OpenTelemetrySpan, DefaultType] = DEFAULT,
     ) -> TransportApiResponse:
         """
         Perform the actual request. Retrieve a node from the node
@@ -208,6 +210,7 @@
         :arg retry_on_timeout: Set to true to retry after timeout errors.
         :arg request_timeout: Amount of time to wait for a response to fail 
with a timeout error.
         :arg client_meta: Extra client metadata key-value pairs to send in the 
client meta header.
+        :arg otel_span: OpenTelemetry span used to add metadata to the span.
         :returns: Tuple of the :class:`elastic_transport.ApiResponseMeta` with 
the deserialized response.
         """
         await self._async_call()
@@ -219,6 +222,7 @@
         max_retries = resolve_default(max_retries, self.max_retries)
         retry_on_timeout = resolve_default(retry_on_timeout, 
self.retry_on_timeout)
         retry_on_status = resolve_default(retry_on_status, 
self.retry_on_status)
+        otel_span = resolve_default(otel_span, OpenTelemetrySpan(None))
 
         if self.meta_header:
             request_headers["x-elastic-client-meta"] = ",".join(
@@ -237,6 +241,7 @@
             request_body = self.serializers.dumps(
                 body, mimetype=request_headers["content-type"]
             )
+            otel_span.set_db_statement(request_body)
         else:
             request_body = None
 
@@ -255,6 +260,7 @@
             node: BaseAsyncNode = self.node_pool.get()  # type: 
ignore[assignment]
             start_time = self._loop.time()
             try:
+                otel_span.set_node_metadata(node.host, node.port, 
node.base_url, target)
                 resp = await node.perform_request(
                     method,
                     target,
@@ -459,6 +465,6 @@
         """
         if self._loop is not None:
             return  # Call at most once!
-        self._loop = get_running_loop()
+        self._loop = asyncio.get_running_loop()
         if self._sniff_on_start:
             await self.sniff(True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_compat.py 
new/elastic-transport-python-8.13.0/elastic_transport/_compat.py
--- old/elastic-transport-python-8.12.0/elastic_transport/_compat.py    
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/elastic_transport/_compat.py    
2024-03-27 07:15:44.000000000 +0100
@@ -15,7 +15,6 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-import asyncio
 import inspect
 import sys
 from pathlib import Path
@@ -30,16 +29,6 @@
 else:
     from collections import OrderedDict as ordered_dict
 
-try:
-    from asyncio import get_running_loop
-except ImportError:
-
-    def get_running_loop() -> asyncio.AbstractEventLoop:
-        loop = asyncio.get_event_loop()
-        if not loop.is_running():
-            raise RuntimeError("no running event loop")
-        return loop
-
 
 T = TypeVar("T")
 
@@ -118,7 +107,6 @@
 
 __all__ = [
     "await_if_coro",
-    "get_running_loop",
     "ordered_dict",
     "quote",
     "urlparse",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_node/__init__.py 
new/elastic-transport-python-8.13.0/elastic_transport/_node/__init__.py
--- old/elastic-transport-python-8.12.0/elastic_transport/_node/__init__.py     
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/elastic_transport/_node/__init__.py     
2024-03-27 07:15:44.000000000 +0100
@@ -18,6 +18,7 @@
 from ._base import BaseNode, NodeApiResponse
 from ._base_async import BaseAsyncNode
 from ._http_aiohttp import AiohttpHttpNode
+from ._http_httpx import HttpxAsyncHttpNode
 from ._http_requests import RequestsHttpNode
 from ._http_urllib3 import Urllib3HttpNode
 
@@ -28,4 +29,5 @@
     "NodeApiResponse",
     "RequestsHttpNode",
     "Urllib3HttpNode",
+    "HttpxAsyncHttpNode",
 ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_node/_base.py 
new/elastic-transport-python-8.13.0/elastic_transport/_node/_base.py
--- old/elastic-transport-python-8.12.0/elastic_transport/_node/_base.py        
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/elastic_transport/_node/_base.py        
2024-03-27 07:15:44.000000000 +0100
@@ -269,18 +269,20 @@
         _SSL_PROTOCOL_VERSION_TO_TLS_VERSION[_tls_version_value] = 
_tls_version_value
 
     # Because we're setting a minimum version we binary OR all the options 
together.
-    _SSL_PROTOCOL_VERSION_TO_OPTIONS[
-        _protocol_value
-    ] = _SSL_PROTOCOL_VERSION_DEFAULT | sum(
-        getattr(ssl, f"OP_NO_{_attr}", 0) for _attr in 
_SSL_PROTOCOL_VERSION_ATTRS[:i]
+    _SSL_PROTOCOL_VERSION_TO_OPTIONS[_protocol_value] = (
+        _SSL_PROTOCOL_VERSION_DEFAULT
+        | sum(
+            getattr(ssl, f"OP_NO_{_attr}", 0)
+            for _attr in _SSL_PROTOCOL_VERSION_ATTRS[:i]
+        )
     )
 
 # TLSv1.3 is unique, doesn't have a PROTOCOL_TLSvX counterpart. So we have to 
set it manually.
 if _HAS_TLS_VERSION:
     try:
-        _SSL_PROTOCOL_VERSION_TO_TLS_VERSION[
+        _SSL_PROTOCOL_VERSION_TO_TLS_VERSION[ssl.TLSVersion.TLSv1_3] = (
             ssl.TLSVersion.TLSv1_3
-        ] = ssl.TLSVersion.TLSv1_3
+        )
     except AttributeError:  # pragma: nocover
         pass
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_node/_http_aiohttp.py 
new/elastic-transport-python-8.13.0/elastic_transport/_node/_http_aiohttp.py
--- 
old/elastic-transport-python-8.12.0/elastic_transport/_node/_http_aiohttp.py    
    2024-01-19 09:51:06.000000000 +0100
+++ 
new/elastic-transport-python-8.13.0/elastic_transport/_node/_http_aiohttp.py    
    2024-03-27 07:15:44.000000000 +0100
@@ -25,7 +25,7 @@
 import warnings
 from typing import Optional, Union
 
-from .._compat import get_running_loop, warn_stacklevel
+from .._compat import warn_stacklevel
 from .._exceptions import ConnectionError, ConnectionTimeout, SecurityWarning, 
TlsError
 from .._models import ApiResponseMeta, HttpHeaders, NodeConfig
 from ..client_utils import DEFAULT, DefaultType, client_meta_version
@@ -248,7 +248,7 @@
         a chance to set AiohttpHttpNode.loop
         """
         if self._loop is None:
-            self._loop = get_running_loop()
+            self._loop = asyncio.get_running_loop()
         self.session = aiohttp.ClientSession(
             headers=self.headers,
             skip_auto_headers=("accept", "accept-encoding", "user-agent"),
@@ -259,7 +259,7 @@
                 limit_per_host=self._connections_per_node,
                 use_dns_cache=True,
                 enable_cleanup_closed=True,
-                ssl=self._ssl_context,
+                ssl=self._ssl_context or False,
             ),
         )
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_node/_http_httpx.py 
new/elastic-transport-python-8.13.0/elastic_transport/_node/_http_httpx.py
--- old/elastic-transport-python-8.12.0/elastic_transport/_node/_http_httpx.py  
1970-01-01 01:00:00.000000000 +0100
+++ new/elastic-transport-python-8.13.0/elastic_transport/_node/_http_httpx.py  
2024-03-27 07:15:44.000000000 +0100
@@ -0,0 +1,194 @@
+#  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 gzip
+import os.path
+import ssl
+import time
+import warnings
+from typing import Optional, Union
+
+from .._compat import warn_stacklevel
+from .._exceptions import ConnectionError, ConnectionTimeout, SecurityWarning, 
TlsError
+from .._models import ApiResponseMeta, HttpHeaders, NodeConfig
+from ..client_utils import DEFAULT, DefaultType, client_meta_version
+from ._base import (
+    BUILTIN_EXCEPTIONS,
+    DEFAULT_CA_CERTS,
+    RERAISE_EXCEPTIONS,
+    NodeApiResponse,
+    ssl_context_from_node_config,
+)
+from ._base_async import BaseAsyncNode
+
+try:
+    import httpx
+
+    _HTTPX_AVAILABLE = True
+    _HTTPX_META_VERSION = client_meta_version(httpx.__version__)
+except ImportError:
+    _HTTPX_AVAILABLE = False
+    _HTTPX_META_VERSION = ""
+
+
+class HttpxAsyncHttpNode(BaseAsyncNode):
+    _CLIENT_META_HTTP_CLIENT = ("hx", _HTTPX_META_VERSION)
+
+    def __init__(self, config: NodeConfig):
+        if not _HTTPX_AVAILABLE:  # pragma: nocover
+            raise ValueError("You must have 'httpx' installed to use 
HttpxNode")
+        super().__init__(config)
+
+        if config.ssl_assert_fingerprint:
+            raise ValueError(
+                "httpx does not support certificate pinning. 
https://github.com/encode/httpx/issues/761";
+            )
+
+        # TODO switch to Literal[False] when dropping Python 3.7 support
+        ssl_context: Union[ssl.SSLContext, bool] = False
+        if config.scheme == "https":
+            if config.ssl_context is not None:
+                ssl_context = ssl_context_from_node_config(config)
+            else:
+                ssl_context = ssl_context_from_node_config(config)
+
+                ca_certs = (
+                    DEFAULT_CA_CERTS if config.ca_certs is None else 
config.ca_certs
+                )
+                if config.verify_certs:
+                    if not ca_certs:
+                        raise ValueError(
+                            "Root certificates are missing for certificate "
+                            "validation. Either pass them in using the 
ca_certs parameter or "
+                            "install certifi to use it automatically."
+                        )
+                else:
+                    if config.ssl_show_warn:
+                        warnings.warn(
+                            f"Connecting to {self.base_url!r} using TLS with 
verify_certs=False is insecure",
+                            stacklevel=warn_stacklevel(),
+                            category=SecurityWarning,
+                        )
+
+                if ca_certs is not None:
+                    if os.path.isfile(ca_certs):
+                        ssl_context.load_verify_locations(cafile=ca_certs)
+                    elif os.path.isdir(ca_certs):
+                        ssl_context.load_verify_locations(capath=ca_certs)
+                    else:
+                        raise ValueError("ca_certs parameter is not a path")
+
+                # Use client_cert and client_key variables for SSL certificate 
configuration.
+                if config.client_cert and not 
os.path.isfile(config.client_cert):
+                    raise ValueError("client_cert is not a path to a file")
+                if config.client_key and not os.path.isfile(config.client_key):
+                    raise ValueError("client_key is not a path to a file")
+                if config.client_cert and config.client_key:
+                    ssl_context.load_cert_chain(config.client_cert, 
config.client_key)
+                elif config.client_cert:
+                    ssl_context.load_cert_chain(config.client_cert)
+
+        self.client = httpx.AsyncClient(
+            base_url=f"{config.scheme}://{config.host}:{config.port}",
+            limits=httpx.Limits(max_connections=config.connections_per_node),
+            verify=ssl_context or False,
+            timeout=config.request_timeout,
+        )
+
+    async def perform_request(  # type: ignore[override]
+        self,
+        method: str,
+        target: str,
+        body: Optional[bytes] = None,
+        headers: Optional[HttpHeaders] = None,
+        request_timeout: Union[DefaultType, Optional[float]] = DEFAULT,
+    ) -> NodeApiResponse:
+        resolved_headers = self._headers.copy()
+        if headers:
+            resolved_headers.update(headers)
+
+        if body:
+            if self._http_compress:
+                resolved_body = gzip.compress(body)
+                resolved_headers["content-encoding"] = "gzip"
+            else:
+                resolved_body = body
+        else:
+            resolved_body = None
+
+        try:
+            start = time.perf_counter()
+            if request_timeout is DEFAULT:
+                resp = await self.client.request(
+                    method,
+                    target,
+                    content=resolved_body,
+                    headers=dict(resolved_headers),
+                )
+            else:
+                resp = await self.client.request(
+                    method,
+                    target,
+                    content=resolved_body,
+                    headers=dict(resolved_headers),
+                    timeout=request_timeout,
+                )
+            resp.raise_for_status()
+            response_body = resp.read()
+            duration = time.perf_counter() - start
+        except RERAISE_EXCEPTIONS + BUILTIN_EXCEPTIONS:
+            raise
+        except Exception as e:
+            err: Exception
+            if isinstance(e, (TimeoutError, httpx.TimeoutException)):
+                err = ConnectionTimeout(
+                    "Connection timed out during request", errors=(e,)
+                )
+            elif isinstance(e, ssl.SSLError):
+                err = TlsError(str(e), errors=(e,))
+            else:
+                err = ConnectionError(str(e), errors=(e,))
+            self._log_request(
+                method=method,
+                target=target,
+                headers=resolved_headers,
+                body=body,
+                exception=err,
+            )
+            raise err from None
+
+        meta = ApiResponseMeta(
+            resp.status_code,
+            resp.http_version,
+            HttpHeaders(resp.headers),
+            duration,
+            self.config,
+        )
+
+        self._log_request(
+            method=method,
+            target=target,
+            headers=resolved_headers,
+            body=body,
+            meta=meta,
+            response=response_body,
+        )
+
+        return NodeApiResponse(meta, response_body)
+
+    async def close(self) -> None:  # type: ignore[override]
+        await self.client.aclose()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_node/_http_requests.py 
new/elastic-transport-python-8.13.0/elastic_transport/_node/_http_requests.py
--- 
old/elastic-transport-python-8.12.0/elastic_transport/_node/_http_requests.py   
    2024-01-19 09:51:06.000000000 +0100
+++ 
new/elastic-transport-python-8.13.0/elastic_transport/_node/_http_requests.py   
    2024-03-27 07:15:44.000000000 +0100
@@ -75,9 +75,9 @@
                     ssl_context.check_hostname = False
                     ssl_context.verify_mode = ssl.CERT_NONE
 
-                    pool_kwargs[
-                        "assert_fingerprint"
-                    ] = self._node_config.ssl_assert_fingerprint
+                    pool_kwargs["assert_fingerprint"] = (
+                        self._node_config.ssl_assert_fingerprint
+                    )
                     pool_kwargs["cert_reqs"] = "CERT_NONE"
                     pool_kwargs["assert_hostname"] = False
 
@@ -203,9 +203,11 @@
         )
         prepared_request = self.session.prepare_request(request)
         send_kwargs = {
-            "timeout": request_timeout
-            if request_timeout is not DEFAULT
-            else self.config.request_timeout
+            "timeout": (
+                request_timeout
+                if request_timeout is not DEFAULT
+                else self.config.request_timeout
+            )
         }
         send_kwargs.update(
             self.session.merge_environment_settings(  # type: ignore[arg-type]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_node/_http_urllib3.py 
new/elastic-transport-python-8.13.0/elastic_transport/_node/_http_urllib3.py
--- 
old/elastic-transport-python-8.12.0/elastic_transport/_node/_http_urllib3.py    
    2024-01-19 09:51:06.000000000 +0100
+++ 
new/elastic-transport-python-8.13.0/elastic_transport/_node/_http_urllib3.py    
    2024-03-27 07:15:44.000000000 +0100
@@ -24,7 +24,7 @@
 try:
     from importlib import metadata
 except ImportError:
-    import importlib_metadata as metadata  # type: 
ignore[import-not-found,no-redef]
+    import importlib_metadata as metadata  # type: ignore[no-redef]
 
 import urllib3
 from urllib3.exceptions import ConnectTimeoutError, NewConnectionError, 
ReadTimeoutError
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_node_pool.py 
new/elastic-transport-python-8.13.0/elastic_transport/_node_pool.py
--- old/elastic-transport-python-8.12.0/elastic_transport/_node_pool.py 
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/elastic_transport/_node_pool.py 
2024-03-27 07:15:44.000000000 +0100
@@ -272,12 +272,10 @@
             )
 
     @overload
-    def resurrect(self, force: "Literal[True]" = ...) -> BaseNode:
-        ...
+    def resurrect(self, force: "Literal[True]" = ...) -> BaseNode: ...
 
     @overload
-    def resurrect(self, force: "Literal[False]" = ...) -> Optional[BaseNode]:
-        ...
+    def resurrect(self, force: "Literal[False]" = ...) -> Optional[BaseNode]: 
...
 
     def resurrect(self, force: bool = False) -> Optional[BaseNode]:
         """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_otel.py 
new/elastic-transport-python-8.13.0/elastic_transport/_otel.py
--- old/elastic-transport-python-8.12.0/elastic_transport/_otel.py      
1970-01-01 01:00:00.000000000 +0100
+++ new/elastic-transport-python-8.13.0/elastic_transport/_otel.py      
2024-03-27 07:15:44.000000000 +0100
@@ -0,0 +1,86 @@
+#  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.
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Mapping
+
+if TYPE_CHECKING:
+    from typing import Literal
+
+    from opentelemetry.trace import Span
+
+
+# A list of the Elasticsearch endpoints that qualify as "search" endpoints. 
The search query in
+# the request body may be captured for these endpoints, depending on the body 
capture strategy.
+SEARCH_ENDPOINTS = (
+    "search",
+    "async_search.submit",
+    "msearch",
+    "eql.search",
+    "esql.query",
+    "terms_enum",
+    "search_template",
+    "msearch_template",
+    "render_search_template",
+)
+
+
+class OpenTelemetrySpan:
+    def __init__(
+        self,
+        otel_span: Span | None,
+        endpoint_id: str | None = None,
+        # TODO import Literal at the top-level when dropping Python 3.7
+        body_strategy: 'Literal["omit", "raw"]' = "omit",
+    ):
+        self.otel_span = otel_span
+        self.body_strategy = body_strategy
+        self.endpoint_id = endpoint_id
+
+    def set_node_metadata(
+        self, host: str, port: int, base_url: str, target: str
+    ) -> None:
+        if self.otel_span is None:
+            return
+
+        # url.full does not contain auth info which is passed as headers
+        self.otel_span.set_attribute("url.full", base_url + target)
+        self.otel_span.set_attribute("server.address", host)
+        self.otel_span.set_attribute("server.port", port)
+
+    def set_elastic_cloud_metadata(self, headers: Mapping[str, str]) -> None:
+        if self.otel_span is None:
+            return
+
+        cluster_name = headers.get("X-Found-Handling-Cluster")
+        if cluster_name is not None:
+            self.otel_span.set_attribute("db.elasticsearch.cluster.name", 
cluster_name)
+        node_name = headers.get("X-Found-Handling-Instance")
+        if node_name is not None:
+            self.otel_span.set_attribute("db.elasticsearch.node.name", 
node_name)
+
+    def set_db_statement(self, serialized_body: bytes) -> None:
+        if self.otel_span is None:
+            return
+
+        if self.body_strategy == "omit":
+            return
+        elif self.body_strategy == "raw" and self.endpoint_id in 
SEARCH_ENDPOINTS:
+            self.otel_span.set_attribute(
+                "db.statement", serialized_body.decode("utf-8")
+            )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_response.py 
new/elastic-transport-python-8.13.0/elastic_transport/_response.py
--- old/elastic-transport-python-8.12.0/elastic_transport/_response.py  
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/elastic_transport/_response.py  
2024-03-27 07:15:44.000000000 +0100
@@ -151,12 +151,10 @@
         return iter(self.body)
 
     @overload
-    def __getitem__(self, item: slice) -> bytes:
-        ...
+    def __getitem__(self, item: slice) -> bytes: ...
 
     @overload
-    def __getitem__(self, item: int) -> int:
-        ...
+    def __getitem__(self, item: int) -> int: ...
 
     def __getitem__(self, item: Union[int, slice]) -> Union[int, bytes]:
         return self.body[item]
@@ -201,12 +199,10 @@
     """API responses which are a list of items. Can be NDJSON or a JSON list"""
 
     @overload
-    def __getitem__(self, item: slice) -> List[_ListItemBodyType]:
-        ...
+    def __getitem__(self, item: slice) -> List[_ListItemBodyType]: ...
 
     @overload
-    def __getitem__(self, item: int) -> _ListItemBodyType:
-        ...
+    def __getitem__(self, item: int) -> _ListItemBodyType: ...
 
     def __getitem__(
         self, item: Union[int, slice]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_serializer.py 
new/elastic-transport-python-8.13.0/elastic_transport/_serializer.py
--- old/elastic-transport-python-8.12.0/elastic_transport/_serializer.py        
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/elastic_transport/_serializer.py        
2024-03-27 07:15:44.000000000 +0100
@@ -24,8 +24,15 @@
 
 from ._exceptions import SerializationError
 
+try:
+    import orjson
+except ModuleNotFoundError:
+    orjson = None  # type: ignore[assignment]
+
 
 class Serializer:
+    """Serializer interface."""
+
     mimetype: ClassVar[str]
 
     def loads(self, data: bytes) -> Any:  # pragma: nocover
@@ -36,6 +43,8 @@
 
 
 class TextSerializer(Serializer):
+    """Text serializer to and from UTF-8."""
+
     mimetype: ClassVar[str] = "text/*"
 
     def loads(self, data: bytes) -> str:
@@ -62,6 +71,8 @@
 
 
 class JsonSerializer(Serializer):
+    """JSON serializer relying on the standard library json module."""
+
     mimetype: ClassVar[str] = "application/json"
 
     def default(self, data: Any) -> Any:
@@ -81,14 +92,15 @@
         ).encode("utf-8", "surrogatepass")
 
     def json_loads(self, data: bytes) -> Any:
+        return json.loads(data)
+
+    def loads(self, data: bytes) -> Any:
         # Sometimes responses use Content-Type: json but actually
         # don't contain any data. We should return something instead
         # of erroring in these cases.
         if data == b"":
             return None
-        return json.loads(data)
 
-    def loads(self, data: bytes) -> Any:
         try:
             return self.json_loads(data)
         except (ValueError, TypeError) as e:
@@ -115,7 +127,26 @@
             )
 
 
+if orjson is not None:
+
+    class OrjsonSerializer(JsonSerializer):
+        """JSON serializer relying on the orjson package.
+
+        Only available if orjson if installed. It is faster, especially for 
vectors, but is also stricter.
+        """
+
+        def json_dumps(self, data: Any) -> bytes:
+            return orjson.dumps(
+                data, default=self.default, option=orjson.OPT_SERIALIZE_NUMPY
+            )
+
+        def json_loads(self, data: bytes) -> Any:
+            return orjson.loads(data)
+
+
 class NdjsonSerializer(JsonSerializer):
+    """Newline delimited JSON (NDJSON) serializer relying on the standard 
library json module."""
+
     mimetype: ClassVar[str] = "application/x-ndjson"
 
     def loads(self, data: bytes) -> Any:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_transport.py 
new/elastic-transport-python-8.13.0/elastic_transport/_transport.py
--- old/elastic-transport-python-8.12.0/elastic_transport/_transport.py 
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/elastic_transport/_transport.py 
2024-03-27 07:15:44.000000000 +0100
@@ -52,8 +52,15 @@
     NodeConfig,
     SniffOptions,
 )
-from ._node import AiohttpHttpNode, BaseNode, RequestsHttpNode, Urllib3HttpNode
+from ._node import (
+    AiohttpHttpNode,
+    BaseNode,
+    HttpxAsyncHttpNode,
+    RequestsHttpNode,
+    Urllib3HttpNode,
+)
 from ._node_pool import NodePool, NodeSelector
+from ._otel import OpenTelemetrySpan
 from ._serializer import DEFAULT_SERIALIZERS, Serializer, SerializerCollection
 from ._version import __version__
 from .client_utils import client_meta_version, resolve_default
@@ -63,6 +70,7 @@
     "urllib3": Urllib3HttpNode,
     "requests": RequestsHttpNode,
     "aiohttp": AiohttpHttpNode,
+    "httpxasync": HttpxAsyncHttpNode,
 }
 # These are HTTP status errors that shouldn't be considered
 # 'errors' for marking a node as dead. These errors typically
@@ -114,7 +122,7 @@
         ] = None,
         meta_header: bool = True,
         client_meta_service: Tuple[str, str] = DEFAULT_CLIENT_META_SERVICE,
-    ) -> None:
+    ):
         """
         :arg node_configs: List of 'NodeConfig' instances to create initial 
set of nodes.
         :arg node_class: subclass of :class:`~elastic_transport.BaseNode` to 
use
@@ -257,6 +265,7 @@
         retry_on_timeout: Union[bool, DefaultType] = DEFAULT,
         request_timeout: Union[Optional[float], DefaultType] = DEFAULT,
         client_meta: Union[Tuple[Tuple[str, str], ...], DefaultType] = DEFAULT,
+        otel_span: Union[OpenTelemetrySpan, DefaultType] = DEFAULT,
     ) -> TransportApiResponse:
         """
         Perform the actual request. Retrieve a node from the node
@@ -280,6 +289,8 @@
         :arg retry_on_timeout: Set to true to retry after timeout errors.
         :arg request_timeout: Amount of time to wait for a response to fail 
with a timeout error.
         :arg client_meta: Extra client metadata key-value pairs to send in the 
client meta header.
+        :arg otel_span: OpenTelemetry span used to add metadata to the span.
+
         :returns: Tuple of the :class:`elastic_transport.ApiResponseMeta` with 
the deserialized response.
         """
         if headers is DEFAULT:
@@ -289,6 +300,7 @@
         max_retries = resolve_default(max_retries, self.max_retries)
         retry_on_timeout = resolve_default(retry_on_timeout, 
self.retry_on_timeout)
         retry_on_status = resolve_default(retry_on_status, 
self.retry_on_status)
+        otel_span = resolve_default(otel_span, OpenTelemetrySpan(None))
 
         if self.meta_header:
             request_headers["x-elastic-client-meta"] = ",".join(
@@ -307,6 +319,7 @@
             request_body = self.serializers.dumps(
                 body, mimetype=request_headers["content-type"]
             )
+            otel_span.set_db_statement(request_body)
         else:
             request_body = None
 
@@ -325,7 +338,8 @@
             node = self.node_pool.get()
             start_time = time.time()
             try:
-                meta, raw_data = node.perform_request(
+                otel_span.set_node_metadata(node.host, node.port, 
node.base_url, target)
+                resp = node.perform_request(
                     method,
                     target,
                     body=request_body,
@@ -338,26 +352,32 @@
                         method,
                         node.base_url,
                         target,
-                        meta.status,
+                        resp.meta.status,
                         time.time() - start_time,
                     )
                 )
 
                 if method != "HEAD":
-                    data = self.serializers.loads(raw_data, meta.mimetype)
+                    body = self.serializers.loads(resp.body, 
resp.meta.mimetype)
                 else:
-                    data = None
+                    body = None
 
-                if meta.status in retry_on_status:
+                if resp.meta.status in retry_on_status:
                     retry = True
                     # Keep track of the last response we see so we can return
                     # it in case the retried request returns with a transport 
error.
-                    last_response = TransportApiResponse(meta, data)
+                    last_response = TransportApiResponse(resp.meta, body)
 
             except TransportError as e:
                 _logger.info(
                     "%s %s%s [status:%s duration:%.3fs]"
-                    % (method, node.base_url, target, "N/A", time.time() - 
start_time)
+                    % (
+                        method,
+                        node.base_url,
+                        target,
+                        "N/A",
+                        time.time() - start_time,
+                    )
                 )
 
                 if isinstance(e, ConnectionTimeout):
@@ -404,8 +424,8 @@
                 # If we got back a response we need to check if that status
                 # is indicative of a healthy node even if it's a non-2XX status
                 if (
-                    200 <= meta.status < 299
-                    or meta.status in NOT_DEAD_NODE_HTTP_STATUSES
+                    200 <= resp.meta.status < 299
+                    or resp.meta.status in NOT_DEAD_NODE_HTTP_STATUSES
                 ):
                     self.node_pool.mark_live(node)
                 else:
@@ -422,11 +442,11 @@
                 # We either got a response we're happy with or
                 # we've exhausted all of our retries so we return it.
                 if not retry or attempt >= max_retries:
-                    return TransportApiResponse(meta, data)
+                    return TransportApiResponse(resp.meta, body)
                 else:
                     _logger.warning(
                         "Retrying request after non-successful status %d 
(attempt %d of %d)",
-                        meta.status,
+                        resp.meta.status,
                         attempt,
                         max_retries,
                     )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/elastic_transport/_version.py 
new/elastic-transport-python-8.13.0/elastic_transport/_version.py
--- old/elastic-transport-python-8.12.0/elastic_transport/_version.py   
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/elastic_transport/_version.py   
2024-03-27 07:15:44.000000000 +0100
@@ -15,4 +15,4 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-__version__ = "8.12.0"
+__version__ = "8.13.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elastic-transport-python-8.12.0/noxfile.py 
new/elastic-transport-python-8.13.0/noxfile.py
--- old/elastic-transport-python-8.12.0/noxfile.py      2024-01-19 
09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/noxfile.py      2024-03-27 
07:15:44.000000000 +0100
@@ -29,7 +29,7 @@
 
 @nox.session()
 def format(session):
-    session.install("black~=23.0", "isort", "pyupgrade")
+    session.install("black~=24.0", "isort", "pyupgrade")
     session.run("black", "--target-version=py37", *SOURCE_FILES)
     session.run("isort", *SOURCE_FILES)
     session.run("python", "utils/license-headers.py", "fix", *SOURCE_FILES)
@@ -41,7 +41,7 @@
 def lint(session):
     session.install(
         "flake8",
-        "black~=23.0",
+        "black~=24.0",
         "isort",
         "mypy==1.7.1",
         "types-requests",
@@ -54,7 +54,7 @@
     session.install(".[develop]")
     session.run("black", "--check", "--target-version=py37", *SOURCE_FILES)
     session.run("isort", "--check", *SOURCE_FILES)
-    session.run("flake8", "--ignore=E501,W503,E203", *SOURCE_FILES)
+    session.run("flake8", "--ignore=E501,W503,E203,E704", *SOURCE_FILES)
     session.run("python", "utils/license-headers.py", "check", *SOURCE_FILES)
     session.run("mypy", "--strict", "--show-error-codes", "elastic_transport/")
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elastic-transport-python-8.12.0/setup.py 
new/elastic-transport-python-8.13.0/setup.py
--- old/elastic-transport-python-8.12.0/setup.py        2024-01-19 
09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/setup.py        2024-03-27 
07:15:44.000000000 +0100
@@ -52,7 +52,6 @@
     install_requires=[
         "urllib3>=1.26.2, <3",
         "certifi",
-        "dataclasses; python_version<'3.7'",
         "importlib-metadata; python_version<'3.8'",
     ],
     python_requires=">=3.7",
@@ -67,6 +66,11 @@
             "mock",
             "requests",
             "aiohttp",
+            "httpx",
+            "respx",
+            "opentelemetry-api",
+            "opentelemetry-sdk",
+            "orjson",
             # Override Read the Docs default (sphinx<2)
             "sphinx>2",
             "furo",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/tests/async_/test_async_transport.py 
new/elastic-transport-python-8.13.0/tests/async_/test_async_transport.py
--- old/elastic-transport-python-8.12.0/tests/async_/test_async_transport.py    
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/tests/async_/test_async_transport.py    
2024-03-27 07:15:44.000000000 +0100
@@ -30,6 +30,7 @@
     AsyncTransport,
     ConnectionError,
     ConnectionTimeout,
+    HttpxAsyncHttpNode,
     NodeConfig,
     RequestsHttpNode,
     SniffingError,
@@ -38,7 +39,6 @@
     TransportWarning,
     Urllib3HttpNode,
 )
-from elastic_transport._compat import get_running_loop
 from elastic_transport._node._base import DEFAULT_USER_AGENT
 from elastic_transport.client_utils import DEFAULT
 from tests.conftest import AsyncDummyNode
@@ -303,11 +303,14 @@
     t = AsyncTransport([NodeConfig("http", "localhost", 80)], 
node_class="aiohttp")
     assert isinstance(t.node_pool.get(), AiohttpHttpNode)
 
+    t = AsyncTransport([NodeConfig("http", "localhost", 80)], 
node_class="httpxasync")
+    assert isinstance(t.node_pool.get(), HttpxAsyncHttpNode)
+
     with pytest.raises(ValueError) as e:
         AsyncTransport([NodeConfig("http", "localhost", 80)], 
node_class="huh?")
     assert str(e.value) == (
         "Unknown option for node_class: 'huh?'. "
-        "Available options are: 'aiohttp', 'requests', 'urllib3'"
+        "Available options are: 'aiohttp', 'httpxasync', 'requests', 'urllib3'"
     )
 
 
@@ -337,21 +340,29 @@
 
 
 @pytest.mark.parametrize(
-    "node_class",
-    ["aiohttp", AiohttpHttpNode],
+    "node_class, client_short_name",
+    [
+        ("aiohttp", "ai"),
+        (AiohttpHttpNode, "ai"),
+        ("httpxasync", "hx"),
+        (HttpxAsyncHttpNode, "hx"),
+    ],
 )
 @pytest.mark.asyncio
-async def test_transport_client_meta_node_class(node_class):
+async def test_transport_client_meta_node_class(node_class, client_short_name):
     t = AsyncTransport([NodeConfig("http", "localhost", 80)], 
node_class=node_class)
     assert (
         t._transport_client_meta[3] == 
t.node_pool.node_class._CLIENT_META_HTTP_CLIENT
     )
-    assert t._transport_client_meta[3][0] == "ai"
+    assert t._transport_client_meta[3][0] == client_short_name
     assert re.match(
-        r"^et=[0-9.]+p?,py=[0-9.]+p?,t=[0-9.]+p?,ai=[0-9.]+p?$",
+        
rf"^et=[0-9.]+p?,py=[0-9.]+p?,t=[0-9.]+p?,{client_short_name}=[0-9.]+p?$",
         ",".join(f"{k}={v}" for k, v in t._transport_client_meta),
     )
 
+
[email protected]
+async def test_transport_default_client_meta_node_class():
     # Defaults to aiohttp
     t = AsyncTransport(
         [NodeConfig("http", "localhost", 80)], client_meta_service=("es", 
"8.0.0p")
@@ -520,7 +531,7 @@
         NodeConfig("http", "localhost", 81),
     ]
 
-    loop = get_running_loop()
+    loop = asyncio.get_running_loop()
     sniffed_at = 0.0
 
     # Test that we accept both sync and async sniff_callbacks
@@ -638,7 +649,7 @@
         sniff_callback=sniff_callback,
     )
 
-    loop = get_running_loop()
+    loop = asyncio.get_running_loop()
     start = loop.time()
 
     async def run_requests():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/tests/node/test_base.py 
new/elastic-transport-python-8.13.0/tests/node/test_base.py
--- old/elastic-transport-python-8.12.0/tests/node/test_base.py 2024-01-19 
09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/tests/node/test_base.py 2024-03-27 
07:15:44.000000000 +0100
@@ -19,6 +19,7 @@
 
 from elastic_transport import (
     AiohttpHttpNode,
+    HttpxAsyncHttpNode,
     NodeConfig,
     RequestsHttpNode,
     Urllib3HttpNode,
@@ -27,7 +28,7 @@
 
 
 @pytest.mark.parametrize(
-    "node_cls", [Urllib3HttpNode, RequestsHttpNode, AiohttpHttpNode]
+    "node_cls", [Urllib3HttpNode, RequestsHttpNode, AiohttpHttpNode, 
HttpxAsyncHttpNode]
 )
 def test_unknown_parameter(node_cls):
     with pytest.raises(TypeError):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/tests/node/test_http_httpx.py 
new/elastic-transport-python-8.13.0/tests/node/test_http_httpx.py
--- old/elastic-transport-python-8.12.0/tests/node/test_http_httpx.py   
1970-01-01 01:00:00.000000000 +0100
+++ new/elastic-transport-python-8.13.0/tests/node/test_http_httpx.py   
2024-03-27 07:15:44.000000000 +0100
@@ -0,0 +1,157 @@
+#  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 gzip
+import ssl
+import warnings
+
+import pytest
+import respx
+
+from elastic_transport import HttpxAsyncHttpNode, NodeConfig
+from elastic_transport._node._base import DEFAULT_USER_AGENT
+
+
+def create_node(node_config: NodeConfig):
+    return HttpxAsyncHttpNode(node_config)
+
+
+class TestHttpxAsyncNodeCreation:
+    def test_ssl_context(self):
+        ssl_context = ssl.create_default_context()
+        with warnings.catch_warnings(record=True) as w:
+            node = create_node(
+                NodeConfig(
+                    scheme="https",
+                    host="localhost",
+                    port=80,
+                    ssl_context=ssl_context,
+                )
+            )
+        assert node.client._transport._pool._ssl_context is ssl_context
+        assert len(w) == 0
+
+    def test_uses_https_if_verify_certs_is_off(self):
+        with warnings.catch_warnings(record=True) as w:
+            _ = create_node(NodeConfig("https", "localhost", 443, 
verify_certs=False))
+        assert (
+            str(w[0].message)
+            == "Connecting to 'https://localhost:443' using TLS with 
verify_certs=False is insecure"
+        )
+
+    def test_no_warn_when_uses_https_if_verify_certs_is_off(self):
+        with warnings.catch_warnings(record=True) as w:
+            _ = create_node(
+                NodeConfig(
+                    "https",
+                    "localhost",
+                    443,
+                    verify_certs=False,
+                    ssl_show_warn=False,
+                )
+            )
+        assert 0 == len(w)
+
+    def test_ca_certs_with_verify_ssl_false_raises_error(self):
+        with pytest.raises(ValueError) as exc:
+            create_node(
+                NodeConfig(
+                    "https",
+                    "localhost",
+                    443,
+                    ca_certs="/ca/certs",
+                    verify_certs=False,
+                )
+            )
+            assert (
+                str(exc.value) == "You cannot use 'ca_certs' when 
'verify_certs=False'"
+            )
+
+
[email protected]
+class TestHttpxAsyncNode:
+    @respx.mock
+    async def test_simple_request(self):
+        node = create_node(NodeConfig(scheme="http", host="localhost", 
port=80))
+        respx.get("http://localhost/index";)
+        await node.perform_request(
+            "GET", "/index", b"hello world", headers={"key": "value"}
+        )
+        request = respx.calls.last.request
+        assert request.content == b"hello world"
+        assert {
+            "key": "value",
+            "connection": "keep-alive",
+            "user-agent": DEFAULT_USER_AGENT,
+        }.items() <= request.headers.items()
+
+    @respx.mock
+    async def test_compression(self):
+        node = create_node(
+            NodeConfig(scheme="http", host="localhost", port=80, 
http_compress=True)
+        )
+        respx.get("http://localhost/index";)
+        await node.perform_request("GET", "/index", b"hello world")
+        request = respx.calls.last.request
+        assert gzip.decompress(request.content) == b"hello world"
+        assert {"content-encoding": "gzip"}.items() <= request.headers.items()
+
+    @respx.mock
+    async def test_default_timeout(self):
+        node = create_node(
+            NodeConfig(scheme="http", host="localhost", port=80, 
request_timeout=10)
+        )
+        respx.get("http://localhost/index";)
+        await node.perform_request("GET", "/index", b"hello world")
+        request = respx.calls.last.request
+        assert request.extensions["timeout"]["connect"] == 10
+
+    @respx.mock
+    async def test_overwritten_timeout(self):
+        node = create_node(
+            NodeConfig(scheme="http", host="localhost", port=80, 
request_timeout=10)
+        )
+        respx.get("http://localhost/index";)
+        await node.perform_request("GET", "/index", b"hello world", 
request_timeout=15)
+        request = respx.calls.last.request
+        assert request.extensions["timeout"]["connect"] == 15
+
+    @respx.mock
+    async def test_merge_headers(self):
+        node = create_node(
+            NodeConfig("http", "localhost", 80, headers={"h1": "v1", "h2": 
"v2"})
+        )
+        respx.get("http://localhost/index";)
+        await node.perform_request(
+            "GET", "/index", b"hello world", headers={"h2": "v2p", "h3": "v3"}
+        )
+        request = respx.calls.last.request
+        assert request.headers["h1"] == "v1"
+        assert request.headers["h2"] == "v2p"
+        assert request.headers["h3"] == "v3"
+
+
+def test_ssl_assert_fingerprint(httpbin_cert_fingerprint):
+    with pytest.raises(ValueError, match="httpx does not support certificate 
pinning"):
+        HttpxAsyncHttpNode(
+            NodeConfig(
+                scheme="https",
+                host="httpbin.org",
+                port=443,
+                ssl_assert_fingerprint=httpbin_cert_fingerprint,
+            )
+        )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/tests/node/test_tls_versions.py 
new/elastic-transport-python-8.13.0/tests/node/test_tls_versions.py
--- old/elastic-transport-python-8.12.0/tests/node/test_tls_versions.py 
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/tests/node/test_tls_versions.py 
2024-03-27 07:15:44.000000000 +0100
@@ -23,6 +23,7 @@
 
 from elastic_transport import (
     AiohttpHttpNode,
+    HttpxAsyncHttpNode,
     NodeConfig,
     RequestsHttpNode,
     TlsError,
@@ -36,7 +37,8 @@
 TLSv1_2_URL = "https://tls-v1-2.badssl.com:1012";
 
 node_classes = pytest.mark.parametrize(
-    "node_class", [AiohttpHttpNode, Urllib3HttpNode, RequestsHttpNode]
+    "node_class",
+    [AiohttpHttpNode, Urllib3HttpNode, RequestsHttpNode, HttpxAsyncHttpNode],
 )
 
 supported_version_params = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elastic-transport-python-8.12.0/tests/test_otel.py 
new/elastic-transport-python-8.13.0/tests/test_otel.py
--- old/elastic-transport-python-8.12.0/tests/test_otel.py      1970-01-01 
01:00:00.000000000 +0100
+++ new/elastic-transport-python-8.13.0/tests/test_otel.py      2024-03-27 
07:15:44.000000000 +0100
@@ -0,0 +1,99 @@
+#  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.
+
+from opentelemetry.sdk.trace import TracerProvider, export
+from opentelemetry.sdk.trace.export.in_memory_span_exporter import 
InMemorySpanExporter
+
+from elastic_transport import JsonSerializer
+from elastic_transport._otel import OpenTelemetrySpan
+
+
+def setup_tracing():
+    tracer_provider = TracerProvider()
+    memory_exporter = InMemorySpanExporter()
+    span_processor = export.SimpleSpanProcessor(memory_exporter)
+    tracer_provider.add_span_processor(span_processor)
+    tracer = tracer_provider.get_tracer(__name__)
+
+    return tracer, memory_exporter
+
+
+def test_no_span():
+    # With telemetry disabled, those calls should not raise
+    span = OpenTelemetrySpan(None)
+    span.set_db_statement(JsonSerializer().dumps({"timeout": "1m"}))
+    span.set_node_metadata(
+        "localhost",
+        9200,
+        "http://localhost:9200/";,
+        "_ml/anomaly_detectors/my-job/_open",
+    )
+    span.set_elastic_cloud_metadata(
+        {
+            "X-Found-Handling-Cluster": "e9106fc68e3044f0b1475b04bf4ffd5f",
+            "X-Found-Handling-Instance": "instance-0000000001",
+        }
+    )
+
+
+def test_detailed_span():
+    tracer, memory_exporter = setup_tracing()
+    with tracer.start_as_current_span("ml.open_job") as otel_span:
+        span = OpenTelemetrySpan(
+            otel_span,
+            endpoint_id="my-job/_open",
+            body_strategy="omit",
+        )
+
+        span.set_db_statement(JsonSerializer().dumps({"timeout": "1m"}))
+        span.set_node_metadata(
+            "localhost",
+            9200,
+            "http://localhost:9200/";,
+            "_ml/anomaly_detectors/my-job/_open",
+        )
+        span.set_elastic_cloud_metadata(
+            {
+                "X-Found-Handling-Cluster": "e9106fc68e3044f0b1475b04bf4ffd5f",
+                "X-Found-Handling-Instance": "instance-0000000001",
+            }
+        )
+
+    spans = memory_exporter.get_finished_spans()
+    assert len(spans) == 1
+    assert spans[0].name == "ml.open_job"
+    assert spans[0].attributes == {
+        "url.full": "http://localhost:9200/_ml/anomaly_detectors/my-job/_open";,
+        "server.address": "localhost",
+        "server.port": 9200,
+        "db.elasticsearch.cluster.name": "e9106fc68e3044f0b1475b04bf4ffd5f",
+        "db.elasticsearch.node.name": "instance-0000000001",
+    }
+
+
+def test_db_statement():
+    tracer, memory_exporter = setup_tracing()
+    with tracer.start_as_current_span("search") as otel_span:
+        span = OpenTelemetrySpan(otel_span, endpoint_id="search", 
body_strategy="raw")
+        span.set_db_statement(JsonSerializer().dumps({"query": {"match_all": 
{}}}))
+
+    spans = memory_exporter.get_finished_spans()
+    assert len(spans) == 1
+    assert spans[0].name == "search"
+    assert spans[0].attributes == {
+        "db.statement": '{"query":{"match_all":{}}}',
+    }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/tests/test_package.py 
new/elastic-transport-python-8.13.0/tests/test_package.py
--- old/elastic-transport-python-8.12.0/tests/test_package.py   2024-01-19 
09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/tests/test_package.py   2024-03-27 
07:15:44.000000000 +0100
@@ -25,8 +25,11 @@
 
 @modules
 def test__all__sorted(module):
-    print(sorted(module.__all__))
-    assert module.__all__ == sorted(module.__all__)
+    module_all = module.__all__.copy()
+    # Optional dependencies are added at the end
+    if "OrjsonSerializer" in module_all:
+        module_all.remove("OrjsonSerializer")
+    assert module_all == sorted(module_all)
 
 
 @modules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/tests/test_serializer.py 
new/elastic-transport-python-8.13.0/tests/test_serializer.py
--- old/elastic-transport-python-8.12.0/tests/test_serializer.py        
2024-01-19 09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/tests/test_serializer.py        
2024-03-27 07:15:44.000000000 +0100
@@ -24,6 +24,7 @@
 from elastic_transport import (
     JsonSerializer,
     NdjsonSerializer,
+    OrjsonSerializer,
     SerializationError,
     SerializerCollection,
     TextSerializer,
@@ -33,66 +34,86 @@
 serializers = SerializerCollection(DEFAULT_SERIALIZERS)
 
 
-def test_date_serialization():
-    assert b'{"d":"2010-10-01"}' == JsonSerializer().dumps({"d": date(2010, 
10, 1)})
[email protected](params=[JsonSerializer, OrjsonSerializer])
+def json_serializer(request: pytest.FixtureRequest):
+    yield request.param()
 
 
-def test_decimal_serialization():
-    assert b'{"d":3.8}' == JsonSerializer().dumps({"d": Decimal("3.8")})
+def test_date_serialization(json_serializer):
+    assert b'{"d":"2010-10-01"}' == json_serializer.dumps({"d": date(2010, 10, 
1)})
 
 
-def test_uuid_serialization():
-    assert b'{"d":"00000000-0000-0000-0000-000000000003"}' == 
JsonSerializer().dumps(
+def test_decimal_serialization(json_serializer):
+    assert b'{"d":3.8}' == json_serializer.dumps({"d": Decimal("3.8")})
+
+
+def test_uuid_serialization(json_serializer):
+    assert b'{"d":"00000000-0000-0000-0000-000000000003"}' == 
json_serializer.dumps(
         {"d": uuid.UUID("00000000-0000-0000-0000-000000000003")}
     )
 
 
 def test_serializes_nan():
     assert b'{"d":NaN}' == JsonSerializer().dumps({"d": float("NaN")})
+    # NaN is invalid JSON, and orjson silently converts it to null
+    assert b'{"d":null}' == OrjsonSerializer().dumps({"d": float("NaN")})
 
 
-def test_raises_serialization_error_on_dump_error():
+def test_raises_serialization_error_on_dump_error(json_serializer):
     with pytest.raises(SerializationError):
-        JsonSerializer().dumps(object())
+        json_serializer.dumps(object())
     with pytest.raises(SerializationError):
         TextSerializer().dumps({})
 
 
-def test_raises_serialization_error_on_load_error():
+def test_raises_serialization_error_on_load_error(json_serializer):
     with pytest.raises(SerializationError):
-        JsonSerializer().loads(object())
+        json_serializer.loads(object())
     with pytest.raises(SerializationError):
-        JsonSerializer().loads(b"{{")
+        json_serializer.loads(b"{{")
 
 
-def test_unicode_is_handled():
-    j = JsonSerializer()
+def test_json_unicode_is_handled(json_serializer):
     assert (
-        j.dumps({"你好": "你好"})
+        json_serializer.dumps({"你好": "你好"})
         == b'{"\xe4\xbd\xa0\xe5\xa5\xbd":"\xe4\xbd\xa0\xe5\xa5\xbd"}'
     )
-    assert j.loads(b'{"\xe4\xbd\xa0\xe5\xa5\xbd":"\xe4\xbd\xa0\xe5\xa5\xbd"}') 
== {
-        "你好": "你好"
-    }
+    assert json_serializer.loads(
+        b'{"\xe4\xbd\xa0\xe5\xa5\xbd":"\xe4\xbd\xa0\xe5\xa5\xbd"}'
+    ) == {"你好": "你好"}
 
-    t = TextSerializer()
-    assert t.dumps("你好") == b"\xe4\xbd\xa0\xe5\xa5\xbd"
-    assert t.loads(b"\xe4\xbd\xa0\xe5\xa5\xbd") == "你好"
 
+def test_text_unicode_is_handled():
+    text_serializer = TextSerializer()
+    assert text_serializer.dumps("你好") == b"\xe4\xbd\xa0\xe5\xa5\xbd"
+    assert text_serializer.loads(b"\xe4\xbd\xa0\xe5\xa5\xbd") == "你好"
 
-def test_unicode_surrogates_handled():
-    j = JsonSerializer()
+
+def test_json_unicode_surrogates_handled():
     assert (
-        j.dumps({"key": "你好\uda6a"})
+        JsonSerializer().dumps({"key": "你好\uda6a"})
         == b'{"key":"\xe4\xbd\xa0\xe5\xa5\xbd\xed\xa9\xaa"}'
     )
-    assert j.loads(b'{"key":"\xe4\xbd\xa0\xe5\xa5\xbd\xed\xa9\xaa"}') == {
-        "key": "你好\uda6a"
-    }
-
-    t = TextSerializer()
-    assert t.dumps("你好\uda6a") == b"\xe4\xbd\xa0\xe5\xa5\xbd\xed\xa9\xaa"
-    assert t.loads(b"\xe4\xbd\xa0\xe5\xa5\xbd\xed\xa9\xaa") == "你好\uda6a"
+    assert JsonSerializer().loads(
+        b'{"key":"\xe4\xbd\xa0\xe5\xa5\xbd\xed\xa9\xaa"}'
+    ) == {"key": "你好\uda6a"}
+
+    # orjson is strict about UTF-8
+    with pytest.raises(SerializationError):
+        OrjsonSerializer().dumps({"key": "你好\uda6a"})
+
+    with pytest.raises(SerializationError):
+        
OrjsonSerializer().loads(b'{"key":"\xe4\xbd\xa0\xe5\xa5\xbd\xed\xa9\xaa"}')
+
+
+def test_text_unicode_surrogates_handled(json_serializer):
+    text_serializer = TextSerializer()
+    assert (
+        text_serializer.dumps("你好\uda6a") == 
b"\xe4\xbd\xa0\xe5\xa5\xbd\xed\xa9\xaa"
+    )
+    assert (
+        text_serializer.loads(b"\xe4\xbd\xa0\xe5\xa5\xbd\xed\xa9\xaa") == "ä½ 
好\uda6a"
+    )
 
 
 def test_deserializes_json_by_default():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elastic-transport-python-8.12.0/tests/test_transport.py 
new/elastic-transport-python-8.13.0/tests/test_transport.py
--- old/elastic-transport-python-8.12.0/tests/test_transport.py 2024-01-19 
09:51:06.000000000 +0100
+++ new/elastic-transport-python-8.13.0/tests/test_transport.py 2024-03-27 
07:15:44.000000000 +0100
@@ -327,7 +327,7 @@
         Transport([NodeConfig("http", "localhost", 80)], node_class="huh?")
     assert str(e.value) == (
         "Unknown option for node_class: 'huh?'. "
-        "Available options are: 'aiohttp', 'requests', 'urllib3'"
+        "Available options are: 'aiohttp', 'httpxasync', 'requests', 'urllib3'"
     )
 
 

++++++ requests232.patch ++++++
>From d49d5dda344f0a458c020a8a3c0032480e6b57d5 Mon Sep 17 00:00:00 2001
From: Quentin Pradet <[email protected]>
Date: Thu, 23 May 2024 11:48:10 +0400
Subject: [PATCH 1/3] Fix requests 2.32 compatibility

---
 elastic_transport/_node/_http_requests.py | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/elastic_transport/_node/_http_requests.py 
b/elastic_transport/_node/_http_requests.py
index 19cec37..e439865 100644
--- a/elastic_transport/_node/_http_requests.py
+++ b/elastic_transport/_node/_http_requests.py
@@ -169,7 +169,16 @@ def __init__(self, config: NodeConfig):
         )
         # Preload the HTTPConnectionPool so initialization issues
         # are raised here instead of in perform_request()
-        adapter.get_connection(self.base_url)  # type: ignore[no-untyped-call]
+        if hasattr(adapter, "get_connection_with_tls_context"):
+            adapter.get_connection_with_tls_context(
+                requests.Request(url=self.base_url), verify=self.session.verify
+            )
+        else:
+            # elastic-transport is not vulnerable to CVE-2024-35195 because it 
uses
+            # requests.Session and an SSLContext without using the verify 
parameter.
+            # We should remove this branch when requiring requests 2.32 or 
later.
+            adapter.get_connection(self.base_url)  # type: ignore 
[no-untyped-call]
+
         self.session.mount(prefix=f"{self.scheme}://", adapter=adapter)
 
     def perform_request(

>From 56d1e6832d0b438ee7cee3ab0f8dea6a14a89eb8 Mon Sep 17 00:00:00 2001
From: Quentin Pradet <[email protected]>
Date: Thu, 23 May 2024 11:59:42 +0400
Subject: [PATCH 2/3] Fix lint

---
 elastic_transport/_node/_http_requests.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/elastic_transport/_node/_http_requests.py 
b/elastic_transport/_node/_http_requests.py
index e439865..4b2d502 100644
--- a/elastic_transport/_node/_http_requests.py
+++ b/elastic_transport/_node/_http_requests.py
@@ -170,14 +170,16 @@ def __init__(self, config: NodeConfig):
         # Preload the HTTPConnectionPool so initialization issues
         # are raised here instead of in perform_request()
         if hasattr(adapter, "get_connection_with_tls_context"):
+            request = requests.Request(url=self.base_url)
+            prepared_request = self.session.prepare_request(request)
             adapter.get_connection_with_tls_context(
-                requests.Request(url=self.base_url), verify=self.session.verify
+                prepared_request, verify=self.session.verify
             )
         else:
             # elastic-transport is not vulnerable to CVE-2024-35195 because it 
uses
             # requests.Session and an SSLContext without using the verify 
parameter.
             # We should remove this branch when requiring requests 2.32 or 
later.
-            adapter.get_connection(self.base_url)  # type: ignore 
[no-untyped-call]
+            adapter.get_connection(self.base_url)
 
         self.session.mount(prefix=f"{self.scheme}://", adapter=adapter)
 

>From 8a222e2c9b81dc9f7a1e4583de59ecc0d4c4d803 Mon Sep 17 00:00:00 2001
From: Quentin Pradet <[email protected]>
Date: Thu, 23 May 2024 12:02:53 +0400
Subject: [PATCH 3/3] Fix prepared request

---
 elastic_transport/_node/_http_requests.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/elastic_transport/_node/_http_requests.py 
b/elastic_transport/_node/_http_requests.py
index 4b2d502..941e3cc 100644
--- a/elastic_transport/_node/_http_requests.py
+++ b/elastic_transport/_node/_http_requests.py
@@ -170,7 +170,7 @@ def __init__(self, config: NodeConfig):
         # Preload the HTTPConnectionPool so initialization issues
         # are raised here instead of in perform_request()
         if hasattr(adapter, "get_connection_with_tls_context"):
-            request = requests.Request(url=self.base_url)
+            request = requests.Request(method="GET", url=self.base_url)
             prepared_request = self.session.prepare_request(request)
             adapter.get_connection_with_tls_context(
                 prepared_request, verify=self.session.verify

Reply via email to