From a5de821f36270247318f3dc9a37bc6fb8372ec2b Mon Sep 17 00:00:00 2001 From: Vincent Roseberry Date: Fri, 30 Jan 2026 21:30:38 +0000 Subject: [PATCH 1/5] Upgrade Colab base image From `20251024-060052_RC00` to `20260126-060048_RC00`. Added justification to the diff about other changes included. http://b/331651883 --- Dockerfile.tmpl | 10 ++-------- config.txt | 2 +- kaggle_requirements.txt | 3 +-- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/Dockerfile.tmpl b/Dockerfile.tmpl index 8f45f265..1aaeaf2d 100644 --- a/Dockerfile.tmpl +++ b/Dockerfile.tmpl @@ -23,15 +23,9 @@ RUN uv pip uninstall --system --no-cache google-cloud-bigquery-storage # to avoid affecting the larger build, we'll post-install it. RUN uv pip install --no-build-isolation --no-cache --system "git+https://github.com/Kaggle/learntools" -# newer daal4py requires tbb>=2022, but libpysal is downgrading it for some reason -RUN uv pip install --system --no-cache "tbb>=2022" "libpysal==4.9.2" - -# b/404590350: Ray and torchtune have conflicting tune cli, we will prioritize torchtune. -# b/315753846: Unpin translate package, currently conflicts with adk 1.17.0 -# b/468379293: Unpin Pandas once cuml/cudf are compatible, version 3.0 causes issues -# b/468383498: numpy will auto-upgrade to 2.4.x, which causes issues with numerous packages +# b/404590350: Ray and torchtune have conflicting cli named `tune`. `ray` is not part of Colab's base image. Re-install `tune` to ensure the torchtune CLI is available by default. # b/468367647: Unpin protobuf, version greater than v5.29.5 causes issues with numerous packages -RUN uv pip install --system --force-reinstall --no-cache --no-deps torchtune "google-cloud-translate==3.12.1" "numpy==2.0.2" "pandas==2.2.2" +RUN uv pip install --system --force-reinstall --no-cache --no-deps torchtune RUN uv pip install --system --force-reinstall --no-cache "protobuf==5.29.5" # Adding non-package dependencies: diff --git a/config.txt b/config.txt index 9546b47a..e9c2ea30 100644 --- a/config.txt +++ b/config.txt @@ -1,4 +1,4 @@ BASE_IMAGE=us-docker.pkg.dev/colab-images/public/runtime -BASE_IMAGE_TAG=release-colab-external_20251024-060052_RC00 +BASE_IMAGE_TAG=release-colab-external_20260126-060048_RC00 CUDA_MAJOR_VERSION=12 CUDA_MINOR_VERSION=5 diff --git a/kaggle_requirements.txt b/kaggle_requirements.txt index 4799254b..6893fb68 100644 --- a/kaggle_requirements.txt +++ b/kaggle_requirements.txt @@ -65,8 +65,7 @@ keras-nlp keras-tuner kornia langid -# b/328788268: libpysal 4.10 seems to fail with "module 'shapely' has no attribute 'Geometry'. Did you mean: 'geometry'" -libpysal<=4.9.2 +libpysal lime line_profiler mamba From 0df14eab547a843b06690a335056c63da925d7f6 Mon Sep 17 00:00:00 2001 From: Vincent Roseberry Date: Fri, 30 Jan 2026 22:35:10 +0000 Subject: [PATCH 2/5] remove google translation magic & add torchcodec --- kaggle_requirements.txt | 2 +- patches/kaggle_gcp.py | 29 --------- tests/test_translation.py | 131 -------------------------------------- 3 files changed, 1 insertion(+), 161 deletions(-) delete mode 100644 tests/test_translation.py diff --git a/kaggle_requirements.txt b/kaggle_requirements.txt index 6893fb68..4a0f0c9c 100644 --- a/kaggle_requirements.txt +++ b/kaggle_requirements.txt @@ -115,8 +115,8 @@ scikit-plot scikit-surprise git+https://github.com/facebookresearch/segment-anything.git squarify -tensorflow-cloud tensorflow-io +torchcodec torchinfo torchmetrics torchtune diff --git a/patches/kaggle_gcp.py b/patches/kaggle_gcp.py index 4cb98858..50ef4859 100644 --- a/patches/kaggle_gcp.py +++ b/patches/kaggle_gcp.py @@ -252,33 +252,6 @@ def init_gcs(): KaggleKernelCredentials(target=GcpTarget.GCS)) return storage -def init_translation_v2(): - from google.cloud import translate_v2 - if not is_user_secrets_token_set(): - return translate_v2 - - from kaggle_gcp import get_integrations - if not get_integrations().has_cloudai(): - return translate_v2 - from kaggle_secrets import GcpTarget - kernel_credentials = KaggleKernelCredentials(target=GcpTarget.CLOUDAI) - monkeypatch_client(translate_v2.Client, kernel_credentials) - return translate_v2 - -def init_translation_v3(): - # Translate v3 exposes different client than translate v2. - from google.cloud import translate_v3 - if not is_user_secrets_token_set(): - return translate_v3 - - from kaggle_gcp import get_integrations - if not get_integrations().has_cloudai(): - return translate_v3 - from kaggle_secrets import GcpTarget - kernel_credentials = KaggleKernelCredentials(target=GcpTarget.CLOUDAI) - monkeypatch_client(translate_v3.TranslationServiceClient, kernel_credentials) - return translate_v3 - def init_natural_language(): from google.cloud import language if not is_user_secrets_token_set(): @@ -347,8 +320,6 @@ def init_vision(): def init(): init_bigquery() init_gcs() - init_translation_v2() - init_translation_v3() init_natural_language() init_video_intelligence() init_vision() diff --git a/tests/test_translation.py b/tests/test_translation.py deleted file mode 100644 index 5bb41b62..00000000 --- a/tests/test_translation.py +++ /dev/null @@ -1,131 +0,0 @@ -import unittest -import inspect - -from unittest.mock import Mock, patch - -from kaggle_gcp import KaggleKernelCredentials, KaggleKernelWithProjetCredentials, init_translation_v2, init_translation_v3 -from test.support.os_helper import EnvironmentVarGuard -from google.api_core import client_options -from google.cloud import translate, translate_v2 - -def _make_credentials(): - import google.auth.credentials - return Mock(spec=google.auth.credentials.Credentials) - -class TestCloudTranslation(unittest.TestCase): - class FakeClient: - def __init__(self, credentials=None, client_info=None, client_options=None, **kwargs): - self.credentials = credentials - self.client_options = client_options - - class FakeConnection(): - def __init__(self, user_agent): - self.user_agent = user_agent - if (client_info is not None): - self._connection = FakeConnection(client_info.user_agent) - - @patch("google.cloud.translate_v2.Client", new=FakeClient) - def test_default_credentials_v2(self): - env = EnvironmentVarGuard() - env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') - env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') - with env: - init_translation_v2() - client = translate_v2.Client() - self.assertIsNotNone(client.credentials) - self.assertIsInstance(client.credentials, KaggleKernelCredentials) - - - @patch("google.cloud.translate_v2.Client", new=FakeClient) - def test_user_provided_credentials_v2(self): - credentials = _make_credentials() - env = EnvironmentVarGuard() - env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') - env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') - with env: - init_translation_v2() - client = translate_v2.Client(credentials=credentials) - self.assertIsNotNone(client.credentials) - self.assertNotIsInstance(client.credentials, KaggleKernelCredentials) - - @patch("google.cloud.translate.TranslationServiceClient", new=FakeClient) - def test_default_credentials_v3(self): - env = EnvironmentVarGuard() - env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') - env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') - with env: - init_translation_v3() - client = translate.TranslationServiceClient() - self.assertIsNotNone(client.credentials) - self.assertIsInstance(client.credentials, KaggleKernelCredentials) - - - @patch("google.cloud.translate.TranslationServiceClient", new=FakeClient) - def test_user_provided_credentials_v3(self): - credentials = _make_credentials() - env = EnvironmentVarGuard() - env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') - env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') - with env: - init_translation_v3() - client = translate.TranslationServiceClient(credentials=credentials) - self.assertIsNotNone(client.credentials) - self.assertNotIsInstance(client.credentials, KaggleKernelCredentials) - - - def test_monkeypatching_succeed(self): - env = EnvironmentVarGuard() - env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') - env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') - with env: - init_translation_v2() - init_translation_v3() - # Translation V2 - client2 = translate_v2.Client.__init__ - self.assertTrue("kaggle_gcp" in inspect.getsourcefile(client2)) - # Translation V3 - client3 = translate.TranslationServiceClient.__init__ - self.assertTrue("kaggle_gcp" in inspect.getsourcefile(client3)) - - def test_monkeypatching_idempotent(self): - env = EnvironmentVarGuard() - env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') - env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') - with env: - init_translation_v2() - init_translation_v3() - # Translation V2 - client2_1 = translate_v2.client.Client.__init__ - # Translation V3 - client3_1 = translate.TranslationServiceClient.__init__ - - init_translation_v2() - init_translation_v3() - - client2_2 = translate_v2.Client.__init__ - client3_2 = translate.TranslationServiceClient.__init__ - self.assertEqual(client2_1, client2_2) - self.assertEqual(client3_1, client3_2) - - @patch("google.cloud.translate.TranslationServiceClient", new=FakeClient) - def test_client_credential_uniqueness_v3(self): - """ - Client instance must use unique KaggleKernelWithProjetCredentials with quota_project_id - when client_options.quota_project_id provided. (even if quota_project_id is same) - """ - credentials = _make_credentials() - env = EnvironmentVarGuard() - env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') - env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') - with env: - init_translation_v3() - client1 = translate.TranslationServiceClient() - client2 = translate.TranslationServiceClient(client_options=client_options.ClientOptions(quota_project_id="_doesn't_matter")) - client3 = translate.TranslationServiceClient(client_options=client_options.ClientOptions(quota_project_id="_doesn't_matter2")) - self.assertIsNotNone(client1.credentials) - self.assertIsNotNone(client2.credentials) - self.assertIsNotNone(client3.credentials) - self.assertIsInstance(client2.credentials, KaggleKernelWithProjetCredentials) - self.assertIsInstance(client3.credentials, KaggleKernelWithProjetCredentials) - self.assertNotEqual(client1.credentials, client2.credentials) - self.assertNotEqual(client2.credentials, client3.credentials) From b3f161e81bad32a9023dfa5129aa021859ed90a6 Mon Sep 17 00:00:00 2001 From: Vincent Roseberry Date: Fri, 30 Jan 2026 23:08:18 +0000 Subject: [PATCH 3/5] more fixes --- kaggle_requirements.txt | 3 ++- patches/sitecustomize.py | 6 ------ tests/test_tensorflow_cloud.py | 8 -------- tests/test_user_secrets.py | 16 ---------------- 4 files changed, 2 insertions(+), 31 deletions(-) delete mode 100644 tests/test_tensorflow_cloud.py diff --git a/kaggle_requirements.txt b/kaggle_requirements.txt index 4a0f0c9c..4ed1a7b9 100644 --- a/kaggle_requirements.txt +++ b/kaggle_requirements.txt @@ -116,7 +116,8 @@ scikit-surprise git+https://github.com/facebookresearch/segment-anything.git squarify tensorflow-io -torchcodec +# Must be compatible with torch version: https://github.com/meta-pytorch/torchcodec?tab=readme-ov-file#installing-torchcodec +torchcodec=0.9 torchinfo torchmetrics torchtune diff --git a/patches/sitecustomize.py b/patches/sitecustomize.py index 1bb8a1b6..c0efd45a 100644 --- a/patches/sitecustomize.py +++ b/patches/sitecustomize.py @@ -12,9 +12,6 @@ class GcpModuleFinder(importlib.abc.MetaPathFinder): _MODULES = [ 'google.cloud.bigquery', 'google.cloud.storage', - 'google.cloud.translate', - 'google.cloud.translate_v2', - 'google.cloud.translate_v3', 'google.cloud.language', 'google.cloud.language_v1', 'google.cloud.videointelligence', @@ -54,9 +51,6 @@ def create_module(self, spec): _LOADERS = { 'google.cloud.bigquery': kaggle_gcp.init_bigquery, 'google.cloud.storage': kaggle_gcp.init_gcs, - 'google.cloud.translate': kaggle_gcp.init_translation_v3, - 'google.cloud.translate_v2': kaggle_gcp.init_translation_v2, - 'google.cloud.translate_v3': kaggle_gcp.init_translation_v3, 'google.cloud.language': kaggle_gcp.init_natural_language, 'google.cloud.language_v1': kaggle_gcp.init_natural_language, 'google.cloud.videointelligence': kaggle_gcp.init_video_intelligence, diff --git a/tests/test_tensorflow_cloud.py b/tests/test_tensorflow_cloud.py deleted file mode 100644 index 2875e121..00000000 --- a/tests/test_tensorflow_cloud.py +++ /dev/null @@ -1,8 +0,0 @@ -import unittest - -import tensorflow_cloud as tfc - - -class TestTensorflowCloud(unittest.TestCase): - def test_remote(self): - self.assertFalse(tfc.remote()) diff --git a/tests/test_user_secrets.py b/tests/test_user_secrets.py index 67c628f7..c11432fe 100644 --- a/tests/test_user_secrets.py +++ b/tests/test_user_secrets.py @@ -200,22 +200,6 @@ def call_get_cloudai_access_token(): client = UserSecretsClient() secret_response = client._get_cloudai_access_token() self.assertEqual(secret_response, (secret, now + timedelta(seconds=3600))) - def call_get_translation_access_token(): - client = UserSecretsClient() - secret_response = client._get_translation_access_token() - self.assertEqual(secret_response, (secret, now + timedelta(seconds=3600))) - def call_get_natural_lang_access_token(): - client = UserSecretsClient() - secret_response = client._get_natural_language_access_token() - self.assertEqual(secret_response, (secret, now + timedelta(seconds=3600))) - def call_get_video_intell_access_token(): - client = UserSecretsClient() - secret_response = client._get_video_intelligence_access_token() - self.assertEqual(secret_response, (secret, now + timedelta(seconds=3600))) - def call_get_vision_access_token(): - client = UserSecretsClient() - secret_response = client._get_vision_access_token() - self.assertEqual(secret_response, (secret, now + timedelta(seconds=3600))) self._test_client(call_get_bigquery_access_token, '/requests/GetUserSecretRequest', {'Target': GcpTarget.BIGQUERY.target}, From b9a94f7d3c408a9904dd3de2c7abc565fbd4f42d Mon Sep 17 00:00:00 2001 From: Vincent Roseberry Date: Fri, 30 Jan 2026 23:12:42 +0000 Subject: [PATCH 4/5] Fix typo in requirement --- kaggle_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kaggle_requirements.txt b/kaggle_requirements.txt index 4ed1a7b9..30e0683f 100644 --- a/kaggle_requirements.txt +++ b/kaggle_requirements.txt @@ -117,7 +117,7 @@ git+https://github.com/facebookresearch/segment-anything.git squarify tensorflow-io # Must be compatible with torch version: https://github.com/meta-pytorch/torchcodec?tab=readme-ov-file#installing-torchcodec -torchcodec=0.9 +torchcodec==0.9 torchinfo torchmetrics torchtune From 1d23994a06791be67571a749c6b4997c551ccb32 Mon Sep 17 00:00:00 2001 From: Vincent Roseberry Date: Sat, 31 Jan 2026 00:53:02 +0000 Subject: [PATCH 5/5] add back translation --- patches/kaggle_gcp.py | 29 +++++++++ patches/sitecustomize.py | 6 ++ tests/test_translation.py | 130 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 tests/test_translation.py diff --git a/patches/kaggle_gcp.py b/patches/kaggle_gcp.py index 50ef4859..4cb98858 100644 --- a/patches/kaggle_gcp.py +++ b/patches/kaggle_gcp.py @@ -252,6 +252,33 @@ def init_gcs(): KaggleKernelCredentials(target=GcpTarget.GCS)) return storage +def init_translation_v2(): + from google.cloud import translate_v2 + if not is_user_secrets_token_set(): + return translate_v2 + + from kaggle_gcp import get_integrations + if not get_integrations().has_cloudai(): + return translate_v2 + from kaggle_secrets import GcpTarget + kernel_credentials = KaggleKernelCredentials(target=GcpTarget.CLOUDAI) + monkeypatch_client(translate_v2.Client, kernel_credentials) + return translate_v2 + +def init_translation_v3(): + # Translate v3 exposes different client than translate v2. + from google.cloud import translate_v3 + if not is_user_secrets_token_set(): + return translate_v3 + + from kaggle_gcp import get_integrations + if not get_integrations().has_cloudai(): + return translate_v3 + from kaggle_secrets import GcpTarget + kernel_credentials = KaggleKernelCredentials(target=GcpTarget.CLOUDAI) + monkeypatch_client(translate_v3.TranslationServiceClient, kernel_credentials) + return translate_v3 + def init_natural_language(): from google.cloud import language if not is_user_secrets_token_set(): @@ -320,6 +347,8 @@ def init_vision(): def init(): init_bigquery() init_gcs() + init_translation_v2() + init_translation_v3() init_natural_language() init_video_intelligence() init_vision() diff --git a/patches/sitecustomize.py b/patches/sitecustomize.py index c0efd45a..1bb8a1b6 100644 --- a/patches/sitecustomize.py +++ b/patches/sitecustomize.py @@ -12,6 +12,9 @@ class GcpModuleFinder(importlib.abc.MetaPathFinder): _MODULES = [ 'google.cloud.bigquery', 'google.cloud.storage', + 'google.cloud.translate', + 'google.cloud.translate_v2', + 'google.cloud.translate_v3', 'google.cloud.language', 'google.cloud.language_v1', 'google.cloud.videointelligence', @@ -51,6 +54,9 @@ def create_module(self, spec): _LOADERS = { 'google.cloud.bigquery': kaggle_gcp.init_bigquery, 'google.cloud.storage': kaggle_gcp.init_gcs, + 'google.cloud.translate': kaggle_gcp.init_translation_v3, + 'google.cloud.translate_v2': kaggle_gcp.init_translation_v2, + 'google.cloud.translate_v3': kaggle_gcp.init_translation_v3, 'google.cloud.language': kaggle_gcp.init_natural_language, 'google.cloud.language_v1': kaggle_gcp.init_natural_language, 'google.cloud.videointelligence': kaggle_gcp.init_video_intelligence, diff --git a/tests/test_translation.py b/tests/test_translation.py new file mode 100644 index 00000000..52de2a08 --- /dev/null +++ b/tests/test_translation.py @@ -0,0 +1,130 @@ +import unittest +import inspect + +from unittest.mock import Mock, patch + +from kaggle_gcp import KaggleKernelCredentials, KaggleKernelWithProjetCredentials, init_translation_v2, init_translation_v3 +from test.support.os_helper import EnvironmentVarGuard +from google.api_core import client_options +from google.cloud import translate_v3 as translate, translate_v2 + +def _make_credentials(): + import google.auth.credentials + return Mock(spec=google.auth.credentials.Credentials) + +class TestCloudTranslation(unittest.TestCase): + class FakeClient: + def __init__(self, credentials=None, client_info=None, client_options=None, **kwargs): + self.credentials = credentials + self.client_options = client_options + + class FakeConnection(): + def __init__(self, user_agent): + self.user_agent = user_agent + if (client_info is not None): + self._connection = FakeConnection(client_info.user_agent) + + @patch("google.cloud.translate_v2.Client", new=FakeClient) + def test_default_credentials_v2(self): + env = EnvironmentVarGuard() + env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') + env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') + with env: + init_translation_v2() + client = translate_v2.Client() + self.assertIsNotNone(client.credentials) + self.assertIsInstance(client.credentials, KaggleKernelCredentials) + + + @patch("google.cloud.translate_v2.Client", new=FakeClient) + def test_user_provided_credentials_v2(self): + credentials = _make_credentials() + env = EnvironmentVarGuard() + env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') + env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') + with env: + init_translation_v2() + client = translate_v2.Client(credentials=credentials) + self.assertIsNotNone(client.credentials) + self.assertNotIsInstance(client.credentials, KaggleKernelCredentials) + + @patch("google.cloud.translate_v3.TranslationServiceClient", new=FakeClient) + def test_default_credentials_v3(self): + env = EnvironmentVarGuard() + env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') + env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') + with env: + init_translation_v3() + client = translate.TranslationServiceClient() + self.assertIsNotNone(client.credentials) + self.assertIsInstance(client.credentials, KaggleKernelCredentials) + + + @patch("google.cloud.translate_v3.TranslationServiceClient", new=FakeClient) + def test_user_provided_credentials_v3(self): + credentials = _make_credentials() + env = EnvironmentVarGuard() + env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') + env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') + with env: + init_translation_v3() + client = translate.TranslationServiceClient(credentials=credentials) + self.assertIsNotNone(client.credentials) + self.assertNotIsInstance(client.credentials, KaggleKernelCredentials) + + + def test_monkeypatching_succeed(self): + env = EnvironmentVarGuard() + env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') + env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') + with env: + init_translation_v2() + init_translation_v3() + # Translation V2 + client2 = translate_v2.Client.__init__ + self.assertTrue("kaggle_gcp" in inspect.getsourcefile(client2)) + # Translation V3 + client3 = translate.TranslationServiceClient.__init__ + self.assertTrue("kaggle_gcp" in inspect.getsourcefile(client3)) + + def test_monkeypatching_idempotent(self): + env = EnvironmentVarGuard() + env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') + env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') + with env: + init_translation_v2() + init_translation_v3() + # Translation V2 + client2_1 = translate_v2.client.Client.__init__ + # Translation V3 + client3_1 = translate.TranslationServiceClient.__init__ + + init_translation_v2() + init_translation_v3() + + client2_2 = translate_v2.Client.__init__ + client3_2 = translate.TranslationServiceClient.__init__ + self.assertEqual(client2_1, client2_2) + self.assertEqual(client3_1, client3_2) + + @patch("google.cloud.translate_v3.TranslationServiceClient", new=FakeClient) + def test_client_credential_uniqueness_v3(self): + """ + Client instance must use unique KaggleKernelWithProjetCredentials with quota_project_id + when client_options.quota_project_id provided. (even if quota_project_id is same) + """ + env = EnvironmentVarGuard() + env.set('KAGGLE_USER_SECRETS_TOKEN', 'foobar') + env.set('KAGGLE_KERNEL_INTEGRATIONS', 'CLOUDAI') + with env: + init_translation_v3() + client1 = translate.TranslationServiceClient() + client2 = translate.TranslationServiceClient(client_options=client_options.ClientOptions(quota_project_id="_doesn't_matter")) + client3 = translate.TranslationServiceClient(client_options=client_options.ClientOptions(quota_project_id="_doesn't_matter2")) + self.assertIsNotNone(client1.credentials) + self.assertIsNotNone(client2.credentials) + self.assertIsNotNone(client3.credentials) + self.assertIsInstance(client2.credentials, KaggleKernelWithProjetCredentials) + self.assertIsInstance(client3.credentials, KaggleKernelWithProjetCredentials) + self.assertNotEqual(client1.credentials, client2.credentials) + self.assertNotEqual(client2.credentials, client3.credentials)