diff --git a/docs/supported-databases/bigquery.rst b/docs/supported-databases/bigquery.rst index c9bfdcc..6fc31c4 100644 --- a/docs/supported-databases/bigquery.rst +++ b/docs/supported-databases/bigquery.rst @@ -1,9 +1,8 @@ BigQuery ======== -Integration with `Google BigQuery `_ using the `BigQuery Emulator `_ - -This integration uses the official `Google Cloud BigQuery Python Client `_ for testing against the BigQuery Emulator. The emulator is a third-party project that provides a local development environment that mimics the behavior of BigQuery, allowing you to test your application without connecting to the actual service. +Integration with `Google BigQuery `_ using the +`BigQuery Emulator `_. Installation ------------ @@ -12,37 +11,39 @@ Installation pip install pytest-databases[bigquery] +The ``bigquery`` extra is kept as a compatibility group. Install the BigQuery client +that your application already uses. + Usage Example ------------- .. code-block:: python - import pytest + from google.api_core.client_options import ClientOptions + from google.auth.credentials import AnonymousCredentials from google.cloud import bigquery + from pytest_databases.docker.bigquery import BigQueryService pytest_plugins = ["pytest_databases.docker.bigquery"] + def test(bigquery_service: BigQueryService) -> None: client = bigquery.Client( project=bigquery_service.project, - client_options=bigquery_service.client_options, - credentials=bigquery_service.credentials, + client_options=ClientOptions(api_endpoint=bigquery_service.endpoint), + credentials=AnonymousCredentials(), ) - job = client.query(query="SELECT 1 as one") - resp = list(job.result()) - assert resp[0].one == 1 - - def test(bigquery_client: bigquery.Client) -> None: - assert isinstance(bigquery_client, bigquery.Client) + job = client.query(query="SELECT 1 AS one") + rows = list(job.result()) + assert rows[0].one == 1 Available Fixtures ------------------ -* ``bigquery_image``: The Docker image to use for BigQuery. -* ``bigquery_service``: A fixture that provides a BigQuery service. -* ``bigquery_client``: A fixture that provides a BigQuery client. +* ``bigquery_image``: The Docker image to use for the BigQuery emulator. +* ``bigquery_service``: A fixture that provides a running BigQuery emulator service. Service API ----------- diff --git a/pyproject.toml b/pyproject.toml index af70e1f..2311087 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,7 @@ Source = "https://github.com/litestar-org/pytest-databases" [project.optional-dependencies] azure-storage = ["azure-storage-blob"] -bigquery = ["google-cloud-bigquery"] +bigquery = [] cockroachdb = ["psycopg"] dragonfly = ["redis"] elasticsearch7 = ["elasticsearch7"] @@ -195,10 +195,6 @@ warn_unused_ignores = true disable_error_code = "attr-defined" module = "pytest_databases.docker.spanner" -[[tool.mypy.overrides]] -disable_error_code = "attr-defined" -module = "pytest_databases.docker.bigquery" - [[tool.mypy.overrides]] disable_error_code = "attr-defined" disallow_untyped_decorators = false diff --git a/src/pytest_databases/docker/bigquery.py b/src/pytest_databases/docker/bigquery.py index ffe7a6f..8360d0a 100644 --- a/src/pytest_databases/docker/bigquery.py +++ b/src/pytest_databases/docker/bigquery.py @@ -1,12 +1,12 @@ from __future__ import annotations +import json +import urllib.error +import urllib.request from dataclasses import dataclass -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import pytest -from google.api_core.client_options import ClientOptions -from google.auth.credentials import AnonymousCredentials, Credentials -from google.cloud import bigquery from pytest_databases.helpers import get_xdist_worker_num from pytest_databases.types import ServiceContainer, XdistIsolationLevel @@ -36,15 +36,29 @@ def platform() -> str: class BigQueryService(ServiceContainer): project: str dataset: str - credentials: Credentials @property def endpoint(self) -> str: return f"http://{self.host}:{self.port}" - @property - def client_options(self) -> ClientOptions: - return ClientOptions(api_endpoint=self.endpoint) + +def _query_bigquery_emulator( + host: str, + port: int, + project: str, + sql: str, + *, + timeout: float = 2.0, +) -> dict[str, Any]: + body = json.dumps({"query": sql, "useLegacySql": False}).encode("utf-8") + request = urllib.request.Request( + f"http://{host}:{port}/bigquery/v2/projects/{project}/queries", + data=body, + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(request, timeout=timeout) as response: # noqa: S310 + return json.loads(response.read().decode("utf-8")) @pytest.fixture(scope="session") @@ -64,17 +78,19 @@ def bigquery_service( def check(_service: ServiceContainer) -> bool: try: - client = bigquery.Client( - project=project, - client_options=ClientOptions(api_endpoint=f"http://{_service.host}:{_service.port}"), - credentials=AnonymousCredentials(), + payload = _query_bigquery_emulator( + _service.host, + _service.port, + project, + "SELECT 1 as one", ) - - job = client.query(query="SELECT 1 as one") - - resp = list(job.result()) - return resp[0].one == 1 - except Exception: # noqa: BLE001 + except (urllib.error.URLError, urllib.error.HTTPError, json.JSONDecodeError, TimeoutError, OSError): + return False + if payload.get("jobComplete") is not True: + return False + try: + return payload["rows"][0]["f"][0]["v"] == "1" + except (KeyError, IndexError, TypeError): return False with docker_service.run( @@ -97,14 +113,4 @@ def check(_service: ServiceContainer) -> bool: container=service.container, project=project, dataset=dataset, - credentials=AnonymousCredentials(), ) - - -@pytest.fixture(scope="session") -def bigquery_client(bigquery_service: BigQueryService) -> Generator[bigquery.Client, None, None]: - yield bigquery.Client( - project=bigquery_service.project, - client_options=bigquery_service.client_options, - credentials=bigquery_service.credentials, - ) diff --git a/tests/test_bigquery.py b/tests/test_bigquery.py index 0f26c2a..f5552dd 100644 --- a/tests/test_bigquery.py +++ b/tests/test_bigquery.py @@ -6,37 +6,56 @@ import pytest -def test_service_fixture(pytester: pytest.Pytester) -> None: +def test_plugin_imports_without_google_cloud_bigquery(pytester: pytest.Pytester) -> None: pytester.makepyfile(""" - from google.cloud import bigquery - - pytest_plugins = ["pytest_databases.docker.bigquery"] - - def test(bigquery_service) -> None: - client = bigquery.Client( - project=bigquery_service.project, - client_options=bigquery_service.client_options, - credentials=bigquery_service.credentials, - ) - - job = client.query(query="SELECT 1 as one") - - resp = list(job.result()) - assert resp[0].one == 1 + import builtins + + def test_import() -> None: + original_import = builtins.__import__ + blocked = { + "google.cloud.bigquery", + "google.api_core.client_options", + "google.auth.credentials", + } + + def blocked_import(name, globals=None, locals=None, fromlist=(), level=0): + if name in blocked: + raise ModuleNotFoundError(name) + return original_import(name, globals, locals, fromlist, level) + + builtins.__import__ = blocked_import + try: + import pytest_databases.docker.bigquery + finally: + builtins.__import__ = original_import """) - result = pytester.runpytest_subprocess("-p", "pytest_databases") + result = pytester.runpytest_subprocess("-p", "pytest_databases", "-vv") result.assert_outcomes(passed=1) -def test_client_fixture(pytester: pytest.Pytester) -> None: +def test_service_fixture(pytester: pytest.Pytester) -> None: pytester.makepyfile(""" - from google.cloud import bigquery + import json + import urllib.request pytest_plugins = ["pytest_databases.docker.bigquery"] - def test(bigquery_client) -> None: - assert isinstance(bigquery_client, bigquery.Client) + def run_bigquery(service, sql): + body = json.dumps({"query": sql, "useLegacySql": False}).encode("utf-8") + request = urllib.request.Request( + f"{service.endpoint}/bigquery/v2/projects/{service.project}/queries", + data=body, + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(request, timeout=10) as response: + return json.loads(response.read().decode("utf-8")) + + def test(bigquery_service) -> None: + payload = run_bigquery(bigquery_service, "SELECT 1 as one") + assert payload.get("jobComplete") is True + assert payload["rows"][0]["f"][0]["v"] == "1" """) result = pytester.runpytest_subprocess("-p", "pytest_databases") @@ -45,15 +64,33 @@ def test(bigquery_client) -> None: def test_xdist(pytester: pytest.Pytester) -> None: pytester.makepyfile(""" - from google.cloud import bigquery + import json + import urllib.request pytest_plugins = ["pytest_databases.docker.bigquery"] - def test_one(bigquery_client, bigquery_service) -> None: - bigquery_client.query(f"CREATE TABLE `{bigquery_service.dataset}.test` AS select 1 as the_value") + def run_bigquery(service, sql): + body = json.dumps({"query": sql, "useLegacySql": False}).encode("utf-8") + request = urllib.request.Request( + f"{service.endpoint}/bigquery/v2/projects/{service.project}/queries", + data=body, + headers={"Content-Type": "application/json"}, + method="POST", + ) + with urllib.request.urlopen(request, timeout=30) as response: + return json.loads(response.read().decode("utf-8")) + + def test_one(bigquery_service) -> None: + run_bigquery( + bigquery_service, + f"CREATE TABLE `{bigquery_service.dataset}.test_one` AS SELECT 1 AS the_value", + ) - def test_two(bigquery_client, bigquery_service) -> None: - bigquery_client.query(f"CREATE TABLE `{bigquery_service.dataset}.test` AS select 1 as the_value") + def test_two(bigquery_service) -> None: + run_bigquery( + bigquery_service, + f"CREATE TABLE `{bigquery_service.dataset}.test_two` AS SELECT 1 AS the_value", + ) """) result = pytester.runpytest_subprocess("-p", "pytest_databases", "-n", "2") diff --git a/uv.lock b/uv.lock index 7c7eeef..04e7752 100644 --- a/uv.lock +++ b/uv.lock @@ -1345,7 +1345,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1455,28 +1455,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4a/c9/db44165ba7c581268c6d46017ef63339110378305062830104fc7fa144cb/google_auth-2.53.0-py3-none-any.whl", hash = "sha256:6e7449917c599b35126a99ec268ec6880301f2fea41dce198fe8fd83ff642b68", size = 246071, upload-time = "2026-05-15T20:53:05.609Z" }, ] -[[package]] -name = "google-cloud-bigquery" -version = "3.41.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth", version = "2.50.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "google-auth", version = "2.53.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "google-cloud-core", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "google-cloud-core", version = "2.6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "google-resumable-media", version = "2.8.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "google-resumable-media", version = "2.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "packaging" }, - { name = "python-dateutil" }, - { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "requests", version = "2.34.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/13/6515c7aab55a4a0cf708ffd309fb9af5bab54c13e32dc22c5acd6497193c/google_cloud_bigquery-3.41.0.tar.gz", hash = "sha256:2217e488b47ed576360c9b2cc07d59d883a54b83167c0ef37f915c26b01a06fe", size = 513434, upload-time = "2026-03-30T22:50:55.347Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/33/1d3902efadef9194566d499d61507e1f038454e0b55499d2d7f8ab2a4fee/google_cloud_bigquery-3.41.0-py3-none-any.whl", hash = "sha256:2a5b5a737b401cbd824a6e5eac7554100b878668d908e6548836b5d8aaa4dcaa", size = 262343, upload-time = "2026-03-30T22:48:45.444Z" }, -] - [[package]] name = "google-cloud-core" version = "2.5.1" @@ -1563,82 +1541,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/61/4e/5111be2281faad007d7f85b1bce6e1ae68a10946e302000470835f81cf72/google_cloud_spanner-3.66.0-py3-none-any.whl", hash = "sha256:a5ec48576022fc064d7217ec5011ce1f159eb8eac669de0acd8a4497c205d872", size = 613881, upload-time = "2026-05-07T08:03:13.118Z" }, ] -[[package]] -name = "google-crc32c" -version = "1.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192, upload-time = "2025-12-16T00:35:25.142Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/ac/6f7bc93886a823ab545948c2dd48143027b2355ad1944c7cf852b338dc91/google_crc32c-1.8.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0470b8c3d73b5f4e3300165498e4cf25221c7eb37f1159e221d1825b6df8a7ff", size = 31296, upload-time = "2025-12-16T00:19:07.261Z" }, - { url = "https://files.pythonhosted.org/packages/f7/97/a5accde175dee985311d949cfcb1249dcbb290f5ec83c994ea733311948f/google_crc32c-1.8.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:119fcd90c57c89f30040b47c211acee231b25a45d225e3225294386f5d258288", size = 30870, upload-time = "2025-12-16T00:29:17.669Z" }, - { url = "https://files.pythonhosted.org/packages/3d/63/bec827e70b7a0d4094e7476f863c0dbd6b5f0f1f91d9c9b32b76dcdfeb4e/google_crc32c-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f35aaffc8ccd81ba3162443fabb920e65b1f20ab1952a31b13173a67811467d", size = 33214, upload-time = "2025-12-16T00:40:19.618Z" }, - { url = "https://files.pythonhosted.org/packages/63/bc/11b70614df04c289128d782efc084b9035ef8466b3d0a8757c1b6f5cf7ac/google_crc32c-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:864abafe7d6e2c4c66395c1eb0fe12dc891879769b52a3d56499612ca93b6092", size = 33589, upload-time = "2025-12-16T00:40:20.7Z" }, - { url = "https://files.pythonhosted.org/packages/3e/00/a08a4bc24f1261cc5b0f47312d8aebfbe4b53c2e6307f1b595605eed246b/google_crc32c-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:db3fe8eaf0612fc8b20fa21a5f25bd785bc3cd5be69f8f3412b0ac2ffd49e733", size = 34437, upload-time = "2025-12-16T00:35:19.437Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ef/21ccfaab3d5078d41efe8612e0ed0bfc9ce22475de074162a91a25f7980d/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:014a7e68d623e9a4222d663931febc3033c5c7c9730785727de2a81f87d5bab8", size = 31298, upload-time = "2025-12-16T00:20:32.241Z" }, - { url = "https://files.pythonhosted.org/packages/c5/b8/f8413d3f4b676136e965e764ceedec904fe38ae8de0cdc52a12d8eb1096e/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:86cfc00fe45a0ac7359e5214a1704e51a99e757d0272554874f419f79838c5f7", size = 30872, upload-time = "2025-12-16T00:33:58.785Z" }, - { url = "https://files.pythonhosted.org/packages/f6/fd/33aa4ec62b290477181c55bb1c9302c9698c58c0ce9a6ab4874abc8b0d60/google_crc32c-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:19b40d637a54cb71e0829179f6cb41835f0fbd9e8eb60552152a8b52c36cbe15", size = 33243, upload-time = "2025-12-16T00:40:21.46Z" }, - { url = "https://files.pythonhosted.org/packages/71/03/4820b3bd99c9653d1a5210cb32f9ba4da9681619b4d35b6a052432df4773/google_crc32c-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:17446feb05abddc187e5441a45971b8394ea4c1b6efd88ab0af393fd9e0a156a", size = 33608, upload-time = "2025-12-16T00:40:22.204Z" }, - { url = "https://files.pythonhosted.org/packages/7c/43/acf61476a11437bf9733fb2f70599b1ced11ec7ed9ea760fdd9a77d0c619/google_crc32c-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:71734788a88f551fbd6a97be9668a0020698e07b2bf5b3aa26a36c10cdfb27b2", size = 34439, upload-time = "2025-12-16T00:35:20.458Z" }, - { url = "https://files.pythonhosted.org/packages/e9/5f/7307325b1198b59324c0fa9807cafb551afb65e831699f2ce211ad5c8240/google_crc32c-1.8.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:4b8286b659c1335172e39563ab0a768b8015e88e08329fa5321f774275fc3113", size = 31300, upload-time = "2025-12-16T00:21:56.723Z" }, - { url = "https://files.pythonhosted.org/packages/21/8e/58c0d5d86e2220e6a37befe7e6a94dd2f6006044b1a33edf1ff6d9f7e319/google_crc32c-1.8.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:2a3dc3318507de089c5384cc74d54318401410f82aa65b2d9cdde9d297aca7cb", size = 30867, upload-time = "2025-12-16T00:38:31.302Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a9/a780cc66f86335a6019f557a8aaca8fbb970728f0efd2430d15ff1beae0e/google_crc32c-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14f87e04d613dfa218d6135e81b78272c3b904e2a7053b841481b38a7d901411", size = 33364, upload-time = "2025-12-16T00:40:22.96Z" }, - { url = "https://files.pythonhosted.org/packages/21/3f/3457ea803db0198c9aaca2dd373750972ce28a26f00544b6b85088811939/google_crc32c-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb5c869c2923d56cb0c8e6bcdd73c009c36ae39b652dbe46a05eb4ef0ad01454", size = 33740, upload-time = "2025-12-16T00:40:23.96Z" }, - { url = "https://files.pythonhosted.org/packages/df/c0/87c2073e0c72515bb8733d4eef7b21548e8d189f094b5dad20b0ecaf64f6/google_crc32c-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:3cc0c8912038065eafa603b238abf252e204accab2a704c63b9e14837a854962", size = 34437, upload-time = "2025-12-16T00:35:21.395Z" }, - { url = "https://files.pythonhosted.org/packages/d1/db/000f15b41724589b0e7bc24bc7a8967898d8d3bc8caf64c513d91ef1f6c0/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b", size = 31297, upload-time = "2025-12-16T00:23:20.709Z" }, - { url = "https://files.pythonhosted.org/packages/d7/0d/8ebed0c39c53a7e838e2a486da8abb0e52de135f1b376ae2f0b160eb4c1a/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27", size = 30867, upload-time = "2025-12-16T00:43:14.628Z" }, - { url = "https://files.pythonhosted.org/packages/ce/42/b468aec74a0354b34c8cbf748db20d6e350a68a2b0912e128cabee49806c/google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa", size = 33344, upload-time = "2025-12-16T00:40:24.742Z" }, - { url = "https://files.pythonhosted.org/packages/1c/e8/b33784d6fc77fb5062a8a7854e43e1e618b87d5ddf610a88025e4de6226e/google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8", size = 33694, upload-time = "2025-12-16T00:40:25.505Z" }, - { url = "https://files.pythonhosted.org/packages/92/b1/d3cbd4d988afb3d8e4db94ca953df429ed6db7282ed0e700d25e6c7bfc8d/google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f", size = 34435, upload-time = "2025-12-16T00:35:22.107Z" }, - { url = "https://files.pythonhosted.org/packages/21/88/8ecf3c2b864a490b9e7010c84fd203ec8cf3b280651106a3a74dd1b0ca72/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:e6584b12cb06796d285d09e33f63309a09368b9d806a551d8036a4207ea43697", size = 31301, upload-time = "2025-12-16T00:24:48.527Z" }, - { url = "https://files.pythonhosted.org/packages/36/c6/f7ff6c11f5ca215d9f43d3629163727a272eabc356e5c9b2853df2bfe965/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:f4b51844ef67d6cf2e9425983274da75f18b1597bb2c998e1c0a0e8d46f8f651", size = 30868, upload-time = "2025-12-16T00:48:12.163Z" }, - { url = "https://files.pythonhosted.org/packages/56/15/c25671c7aad70f8179d858c55a6ae8404902abe0cdcf32a29d581792b491/google_crc32c-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b0d1a7afc6e8e4635564ba8aa5c0548e3173e41b6384d7711a9123165f582de2", size = 33381, upload-time = "2025-12-16T00:40:26.268Z" }, - { url = "https://files.pythonhosted.org/packages/42/fa/f50f51260d7b0ef5d4898af122d8a7ec5a84e2984f676f746445f783705f/google_crc32c-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3f68782f3cbd1bce027e48768293072813469af6a61a86f6bb4977a4380f21", size = 33734, upload-time = "2025-12-16T00:40:27.028Z" }, - { url = "https://files.pythonhosted.org/packages/08/a5/7b059810934a09fb3ccb657e0843813c1fee1183d3bc2c8041800374aa2c/google_crc32c-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:d511b3153e7011a27ab6ee6bb3a5404a55b994dc1a7322c0b87b29606d9790e2", size = 34878, upload-time = "2025-12-16T00:35:23.142Z" }, - { url = "https://files.pythonhosted.org/packages/42/c5/4c4cde2e7e54d9cde5c3d131f54a609eb3a77e60a04ec348051f61071fc2/google_crc32c-1.8.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:ba6aba18daf4d36ad4412feede6221414692f44d17e5428bdd81ad3fc1eee5dc", size = 31291, upload-time = "2025-12-16T00:17:45.878Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/abae5a7ca05c07dc7f129b32f7f8cce5314172fd2300c7aec305427a637e/google_crc32c-1.8.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:87b0072c4ecc9505cfa16ee734b00cd7721d20a0f595be4d40d3d21b41f65ae2", size = 30862, upload-time = "2025-12-16T00:25:03.867Z" }, - { url = "https://files.pythonhosted.org/packages/1e/c4/7032f0e87ee0b0f65669ac8a1022beabd80afe5da69f4bbf49eb7fea9c40/google_crc32c-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3d488e98b18809f5e322978d4506373599c0c13e6c5ad13e53bb44758e18d215", size = 33063, upload-time = "2025-12-16T00:40:27.789Z" }, - { url = "https://files.pythonhosted.org/packages/cc/fc/831d92dd02bc145523590db3927a73300f5121a34b56c2696e4305411b67/google_crc32c-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01f126a5cfddc378290de52095e2c7052be2ba7656a9f0caf4bcd1bfb1833f8a", size = 33434, upload-time = "2025-12-16T00:40:28.555Z" }, - { url = "https://files.pythonhosted.org/packages/ca/ef/74accbe6e6892c3bcbe5a7ed8d650a23b3042ddcc0b301896c22e6733bea/google_crc32c-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:61f58b28e0b21fcb249a8247ad0db2e64114e201e2e9b4200af020f3b6242c9f", size = 34432, upload-time = "2025-12-16T00:35:24.136Z" }, - { url = "https://files.pythonhosted.org/packages/52/c5/c171e4d8c44fec1422d801a6d2e5d7ddabd733eeda505c79730ee9607f07/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:87fa445064e7db928226b2e6f0d5304ab4cd0339e664a4e9a25029f384d9bb93", size = 28615, upload-time = "2025-12-16T00:40:29.298Z" }, - { url = "https://files.pythonhosted.org/packages/9c/97/7d75fe37a7a6ed171a2cf17117177e7aab7e6e0d115858741b41e9dd4254/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f639065ea2042d5c034bf258a9f085eaa7af0cd250667c0635a3118e8f92c69c", size = 28800, upload-time = "2025-12-16T00:40:30.322Z" }, -] - -[[package]] -name = "google-resumable-media" -version = "2.8.2" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version > '3.9' and python_full_version < '3.10'", - "python_full_version <= '3.9'", -] -dependencies = [ - { name = "google-crc32c", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3f/d1/b1ea14b93b6b78f57fc580125de44e9f593ab88dd2460f1a8a8d18f74754/google_resumable_media-2.8.2.tar.gz", hash = "sha256:f3354a182ebd193ae3f42e3ef95e6c9b10f128320de23ac7637236713b1acd70", size = 2164510, upload-time = "2026-03-30T23:34:25.369Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/f8/50bfaf4658431ff9de45c5c3935af7ab01157a4903c603cd0eee6e78e087/google_resumable_media-2.8.2-py3-none-any.whl", hash = "sha256:82b6d8ccd11765268cdd2a2123f417ec806b8eef3000a9a38dfe3033da5fb220", size = 81511, upload-time = "2026-03-30T23:34:09.671Z" }, -] - -[[package]] -name = "google-resumable-media" -version = "2.9.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.15'", - "python_full_version == '3.14.*'", - "python_full_version == '3.13.*'", - "python_full_version == '3.12.*'", - "python_full_version == '3.11.*'", - "python_full_version == '3.10.*'", -] -dependencies = [ - { name = "google-crc32c", marker = "python_full_version >= '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/4b/0b235beccc310d0a48adbc7246b719d173cca6c88c572dfa4b090e39143c/google_resumable_media-2.9.0.tar.gz", hash = "sha256:f7cfb224846a9dd444d125115dfbe8ef02a2b893e78f087762fe716a255a734b", size = 2164534, upload-time = "2026-05-07T08:04:44.236Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/73/3518e63deb1667c5409a4579e28daf5e84479a87a72c547e0487f7883dcd/google_resumable_media-2.9.0-py3-none-any.whl", hash = "sha256:c8901e88e389af8bed64d9696c74d8bad961865eb2236e13e0bfca9bb0a65ca3", size = 81507, upload-time = "2026-05-07T08:03:23.809Z" }, -] - [[package]] name = "googleapis-common-protos" version = "1.75.0" @@ -3982,9 +3884,6 @@ dependencies = [ azure-storage = [ { name = "azure-storage-blob" }, ] -bigquery = [ - { name = "google-cloud-bigquery" }, -] cockroachdb = [ { name = "psycopg", version = "3.2.13", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "psycopg", version = "3.3.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, @@ -4172,7 +4071,6 @@ requires-dist = [ { name = "elasticsearch7", marker = "extra == 'elasticsearch7'" }, { name = "elasticsearch8", marker = "extra == 'elasticsearch8'" }, { name = "filelock" }, - { name = "google-cloud-bigquery", marker = "extra == 'bigquery'" }, { name = "google-cloud-spanner", marker = "extra == 'spanner'" }, { name = "oracledb", marker = "extra == 'oracle'" }, { name = "psycopg", marker = "extra == 'cockroachdb'" },