diff --git a/docs/modules/couchbase.md b/docs/modules/couchbase.md new file mode 100644 index 000000000..9ebaa4890 --- /dev/null +++ b/docs/modules/couchbase.md @@ -0,0 +1,23 @@ +# Couchbase + +Since testcontainers-python :material-tag: v4.15.0-rc2 + +## Introduction + +The Testcontainers module for Couchbase. + +## Adding this module to your project dependencies + +Please run the following command to add the Couchbase module to your python dependencies: + +```bash +pip install testcontainers[couchbase] +``` + +## Usage example + + + +[Creating a Couchbase container](../../modules/couchbase/example_basic.py) + + diff --git a/mkdocs.yml b/mkdocs.yml index 0a31629a2..2bac9d3f8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -58,6 +58,7 @@ nav: - modules/clickhouse.md - modules/cockroachdb.md - modules/cosmosdb.md + - modules/couchbase.md - modules/db2.md - modules/elasticsearch.md - modules/influxdb.md diff --git a/modules/couchbase/README.rst b/modules/couchbase/README.rst new file mode 100644 index 000000000..d9d0ae9c1 --- /dev/null +++ b/modules/couchbase/README.rst @@ -0,0 +1,2 @@ +.. autoclass:: testcontainers.couchbase.CouchbaseContainer +.. title:: testcontainers.couchbase.CouchbaseContainer diff --git a/modules/couchbase/example_basic.py b/modules/couchbase/example_basic.py new file mode 100644 index 000000000..ae5ff350a --- /dev/null +++ b/modules/couchbase/example_basic.py @@ -0,0 +1,18 @@ +from testcontainers.couchbase import CouchbaseContainer + +# Initialize Couchbase container +with CouchbaseContainer( + username="administrator", password="password", bucket="mybucket", scope="myscope", collection="mycollection" +) as couchbase: + # Get a client + cluster = couchbase.client() + + # Get a collection + collection = cluster.bucket("mybucket").scope("myscope").collection("mycollection") + + # Upsert a document + collection.upsert("hello", {"world": "from python"}) + + # Get a document + result = collection.get("hello") + print(result.value) diff --git a/modules/couchbase/testcontainers/couchbase/__init__.py b/modules/couchbase/testcontainers/couchbase/__init__.py new file mode 100644 index 000000000..45ab8296c --- /dev/null +++ b/modules/couchbase/testcontainers/couchbase/__init__.py @@ -0,0 +1,186 @@ +import os +from datetime import timedelta +from time import sleep +from typing import Optional + +import requests +from requests.auth import HTTPBasicAuth + +from couchbase.auth import PasswordAuthenticator +from couchbase.cluster import Cluster +from couchbase.options import ClusterOptions, ClusterTimeoutOptions, TLSVerifyMode +from testcontainers.core.generic import DbContainer +from testcontainers.core.waiting_utils import wait_container_is_ready, wait_for_logs + + +# noinspection HttpUrlsUsage,SpellCheckingInspection +class CouchbaseContainer(DbContainer): + """ + Couchbase database container. + + Example: + The example spins up a Couchbase database and connects to it using + the `Couchbase Python Client`. + + .. doctest:: + + >>> from couchbase.auth import PasswordAuthenticator + >>> from couchbase.cluster import Cluster + >>> from testcontainers.couchbase import CouchbaseContainer + + >>> with CouchbaseContainer("couchbase:latest") as couchbase: + ... cluster = couchbase.client() + ... # Use the cluster for various operations + + This creates a single-node Couchbase database container with the default bucket, scope, and collection. + + If you would like to pass custom values for the image, cluster_port, username, password, bucket, scope, and collection, you can use: + username = "administrator" + password = "password" + bucket_name = "mybucket" + scope_name = "myscope" + collection_name = "mycollection" + image = "couchbase:latest" + cluster_port = 8091 + + with CouchbaseContainer(image=image, cluster_port=cluster_port, username=username, password=password, bucket=bucket_name, scope=scope_name, + collection=collection_name) as couchbase_container: + cluster = couchbase_container.client() + collection = cluster.bucket(bucket_name=bucket_name).scope(name=scope_name).collection(name=collection_name) + key = uuid.uuid4().hex + value = "world" + doc = { + "hello": value, + } + collection.upsert(key=key, value=doc) + returned_doc = collection.get(key=key) + print(returned_doc.value['hello']) + + # Output: world + """ + + def __init__( + self, + image: str = "couchbase:latest", + cluster_port: Optional[int] = 8091, + username: Optional[str] = None, + password: Optional[str] = None, + bucket: Optional[str] = None, + scope: Optional[str] = None, + collection: Optional[str] = None, + **kwargs, + ) -> None: + super().__init__(image=image, **kwargs) + self._username = username or os.environ.get("COUCHBASE_USERNAME", "Administrator") + self._password = password or os.environ.get("COUCHBASE_PASSWORD", "password") + self._bucket = bucket or os.environ.get("COUCHBASE_BUCKET", "default") + self._scope = scope or os.environ.get("COUCHBASE_SCOPE", "default") + self._collection = collection or os.environ.get("COUCHBASE_COLLECTION", "default") + self._cluster_port = cluster_port + + ports = [ + cluster_port, + 8092, + 8093, + 8094, + 8095, + 8096, + 8097, + 9123, + 11207, + 11210, + 11280, + 18091, + 18092, + 18093, + 18094, + 18095, + 18096, + 18097, + ] + + for port in ports: + self.with_exposed_ports(port) + self.with_bind_ports(port, port) + + @wait_container_is_ready() + def _connect(self): + wait_for_logs(self, "and logs available in") + while True: + sleep(1) + try: + url = f"http://{self.get_container_host_ip()}:{self.get_exposed_port(self._cluster_port)}/settings/web" + response = requests.get(url) + if 200 <= response.status_code < 300: + break + else: + pass + except requests.exceptions.ConnectionError: + pass + + def _configure(self) -> None: + self.with_env("COUCHBASE_USERNAME", self._username) + self.with_env("COUCHBASE_PASSWORD", self._password) + self.with_env("COUCHBASE_BUCKET", self._bucket) + + def start(self) -> "CouchbaseContainer": + self._configure() + super().start() + self._connect() + self.set_admin_credentials() + self._create_bucket() + self._create_scope() + self._create_collection() + return self + + def set_admin_credentials(self): + url = f"http://{self.get_container_host_ip()}:{self.get_exposed_port(self._cluster_port)}/settings/web" + data = {"username": self._username, "password": self._password, "port": "SAME"} + response = requests.post(url, data=data) + if 200 <= response.status_code < 300: + return + else: + raise RuntimeError(response.text) + + def _create_bucket(self) -> None: + url = f"http://{self.get_container_host_ip()}:{self.get_exposed_port(self._cluster_port)}/pools/default/buckets" + data = {"name": self._bucket, "bucketType": "couchbase", "ramQuotaMB": 256} + response = requests.post(url, data=data, auth=HTTPBasicAuth(self._username, self._password)) + if 200 <= response.status_code < 300: + return + else: + raise RuntimeError(response.text) + + def _create_scope(self): + url = f"http://{self.get_container_host_ip()}:{self.get_exposed_port(self._cluster_port)}/pools/default/buckets/{self._bucket}/scopes" + data = {"name": self._scope} + response = requests.post(url, data=data, auth=HTTPBasicAuth(self._username, self._password)) + if 200 <= response.status_code < 300: + return + else: + raise RuntimeError(response.text) + + def _create_collection(self): + url = f"http://{self.get_container_host_ip()}:{self.get_exposed_port(self._cluster_port)}/pools/default/buckets/{self._bucket}/scopes/{self._scope}/collections" + data = {"name": self._collection, "maxTTL": 3600, "history": str(False).lower()} + response = requests.post(url, data=data, auth=HTTPBasicAuth(self._username, self._password)) + if 200 <= response.status_code < 300: + return + else: + raise RuntimeError(response.text) + + def get_connection_url(self) -> str: + return f"couchbases://{self.get_container_host_ip()}" + + def client(self, cluster_options: ClusterOptions = None): + auth = PasswordAuthenticator(self._username, self._password) + if cluster_options is None: + cluster_options = ClusterOptions( + auth, + timeout_options=ClusterTimeoutOptions(kv_timeout=timedelta(seconds=10)), + enable_tcp_keep_alive=True, + tls_verify=TLSVerifyMode.NONE, + ) + cluster = Cluster(self.get_connection_url(), cluster_options) + cluster.wait_until_ready(timedelta(seconds=15)) + return cluster diff --git a/modules/couchbase/tests/test_couchbase.py b/modules/couchbase/tests/test_couchbase.py new file mode 100644 index 000000000..d581a9f36 --- /dev/null +++ b/modules/couchbase/tests/test_couchbase.py @@ -0,0 +1,29 @@ +import uuid + +import pytest + +from testcontainers.couchbase import CouchbaseContainer + + +# The versions below should reflect the latest stable releases +@pytest.mark.parametrize("version", ["7.17.18", "8.12.2"]) +def test_docker_run_couchbase(version): + username = "administrator" + password = "password" + bucket_name = "mybucket" + scope_name = "myscope" + collection_name = "mycollection" + + with CouchbaseContainer( + username=username, password=password, bucket=bucket_name, scope=scope_name, collection=collection_name + ) as couchbase_container: + cluster = couchbase_container.client() + collection = cluster.bucket(bucket_name=bucket_name).scope(name=scope_name).collection(name=collection_name) + key = uuid.uuid4().hex + value = "world" + doc = { + "hello": value, + } + collection.upsert(key=key, value=doc) + returned_doc = collection.get(key=key) + assert returned_doc.value["hello"] == value diff --git a/pyproject.toml b/pyproject.toml index 8f90bfda8..27170b135 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,7 @@ cassandra = [] clickhouse = ["clickhouse-driver"] cosmosdb = ["azure-cosmos>=4"] cockroachdb = [] +couchbase = ['couchbase'] db2 = [ "sqlalchemy>=2", "ibm_db_sa; platform_machine != 'aarch64' and platform_machine != 'arm64'", @@ -185,6 +186,7 @@ packages = [ "modules/clickhouse/testcontainers", "modules/cockroachdb/testcontainers", "modules/cosmosdb/testcontainers", + "modules/couchbase/testcontainers", "modules/db2/testcontainers", "modules/elasticsearch/testcontainers", "modules/generic/testcontainers", @@ -235,6 +237,7 @@ dev-mode-dirs = [ "modules/clickhouse", "modules/cockroachdb", "modules/cosmosdb", + "modules/couchbase", "modules/db2", "modules/elasticsearch", "modules/generic", diff --git a/uv.lock b/uv.lock index 4d65c6f7d..b6d553111 100644 --- a/uv.lock +++ b/uv.lock @@ -829,6 +829,47 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "couchbase" +version = "4.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/8c/ecbf99eedbd8e39391d4eb44ff37517f3c5efb1a0879357ccc8ba7a0d106/couchbase-4.6.1.tar.gz", hash = "sha256:d15dd81c0789f5d3bda76e22c6636a0689afe065cf2db024ca074b6c208b79e4", size = 6712137, upload-time = "2026-04-29T21:27:59.694Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/c1/a0df92ca12e262e11a9bb6a935d154879d6a5b527cac1fb8db893ff986b8/couchbase-4.6.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:eb9ac0a7d945f0be89979e8d1e2d52e9a05a37baeaa7e46863d64a7d77e1c687", size = 5601430, upload-time = "2026-04-29T21:26:42.04Z" }, + { url = "https://files.pythonhosted.org/packages/77/fd/02cbe8644cd10978a41041272639f719cd25489a2d8724ddad385f78544c/couchbase-4.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:19cbb1fe2f989783bcfc325668d8542ac7c3e79115cf0a3de70da48ec507fc79", size = 4725322, upload-time = "2026-04-29T21:26:44.583Z" }, + { url = "https://files.pythonhosted.org/packages/ec/f7/e83cb04c7a414f6ef2411249882411665d19ac4aad3cd3cc073c4d0b7a91/couchbase-4.6.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ed30b14004a569c518adc636ffc4ceeebc84d0c5ae2e11e8d03a3b0e83fb6844", size = 5603913, upload-time = "2026-04-29T21:26:46.619Z" }, + { url = "https://files.pythonhosted.org/packages/ea/21/86e6bb8801b3f52dfbe4c66854e7da7149a6d95babac97fc02dba75b7d0b/couchbase-4.6.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4a125ceebe42abb16195d3c20808014680319bdfdc3d2385c11dda8d18b49961", size = 5867646, upload-time = "2026-04-29T21:26:48.631Z" }, + { url = "https://files.pythonhosted.org/packages/6f/58/f3b8bce2dc8c921d40a2210a61c2be643d44cf0a5c9ff5c2eee0098e0868/couchbase-4.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f9d46419987ef5a0b3a42c1fc77bfad7afb3f4d41a84cb17afadc32176f8b144", size = 7326281, upload-time = "2026-04-29T21:26:50.719Z" }, + { url = "https://files.pythonhosted.org/packages/9d/f0/8a9106264eab0cd3b2f35438bc97d324c71a634da00937579a2818352a01/couchbase-4.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:ba6e047af73bbde5e42ba8bf5ab1127b4b9f324842ba9b3d48d4a586abe3f86e", size = 4543740, upload-time = "2026-04-29T21:26:52.724Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ae/4b5df74d4ebe1e2e4361d484c7e2b25778c256be224ad7ffa78ad5dfd91a/couchbase-4.6.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:b9b917c2e5bfe72583e78fc07e1b8864f0d44c83aee4a1cd7b53c213f0852d89", size = 5519936, upload-time = "2026-04-29T21:26:54.818Z" }, + { url = "https://files.pythonhosted.org/packages/c3/ce/261e861a85aa0a9a5e6c278079479a0c183123aed44e3a39227d7acee42d/couchbase-4.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea601eeedb5c119f5ceceb360226332d96e6388e6427a18eb8593d45c547cecf", size = 4725320, upload-time = "2026-04-29T21:26:56.789Z" }, + { url = "https://files.pythonhosted.org/packages/0b/40/0030e8ee5578469c50d8c7ba3a88bcf5660de9eff44669e7d0884f26b19a/couchbase-4.6.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48d757ee6aeba47ba86ab0d71718ea7c6b32a11ff165bf727646465b5e969ca0", size = 5603919, upload-time = "2026-04-29T21:26:58.986Z" }, + { url = "https://files.pythonhosted.org/packages/f9/12/9eccb2d6d2b948c930bd1b76eb298b94c271bc6efbdfb820b795fd22724b/couchbase-4.6.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3f27acb68bb2ce523bc07b9c3d37d3578e34559087a03eac2ff9af16c90a3462", size = 5867649, upload-time = "2026-04-29T21:27:01.481Z" }, + { url = "https://files.pythonhosted.org/packages/44/5f/a54395545d57dd667e316ce16ec9b63d85f01bf57ac5b39e38f53871ef76/couchbase-4.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:817248bdf73ebbbb90d831bcad414c5914c0e4427be6ff0128bdd54fd9eded03", size = 7326284, upload-time = "2026-04-29T21:27:04.121Z" }, + { url = "https://files.pythonhosted.org/packages/d4/0d/59c856e16f07f662b7f07fbd018e9e6b361bc77936129ea51069bdd63484/couchbase-4.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:531abb82cc2f8559238988e5c394fdea0463dd15a9d8587cceba9eea6d188033", size = 4545377, upload-time = "2026-04-29T21:27:06.079Z" }, + { url = "https://files.pythonhosted.org/packages/fc/22/2dd059aa6bc912e4d2f62fbc722493d78582ae286c33fac7a78c3bba6af0/couchbase-4.6.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:35dfbee6f48b9f3eab9d2a07c80747f09d8b4b3d15b312190b3ae88e8e24cb6b", size = 5596715, upload-time = "2026-04-29T21:27:08.06Z" }, + { url = "https://files.pythonhosted.org/packages/28/77/00039e48470ca3413eba056b13f5c7d071b49e558fc8e8ec5ae84c072108/couchbase-4.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99afefbe46792cb45e55747dbd61ca64f806484fc0b1cdd1afa0b909d1a56744", size = 4724349, upload-time = "2026-04-29T21:27:10.272Z" }, + { url = "https://files.pythonhosted.org/packages/9d/f0/80207bdc94b441aae75db99799ec4439e1c483f3cc5b50b4fea0d23b04e8/couchbase-4.6.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:46073464a94a4767dc5888c9ede21c76c82054479ff12914026b6cbf0468c503", size = 5605918, upload-time = "2026-04-29T21:27:13.067Z" }, + { url = "https://files.pythonhosted.org/packages/30/44/2555e2823656bc9329e9bbe4b1ffb20ee5047fe7ffbb4eb2c55909a3fb1b/couchbase-4.6.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a0a37c8bfe4fcdf0089f40d1e306f9dff72802486a53c1cf530c5fe53031a548", size = 5870083, upload-time = "2026-04-29T21:27:15.449Z" }, + { url = "https://files.pythonhosted.org/packages/c4/92/143b000fbfa6443bf55644537d9b09c07c9ee3150d7b80c64e0164ee969a/couchbase-4.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8afdaeccec56308264fee90c4b53605d09b635154e3205824dbd4c5cb98deff7", size = 7335690, upload-time = "2026-04-29T21:27:18.291Z" }, + { url = "https://files.pythonhosted.org/packages/7a/13/4423cd492e306bef9c9f4d035c0061a906db7dd7961c208a7c6f37c4d3ad/couchbase-4.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:877fc6be2a59b7e851cb0790eccdcbb9fdfac7a951387518938ee67c727419af", size = 4544430, upload-time = "2026-04-29T21:27:20.241Z" }, + { url = "https://files.pythonhosted.org/packages/a0/19/5e4d888386a734a34e2a1271ed633094da5382d6de5c9d2770b01e722896/couchbase-4.6.1-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:03f7bea664ab88fcb240705175103bb2c549321caff49f4c435c2545269bf9ab", size = 5515592, upload-time = "2026-04-29T21:27:22.318Z" }, + { url = "https://files.pythonhosted.org/packages/c7/c6/f16440cc7f7d4fbc49a0ee2b8d2cf44fb091d348793c1bec170778460f40/couchbase-4.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6c64b665c6036714232866ed790f90accdca35c809eb8ed9f622ffc60f33e755", size = 4724353, upload-time = "2026-04-29T21:27:24.282Z" }, + { url = "https://files.pythonhosted.org/packages/93/f6/ca5597f03093c356c896eb5a2261c77e3722e12f340e3041c59c321dcec0/couchbase-4.6.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c11687d71610b99b5d856663ec97c5b07d916eb21a19c97889042287920449b", size = 5605915, upload-time = "2026-04-29T21:27:26.559Z" }, + { url = "https://files.pythonhosted.org/packages/c4/95/4edcace26009d91dc1e112271ceecbc595c6518ce4c5d91ec023ea2d09e8/couchbase-4.6.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465cf1ca027c07f2fc10daf9c3e522e631cd4a0682977d1c21efd01d91ae3403", size = 5870093, upload-time = "2026-04-29T21:27:28.691Z" }, + { url = "https://files.pythonhosted.org/packages/6f/a3/37fd54af47fbb415129a3406f52b16c288ed7541eb844a035f9979344308/couchbase-4.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45bb413b4d9a46af3439950ebc7eee10573183cdcee6a5008b1eaf46b79c9c62", size = 7335676, upload-time = "2026-04-29T21:27:30.954Z" }, + { url = "https://files.pythonhosted.org/packages/eb/21/4b5e94128a30411bb9e7b97c72b9526f62125e59021eaaafa0c49e47510a/couchbase-4.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:00a36c419e69ef5e5063d959840a2164df7b65a8f2ab5da684ea8eecbfac8713", size = 4544555, upload-time = "2026-04-29T21:27:33.03Z" }, + { url = "https://files.pythonhosted.org/packages/65/f4/7ca3fae2f725bc45150bf9ff14cc082d25f5131fc49048b7f045f3ca2079/couchbase-4.6.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:87b03ab37594f499c001475766ae1d8dbbc41aa9d4a4606571467d010f763de0", size = 5596005, upload-time = "2026-04-29T21:27:36.064Z" }, + { url = "https://files.pythonhosted.org/packages/e2/b7/fab772b47f86018f24027f15ac0b8b97d962ab8e8c3a2bdbd3abb3fa7d6b/couchbase-4.6.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3c47c47fb3a11f78127381a478db727a5591da77ae15346b2a92506b2555b815", size = 4724738, upload-time = "2026-04-29T21:27:38.224Z" }, + { url = "https://files.pythonhosted.org/packages/36/da/65159bb2f878a70c46b6e8570977f96fe747c09798f2f36e79bba59781f8/couchbase-4.6.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2c4d2ff4b43eea0cd0c341271912ac903adde5ab7939fb4518479f2a4d5b67de", size = 5606272, upload-time = "2026-04-29T21:27:42.528Z" }, + { url = "https://files.pythonhosted.org/packages/bf/2e/af98e1a708f9b540c478e1f49535a3e96f2f17fdf1e08ef99fda4dec69c2/couchbase-4.6.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:31a3e2bce4be352c7e652d957e1c4fa7874f881129230225ba80993eec80405f", size = 5870198, upload-time = "2026-04-29T21:27:48.098Z" }, + { url = "https://files.pythonhosted.org/packages/25/61/6dae8c9db230411287c4c0ca6a86d6701596026806264b403bc6b818b7b1/couchbase-4.6.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0f73fb3ff16938841f326424172f624dd677051a6a0248e6446bf8cacda6da1e", size = 7337096, upload-time = "2026-04-29T21:27:52.849Z" }, + { url = "https://files.pythonhosted.org/packages/67/15/a301401c13ba1ae215044d64e16d31a02141780f3fc86b530f1e6ab055d9/couchbase-4.6.1-cp314-cp314-win_amd64.whl", hash = "sha256:fdc6e6f1e19f530a4eda513b14cf1a7e56fcdc2070955a4ca84201638c69fe95", size = 4674349, upload-time = "2026-04-29T21:27:56.478Z" }, +] + [[package]] name = "coverage" version = "7.13.1" @@ -1368,6 +1409,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/32/6a/33d1702184d94106d3cdd7bfb788e19723206fce152e303473ca3b946c7b/greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d", size = 273658, upload-time = "2025-12-04T14:23:37.494Z" }, { url = "https://files.pythonhosted.org/packages/d6/b7/2b5805bbf1907c26e434f4e448cd8b696a0b71725204fa21a211ff0c04a7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb", size = 574810, upload-time = "2025-12-04T14:50:04.154Z" }, { url = "https://files.pythonhosted.org/packages/94/38/343242ec12eddf3d8458c73f555c084359883d4ddc674240d9e61ec51fd6/greenlet-3.3.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd", size = 586248, upload-time = "2025-12-04T14:57:39.35Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d0/0ae86792fb212e4384041e0ef8e7bc66f59a54912ce407d26a966ed2914d/greenlet-3.3.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b", size = 597403, upload-time = "2025-12-04T15:07:10.831Z" }, { url = "https://files.pythonhosted.org/packages/b6/a8/15d0aa26c0036a15d2659175af00954aaaa5d0d66ba538345bd88013b4d7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5", size = 586910, upload-time = "2025-12-04T14:25:59.705Z" }, { url = "https://files.pythonhosted.org/packages/e1/9b/68d5e3b7ccaba3907e5532cf8b9bf16f9ef5056a008f195a367db0ff32db/greenlet-3.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9", size = 1547206, upload-time = "2025-12-04T15:04:21.027Z" }, { url = "https://files.pythonhosted.org/packages/66/bd/e3086ccedc61e49f91e2cfb5ffad9d8d62e5dc85e512a6200f096875b60c/greenlet-3.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d", size = 1613359, upload-time = "2025-12-04T14:27:26.548Z" }, @@ -1375,6 +1417,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1f/cb/48e964c452ca2b92175a9b2dca037a553036cb053ba69e284650ce755f13/greenlet-3.3.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e29f3018580e8412d6aaf5641bb7745d38c85228dacf51a73bd4e26ddf2a6a8e", size = 274908, upload-time = "2025-12-04T14:23:26.435Z" }, { url = "https://files.pythonhosted.org/packages/28/da/38d7bff4d0277b594ec557f479d65272a893f1f2a716cad91efeb8680953/greenlet-3.3.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a687205fb22794e838f947e2194c0566d3812966b41c78709554aa883183fb62", size = 577113, upload-time = "2025-12-04T14:50:05.493Z" }, { url = "https://files.pythonhosted.org/packages/3c/f2/89c5eb0faddc3ff014f1c04467d67dee0d1d334ab81fadbf3744847f8a8a/greenlet-3.3.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4243050a88ba61842186cb9e63c7dfa677ec146160b0efd73b855a3d9c7fcf32", size = 590338, upload-time = "2025-12-04T14:57:41.136Z" }, + { url = "https://files.pythonhosted.org/packages/80/d7/db0a5085035d05134f8c089643da2b44cc9b80647c39e93129c5ef170d8f/greenlet-3.3.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:670d0f94cd302d81796e37299bcd04b95d62403883b24225c6b5271466612f45", size = 601098, upload-time = "2025-12-04T15:07:11.898Z" }, { url = "https://files.pythonhosted.org/packages/dc/a6/e959a127b630a58e23529972dbc868c107f9d583b5a9f878fb858c46bc1a/greenlet-3.3.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb3a8ec3db4a3b0eb8a3c25436c2d49e3505821802074969db017b87bc6a948", size = 590206, upload-time = "2025-12-04T14:26:01.254Z" }, { url = "https://files.pythonhosted.org/packages/48/60/29035719feb91798693023608447283b266b12efc576ed013dd9442364bb/greenlet-3.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2de5a0b09eab81fc6a382791b995b1ccf2b172a9fec934747a7a23d2ff291794", size = 1550668, upload-time = "2025-12-04T15:04:22.439Z" }, { url = "https://files.pythonhosted.org/packages/0a/5f/783a23754b691bfa86bd72c3033aa107490deac9b2ef190837b860996c9f/greenlet-3.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4449a736606bd30f27f8e1ff4678ee193bc47f6ca810d705981cfffd6ce0d8c5", size = 1615483, upload-time = "2025-12-04T14:27:28.083Z" }, @@ -1382,6 +1425,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f8/0a/a3871375c7b9727edaeeea994bfff7c63ff7804c9829c19309ba2e058807/greenlet-3.3.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:b01548f6e0b9e9784a2c99c5651e5dc89ffcbe870bc5fb2e5ef864e9cc6b5dcb", size = 276379, upload-time = "2025-12-04T14:23:30.498Z" }, { url = "https://files.pythonhosted.org/packages/43/ab/7ebfe34dce8b87be0d11dae91acbf76f7b8246bf9d6b319c741f99fa59c6/greenlet-3.3.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349345b770dc88f81506c6861d22a6ccd422207829d2c854ae2af8025af303e3", size = 597294, upload-time = "2025-12-04T14:50:06.847Z" }, { url = "https://files.pythonhosted.org/packages/a4/39/f1c8da50024feecd0793dbd5e08f526809b8ab5609224a2da40aad3a7641/greenlet-3.3.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e8e18ed6995e9e2c0b4ed264d2cf89260ab3ac7e13555b8032b25a74c6d18655", size = 607742, upload-time = "2025-12-04T14:57:42.349Z" }, + { url = "https://files.pythonhosted.org/packages/77/cb/43692bcd5f7a0da6ec0ec6d58ee7cddb606d055ce94a62ac9b1aa481e969/greenlet-3.3.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c024b1e5696626890038e34f76140ed1daf858e37496d33f2af57f06189e70d7", size = 622297, upload-time = "2025-12-04T15:07:13.552Z" }, { url = "https://files.pythonhosted.org/packages/75/b0/6bde0b1011a60782108c01de5913c588cf51a839174538d266de15e4bf4d/greenlet-3.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:047ab3df20ede6a57c35c14bf5200fcf04039d50f908270d3f9a7a82064f543b", size = 609885, upload-time = "2025-12-04T14:26:02.368Z" }, { url = "https://files.pythonhosted.org/packages/49/0e/49b46ac39f931f59f987b7cd9f34bfec8ef81d2a1e6e00682f55be5de9f4/greenlet-3.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d9ad37fc657b1102ec880e637cccf20191581f75c64087a549e66c57e1ceb53", size = 1567424, upload-time = "2025-12-04T15:04:23.757Z" }, { url = "https://files.pythonhosted.org/packages/05/f5/49a9ac2dff7f10091935def9165c90236d8f175afb27cbed38fb1d61ab6b/greenlet-3.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83cd0e36932e0e7f36a64b732a6f60c2fc2df28c351bae79fbaf4f8092fe7614", size = 1636017, upload-time = "2025-12-04T14:27:29.688Z" }, @@ -1389,6 +1433,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/2f/28592176381b9ab2cafa12829ba7b472d177f3acc35d8fbcf3673d966fff/greenlet-3.3.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739", size = 275140, upload-time = "2025-12-04T14:23:01.282Z" }, { url = "https://files.pythonhosted.org/packages/2c/80/fbe937bf81e9fca98c981fe499e59a3f45df2a04da0baa5c2be0dca0d329/greenlet-3.3.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808", size = 599219, upload-time = "2025-12-04T14:50:08.309Z" }, { url = "https://files.pythonhosted.org/packages/c2/ff/7c985128f0514271b8268476af89aee6866df5eec04ac17dcfbc676213df/greenlet-3.3.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54", size = 610211, upload-time = "2025-12-04T14:57:43.968Z" }, + { url = "https://files.pythonhosted.org/packages/79/07/c47a82d881319ec18a4510bb30463ed6891f2ad2c1901ed5ec23d3de351f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492", size = 624311, upload-time = "2025-12-04T15:07:14.697Z" }, { url = "https://files.pythonhosted.org/packages/fd/8e/424b8c6e78bd9837d14ff7df01a9829fc883ba2ab4ea787d4f848435f23f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527", size = 612833, upload-time = "2025-12-04T14:26:03.669Z" }, { url = "https://files.pythonhosted.org/packages/b5/ba/56699ff9b7c76ca12f1cdc27a886d0f81f2189c3455ff9f65246780f713d/greenlet-3.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39", size = 1567256, upload-time = "2025-12-04T15:04:25.276Z" }, { url = "https://files.pythonhosted.org/packages/1e/37/f31136132967982d698c71a281a8901daf1a8fbab935dce7c0cf15f942cc/greenlet-3.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8", size = 1636483, upload-time = "2025-12-04T14:27:30.804Z" }, @@ -1396,6 +1441,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/7c/f0a6d0ede2c7bf092d00bc83ad5bafb7e6ec9b4aab2fbdfa6f134dc73327/greenlet-3.3.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f", size = 275671, upload-time = "2025-12-04T14:23:05.267Z" }, { url = "https://files.pythonhosted.org/packages/44/06/dac639ae1a50f5969d82d2e3dd9767d30d6dbdbab0e1a54010c8fe90263c/greenlet-3.3.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365", size = 646360, upload-time = "2025-12-04T14:50:10.026Z" }, { url = "https://files.pythonhosted.org/packages/e0/94/0fb76fe6c5369fba9bf98529ada6f4c3a1adf19e406a47332245ef0eb357/greenlet-3.3.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3", size = 658160, upload-time = "2025-12-04T14:57:45.41Z" }, + { url = "https://files.pythonhosted.org/packages/93/79/d2c70cae6e823fac36c3bbc9077962105052b7ef81db2f01ec3b9bf17e2b/greenlet-3.3.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45", size = 671388, upload-time = "2025-12-04T15:07:15.789Z" }, { url = "https://files.pythonhosted.org/packages/b8/14/bab308fc2c1b5228c3224ec2bf928ce2e4d21d8046c161e44a2012b5203e/greenlet-3.3.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955", size = 660166, upload-time = "2025-12-04T14:26:05.099Z" }, { url = "https://files.pythonhosted.org/packages/4b/d2/91465d39164eaa0085177f61983d80ffe746c5a1860f009811d498e7259c/greenlet-3.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55", size = 1615193, upload-time = "2025-12-04T15:04:27.041Z" }, { url = "https://files.pythonhosted.org/packages/42/1b/83d110a37044b92423084d52d5d5a3b3a73cafb51b547e6d7366ff62eff1/greenlet-3.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc", size = 1683653, upload-time = "2025-12-04T14:27:32.366Z" }, @@ -1403,6 +1449,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/66/bd6317bc5932accf351fc19f177ffba53712a202f9df10587da8df257c7e/greenlet-3.3.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931", size = 282638, upload-time = "2025-12-04T14:25:20.941Z" }, { url = "https://files.pythonhosted.org/packages/30/cf/cc81cb030b40e738d6e69502ccbd0dd1bced0588e958f9e757945de24404/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388", size = 651145, upload-time = "2025-12-04T14:50:11.039Z" }, { url = "https://files.pythonhosted.org/packages/9c/ea/1020037b5ecfe95ca7df8d8549959baceb8186031da83d5ecceff8b08cd2/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3", size = 654236, upload-time = "2025-12-04T14:57:47.007Z" }, + { url = "https://files.pythonhosted.org/packages/69/cc/1e4bae2e45ca2fa55299f4e85854606a78ecc37fead20d69322f96000504/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221", size = 662506, upload-time = "2025-12-04T15:07:16.906Z" }, { url = "https://files.pythonhosted.org/packages/57/b9/f8025d71a6085c441a7eaff0fd928bbb275a6633773667023d19179fe815/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b", size = 653783, upload-time = "2025-12-04T14:26:06.225Z" }, { url = "https://files.pythonhosted.org/packages/f6/c7/876a8c7a7485d5d6b5c6821201d542ef28be645aa024cfe1145b35c120c1/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd", size = 1614857, upload-time = "2025-12-04T15:04:28.484Z" }, { url = "https://files.pythonhosted.org/packages/4f/dc/041be1dff9f23dac5f48a43323cd0789cb798342011c19a248d9c9335536/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9", size = 1676034, upload-time = "2025-12-04T14:27:33.531Z" }, @@ -4891,7 +4938,7 @@ wheels = [ [[package]] name = "testcontainers" -version = "4.15.0rc1" +version = "4.15.0rc2" source = { editable = "." } dependencies = [ { name = "docker" }, @@ -4921,6 +4968,9 @@ clickhouse = [ cosmosdb = [ { name = "azure-cosmos" }, ] +couchbase = [ + { name = "couchbase" }, +] db2 = [ { name = "ibm-db-sa", marker = "platform_machine != 'aarch64' and platform_machine != 'arm64'" }, { name = "sqlalchemy" }, @@ -5096,6 +5146,7 @@ requires-dist = [ { name = "cassandra-driver", marker = "python_full_version < '3.14' and extra == 'scylla'", specifier = ">=3" }, { name = "chromadb-client", marker = "extra == 'chroma'", specifier = ">=1" }, { name = "clickhouse-driver", marker = "extra == 'clickhouse'" }, + { name = "couchbase", marker = "extra == 'couchbase'" }, { name = "cryptography", marker = "extra == 'mailpit'" }, { name = "cryptography", marker = "extra == 'sftp'" }, { name = "docker" }, @@ -5139,7 +5190,7 @@ requires-dist = [ { name = "weaviate-client", marker = "extra == 'weaviate'", specifier = ">=4" }, { name = "wrapt" }, ] -provides-extras = ["arangodb", "aws", "azurite", "cassandra", "clickhouse", "cosmosdb", "cockroachdb", "db2", "elasticsearch", "generic", "test-module-import", "google", "influxdb", "k3s", "kafka", "keycloak", "localstack", "mailpit", "memcached", "minio", "milvus", "mongodb", "mqtt", "mssql", "mysql", "nats", "neo4j", "nginx", "openfga", "opensearch", "ollama", "oracle", "oracle-free", "postgres", "qdrant", "rabbitmq", "redis", "registry", "selenium", "scylla", "sftp", "valkey", "vault", "weaviate", "chroma", "trino"] +provides-extras = ["arangodb", "aws", "azurite", "cassandra", "clickhouse", "cosmosdb", "cockroachdb", "couchbase", "db2", "elasticsearch", "generic", "test-module-import", "google", "influxdb", "k3s", "kafka", "keycloak", "localstack", "mailpit", "memcached", "minio", "milvus", "mongodb", "mqtt", "mssql", "mysql", "nats", "neo4j", "nginx", "openfga", "opensearch", "ollama", "oracle", "oracle-free", "postgres", "qdrant", "rabbitmq", "redis", "registry", "selenium", "scylla", "sftp", "valkey", "vault", "weaviate", "chroma", "trino"] [package.metadata.requires-dev] dev = [