Releases: ClickHouse/clickhouse-connect
v0.12.0rc1
Native Async Client (Pre-release)
This is a pre-release for testing and feedback on the new native async client built on aiohttp. Closes #141.
If you're using the sync client and have been looking for a reason to go async, this is a good opportunity to give it a shot. If you're already using AsyncClient, this is a drop-in upgrade. The API surface is identical but under the hood it's completely redesigned.
Previously, the AsyncClient was just the sync urllib3 client wrapped in a thread executor. This is a from-scratch async implementation with real async I/O, proper connection pooling, and a pipelined architecture that streams and processes response data concurrently rather than a read-then-parse pattern, providing a potentially significant performance increase depending on your workload. The old executor-based path still works but is now deprecated and will be removed after release candidate testing and benchmarking is completed.
Install
aiohttp is now a required dependency for using the native async client, but its installation is not included by default. To install this release candidate with the required aiohttp for async use, install clickhouse_connect as follows:
pip install clickhouse-connect[async]==0.12.0rc1
Usage
import asyncio
import clickhouse_connect
async def main():
async with await clickhouse_connect.get_async_client(host="localhost") as client:
# create a test table
await client.command(
"CREATE TABLE IF NOT EXISTS test_example "
"(id UInt32, name String) "
"ENGINE MergeTree ORDER BY id"
)
# insert
data = [[1, "clickhouse"], [2, "joe"]]
await client.insert("test_example", data, column_names=["id", "name"])
# query
result = await client.query("SELECT id, name FROM test_example")
print(result.result_rows)
# cleanup
await client.command("DROP TABLE IF EXISTS test_example")
asyncio.run(main())As you can see, the method names and signatures are the same as the sync client, you just await them. And for users of the the original async client, you don't have to change anything.
Migrating from the previous AsyncClient
If you're creating your async client like this, you're already on the new native implementation and no changes are needed:
client = await clickhouse_connect.get_async_client(host="localhost")The only case where you'll still get the old executor-based wrapper is if you're explicitly constructing it from a sync client:
from clickhouse_connect.driver import AsyncClient
sync_client = clickhouse_connect.get_client(host="localhost")
async_client = AsyncClient(client=sync_client) # legacy path, now deprecatedIf you're doing this, it will continue to work for a very short time but you'll see a DeprecationWarning. We recommend switching to get_async_client() when you get a chance so that you're using the native async client, not the deprecated executor-based client. The legacy path has been left in temporarily so users can benchmark it against the native version if they desire, as significant unexpected performance degradation would be very helpful feedback before we remove it entirely.
What we're looking for
- General stability feedback
- Performance compared to the sync client and legacy async client in your workloads
- Any issues with connection pooling, streaming, or concurrent usage
- Edge cases we haven't hit yet
Please report issues on this repo with [async] in the title.
Note
This release also includes everything from v0.11.0 release.
v0.11.0
What's Changed
Improvements
- Add support for mid-stream exceptions. Closes #626
- Add support for QBit data type. Closes #570
- Add the ability to create table from PyArrow objects. Addresses #588
- Always generate
query_idfrom the client side as aUUID4if it is not explicitly set. Closes #596 - Extend support for creating tables from PyArrow objects to include datetime/timestamp types. Closes #605
- Add pre-commit hooks for auto-linting contributions at commit time. Addresses #607
- Auto-enable
cancel_http_readonly_queries_on_client_closesetting for HTTP clients to ensure SELECT queries are cancelled on the server when the client disconnects. Closes #641
Bug Fixes
- Raise
OperationalErrorwhenResponseSourcehits network failure before any data is received. Previously, empty result would be returned. Closes #620 - Fixed a bug where
InsertContextstate was not reset on insert failure, leading to reuse errors when data was passed separately. Closes #616 - Fixed UTC-equivalent timezone recognition issue where servers returning
Etc/UCT,GMT, or other UTC-equivalent timezone names caused inconsistent behavior withutc_tz_aware=False. DateTime columns with explicit UTC timezones now correctly return naive datetimes whenutc_tz_aware=Falseregardless of the specific UTC-equivalent timezone name returned by the server. Closes #629 - Extend UTC-equivalence checks to Arrow queries.
New Contributors
- @akkik04 made their first contribution in #597
- @m-dziuba made their first contribution in #613
- @abhisheksurve45 made their first contribution in #618
- @dave-shawley made their first contribution in #611
- @Milias made their first contribution in #621
- @veeceey made their first contribution in #643
Full Changelog: v0.10.0...v0.11.0
v0.10.0
What's Changed
Improvements
- Added SQLAlchemy core API support for
ARRAY JOINandFINALmodifier. Closes #579 - Added Python 3.14 support 🎉 (non-free-threaded build only; free-threaded builds are not yet supported). Closes #574
- Added
utc_tz_awareparameter to client and query methods to opt in to returning timezone-aware UTC objects forDateTime/DateTime64columns. Default behavior remains the same and returns tz naive objects for backward compatibility.- Note: this parameter will likely be removed and only return tz-aware dts in some future release. Closes #566
- Added
executorparameter toAsyncClientconstructor to allow passing a custom executor for async operations. This allows users to control the concurrency and thread pool used by the async client.
Bug Fixes
- Fixed DST fallback bug in
DateTimeandDateTime64types caused by passing potentially ambiguous times topd.DateTimeIndexconstructor. Closes #585 - Fixed issue with JSON key dot escaping. Closes #571
New Contributors
- @prokofyevDmitry made their first contribution in #569
- @wiese-m made their first contribution in #583
- @meirdev made their first contribution in #578
Full Changelog: v0.9.2...v0.10.0
v0.9.2
What's Changed
- Updated
python_requiresto drop Python 3.8 and advertise support for 3.9–3.13 - Allow passing
roleas a field in thesettingskeyword argument to set a role for a specific query
New Contributors
- @svix-jbrown made their first contribution in #550
Full Changelog: v0.9.1...v0.9.2
v0.9.1
What's Changed
- Fixed typing issue that required numpy to be installed during clickhouse_connect import
Full Changelog: v0.9.0...v0.9.1
v0.9.0
What's Changed
Breaking Changes
- WARNING: BREAKING CHANGE — Removed support for sqlalchemy 1.3 which reached its EOL in 2021. The minimum required version is now 1.4.40.
- WARNING: BREAKING CHANGE — Behavior for reading from IPv6 columns has changed:
- With
read_format='native', the client will always returnipaddress.IPv6Addressobjects, even for IPv4-mapped addresses (e.g.,"::ffff:192.168.1.1"). Previously, the client returnedipaddress.IPv4Addressobjects for these cases. This change enforces type consistency and avoids surprising implicit conversions. If your application requires IPv4 objects, you can explicitly convert using theipv4_mappedattribute ofIPv6Address. - With
read_format='string', the client will always return IPv6 string representations, e.g.,"::ffff:192.168.1.1"instead of"192.168.1.1", for the same reasons as above. If you require only the IPv4 string, you can parse or truncate this in your application code. - Closes #493
- With
Major Features
- Added support for SQLAlchemy 2.x. The minimum required version is 1.4.40. Closes #263
- Added Polars support for Arrow-based query and insert methods (
query_df_arrow,query_df_arrow_stream,insert_df_arrow). This initial implementation provides basic dataframe conversion through the Arrow format, similar to how we support the pyarrow-backed pandas dataframes. Closes #111 and #542 - Added support for querying/inserting pyarrow-backed DataFrames:
query_df_arrow(): returns a pandas DataFrame with PyArrow dtype backend. Note that Arrow data types are preserved without additional conversions.query_df_arrow_stream(): Streaming version ofquery_df_arrow()for processing large result sets.insert_df_arrow(): Optimized insertion method for pandas DataFrames with PyArrow backend, which should provide better performance than standardinsert_df().
- Added Time and Time64 type support. Closes #509
- Support for both pandas 1.x and 2.x.
- Added support for Nullable(JSON) types
- Added support for BFloat16 types
Improvements
- Add support for lightweight
DELETEin sqlalchemy. Closes #382 - Added support for
SELECT/JOINoperations via SQLAlchemy's core API (table operations and explicit statements--not ORM sessions-based queries) - Added client connection option
rename_response_column(defaultNone) that allows the user to define how response columns are automatically renamed according to a predefined scheme. Helpful for stripping alias prefixes, etc. in potentially complex queries. Closes #228 - Add third-party library identifiers (name/version) in the User-Agent, e.g. pandas/2.2.5. Users can opt out by changing the common setting
send_integration_tagstoFalse. - Added support for form encoding query parameters when using HTTP interface. This addresses #342. Query parameters can now be sent as form-encoded data in the request body by setting
form_encode_query_params=Truewhen creating the client. This is particularly useful for queries with large parameter payloads that might exceed URL length limits. - Added support for special interval types. Closes #391
- Added new common setting option "preserve_pandas_datetime_resolution" (default is
False) allowing pandas 2.x users to opt into (when set toTrue) using the additional pandas 2.x datetime64/timedelta64 resolutions of "s", "ms", "us". If set toFalseor using pandas 1.x, all datetime64/timedelta64 resolutions will be coerced to "ns". (See here for more info). Closes #165 and #531 - Tightens up type consistency of date-like objects when using
query_df - When writing to an IPv6 column type, the client will "promote" IPv4 addresses to IPv4-mapped IPv6 addresses to prevent write errors. Closes #498
- Changed
AsyncClient.settingstyping toOptional[Dict[str, Any]]to accept None inputs. - Added more robust error handling and tests. Closes #508
- Replace the use of deprecated
datetime.utcfromtimestamp
Bug Fixes
- Fixed an AttributeError on
http.clientwhen importingclickhouse_connectunder certain circumstances - Fixes problem with df inserts of Time and Time64 types. Closes #524
New Contributors
- @herbert-allium made their first contribution in #512
- @SkytAsul made their first contribution in #518
- @janwijbrand made their first contribution in #545
- @sanjams2 made their first contribution in #543
Full Changelog: v0.8.18...v0.9.0
v0.8.18 Collected bug fixes
What's Changed
- Fix SQLAlchemy execution error by using text() function by @lakako in #491
- Test fixes for main by @genzgd in #497
- Ensure types are returned even if there are no rows by @orian in #500
- Fix some issues with cursor behavior by @joe-clickhouse in #506
- Reset cursor location after performing an execute.
- Fix behavior of
fetchallto only return rows from the current cursor location. - Fixes logic of
fetchmanyto respect size parameter.
- Added a standalone test file (
tests/unit_tests/test_driver/test_cursor.py) for testing cursor behavior
New Contributors
- @lakako made their first contribution in #491
- @joe-clickhouse made their first contribution in #506
Full Changelog: v0.8.17...v0.8.18
v0.8.17 Transport settings
v0.8.16 Collected Bug Fixes
What's Changed
- Gg/update test matrix by @genzgd in #464
- Fix CI tests with default user by @genzgd in #465
- Replace removal of ; in the loop line with rstrip by @sbobryshev in #472
- Docker test fixes by @genzgd in #473
- Update README.md doc link by @genzgd in #476
- Correct typing of create_client(host, username) by @biggerfisch in #482
- Release 0 8 16 by @genzgd in #485
New Contributors
- @sbobryshev made their first contribution in #472
Full Changelog: v0.8.15...v0.8.16
v0.8.15 AsyncInsert Close Fix
What's Changed
- Update
test_tls.pyreference by @emmanuel-ferdman in #455 - Gg/update test jwt by @genzgd in #458
- Fix memory leak in AsyncClient by @pufit in #457
- 0.8.15 release by @genzgd in #459
- Exclude 3.8 Aarch64 builds by @genzgd in #460
New Contributors
- @emmanuel-ferdman made their first contribution in #455
- @pufit made their first contribution in #457
Full Changelog: v0.8.14...v0.8.15