From 6322fe091a08be3e47b78d3d786ce6eb1276916d Mon Sep 17 00:00:00 2001 From: arpitjain099 Date: Sun, 28 Jun 2026 12:29:01 +0900 Subject: [PATCH] fix: stop default_tags leaking across clients via shared PointSettings The write_api() factories and WriteApi.__init__ used PointSettings() as a default argument value, so every call that omitted point_settings shared one PointSettings instance created at function-definition time. _BaseWriteApi then mutated that shared instance in place with the client's default_tags, which caused one client's default_tags to leak into every other client's WriteApi, including clients with no default_tags of their own. The async path had the identical bug. Change the four point_settings defaults from PointSettings() to None and build a fresh PointSettings in _BaseWriteApi when none is supplied. Add a regression test asserting no cross-client leak. Closes #686 Signed-off-by: arpitjain099 --- CHANGELOG.md | 1 + influxdb_client/client/_base.py | 3 ++- influxdb_client/client/influxdb_client.py | 4 ++-- .../client/influxdb_client_async.py | 3 +-- influxdb_client/client/write_api.py | 2 +- influxdb_client/client/write_api_async.py | 2 +- tests/test_InfluxDBClient.py | 19 +++++++++++++++++++ 7 files changed, 27 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be798f4f..98a37713 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Bug Fixes 1. [#706](https://github.com/influxdata/influxdb-client-python/pull/706): Use logger instead logging. +1. [#686](https://github.com/influxdata/influxdb-client-python/issues/686): Stop `default_tags` from one client leaking into other clients' `WriteApi` (shared mutable default `PointSettings`). ## 1.50.0 [2026-01-23] diff --git a/influxdb_client/client/_base.py b/influxdb_client/client/_base.py index d4f17901..fb1b9715 100644 --- a/influxdb_client/client/_base.py +++ b/influxdb_client/client/_base.py @@ -441,8 +441,9 @@ def _build_flux_ast(params: dict = None, profilers: List[str] = None): class _BaseWriteApi(object): def __init__(self, influxdb_client, point_settings=None): + from influxdb_client.client.write_api import PointSettings self._influxdb_client = influxdb_client - self._point_settings = point_settings + self._point_settings = point_settings if point_settings is not None else PointSettings() self._write_service = WriteService(influxdb_client.api_client) if influxdb_client.default_tags: for key, value in influxdb_client.default_tags.items(): diff --git a/influxdb_client/client/influxdb_client.py b/influxdb_client/client/influxdb_client.py index cbae75a9..200536fd 100644 --- a/influxdb_client/client/influxdb_client.py +++ b/influxdb_client/client/influxdb_client.py @@ -16,7 +16,7 @@ from influxdb_client.client.query_api import QueryApi, QueryOptions from influxdb_client.client.tasks_api import TasksApi from influxdb_client.client.users_api import UsersApi -from influxdb_client.client.write_api import WriteApi, WriteOptions, PointSettings +from influxdb_client.client.write_api import WriteApi, WriteOptions logger = logging.getLogger('influxdb_client.client.influxdb_client') @@ -210,7 +210,7 @@ def from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): """ return InfluxDBClient._from_env_properties(debug=debug, enable_gzip=enable_gzip, **kwargs) - def write_api(self, write_options=WriteOptions(), point_settings=PointSettings(), **kwargs) -> WriteApi: + def write_api(self, write_options=WriteOptions(), point_settings=None, **kwargs) -> WriteApi: """ Create Write API instance. diff --git a/influxdb_client/client/influxdb_client_async.py b/influxdb_client/client/influxdb_client_async.py index a8a2d173..87c6ffc5 100644 --- a/influxdb_client/client/influxdb_client_async.py +++ b/influxdb_client/client/influxdb_client_async.py @@ -7,7 +7,6 @@ from influxdb_client.client.delete_api_async import DeleteApiAsync from influxdb_client.client.query_api import QueryOptions from influxdb_client.client.query_api_async import QueryApiAsync -from influxdb_client.client.write_api import PointSettings from influxdb_client.client.write_api_async import WriteApiAsync logger = logging.getLogger('influxdb_client.client.influxdb_client_async') @@ -273,7 +272,7 @@ def query_api(self, query_options: QueryOptions = QueryOptions()) -> QueryApiAsy """ return QueryApiAsync(self, query_options) - def write_api(self, point_settings=PointSettings()) -> WriteApiAsync: + def write_api(self, point_settings=None) -> WriteApiAsync: """ Create an asynchronous Write API instance. diff --git a/influxdb_client/client/write_api.py b/influxdb_client/client/write_api.py index 3b3db68f..ea9fb7b5 100644 --- a/influxdb_client/client/write_api.py +++ b/influxdb_client/client/write_api.py @@ -213,7 +213,7 @@ class WriteApi(_BaseWriteApi): def __init__(self, influxdb_client, write_options: WriteOptions = WriteOptions(), - point_settings: PointSettings = PointSettings(), + point_settings: PointSettings = None, **kwargs) -> None: """ Initialize defaults. diff --git a/influxdb_client/client/write_api_async.py b/influxdb_client/client/write_api_async.py index 38937eca..6134e527 100644 --- a/influxdb_client/client/write_api_async.py +++ b/influxdb_client/client/write_api_async.py @@ -31,7 +31,7 @@ class WriteApiAsync(_BaseWriteApi): write_api = client.write_api() """ - def __init__(self, influxdb_client, point_settings: PointSettings = PointSettings()) -> None: + def __init__(self, influxdb_client, point_settings: PointSettings = None) -> None: """ Initialize defaults. diff --git a/tests/test_InfluxDBClient.py b/tests/test_InfluxDBClient.py index 228f391b..1df29341 100644 --- a/tests/test_InfluxDBClient.py +++ b/tests/test_InfluxDBClient.py @@ -32,6 +32,25 @@ def test_default_conf(self): self.client = InfluxDBClient(url="http://localhost:8086", token="my-token", org="my-org") self.assertIsNotNone(self.client.api_client.configuration.connection_pool_maxsize) + def test_default_tags_not_shared_between_clients(self): + # https://github.com/influxdata/influxdb-client-python/issues/686 + # default_tags from one client must not leak into another client's WriteApi. + self.client = InfluxDBClient(url="http://localhost:8086", token="my-token", org="my-org") + write_plain_before = self.client.write_api(write_options=SYNCHRONOUS) + + client_tagged = InfluxDBClient(url="http://localhost:8086", token="my-token", org="my-org", + default_tags={"id": "client-tagged"}) + client_tagged.write_api(write_options=SYNCHRONOUS) + + write_plain_after = self.client.write_api(write_options=SYNCHRONOUS) + + try: + self.assertEqual({}, write_plain_before._point_settings.defaultTags) + self.assertEqual({}, write_plain_after._point_settings.defaultTags) + self.assertIsNot(write_plain_before._point_settings, write_plain_after._point_settings) + finally: + client_tagged.close() + def test_TrailingSlashInUrl(self): self.client = InfluxDBClient(url="http://localhost:8086", token="my-token", org="my-org") self.assertEqual('http://localhost:8086', self.client.api_client.configuration.host)