Files
nixpkgs/pkgs/development/python-modules/clickhouse-sqlalchemy/update-deps-and-python-version.patch
José Luis Lafuente f40beee7af clickhouse-sqlalchemy: init at 0.3.2-unstable-2025-11-24
Co-authored-by: José Luis Lafuente <jl@lafuente.dev>
Co-authored-by: João Santos Reis <joao.reis@tweag.io>
2026-09-28 15:45:40 +01:00

275 lines
9.6 KiB
Diff

diff a/clickhouse_sqlalchemy/drivers/base.py b/clickhouse_sqlalchemy/drivers/base.py
--- a/clickhouse_sqlalchemy/drivers/base.py
+++ b/clickhouse_sqlalchemy/drivers/base.py
@@ -53,1 +53,1 @@
- 'Object(\'json\')': types.JSON,
+ 'JSON': types.JSON,
diff --git a/clickhouse_sqlalchemy/drivers/asynch/base.py b/clickhouse_sqlalchemy/drivers/asynch/base.py
index 5a28ea6e..b80646c8 100644
--- a/clickhouse_sqlalchemy/drivers/asynch/base.py
+++ b/clickhouse_sqlalchemy/drivers/asynch/base.py
@@ -4,12 +4,36 @@
from sqlalchemy.pool import AsyncAdaptedQueuePool
from .connector import AsyncAdapt_asynch_dbapi
-from ..native.base import ClickHouseDialect_native, ClickHouseExecutionContext
+from ..native.base import (
+ ClickHouseDialect_native,
+ ClickHouseExecutionContext,
+ ClickHouseNativeSQLCompiler,
+)
# Export connector version
VERSION = (0, 0, 1, None)
+try:
+ from importlib.metadata import version
+ _asynch_version_raw = version('asynch')
+except Exception:
+ _asynch_version_raw = getattr(asynch, '__version__', None) or '0'
+_asynch_use_format_placeholders = tuple(
+ int(x) if x.isdigit() else 0 for x in str(_asynch_version_raw).split('.')[:3]
+) == (0, 3, 1)
+
+
+class ClickHouseAsynchSQLCompiler(ClickHouseNativeSQLCompiler):
+ """Emit {name} for asynch 0.3.1 (.format() param style)."""
+
+ def visit_bindparam(self, bindparam, **kw):
+ return "{%s}" % self._truncate_bindparam(bindparam)
+
+ def post_process_text(self, text):
+ return text
+
+
class ClickHouseAsynchExecutionContext(ClickHouseExecutionContext):
def create_server_side_cursor(self):
return self.create_default_cursor()
@@ -18,6 +42,10 @@ def create_server_side_cursor(self):
class ClickHouseDialect_asynch(ClickHouseDialect_native):
driver = 'asynch'
execution_ctx_cls = ClickHouseAsynchExecutionContext
+ statement_compiler = (
+ ClickHouseAsynchSQLCompiler if _asynch_use_format_placeholders
+ else ClickHouseNativeSQLCompiler
+ )
is_async = True
supports_statement_cache = True
diff --git a/clickhouse_sqlalchemy/drivers/asynch/connector.py b/clickhouse_sqlalchemy/drivers/asynch/connector.py
index 99d211a9..32d754c3 100644
--- a/clickhouse_sqlalchemy/drivers/asynch/connector.py
+++ b/clickhouse_sqlalchemy/drivers/asynch/connector.py
@@ -107,6 +107,9 @@ def fetchall(self):
self._rows[:] = []
return retval
+ async def _async_soft_close(self) -> None:
+ return
+
class AsyncAdapt_asynch_dbapi:
def __init__(self, asynch):
@@ -176,10 +179,10 @@ def cursor(self, server_side=False):
return AsyncAdapt_asynch_cursor(self)
def rollback(self):
- self.await_(self._connection.rollback())
+ pass
def commit(self):
- self.await_(self._connection.commit())
+ pass
def close(self):
self.await_(self._connection.close())
diff --git a/clickhouse_sqlalchemy/alembic/comparators.py b/clickhouse_sqlalchemy/alembic/comparators.py
index 6743bea9..a454766e 100644
--- a/clickhouse_sqlalchemy/alembic/comparators.py
+++ b/clickhouse_sqlalchemy/alembic/comparators.py
@@ -2,9 +2,7 @@
from alembic import __version__ as alembic_version
from alembic.autogenerate import comparators
-from alembic.autogenerate.compare import _compare_columns
from alembic.operations.ops import ModifyTableOps
-from alembic.util.sqla_compat import _reflect_table as _alembic_reflect_table
from sqlalchemy import schema as sa_schema
from sqlalchemy import text
@@ -16,6 +14,12 @@
alembic_version = tuple(
(int(x) if x.isdigit() else x) for x in alembic_version.split('.')
)
+_alembic_118 = alembic_version >= (1, 18, 0)
+
+if _alembic_118:
+ from alembic.autogenerate.compare.tables import _compare_columns
+else:
+ from alembic.autogenerate.compare import _compare_columns
def _extract_to_table_name(create_table_query):
@@ -28,20 +32,21 @@ def _extract_to_table_name(create_table_query):
# Direct call .dispatch_for('schema', 'clickhouse') override an Alembic
# default ('schema', 'default') comparator. To avoid it (as we have own
-# implementation only for a materialized views ) register default "schema"
+# implementation only for a materialized views) register default "schema"
# comparators as "clickhouse" comparators too.
-for default_comparator in comparators._registry[('schema', 'default')]:
- comparators.dispatch_for('schema', 'clickhouse')(default_comparator)
-
-
-def _reflect_table(inspector, table):
- if alembic_version >= (1, 11, 0):
- return _alembic_reflect_table(inspector, table)
- else:
- return _alembic_reflect_table(inspector, table, None)
-
-
-@comparators.dispatch_for('schema', 'clickhouse')
+if _alembic_118:
+ for (target, qualifier, priority), fns in comparators._registry.items():
+ if target == 'schema' and qualifier == 'default':
+ for fn, _ in fns:
+ comparators.dispatch_for(
+ 'schema', qualifier='clickhouse', priority=priority
+ )(fn)
+else:
+ for fn in comparators._registry[('schema', 'default')]:
+ comparators.dispatch_for('schema', qualifier='clickhouse')(fn)
+
+
+@comparators.dispatch_for('schema', qualifier='clickhouse')
def compare_mat_view(autogen_context, upgrade_ops, schemas):
connection = autogen_context.connection
dialect = autogen_context.dialect
@@ -127,7 +132,7 @@ def compare_mat_view(autogen_context, upgrade_ops, schemas):
)
else:
table = Table(name, existing_metadata)
- _reflect_table(inspector, table)
+ inspector.reflect_table(table, include_columns=None)
drop = operations.DropMatViewOp(
name, params.as_select, params.engine_full, *table.columns
@@ -144,7 +149,7 @@ def compare_mat_view(autogen_context, upgrade_ops, schemas):
inner_name = '.inner.' + name
conn_table = Table(inner_name, existing_metadata)
- _reflect_table(inspector, conn_table)
+ inspector.reflect_table(conn_table, include_columns=None)
if not autogen_context.run_object_filters(
view, name, 'mat_view', False, conn_table
diff --git a/docs/installation.rst b/docs/installation.rst
index b67e9a12..dec7cc64 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -6,7 +6,7 @@ Installation
Python Version
--------------
-Clickhouse-sqlalchemy supports Python 2.7 and newer.
+Clickhouse-sqlalchemy supports Python 3.8 and newer.
Dependencies
------------
@@ -16,12 +16,10 @@ clickhouse-sqlalchemy:
* `clickhouse-driver`_ ClickHouse Python Driver with native (TCP) interface support.
* `requests`_ a simple and elegant HTTP library.
-* `ipaddress`_ backport ipaddress module.
* `asynch`_ An asyncio ClickHouse Python Driver with native (TCP) interface support.
.. _clickhouse-driver: https://pypi.org/project/clickhouse-driver/
.. _requests: https://pypi.org/project/requests/
-.. _ipaddress: https://pypi.org/project/ipaddress/
.. _asynch: https://pypi.org/project/asynch/
If you are planning to use ``clickhouse-driver`` with compression you should
diff --git a/setup.py b/setup.py
index b7471071..50414982 100644
--- a/setup.py
+++ b/setup.py
@@ -71,13 +71,12 @@ def read_version():
'Programming Language :: SQL',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
+ 'Programming Language :: Python :: 3.13',
'Topic :: Database',
'Topic :: Software Development',
@@ -94,12 +93,12 @@ def read_version():
'Changes': github_url + '/blob/master/CHANGELOG.md'
},
packages=find_packages('.', exclude=["tests*"]),
- python_requires='>=3.7, <4',
+ python_requires='>=3.8, <4',
install_requires=[
'sqlalchemy>=2.0.0,<2.1.0',
'requests',
- 'clickhouse-driver>=0.1.2',
- 'asynch>=0.2.5',
+ 'clickhouse-driver',
+ 'asynch',
],
# Registering `clickhouse` as dialect.
entry_points={
diff --git a/setup.py b/setup.py
index 50414982..364c2015 100644
--- a/setup.py
+++ b/setup.py
@@ -77,6 +77,7 @@ def read_version():
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.13',
+ 'Programming Language :: Python :: 3.14',
'Topic :: Database',
'Topic :: Software Development',
diff --git a/tests/util.py b/tests/util.py
index f2dc6a35..a09cc160 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -7,6 +7,8 @@
from tests.session import http_session, native_session
+_async_test_loop = None
+
def skip_by_server_version(testcase, version_required):
testcase.skipTest(
@@ -88,15 +90,15 @@ def run_async(f):
"""
@wraps(f)
def g(*args, **kwargs):
+ global _async_test_loop
coro = f(*args, **kwargs)
try:
loop = asyncio.get_running_loop()
except RuntimeError:
- try:
- loop = asyncio.get_event_loop_policy().get_event_loop()
- except DeprecationWarning:
- loop = asyncio.new_event_loop()
- asyncio.set_event_loop(loop)
+ if _async_test_loop is None or _async_test_loop.is_closed():
+ _async_test_loop = asyncio.new_event_loop()
+ loop = _async_test_loop
+ asyncio.set_event_loop(loop)
return loop.run_until_complete(coro)
return g