Skip to content

Commit

Permalink
FEATURE: Add support for google.auth.credentials.AnonymousCredentials
Browse files Browse the repository at this point in the history
  • Loading branch information
shrivastava-ankur committed Oct 21, 2024
1 parent d4be89a commit 8403b88
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 3 deletions.
6 changes: 6 additions & 0 deletions .changes/unreleased/Features-20241020-112955.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Features
body: Support google.auth.credentials.AnonymousCredentials for bigquery enabling to unit test models in isolation locally.
time: 2024-10-20T11:29:55.098322635Z
custom:
Author: shrivastava-ankur
Issue: "1377"
18 changes: 16 additions & 2 deletions dbt/adapters/bigquery/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
from contextlib import contextmanager
from dataclasses import dataclass, field
import uuid

from google.api_core.client_options import ClientOptions
from google.auth.credentials import AnonymousCredentials
from mashumaro.helper import pass_through

from functools import lru_cache
Expand Down Expand Up @@ -98,6 +101,7 @@ class BigQueryConnectionMethod(StrEnum):
SERVICE_ACCOUNT = "service-account"
SERVICE_ACCOUNT_JSON = "service-account-json"
OAUTH_SECRETS = "oauth-secrets"
ANONYMOUS = "anonymous"


@dataclass
Expand Down Expand Up @@ -134,6 +138,7 @@ class BigQueryCredentials(Credentials):
job_retries: Optional[int] = 1
job_creation_timeout_seconds: Optional[int] = None
job_execution_timeout_seconds: Optional[int] = None
client_options: Optional[Dict[str, Any]] = None

# Keyfile json creds (unicode or base 64 encoded)
keyfile: Optional[str] = None
Expand Down Expand Up @@ -206,6 +211,7 @@ def _connection_keys(self):
"job_retries",
"job_creation_timeout_seconds",
"job_execution_timeout_seconds",
"client_options",
"timeout_seconds",
"client_id",
"token_uri",
Expand Down Expand Up @@ -383,6 +389,8 @@ def get_google_credentials(cls, profile_credentials) -> GoogleCredentials:
token_uri=profile_credentials.token_uri,
scopes=profile_credentials.scopes,
)
elif method == BigQueryConnectionMethod.ANONYMOUS:
return AnonymousCredentials()

error = 'Invalid `method` in profile: "{}"'.format(method)
raise FailedToConnectError(error)
Expand All @@ -409,13 +417,16 @@ def get_bigquery_client(cls, profile_credentials):
creds = cls.get_credentials(profile_credentials)
execution_project = profile_credentials.execution_project
location = getattr(profile_credentials, "location", None)
client_options_kwargs = getattr(profile_credentials, "client_options", None)

options = ClientOptions(**client_options_kwargs) if client_options_kwargs else None
info = client_info.ClientInfo(user_agent=f"dbt-bigquery-{dbt_version.version}")
return google.cloud.bigquery.Client(
execution_project,
creds,
location=location,
client_info=info,
client_options=options,
)

@classmethod
Expand Down Expand Up @@ -598,8 +609,11 @@ def execute(
conn = self.get_thread_connection()
client = conn.handle
# use anonymous table for num_rows
query_table = client.get_table(query_job.destination)
num_rows = query_table.num_rows
if query_job.destination:
query_table = client.get_table(query_job.destination)
num_rows = query_table.num_rows
else:
num_rows = None

# set common attributes
bytes_processed = query_job.total_bytes_processed
Expand Down
1 change: 1 addition & 0 deletions tests/unit/test_bigquery_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ def test_location_user_agent(self, mock_bq, mock_auth_default):
creds,
location="Luna Station",
client_info=HasUserAgent(),
client_options=None,
)


Expand Down
18 changes: 17 additions & 1 deletion tests/unit/test_bigquery_connection_manager.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import json
import unittest
from contextlib import contextmanager

from google.auth.credentials import AnonymousCredentials
from requests.exceptions import ConnectionError
from unittest.mock import patch, MagicMock, Mock, ANY

import dbt.adapters

from dbt.adapters.bigquery import BigQueryCredentials
from dbt.adapters.bigquery import BigQueryRelation
from dbt.adapters.bigquery.connections import BigQueryConnectionManager
from dbt.adapters.bigquery.connections import BigQueryConnectionManager, BigQueryConnectionMethod


class TestBigQueryConnectionManager(unittest.TestCase):
Expand Down Expand Up @@ -172,3 +174,17 @@ def _copy_table(self, write_disposition):
database="project", schema="dataset", identifier="table2"
)
self.connections.copy_bq_table(source, destination, write_disposition)

def test_local_test_container_connection(self):
# Create a BigQueryCredentials instance with the anonymous method
credentials = BigQueryCredentials(
method=BigQueryConnectionMethod.ANONYMOUS,
database="test-database",
schema="test-schema",
)

# Get the Google credentials using the connection manager
google_credentials = BigQueryConnectionManager.get_google_credentials(credentials)

# Assert that the credentials are an instance of AnonymousCredentials
self.assertIsInstance(google_credentials, AnonymousCredentials)

0 comments on commit 8403b88

Please sign in to comment.