Skip to content

Commit 2aefee2

Browse files
authored
Added ClickHouse support (#173)
* Added ClickHouse support * Improvements for `_configure` method
1 parent 066b178 commit 2aefee2

File tree

10 files changed

+148
-7
lines changed

10 files changed

+148
-7
lines changed

README.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Currently available features:
1919
* Neo4j container
2020
* OracleDb container
2121
* PostgreSQL Db container
22+
* ClickHouse container
2223
* Microsoft SQL Server container
2324
* Generic docker containers
2425
* LocalStack

docs/database.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Database containers
22
===================
33

4-
Allows to spin up database images such as MySQL, PostgreSQL, MariaDB, Oracle XE, MongoDb or Neo4j.
4+
Allows to spin up database images such as MySQL, PostgreSQL, MariaDB, Oracle XE, MongoDb, ClickHouse or Neo4j.
55

66
.. autoclass:: testcontainers.mysql.MySqlContainer
77
.. autoclass:: testcontainers.mysql.MariaDbContainer
@@ -10,4 +10,5 @@ Allows to spin up database images such as MySQL, PostgreSQL, MariaDB, Oracle XE,
1010
.. autoclass:: testcontainers.elasticsearch.ElasticSearchContainer
1111
.. autoclass:: testcontainers.mongodb.MongoDbContainer
1212
.. autoclass:: testcontainers.mssql.SqlServerContainer
13+
.. autoclass:: testcontainers.clickhouse.ClickHouseContainer
1314
.. autoclass:: testcontainers.neo4j.Neo4jContainer

requirements.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-e file:.[docker-compose,mysql,oracle,postgresql,selenium,google-cloud-pubsub,mongo,redis,mssqlserver,neo4j,kafka,rabbitmq]
1+
-e file:.[docker-compose,mysql,oracle,postgresql,selenium,google-cloud-pubsub,mongo,redis,mssqlserver,neo4j,kafka,rabbitmq,clickhouse]
22
codecov>=2.1.0
33
flake8<3.8.0 # 3.8.0 adds a dependency on importlib-metadata which conflicts with other packages.
44
pytest

requirements/3.6.txt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ attrs==21.4.0
1616
# pytest
1717
babel==2.9.1
1818
# via sphinx
19+
backports.zoneinfo==0.2.1
20+
# via
21+
# pytz-deprecation-shim
22+
# tzlocal
1923
bcrypt==3.2.0
2024
# via paramiko
2125
cached-property==1.5.2
@@ -31,6 +35,8 @@ cffi==1.15.0
3135
# pynacl
3236
charset-normalizer==2.0.12
3337
# via requests
38+
clickhouse-driver==0.2.3
39+
# via testcontainers
3440
codecov==2.1.12
3541
# via -r requirements.in
3642
coverage[toml]==6.2
@@ -98,6 +104,8 @@ importlib-metadata==4.8.3
98104
# redis
99105
# sphinx
100106
# sqlalchemy
107+
importlib-resources==5.4.0
108+
# via backports.zoneinfo
101109
iniconfig==1.1.1
102110
# via pytest
103111
jinja2==3.0.3
@@ -170,7 +178,10 @@ python-dotenv==0.20.0
170178
pytz==2022.1
171179
# via
172180
# babel
181+
# clickhouse-driver
173182
# neo4j
183+
pytz-deprecation-shim==0.1.0.post0
184+
# via tzlocal
174185
pyyaml==5.4.1
175186
# via docker-compose
176187
redis==4.2.0
@@ -197,7 +208,7 @@ six==1.16.0
197208
# websocket-client
198209
snowballstemmer==2.2.0
199210
# via sphinx
200-
sphinx==4.4.0
211+
sphinx==4.5.0
201212
# via -r requirements.in
202213
sphinxcontrib-applehelp==1.0.2
203214
# via sphinx
@@ -224,6 +235,10 @@ typing-extensions==4.1.1
224235
# async-timeout
225236
# importlib-metadata
226237
# redis
238+
tzdata==2022.1
239+
# via pytz-deprecation-shim
240+
tzlocal==4.1
241+
# via clickhouse-driver
227242
urllib3==1.26.9
228243
# via
229244
# requests
@@ -237,7 +252,9 @@ wrapt==1.14.0
237252
# deprecated
238253
# testcontainers
239254
zipp==3.6.0
240-
# via importlib-metadata
255+
# via
256+
# importlib-metadata
257+
# importlib-resources
241258

242259
# The following packages are considered to be unsafe in a requirements file:
243260
# setuptools

requirements/3.7.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ attrs==21.4.0
2222
# trio
2323
babel==2.9.1
2424
# via sphinx
25+
backports-zoneinfo==0.2.1
26+
# via
27+
# pytz-deprecation-shim
28+
# tzlocal
2529
bcrypt==3.2.0
2630
# via paramiko
2731
cached-property==1.5.2
@@ -39,6 +43,8 @@ cffi==1.15.0
3943
# pynacl
4044
charset-normalizer==2.0.12
4145
# via requests
46+
clickhouse-driver==0.2.3
47+
# via testcontainers
4248
codecov==2.1.12
4349
# via -r requirements.in
4450
coverage[toml]==6.3.2
@@ -192,7 +198,10 @@ python-dotenv==0.20.0
192198
pytz==2022.1
193199
# via
194200
# babel
201+
# clickhouse-driver
195202
# neo4j
203+
pytz-deprecation-shim==0.1.0.post0
204+
# via tzlocal
196205
pyyaml==5.4.1
197206
# via docker-compose
198207
redis==4.2.0
@@ -223,7 +232,7 @@ snowballstemmer==2.2.0
223232
# via sphinx
224233
sortedcontainers==2.4.0
225234
# via trio
226-
sphinx==4.4.0
235+
sphinx==4.5.0
227236
# via -r requirements.in
228237
sphinxcontrib-applehelp==1.0.2
229238
# via sphinx
@@ -257,6 +266,10 @@ typing-extensions==4.1.1
257266
# h11
258267
# importlib-metadata
259268
# redis
269+
tzdata==2022.1
270+
# via pytz-deprecation-shim
271+
tzlocal==4.1
272+
# via clickhouse-driver
260273
urllib3[secure,socks]==1.26.9
261274
# via
262275
# requests

requirements/3.8.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ attrs==21.4.0
2222
# trio
2323
babel==2.9.1
2424
# via sphinx
25+
backports-zoneinfo==0.2.1
26+
# via
27+
# pytz-deprecation-shim
28+
# tzlocal
2529
bcrypt==3.2.0
2630
# via paramiko
2731
cachetools==5.0.0
@@ -37,6 +41,8 @@ cffi==1.15.0
3741
# pynacl
3842
charset-normalizer==2.0.12
3943
# via requests
44+
clickhouse-driver==0.2.3
45+
# via testcontainers
4046
codecov==2.1.12
4147
# via -r requirements.in
4248
coverage[toml]==6.3.2
@@ -184,7 +190,10 @@ python-dotenv==0.20.0
184190
pytz==2022.1
185191
# via
186192
# babel
193+
# clickhouse-driver
187194
# neo4j
195+
pytz-deprecation-shim==0.1.0.post0
196+
# via tzlocal
188197
pyyaml==5.4.1
189198
# via docker-compose
190199
redis==4.2.0
@@ -215,7 +224,7 @@ snowballstemmer==2.2.0
215224
# via sphinx
216225
sortedcontainers==2.4.0
217226
# via trio
218-
sphinx==4.4.0
227+
sphinx==4.5.0
219228
# via -r requirements.in
220229
sphinxcontrib-applehelp==1.0.2
221230
# via sphinx
@@ -245,6 +254,10 @@ trio-websocket==0.9.2
245254
# via selenium
246255
typing-extensions==4.1.1
247256
# via redis
257+
tzdata==2022.1
258+
# via pytz-deprecation-shim
259+
tzlocal==4.1
260+
# via clickhouse-driver
248261
urllib3[secure,socks]==1.26.9
249262
# via
250263
# requests

requirements/3.9.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ cffi==1.15.0
3737
# pynacl
3838
charset-normalizer==2.0.12
3939
# via requests
40+
clickhouse-driver==0.2.3
41+
# via testcontainers
4042
codecov==2.1.12
4143
# via -r requirements.in
4244
coverage[toml]==6.3.2
@@ -184,7 +186,10 @@ python-dotenv==0.20.0
184186
pytz==2022.1
185187
# via
186188
# babel
189+
# clickhouse-driver
187190
# neo4j
191+
pytz-deprecation-shim==0.1.0.post0
192+
# via tzlocal
188193
pyyaml==5.4.1
189194
# via docker-compose
190195
redis==4.2.0
@@ -215,7 +220,7 @@ snowballstemmer==2.2.0
215220
# via sphinx
216221
sortedcontainers==2.4.0
217222
# via trio
218-
sphinx==4.4.0
223+
sphinx==4.5.0
219224
# via -r requirements.in
220225
sphinxcontrib-applehelp==1.0.2
221226
# via sphinx
@@ -245,6 +250,10 @@ trio-websocket==0.9.2
245250
# via selenium
246251
typing-extensions==4.1.1
247252
# via redis
253+
tzdata==2022.1
254+
# via pytz-deprecation-shim
255+
tzlocal==4.1
256+
# via clickhouse-driver
248257
urllib3[secure,socks]==1.26.9
249258
# via
250259
# requests

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
'neo4j': ['neo4j'],
6666
'kafka': ['kafka-python'],
6767
'rabbitmq': ['pika'],
68+
'clickhouse': ['clickhouse-driver'],
6869
},
6970
long_description_content_type="text/x-rst",
7071
long_description=long_description,

testcontainers/clickhouse.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#
2+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
3+
# not use this file except in compliance with the License. You may obtain
4+
# a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11+
# License for the specific language governing permissions and limitations
12+
# under the License.
13+
import os
14+
15+
import clickhouse_driver
16+
from clickhouse_driver.errors import Error
17+
18+
from testcontainers.core.generic import DbContainer
19+
from testcontainers.core.waiting_utils import wait_container_is_ready
20+
21+
22+
class ClickHouseContainer(DbContainer):
23+
"""
24+
ClickHouse database container.
25+
26+
Example
27+
-------
28+
The example spins up a ClickHouse database and connects to it
29+
using the :code:`clickhouse-driver`.
30+
::
31+
32+
with ClickHouseContainer("clickhouse/clickhouse-server:21.8") as clickhouse:
33+
with clickhouse_driver.Client.from_url(self.get_connection_url()) as client:
34+
result = client.execute("SELECT version()")
35+
"""
36+
37+
CLICKHOUSE_USER = os.environ.get("CLICKHOUSE_USER", "test")
38+
CLICKHOUSE_PASSWORD = os.environ.get("CLICKHOUSE_PASSWORD", "test")
39+
CLICKHOUSE_DB = os.environ.get("CLICKHOUSE_DB", "test")
40+
41+
def __init__(
42+
self,
43+
image="clickhouse/clickhouse-server:latest",
44+
port=9000,
45+
user=None,
46+
password=None,
47+
dbname=None
48+
):
49+
super().__init__(image=image)
50+
51+
self.CLICKHOUSE_USER = user or self.CLICKHOUSE_USER
52+
self.CLICKHOUSE_PASSWORD = password or self.CLICKHOUSE_PASSWORD
53+
self.CLICKHOUSE_DB = dbname or self.CLICKHOUSE_DB
54+
self.port_to_expose = port
55+
56+
@wait_container_is_ready(Error, EOFError)
57+
def _connect(self):
58+
with clickhouse_driver.Client.from_url(self.get_connection_url()) as client:
59+
client.execute("SELECT version()")
60+
61+
def _configure(self):
62+
self.with_exposed_ports(self.port_to_expose)
63+
self.with_env("CLICKHOUSE_USER", self.CLICKHOUSE_USER)
64+
self.with_env("CLICKHOUSE_PASSWORD", self.CLICKHOUSE_PASSWORD)
65+
self.with_env("CLICKHOUSE_DB", self.CLICKHOUSE_DB)
66+
67+
def get_connection_url(self, host=None):
68+
return self._create_connection_url(
69+
dialect="clickhouse",
70+
username=self.CLICKHOUSE_USER,
71+
password=self.CLICKHOUSE_PASSWORD,
72+
db_name=self.CLICKHOUSE_DB,
73+
host=host,
74+
port=self.port_to_expose,
75+
)

tests/test_db_containers.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import sqlalchemy
2+
import clickhouse_driver
23
from pymongo import MongoClient
34
from pymongo.errors import OperationFailure
45
import pytest
56

67
from testcontainers.core.utils import is_arm
8+
from testcontainers.clickhouse import ClickHouseContainer
79
from testcontainers.core.container import DockerContainer
810
from testcontainers.core.waiting_utils import wait_for
911
from testcontainers.mongodb import MongoDbContainer
@@ -151,3 +153,12 @@ def test_docker_run_mssql():
151153
result = e.execute('select @@servicename')
152154
for row in result:
153155
assert row[0] == 'MSSQLSERVER'
156+
157+
158+
def test_docker_run_clickhouse():
159+
clickhouse_container = ClickHouseContainer()
160+
with clickhouse_container as clickhouse:
161+
client = clickhouse_driver.Client.from_url(clickhouse.get_connection_url())
162+
result = client.execute("select 'working'")
163+
164+
assert result == [('working',)]

0 commit comments

Comments
 (0)