diff --git a/google/ads/googleads/config.py b/google/ads/googleads/config.py index 6b766141d..3b382d7d5 100644 --- a/google/ads/googleads/config.py +++ b/google/ads/googleads/config.py @@ -214,10 +214,16 @@ def validate_dict(config_data: dict[str, Any]) -> None: "found. The required fields are: {}".format(str(_REQUIRED_KEYS)) ) - if "login_customer_id" in config_data: + if ( + "login_customer_id" in config_data + and config_data["login_customer_id"] is not None + ): validate_login_customer_id(str(config_data["login_customer_id"])) - if "linked_customer_id" in config_data: + if ( + "linked_customer_id" in config_data + and config_data["linked_customer_id"] is not None + ): validate_linked_customer_id(str(config_data["linked_customer_id"])) diff --git a/tests/client_test.py b/tests/client_test.py index 78274ecb4..093f1c2b6 100644 --- a/tests/client_test.py +++ b/tests/client_test.py @@ -439,6 +439,50 @@ def test_load_from_dict_versioned(self): ads_assistant=None, ) + def test_load_from_dict_login_customer_id_explicit_none(self): + config = { + **self.default_config, + **{ + "client_id": self.client_id, + "client_secret": self.client_secret, + "refresh_token": self.refresh_token, + "login_customer_id": None, + }, + } + mock_credentials_instance = mock.Mock() + + with ( + mock.patch.object( + Client.GoogleAdsClient, "__init__", return_value=None + ) as mock_client_init, + mock.patch.object( + Client.oauth2, + "get_installed_app_credentials", + return_value=mock_credentials_instance, + ) as mock_credentials, + ): + try: + Client.GoogleAdsClient.load_from_dict(config) + except ValueError as ex: + self.fail( + "GoogleAdsClient.load_from_dict raised ValueError " + f"unexpectedly when login_customer_id is None: {ex}" + ) + + mock_client_init.assert_called_once_with( + credentials=mock_credentials_instance, + developer_token=self.developer_token, + use_proto_plus=self.use_proto_plus, + endpoint=None, + login_customer_id=None, + logging_config=None, + linked_customer_id=None, + version=None, + http_proxy=None, + use_cloud_org_for_api_access=None, + ads_assistant=None, + ) + def test_load_from_string(self): config = { **self.default_config, diff --git a/tests/config_test.py b/tests/config_test.py index c1d39a076..be579d5d3 100644 --- a/tests/config_test.py +++ b/tests/config_test.py @@ -289,6 +289,17 @@ def test_load_from_dict(self): } self.assertEqual(config.load_from_dict(config_data), config_data) + def test_load_from_dict_login_customer_id_explicit_none(self): + """Should not raise ValueError when login_customer_id is explicitly None.""" + config_data = { + **self.default_dict_config, + "login_customer_id": None, + } + try: + config.load_from_dict(config_data) + except ValueError as ex: + self.fail(f"load_from_dict raised ValueError unexpectedly: {ex}") + def test_load_from_dict_logging(self): """Should load logging config from dict.""" config_data = {