[7.x] Add support for the HTTP API compatibility header

Co-authored-by: Seth Michael Larson <[email protected]>
This commit is contained in:
github-actions[bot]
2021-04-26 16:55:59 -05:00
committed by GitHub
co-authored by Seth Michael Larson
parent 5ab523b703
commit 2c5f1d1569
9 changed files with 84 additions and 18 deletions
+23 -1
View File
@@ -60,7 +60,29 @@ To create an `SSLContext` object you only need to use one of cafile, capath or c
* `capath` is the directory of a collection of CA's
* `cadata` is either an ASCII string of one or more PEM-encoded certificates or a bytes-like object of DER-encoded certificates.
Please note that the use of SSLContext is only available for Urllib3.
Please note that the use of SSLContext is only available for urllib3.
.. autoclass:: Urllib3HttpConnection
:members:
API Compatibility HTTP Header
-----------------------------
The Python client can be configured to emit an HTTP header
``Accept: application/vnd.elasticsearch+json; compatible-with=7``
which signals to Elasticsearch that the client is requesting
``7.x`` version of request and response bodies. This allows for
upgrading from 7.x to 8.x version of Elasticsearch without upgrading
everything at once. Elasticsearch should be upgraded first after
the compatibility header is configured and clients should be upgraded
second.
.. code-block:: python
from elasticsearch import Elasticsearch
client = Elasticsearch("http://...", headers={"accept": "application/vnd.elasticsearch+json; compatible-with=7"})
If you'd like to have the client emit the header without configuring ``headers`` you
can use the environment variable ``ELASTIC_CLIENT_APIVERSIONING=1``.
+9 -1
View File
@@ -19,6 +19,7 @@ import binascii
import gzip
import io
import logging
import os
import re
import warnings
from platform import python_version
@@ -28,7 +29,7 @@ try:
except ImportError:
import json
from .. import __versionstr__
from .. import __version__, __versionstr__
from ..exceptions import (
HTTP_EXCEPTIONS,
ElasticsearchWarning,
@@ -121,6 +122,13 @@ class Connection(object):
if opaque_id:
self.headers["x-opaque-id"] = opaque_id
if os.getenv("ELASTIC_CLIENT_APIVERSIONING") == "1":
self.headers.setdefault(
"accept",
"application/vnd.elasticsearch+json;compatible-with=%s"
% (str(__version__[0]),),
)
self.headers.setdefault("content-type", "application/json")
self.headers.setdefault("user-agent", self._get_default_user_agent())
+6 -2
View File
@@ -154,8 +154,12 @@ class Deserializer(object):
if not mimetype:
deserializer = self.default
else:
# split out charset
mimetype, _, _ = mimetype.partition(";")
# split out 'charset' and 'compatible-width' options
mimetype = mimetype.partition(";")[0].strip()
# Treat 'application/vnd.elasticsearch+json'
# as application/json for compatibility.
if mimetype == "application/vnd.elasticsearch+json":
mimetype = "application/json"
try:
deserializer = self.serializers[mimetype]
except KeyError:
+21
View File
@@ -18,6 +18,7 @@
import gzip
import io
import os
import re
import ssl
import warnings
@@ -171,6 +172,26 @@ class TestBaseConnection(TestCase):
Connection(meta_header=1)
assert str(e.value) == "meta_header must be of type bool"
def test_compatibility_accept_header(self):
try:
conn = Connection()
assert "accept" not in conn.headers
os.environ["ELASTIC_CLIENT_APIVERSIONING"] = "0"
conn = Connection()
assert "accept" not in conn.headers
os.environ["ELASTIC_CLIENT_APIVERSIONING"] = "1"
conn = Connection()
assert (
conn.headers["accept"]
== "application/vnd.elasticsearch+json;compatible-with=8"
)
finally:
os.environ.pop("ELASTIC_CLIENT_APIVERSIONING")
class TestUrllib3Connection(TestCase):
def _get_mock_connection(self, connection_params={}, response_body=b"{}"):
+11
View File
@@ -185,6 +185,17 @@ class TestDeserializer(TestCase):
self.de.loads('{"some":"data"}', "text/plain; charset=whatever"),
)
def test_deserialize_compatibility_header(self):
for content_type in (
"application/vnd.elasticsearch+json;compatible-with=7",
"application/vnd.elasticsearch+json; compatible-with=7",
"application/vnd.elasticsearch+json;compatible-with=8",
"application/vnd.elasticsearch+json; compatible-with=8",
):
self.assertEqual(
{"some": "data"}, self.de.loads('{"some":"data"}', content_type)
)
def test_raises_serialization_error_on_unknown_mimetype(self):
self.assertRaises(SerializationError, self.de.loads, "{}", "text/html")