Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.14"]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Karel, do you agree with this suggestion?

steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
Expand Down
14 changes: 11 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,26 @@
### Breaking Changes

1. [#238](https://github.com/InfluxCommunity/influxdb3-python/pull/238): Drop support for Python 3.9. Python 3.10 or newer is now required.
1. [#239](https://github.com/InfluxCommunity/influxdb3-python/pull/239): Exception classes now function mostly like a simple data-carrying object.
- `InfluxDBPartialWriteException` class constructor will now accept `message` as an argument.
- `InfluxDBPartialWriteError.from_response(cls, response: HTTPResponse):` function was removed.

### Bug Fixes

1. [#243](https://github.com/InfluxCommunity/influxdb3-python/pull/243): Remove stale `influxdb_client` references from v3 docstrings, examples, comments, and logger names. (Closes #242)

2. [#237](https://github.com/InfluxCommunity/influxdb3-python/pull/237): Makes the writing API simpler and more consistent with other v3 clients:
1. [#237](https://github.com/InfluxCommunity/influxdb3-python/pull/237): Makes the writing API simpler and more consistent with other v3 clients:
- Further simplifies the `WriteApi` request path by constructing v2/v3 requests directly through `RestClient`, while preserving existing write behavior.
1. [#239](https://github.com/InfluxCommunity/influxdb3-python/pull/239):
- Only throws `InfluxDBPartialWriteException` when:
- Error response status code is `400`.
- Error response format `{"error":"...","data":[{"error_message":"...","line_number":2,"original_line": "..."}]}` is returned with `data` must be an array
- `accept_partial` is set to `true`.
- Write endpoint must be `api/v3/write_lp`.
1. [#241](https://github.com/InfluxCommunity/influxdb3-python/pull/241): Harden `MultiprocessingWriter` shutdown and error handling:
- Replaces assertion-based runtime state validation with explicit exceptions.
- Guarantees queue task completion when worker writes fail.
- Adds idempotent `close()` with bounded worker shutdown and a configurable `close_timeout`.
- Ensures `on_shutdown` is invoked at most once.
1. [#243](https://github.com/InfluxCommunity/influxdb3-python/pull/243): Remove stale `influxdb_client` references from v3 docstrings, examples, comments, and logger names. (Closes #242)

## 0.21.0 [2026-08-27]

Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ Users can import data from CSV, JSON, Feather, ORC, Parquet
import influxdb_client_3 as InfluxDBClient3
import pandas as pd
import numpy as np
from influxdb_client_3 import write_client_options, WritePrecision, WriteOptions, InfluxDBError
from influxdb_client_3 import write_client_options, WritePrecision, WriteOptions, InfluxDBWriteException


class BatchingCallback(object):
Expand All @@ -165,10 +165,10 @@ class BatchingCallback(object):
self.write_count += 1
print(f"Written batch: {conf}, data: {data}")

def error(self, conf, data: str, exception: InfluxDBError):
def error(self, conf, data: str, exception: InfluxDBWriteException):
print(f"Cannot write batch: {conf}, data: {data} due: {exception}")

def retry(self, conf, data: str, exception: InfluxDBError):
def retry(self, conf, data: str, exception: InfluxDBWriteException):
print(f"Retryable error occurs for batch: {conf}, data: {data} retry: {exception}")

callback = BatchingCallback()
Expand Down Expand Up @@ -245,11 +245,11 @@ client.write_dataframe(

### Accept partial writes and inspect failed lines
`accept_partial` defaults to `True` and allows partial success when writing through the V3 API endpoint (`use_v2_api=False`) and a batch contains invalid lines.
On partial failure, the client raises `InfluxDBPartialWriteError` with structured `line_errors`.
On partial failure, the client raises `InfluxDBPartialWriteException` with structured `line_errors`.

```python
from influxdb_client_3 import InfluxDBClient3
from influxdb_client_3.exceptions import InfluxDBPartialWriteError
from influxdb_client_3.exceptions import InfluxDBPartialWriteException

client = InfluxDBClient3(
host="http://localhost:8181",
Expand All @@ -261,7 +261,7 @@ lp = "home,room=Sunroom temp=96 1735545600\nhome,room=Sunroom temp=\"hi\" 173554

try:
client.write(lp) # accept_partial=True by default on V3 API endpoint
except InfluxDBPartialWriteError as e:
except InfluxDBPartialWriteException as e:
for line_err in e.line_errors:
print(f"line {line_err.line_number} failed: {line_err.error_message} ({line_err.original_line})")
```
Expand Down
7 changes: 4 additions & 3 deletions examples/advanced/database_transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import os
import time

from influxdb_client_3 import InfluxDBClient3, write_client_options, WriteOptions, InfluxDBError
from influxdb_client_3 import InfluxDBClient3, write_client_options, WriteOptions
from influxdb_client_3.exceptions.write_exceptions import InfluxDBWriteException

HOST = os.getenv('INFLUXDB_HOST') or 'http://localhost:8181'
TOKEN = os.getenv('INFLUXDB_TOKEN') or 'my-token'
Expand All @@ -16,10 +17,10 @@ class BatchingCallback(object):
def success(self, conf, data: str):
print(f"Written batch: {conf}, data: {data}")

def error(self, conf, data: str, exception: InfluxDBError):
def error(self, conf, data: str, exception: InfluxDBWriteException):
print(f"Cannot write batch: {conf}, data: {data} due: {exception}")

def retry(self, conf, data: str, exception: InfluxDBError):
def retry(self, conf, data: str, exception: InfluxDBWriteException):
print(f"Retryable error occurs for batch: {conf}, data: {data} retry: {exception}")


Expand Down
9 changes: 4 additions & 5 deletions examples/advanced/downsample.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

import pandas as pd

from influxdb_client_3 import InfluxDBClient3, InfluxDBError, WriteOptions, write_client_options
from influxdb_client_3 import InfluxDBClient3, WriteOptions, write_client_options
from influxdb_client_3.exceptions.write_exceptions import InfluxDBWriteException

dir_path = os.path.dirname(os.path.realpath(__file__))

Expand All @@ -23,10 +24,10 @@ class BatchingCallback(object):
def success(self, conf, data: str):
print(f"Written batch: {conf}, data: {data}")

def error(self, conf, data: str, exception: InfluxDBError):
def error(self, conf, data: str, exception: InfluxDBWriteException):
print(f"Cannot write batch: {conf}, data: {data} due: {exception}")

def retry(self, conf, data: str, exception: InfluxDBError):
def retry(self, conf, data: str, exception: InfluxDBWriteException):
print(f"Retryable error occurs for batch: {conf}, data: {data} retry: {exception}")


Expand Down Expand Up @@ -74,7 +75,6 @@ def retry(self, conf, data: str, exception: InfluxDBError):
database=DATABASE,
enable_gzip=True,
write_client_options=wco) as prep_client:

# Generating random data
for i in range(num_entries):
trainer = random.choice(trainers)
Expand Down Expand Up @@ -129,7 +129,6 @@ def retry(self, conf, data: str, exception: InfluxDBError):
token=TOKEN,
host=HOST,
database=DATABASE, enable_gzip=True, write_client_options=wco) as ds_client:

# downsample data to average number of catches per quarter-hour
sql = ("SELECT date_bin('15 minutes', \"time\") as window_start, \n"
"AVG(\"num\") as avg\n"
Expand Down
50 changes: 23 additions & 27 deletions examples/jupyter/basic-write-query.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"%env INFLUXDB_HOST=http://localhost:8181\n",
"%env INFLUXDB_TOKEN=<READ_WRITE_TOKEN>\n",
"%env INFLUXDB_DATABASE=my_db\n",
"from influxdb_client_3 import InfluxDBClient3, Point, WritePrecision, InfluxDBError, WriteOptions, write_client_options"
"from influxdb_client_3 import InfluxDBClient3, Point, InfluxDBWriteException, InfluxDB3ClientQueryException"
],
"outputs": [],
"execution_count": null
Expand All @@ -32,9 +32,14 @@
"source": "2. Next, setup a basic sensor class for generating test data. This simple class will generate readings using the built-in Influxdb3 Python `Point` class. Using the `Point` class for writes is recommended in basic applications even though the client `write()` method handles other types of data."
},
{
"metadata": {
"SqlCellData": {
"variableName$1": "df_sql1"
}
},
"cell_type": "code",
"id": "532b67ce851fe031",
"metadata": {},
"outputs": [],
"execution_count": null,
"source": [
"class Sensor:\n",
"\n",
Expand All @@ -54,20 +59,17 @@
" .time(timestamp)\n",
" )\n"
],
"outputs": [],
"execution_count": null
"id": "85b6e79a3388eb30"
},
{
"cell_type": "markdown",
"id": "40ac0ffee0bcaefa",
"id": "532b67ce851fe031",
"metadata": {},
"source": [
"3. Create a client instance. Please note that this client is instantiated using default values only. WriteOptions and QueryOptions can also be added at this step. For simplicity of illustration they have been omitted."
]
"source": "3. Create a client instance. Please note that this client is instantiated using default values only. WriteOptions and QueryOptions can also be added at this step. For simplicity of illustration they have been omitted."
},
{
"cell_type": "code",
"id": "fefbdd206fedf89f",
"id": "40ac0ffee0bcaefa",
"metadata": {},
"source": [
"import logging\n",
Expand All @@ -92,15 +94,13 @@
},
{
"cell_type": "markdown",
"id": "64228a6a65db2dfc",
"id": "fefbdd206fedf89f",
"metadata": {},
"source": [
"4. Generate data points and write them to the database."
]
"source": "4. Generate data points and write them to the database."
},
{
"cell_type": "code",
"id": "1613427c088c1a56",
"id": "64228a6a65db2dfc",
"metadata": {},
"source": [
"import random\n",
Expand Down Expand Up @@ -137,23 +137,21 @@
"try:\n",
" client.write(data)\n",
" logging.info(f\"Write successful!\")\n",
"except InfluxDBError as e:\n",
"except InfluxDBWriteException as e:\n",
" logging.error(\"InfluxDB error: {}\".format(e))\n"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "3422e2abc73a174",
"id": "1613427c088c1a56",
"metadata": {},
"source": [
"Now query"
]
"source": "Now query"
},
{
"cell_type": "code",
"id": "8a2fb254614ccc27",
"id": "3422e2abc73a174",
"metadata": {},
"source": [
"sql = f\"SELECT time, location, model, temperature FROM {measurement} WHERE location = 'hall_east' ORDER BY time DESC\"\n",
Expand All @@ -163,23 +161,21 @@
"try:\n",
" table = client.query(query=sql, language=\"sql\", mode=\"pandas\")\n",
" print(table)\n",
"except InfluxDBError as e:\n",
"except InfluxDB3ClientQueryException as e:\n",
" print(\"InfluxDB error: {}\".format(e))"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "1788e61d03b7f8c5",
"id": "8a2fb254614ccc27",
"metadata": {},
"source": [
"Sample results plot below."
]
"source": "Sample results plot below."
},
{
"cell_type": "code",
"id": "b56ff2f6e600ed01",
"id": "1788e61d03b7f8c5",
"metadata": {},
"source": [
"%matplotlib inline\n",
Expand Down
4 changes: 2 additions & 2 deletions examples/query/handle_query_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import os

from influxdb_client_3 import InfluxDBClient3
from influxdb_client_3.exceptions import InfluxDB3ClientQueryError
from influxdb_client_3.exceptions import InfluxDB3ClientQueryException


def main() -> None:
Expand All @@ -29,7 +29,7 @@ def main() -> None:
try:
# Select from a bucket that doesn't exist
client.query("Select a from cpu11")
except InfluxDB3ClientQueryError as e:
except InfluxDB3ClientQueryException as e:
logging.log(logging.ERROR, e.message)


Expand Down
9 changes: 5 additions & 4 deletions examples/write/batching.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
from bson import ObjectId

import influxdb_client_3 as InfluxDBClient3
from influxdb_client_3 import write_client_options, WritePrecision, WriteOptions, InfluxDBError
from influxdb_client_3 import write_client_options, WritePrecision, WriteOptions
from influxdb_client_3.exceptions.write_exceptions import InfluxDBWriteException


class BatchingCallback(object):
"""
Prepare callbacks to be used to handle batching states.
"""

def __init__(self):
self.write_status_msg = None
self.write_count = 0
Expand All @@ -29,11 +31,11 @@ def success(self, conf, data: str):
self.write_count += 1
self.write_status_msg = f"SUCCESS: {self.write_count} writes"

def error(self, conf, data: str, exception: InfluxDBError):
def error(self, conf, data: str, exception: InfluxDBWriteException):
print(f"Cannot write batch: {conf}, data: {len(data)} bytes, due_to: {exception}")
self.write_status_msg = f"FAILURE - cause: {exception}"

def retry(self, conf, data: str, exception: InfluxDBError):
def retry(self, conf, data: str, exception: InfluxDBWriteException):
print(f"Retryable error occurs for batch: {conf}, data: {len(data)} bytes, retry: {exception}")
self.retry_count += 1

Expand All @@ -42,7 +44,6 @@ def elapsed(self) -> int:


def main() -> None:

host = os.getenv('INFLUXDB_HOST') or 'http://localhost:8181'
token = os.getenv('INFLUXDB_TOKEN') or 'my-token'
database = os.getenv('INFLUXDB_DATABASE') or 'my-db'
Expand Down
6 changes: 3 additions & 3 deletions examples/write/fileimport.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import os

import influxdb_client_3 as InfluxDBClient3
from influxdb_client_3 import write_client_options, WriteOptions, InfluxDBError
from influxdb_client_3 import write_client_options, WriteOptions, InfluxDBWriteException


dir_path = os.path.dirname(os.path.realpath(__file__))
Expand All @@ -28,10 +28,10 @@ def success(self, conf, data: bytes):
self.write_count += 1
print(f"Written batch: {conf}, data: {bytes(data)} bytes")

def error(self, conf, data: bytes, exception: InfluxDBError):
def error(self, conf, data: bytes, exception: InfluxDBWriteException):
print(f"Cannot write batch: {conf}, data: {data} due: {exception}")

def retry(self, conf, data: bytes, exception: InfluxDBError):
def retry(self, conf, data: bytes, exception: InfluxDBWriteException):
print(f"Retryable error occurred for batch: {conf}, data: {bytes(data)} bytes, retry: {exception}")


Expand Down
2 changes: 1 addition & 1 deletion examples/write/handle_http_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def main() -> None:

try:
client.write(lp)
except InfluxDBClient3.InfluxDBError as idberr:
except InfluxDBClient3.InfluxDBWriteException as idberr:
logging.log(logging.ERROR, 'WRITE ERROR: %s (%s)',
idberr.response.status,
idberr.message)
Expand Down
5 changes: 3 additions & 2 deletions examples/write/writeoptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
import logging
import os

from influxdb_client_3 import (exceptions, InfluxDBClient3, Point,
from influxdb_client_3 import (InfluxDBClient3, Point,
WriteOptions, WritePrecision, WriteType, write_client_options)
from influxdb_client_3.exceptions import write_exceptions

logger = logging.getLogger("writeoptions")


# An illustrative callback - see below
def error_callback(conf, data: bytes, exception: exceptions.InfluxDBError):
def error_callback(conf, data: bytes, exception: write_exceptions.InfluxDBWriteException):
now = datetime.datetime.now()
logger.warning(f"[{now}] an error occurred on latest write: {exception}")
logger.warning(f" conf: {conf}")
Expand Down
Loading
Loading