Skip to content
This repository was archived by the owner on Feb 13, 2026. It is now read-only.

Commit efc4bbf

Browse files
authored
fix: pass kwargs through in 'from_service_account_json' (#109)
Also, pin 'googleapis-common-protos' for Python 2.7 tests. Closes #108.
1 parent 1d3e273 commit efc4bbf

3 files changed

Lines changed: 69 additions & 7 deletions

File tree

google/cloud/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def from_service_account_json(cls, json_credentials_path, *args, **kwargs):
106106
with io.open(json_credentials_path, "r", encoding="utf-8") as json_fi:
107107
credentials_info = json.load(json_fi)
108108

109-
return cls.from_service_account_info(credentials_info)
109+
return cls.from_service_account_info(credentials_info, *args, **kwargs)
110110

111111

112112
class Client(_ClientFactoryMixin):

testing/constraints-2.7.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
google-api-core==1.21.0
2+
googleapis-common-protos<1.53.0
23
six==1.12.0

tests/unit/test_client.py

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -420,17 +420,16 @@ def test_constructor_explicit_unicode(self):
420420
def _from_service_account_info_helper(self, project=None):
421421
klass = self._get_target_class()
422422

423-
info = {"dummy": "value", "valid": "json"}
423+
default_project = "eye-d-of-project"
424+
info = {"dummy": "value", "valid": "json", "project_id": default_project}
424425
kwargs = {}
425426

426427
if project is None:
427-
expected_project = "eye-d-of-project"
428+
expected_project = default_project
428429
else:
429430
expected_project = project
430431
kwargs["project"] = project
431432

432-
info["project_id"] = expected_project
433-
434433
constructor_patch = mock.patch(
435434
"google.oauth2.service_account.Credentials.from_service_account_info",
436435
return_value=_make_credentials(),
@@ -451,18 +450,45 @@ def test_from_service_account_info(self):
451450
def test_from_service_account_info_with_project(self):
452451
self._from_service_account_info_helper(project="prah-jekt")
453452

453+
def test_from_service_account_info_with_posarg(self):
454+
class Derived(self._get_target_class()):
455+
def __init__(self, required, **kwargs):
456+
super(Derived, self).__init__(**kwargs)
457+
self.required = required
458+
459+
project = "eye-d-of-project"
460+
info = {"dummy": "value", "valid": "json", "project_id": project}
461+
462+
# Mock both the file opening and the credentials constructor.
463+
constructor_patch = mock.patch(
464+
"google.oauth2.service_account.Credentials.from_service_account_info",
465+
return_value=_make_credentials(),
466+
)
467+
468+
with constructor_patch as constructor:
469+
client_obj = Derived.from_service_account_info(info, "REQUIRED")
470+
471+
self.assertIsInstance(client_obj, Derived)
472+
self.assertIs(client_obj._credentials, constructor.return_value)
473+
self.assertIsNone(client_obj._http_internal)
474+
self.assertEqual(client_obj.project, project)
475+
self.assertEqual(client_obj.required, "REQUIRED")
476+
477+
# Check that mocks were called as expected.
478+
constructor.assert_called_once_with(info)
479+
454480
def _from_service_account_json_helper(self, project=None):
455481
from google.cloud import _helpers
456482

457483
klass = self._get_target_class()
458484

459-
info = {"dummy": "value", "valid": "json"}
485+
default_project = "eye-d-of-project"
486+
info = {"dummy": "value", "valid": "json", "project_id": default_project}
460487
if project is None:
461488
expected_project = "eye-d-of-project"
462489
else:
463490
expected_project = project
464491

465-
info["project_id"] = expected_project
466492
# Mock both the file opening and the credentials constructor.
467493
json_fi = io.StringIO(_helpers._bytes_to_unicode(json.dumps(info)))
468494
file_open_patch = mock.patch("io.open", return_value=json_fi)
@@ -492,3 +518,38 @@ def test_from_service_account_json(self):
492518

493519
def test_from_service_account_json_project_set(self):
494520
self._from_service_account_json_helper(project="prah-jekt")
521+
522+
def test_from_service_account_json_with_posarg(self):
523+
from google.cloud import _helpers
524+
525+
class Derived(self._get_target_class()):
526+
def __init__(self, required, **kwargs):
527+
super(Derived, self).__init__(**kwargs)
528+
self.required = required
529+
530+
project = "eye-d-of-project"
531+
info = {"dummy": "value", "valid": "json", "project_id": project}
532+
533+
# Mock both the file opening and the credentials constructor.
534+
json_fi = io.StringIO(_helpers._bytes_to_unicode(json.dumps(info)))
535+
file_open_patch = mock.patch("io.open", return_value=json_fi)
536+
constructor_patch = mock.patch(
537+
"google.oauth2.service_account.Credentials.from_service_account_info",
538+
return_value=_make_credentials(),
539+
)
540+
541+
with file_open_patch as file_open:
542+
with constructor_patch as constructor:
543+
client_obj = Derived.from_service_account_json(
544+
mock.sentinel.filename, "REQUIRED"
545+
)
546+
547+
self.assertIsInstance(client_obj, Derived)
548+
self.assertIs(client_obj._credentials, constructor.return_value)
549+
self.assertIsNone(client_obj._http_internal)
550+
self.assertEqual(client_obj.project, project)
551+
self.assertEqual(client_obj.required, "REQUIRED")
552+
553+
# Check that mocks were called as expected.
554+
file_open.assert_called_once_with(mock.sentinel.filename, "r", encoding="utf-8")
555+
constructor.assert_called_once_with(info)

0 commit comments

Comments
 (0)