diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml
index f5e48c9eb..ff911719e 100644
--- a/.buildkite/pipeline.yml
+++ b/.buildkite/pipeline.yml
@@ -11,7 +11,6 @@ steps:
matrix:
setup:
python:
- - "3.7"
- "3.8"
- "3.9"
- "3.10"
@@ -24,7 +23,7 @@ steps:
- "test"
adjustments:
- with:
- python: "3.7"
+ python: "3.8"
connection: "urllib3"
nox_session: "test_otel"
- with:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1b662f866..94c554900 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -23,7 +23,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
+ python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
nox-session: [""]
runs-on: ["ubuntu-latest"]
diff --git a/docs/guide/getting-started.asciidoc b/docs/guide/getting-started.asciidoc
index db0a8095b..1b964e50c 100644
--- a/docs/guide/getting-started.asciidoc
+++ b/docs/guide/getting-started.asciidoc
@@ -8,7 +8,7 @@ operations with it.
[discrete]
=== Requirements
-* https://www.python.org/[Python] 3.7 or newer
+* https://www.python.org/[Python] 3.8 or newer
* https://pip.pypa.io/en/stable/[`pip`], installed by default alongside Python
[discrete]
diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py
index e6fe394ec..d7c3f7751 100644
--- a/docs/sphinx/conf.py
+++ b/docs/sphinx/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# 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
diff --git a/docs/sphinx/quickstart.rst b/docs/sphinx/quickstart.rst
index 51938e921..563ea6f23 100644
--- a/docs/sphinx/quickstart.rst
+++ b/docs/sphinx/quickstart.rst
@@ -9,7 +9,7 @@ operations like indexing or searching documents.
Requirements
------------
-- `Python `_ 3.7 or newer
+- `Python `_ 3.8 or newer
- `pip `_
diff --git a/elasticsearch/_otel.py b/elasticsearch/_otel.py
index 9264569b3..039f7798b 100644
--- a/elasticsearch/_otel.py
+++ b/elasticsearch/_otel.py
@@ -19,10 +19,7 @@
import contextlib
import os
-from typing import TYPE_CHECKING, Generator, Mapping
-
-if TYPE_CHECKING:
- from typing import Literal
+from typing import Generator, Literal, Mapping
try:
from opentelemetry import trace
@@ -48,8 +45,7 @@ def __init__(
self,
enabled: bool | None = None,
tracer: trace.Tracer | None = None,
- # TODO import Literal at the top-level when dropping Python 3.7
- body_strategy: 'Literal["omit", "raw"]' | None = None,
+ body_strategy: Literal["omit", "raw"] | None = None,
):
if enabled is None:
enabled = os.environ.get(ENABLED_ENV_VAR, "true") == "true"
diff --git a/examples/bulk-ingest/bulk-ingest.py b/examples/bulk-ingest/bulk-ingest.py
index 4c5c34c86..e1619ecde 100644
--- a/examples/bulk-ingest/bulk-ingest.py
+++ b/examples/bulk-ingest/bulk-ingest.py
@@ -66,7 +66,7 @@ def generate_actions():
yields a single document. This function is passed into the bulk()
helper to create many documents in sequence.
"""
- with open(DATASET_PATH, mode="r") as f:
+ with open(DATASET_PATH) as f:
reader = csv.DictReader(f)
for row in reader:
diff --git a/noxfile.py b/noxfile.py
index 2c97b5679..69e53417f 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -45,14 +45,14 @@ def pytest_argv():
]
-@nox.session(python=["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"])
+@nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12"])
def test(session):
session.install(".[dev]", env=INSTALL_ENV, silent=False)
session.run(*pytest_argv())
-@nox.session(python=["3.7", "3.12"])
+@nox.session(python=["3.8", "3.12"])
def test_otel(session):
session.install(
".[dev]",
diff --git a/pyproject.toml b/pyproject.toml
index 20f206d27..2a35c51f0 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -7,7 +7,7 @@ name = "elasticsearch"
description = "Python client for Elasticsearch"
readme = "README.md"
license = "Apache-2.0"
-requires-python = ">=3.7"
+requires-python = ">=3.8"
authors = [
{ name = "Elastic Client Library Maintainers", email = "client-libs@elastic.co" },
]
@@ -21,7 +21,6 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
@@ -72,8 +71,6 @@ dev = [
"simsimd",
"pandas",
"mapbox-vector-tile",
- # Python 3.7 gets an old version of mapbox-vector-tile, requiring an old version of protobuf
- "protobuf<4; python_version<=\"3.7\"",
]
docs = [
"sphinx",
diff --git a/test_elasticsearch/test_async/test_server/test_clients.py b/test_elasticsearch/test_async/test_server/test_clients.py
index 8ae5726c1..00de2c7fb 100644
--- a/test_elasticsearch/test_async/test_server/test_clients.py
+++ b/test_elasticsearch/test_async/test_server/test_clients.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# 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
@@ -16,7 +15,6 @@
# specific language governing permissions and limitations
# under the License.
-from __future__ import unicode_literals
import pytest
diff --git a/test_elasticsearch/test_async/test_server/test_helpers.py b/test_elasticsearch/test_async/test_server/test_helpers.py
index 6e9de3075..746dc1028 100644
--- a/test_elasticsearch/test_async/test_server/test_helpers.py
+++ b/test_elasticsearch/test_async/test_server/test_helpers.py
@@ -33,13 +33,13 @@
class AsyncMock(MagicMock):
async def __call__(self, *args, **kwargs):
- return super(AsyncMock, self).__call__(*args, **kwargs)
+ return super().__call__(*args, **kwargs)
def __await__(self):
return self().__await__()
-class FailingBulkClient(object):
+class FailingBulkClient:
def __init__(
self,
client,
@@ -68,7 +68,7 @@ def options(self, **_):
return self
-class TestStreamingBulk(object):
+class TestStreamingBulk:
async def test_actions_remain_unchanged(self, async_client):
actions = [{"_id": 1}, {"_id": 2}]
async for ok, item in helpers.async_streaming_bulk(
@@ -294,7 +294,7 @@ async def streaming_bulk():
assert 4 == failing_client._called
-class TestBulk(object):
+class TestBulk:
async def test_bulk_works_with_single_item(self, async_client):
docs = [{"answer": 42, "_id": 1}]
success, failed = await helpers.async_bulk(
@@ -458,7 +458,7 @@ async def scan_teardown(async_client):
await async_client.clear_scroll(scroll_id="_all")
-class TestScan(object):
+class TestScan:
async def test_order_can_be_preserved(self, async_client, scan_teardown):
bulk = []
for x in range(100):
@@ -493,8 +493,8 @@ async def test_all_documents_are_read(self, async_client, scan_teardown):
]
assert 100 == len(docs)
- assert set(map(str, range(100))) == set(d["_id"] for d in docs)
- assert set(range(100)) == set(d["_source"]["answer"] for d in docs)
+ assert set(map(str, range(100))) == {d["_id"] for d in docs}
+ assert set(range(100)) == {d["_source"]["answer"] for d in docs}
async def test_scroll_error(self, async_client, scan_teardown):
bulk = []
@@ -881,7 +881,7 @@ async def reindex_setup(async_client):
yield
-class TestReindex(object):
+class TestReindex:
async def test_reindex_passes_kwargs_to_scan_and_bulk(
self, async_client, reindex_setup
):
@@ -1031,7 +1031,7 @@ async def reindex_data_stream_setup(async_client):
yield
-class TestAsyncDataStreamReindex(object):
+class TestAsyncDataStreamReindex:
@pytest.mark.parametrize("op_type", [None, "create"])
async def test_reindex_index_datastream(
self, op_type, async_client, reindex_data_stream_setup
diff --git a/test_elasticsearch/test_async/test_server/test_rest_api_spec.py b/test_elasticsearch/test_async/test_server/test_rest_api_spec.py
index fd4fd04e3..eee2364f6 100644
--- a/test_elasticsearch/test_async/test_server/test_rest_api_spec.py
+++ b/test_elasticsearch/test_async/test_server/test_rest_api_spec.py
@@ -228,9 +228,9 @@ async def _feature_enabled(self, name):
if XPACK_FEATURES is None:
try:
xinfo = await self.client.xpack.info()
- XPACK_FEATURES = set(
+ XPACK_FEATURES = {
f for f in xinfo["features"] if xinfo["features"][f]["enabled"]
- )
+ }
IMPLEMENTED_FEATURES.add("xpack")
except RequestError:
XPACK_FEATURES = set()
diff --git a/test_elasticsearch/test_async/test_transport.py b/test_elasticsearch/test_async/test_transport.py
index 918e19e57..76a71f50b 100644
--- a/test_elasticsearch/test_async/test_transport.py
+++ b/test_elasticsearch/test_async/test_transport.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# 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
@@ -16,7 +15,6 @@
# specific language governing permissions and limitations
# under the License.
-from __future__ import unicode_literals
import asyncio
import re
@@ -280,7 +278,7 @@ def test_kwargs_passed_on_to_node_pool(self):
)
assert dt is client.transport.node_pool.dead_node_backoff_factor
- class MyConnection(object):
+ class MyConnection:
def __init__(self, *_, **__):
pass
diff --git a/test_elasticsearch/test_client/test_options.py b/test_elasticsearch/test_client/test_options.py
index adf7a1d0d..b7fa3cfda 100644
--- a/test_elasticsearch/test_client/test_options.py
+++ b/test_elasticsearch/test_client/test_options.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# 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
diff --git a/test_elasticsearch/test_client/test_overrides.py b/test_elasticsearch/test_client/test_overrides.py
index fd8ad9f65..28fa8708b 100644
--- a/test_elasticsearch/test_client/test_overrides.py
+++ b/test_elasticsearch/test_client/test_overrides.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# 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
diff --git a/test_elasticsearch/test_client/test_utils.py b/test_elasticsearch/test_client/test_utils.py
index 3c245f397..e53145bfd 100644
--- a/test_elasticsearch/test_client/test_utils.py
+++ b/test_elasticsearch/test_client/test_utils.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# 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
@@ -16,7 +15,6 @@
# specific language governing permissions and limitations
# under the License.
-from __future__ import unicode_literals
from elasticsearch._sync.client.utils import _quote
diff --git a/test_elasticsearch/test_helpers.py b/test_elasticsearch/test_helpers.py
index a8efb151c..c9284afc5 100644
--- a/test_elasticsearch/test_helpers.py
+++ b/test_elasticsearch/test_helpers.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# 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
@@ -75,7 +74,7 @@ def test_chunk_sent_from_different_threads(self, _process_bulk_chunk):
chunk_size=2,
)
)
- assert len(set([r[1] for r in results])) > 1
+ assert len({r[1] for r in results}) > 1
class TestChunkActions:
diff --git a/test_elasticsearch/test_serializer.py b/test_elasticsearch/test_serializer.py
index 4f66ba9a2..ba5f1adec 100644
--- a/test_elasticsearch/test_serializer.py
+++ b/test_elasticsearch/test_serializer.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# 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
diff --git a/test_elasticsearch/test_server/test_clients.py b/test_elasticsearch/test_server/test_clients.py
index e7c2a78e6..93720ed14 100644
--- a/test_elasticsearch/test_server/test_clients.py
+++ b/test_elasticsearch/test_server/test_clients.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# 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
diff --git a/test_elasticsearch/test_server/test_helpers.py b/test_elasticsearch/test_server/test_helpers.py
index 2978e20d9..33c31c364 100644
--- a/test_elasticsearch/test_server/test_helpers.py
+++ b/test_elasticsearch/test_server/test_helpers.py
@@ -27,7 +27,7 @@
from elasticsearch.helpers import ScanError
-class FailingBulkClient(object):
+class FailingBulkClient:
def __init__(
self,
client,
@@ -463,8 +463,8 @@ def test_all_documents_are_read(sync_client):
docs = list(helpers.scan(sync_client, index="test_index", size=2))
assert 100 == len(docs)
- assert set(map(str, range(100))) == set(d["_id"] for d in docs)
- assert set(range(100)) == set(d["_source"]["answer"] for d in docs)
+ assert set(map(str, range(100))) == {d["_id"] for d in docs}
+ assert set(range(100)) == {d["_source"]["answer"] for d in docs}
@pytest.mark.usefixtures("scan_teardown")
diff --git a/test_elasticsearch/test_server/test_rest_api_spec.py b/test_elasticsearch/test_server/test_rest_api_spec.py
index e45625842..6ede3b753 100644
--- a/test_elasticsearch/test_server/test_rest_api_spec.py
+++ b/test_elasticsearch/test_server/test_rest_api_spec.py
@@ -24,7 +24,6 @@
import json
import os
import re
-import sys
import warnings
import zipfile
from typing import Tuple, Union
@@ -131,10 +130,7 @@
XPACK_FEATURES = None
ES_VERSION = None
-RUN_ASYNC_REST_API_TESTS = (
- sys.version_info >= (3, 8)
- and os.environ.get("PYTHON_CONNECTION_CLASS") == "requests"
-)
+RUN_ASYNC_REST_API_TESTS = os.environ.get("PYTHON_CONNECTION_CLASS") == "requests"
FALSEY_VALUES = ("", None, False, 0, 0.0)
@@ -456,7 +452,7 @@ def _resolve(self, value):
if isinstance(value, string_types):
value = value.strip()
elif isinstance(value, dict):
- value = dict((k, self._resolve(v)) for (k, v) in value.items())
+ value = {k: self._resolve(v) for (k, v) in value.items()}
elif isinstance(value, list):
value = list(map(self._resolve, value))
return value
@@ -495,9 +491,9 @@ def _feature_enabled(self, name):
if XPACK_FEATURES is None:
try:
xinfo = self.client.xpack.info()
- XPACK_FEATURES = set(
+ XPACK_FEATURES = {
f for f in xinfo["features"] if xinfo["features"][f]["enabled"]
- )
+ }
IMPLEMENTED_FEATURES.add("xpack")
except RequestError:
XPACK_FEATURES = set()
diff --git a/test_elasticsearch/test_transport.py b/test_elasticsearch/test_transport.py
index ce8b7f901..5161cd8e1 100644
--- a/test_elasticsearch/test_transport.py
+++ b/test_elasticsearch/test_transport.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# 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
@@ -311,7 +310,7 @@ def test_kwargs_passed_on_to_node_pool(self):
assert dt is client.transport.node_pool.dead_node_backoff_factor
def test_custom_node_class(self):
- class MyConnection(object):
+ class MyConnection:
def __init__(self, *_, **__):
pass
diff --git a/utils/build-dists.py b/utils/build-dists.py
index 103e95f0e..15187c5a9 100644
--- a/utils/build-dists.py
+++ b/utils/build-dists.py
@@ -50,7 +50,7 @@ def run(*argv, expect_exit_code=0):
else:
os.chdir(tmp_dir)
- cmd = " ".join(shlex.quote(x) for x in argv)
+ cmd = shlex.join(argv)
print("$ " + cmd)
exit_code = os.system(cmd)
if exit_code != expect_exit_code:
diff --git a/utils/bump-version.py b/utils/bump-version.py
index 821d92344..07507ea48 100644
--- a/utils/bump-version.py
+++ b/utils/bump-version.py
@@ -29,7 +29,7 @@
def find_and_replace(path, pattern, replace):
# Does a find and replace within a file path and complains
# if the given pattern isn't found in the file.
- with open(path, "r") as f:
+ with open(path) as f:
old_data = f.read()
if re.search(pattern, old_data, flags=re.MULTILINE) is None:
diff --git a/utils/license-headers.py b/utils/license-headers.py
index b4fc7432b..4b7b978c5 100644
--- a/utils/license-headers.py
+++ b/utils/license-headers.py
@@ -66,7 +66,7 @@ def find_files_to_fix(sources: List[str]) -> Iterator[str]:
def does_file_need_fix(filepath: str) -> bool:
if not re.search(r"\.pyi?$", filepath):
return False
- with open(filepath, mode="r") as f:
+ with open(filepath) as f:
first_license_line = None
for line in f:
if line == license_header_lines[0]:
@@ -83,7 +83,7 @@ def does_file_need_fix(filepath: str) -> bool:
def add_header_to_file(filepath: str) -> None:
- with open(filepath, mode="r") as f:
+ with open(filepath) as f:
lines = list(f)
i = 0
for i, line in enumerate(lines):