Skip to content

Commit

Permalink
Merge branch 'master' into 8.x
Browse files Browse the repository at this point in the history
  • Loading branch information
untergeek committed Jan 24, 2025
2 parents 3ba5f2f + 39078df commit 60d615a
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 30 deletions.
25 changes: 25 additions & 0 deletions docs/Changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,31 @@
Changelog
=========

8.17.1 (24 Janary 2025)
-----------------------

**Announcements**

* Python 3.13 support...but with a caveat.
* HUGE (potential) caveat, though. The Python 3.13 SSL implementation now has
``X509_V_FLAG_X509_STRICT`` set by default. This unfortunately means that
self-signed certificates created by Elasticsearch's ``certutil`` will not
work with Python 3.13 as they do not yet include the key usage extension.
If you are using ``es_client`` in any way with one of these certificates,
I highly recommend that you not use Python 3.13 until this is resolved.
* 3.13 is excluded from the Hatch test matrix for this reason.
* 3.13 will still be tested manually with each release.

**Changes**

* Python module version bumps:
* ``elasticsearch8==8.17.1``
* ``click==8.1.8``
* ``certifi>=2024.12.14``
* Refactored ``master_only`` functions and tests. I discovered some loopholes
in my code when I was testing Python 3.13 against an Elastic Cloud instance,
so I fixed them. This also necessitated a change in the integration tests.

8.15.2 (30 September 2024)
--------------------------

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@

intersphinx_mapping = {
"python": ("https://docs.python.org/3.12", None),
"elasticsearch8": ("https://elasticsearch-py.readthedocs.io/en/v8.15.1", None),
"elasticsearch8": ("https://elasticsearch-py.readthedocs.io/en/v8.17.1", None),
"elastic-transport": (
"https://elastic-transport-python.readthedocs.io/en/stable",
None,
Expand Down
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
elasticsearch8==8.15.1
elasticsearch8==8.17.1
voluptuous>=0.14.2
pyyaml==6.0.2
pint>=0.19.2
9 changes: 5 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ classifiers = [
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.13',
]
keywords = [
'elasticsearch',
Expand All @@ -27,19 +28,19 @@ keywords = [
'command-line'
]
dependencies = [
'elasticsearch8==8.15.1',
'elasticsearch8==8.17.1',
'ecs-logging==2.2.0',
'dotmap==1.3.30',
'click==8.1.7',
'click==8.1.8',
'pyyaml==6.0.2',
'voluptuous>=0.14.2',
'certifi>=2024.8.30'
'certifi>=2024.12.14'
]

[project.optional-dependencies]
test = [
'requests',
'pytest >=7.2.1',
'pytest>=7.2.1',
'pytest-cov',
'pytest-dotenv',
]
Expand Down
2 changes: 1 addition & 1 deletion src/es_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
from .builder import Builder

__all__ = ["Builder"]
__version__ = "8.15.2"
__version__ = "8.17.1"
37 changes: 20 additions & 17 deletions src/es_client/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def update_config(self) -> None:
self.client_args.update(self.config.client)
self.other_args.update(self.config.other_settings)
self.master_only = self.other_args.master_only
self.is_master = None # Preset, until we populate this later
self.is_master = False # Preset, until we populate this later
if "skip_version_test" in self.other_args:
self.skip_version_test = self.other_args.skip_version_test
else:
Expand Down Expand Up @@ -235,7 +235,10 @@ def connect(self) -> None:
self._get_client()
# Post checks
self._check_version()
self._check_master()
if self.master_only:
self._check_multiple_hosts()
self._find_master()
self._check_if_master()

def _check_basic_auth(self) -> None:
"""Create ``basic_auth`` tuple from username and password"""
Expand Down Expand Up @@ -333,27 +336,27 @@ def _find_master(self) -> None:
master_node_id = self.client.cluster.state(metric="master_node")["master_node"]
self.is_master = my_node_id == master_node_id

def _check_master(self) -> None:
def _check_multiple_hosts(self) -> None:
"""Check for multiple hosts when master_only"""
if "hosts" in self.client_args and isinstance(self.client_args.hosts, list):
if len(self.client_args.hosts) > 1:
raise ConfigurationError(
f'"master_only" cannot be True if more than one host is '
f"specified. Hosts = {self.client_args.hosts}"
)

def _check_if_master(self) -> None:
"""
If :py:attr:`master_only` is ``True`` and we are not connected to the elected
master node, raise :py:exc:`~es_client.exceptions.NotMaster`
If we are not connected to the elected master node, raise
:py:exc:`~es_client.exceptions.NotMaster`
"""
if self.is_master is None:
self._find_master()
if self.master_only:
if not self.is_master:
msg = (
"The master_only flag is set to True, but the client is "
"currently connected to a non-master node."
)
if "hosts" in self.client_args and isinstance(self.client_args.hosts, list):
if len(self.client_args.hosts) > 1:
raise ConfigurationError(
f'"master_only" cannot be True if more than one host is '
f"specified. Hosts = {self.client_args.hosts}"
)
if not self.is_master:
logger.info(msg)
raise NotMaster(msg)
logger.info(msg)
raise NotMaster(msg)

def _check_version(self) -> None:
"""
Expand Down
16 changes: 10 additions & 6 deletions tests/integration/test_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,28 @@ def test_multiple_hosts_raises(self):
"password": PASS,
},
"client": {
"hosts": [HOST, "https://localhost:9200"],
"hosts": [HOST],
"ca_certs": CACRT,
},
}
}
obj = Builder(configdict=local_conf, autoconnect=False)
obj._get_client()
# Cheating in an extra HOST here
obj.client_args.hosts.append(HOST)
with pytest.raises(ConfigurationError):
obj._check_master()
obj._check_multiple_hosts()

def test_exit_if_not_master(self):
"""Raise NotMaster if node is not master"""
obj = Builder(config, autoconnect=False)
obj.master_only = True
obj.is_master = False
obj._get_client()
obj._find_master()
# Cheating in a False result for is_master
obj.is_master = False
with pytest.raises(NotMaster):
obj._check_master()
obj._check_if_master()


class TestCheckVersion(TestCase):
Expand Down Expand Up @@ -82,5 +86,5 @@ def test_client_info(self):
"""Proper connection to client makes for a good response"""
obj = Builder(configdict=config, autoconnect=True)
client = obj.client
expected = client.info()
assert expected == obj.test_connection()
expected = dict(client.info())
assert expected['cluster_name'] == dict(obj.test_connection())['cluster_name']

0 comments on commit 60d615a

Please sign in to comment.