diff --git a/synapseclient/client.py b/synapseclient/client.py index 7d47e4d6c..6c1c686f4 100644 --- a/synapseclient/client.py +++ b/synapseclient/client.py @@ -2,6 +2,7 @@ The `Synapse` object encapsulates a connection to the Synapse service and is used for building projects, uploading and retrieving data, and recording provenance of data analysis. """ + import asyncio import collections import collections.abc @@ -770,12 +771,7 @@ def login( raise SynapseNoCredentialsError("No credentials provided.") if not silent: - profile = self.getUserProfile() - display_name = ( - profile["displayName"] - if "displayName" in profile - else self.credentials.username - ) + display_name = self.credentials.displayname or self.credentials.username self.logger.info(f"Welcome, {display_name}!\n") if cache_client: @@ -1958,9 +1954,14 @@ def store( upload_file_handle_async( self, parent_id_for_upload, - local_state["path"] - if (synapseStore or local_state_fh.get("externalURL") is None) - else local_state_fh.get("externalURL"), + ( + local_state["path"] + if ( + synapseStore + or local_state_fh.get("externalURL") is None + ) + else local_state_fh.get("externalURL") + ), synapse_store=synapseStore, md5=local_file_md5_hex or local_state_fh.get("contentMd5"), file_size=local_state_fh.get("contentSize"), @@ -3130,9 +3131,11 @@ def _convertProvenanceList(self, usedList: list, limitSearch: str = None) -> lis if usedList is None: return None usedList = [ - self.get(target, limitSearch=limitSearch) - if (os.path.isfile(target) if isinstance(target, str) else False) - else target + ( + self.get(target, limitSearch=limitSearch) + if (os.path.isfile(target) if isinstance(target, str) else False) + else target + ) for target in usedList ] return usedList diff --git a/synapseclient/core/credentials/cred_data.py b/synapseclient/core/credentials/cred_data.py index 804a0d3c4..9e0e6fe31 100644 --- a/synapseclient/core/credentials/cred_data.py +++ b/synapseclient/core/credentials/cred_data.py @@ -61,11 +61,14 @@ def _validate_token(cls, token): # ValueError if the split string is not base64 encoded or if the decoded base64 is not json pass - def __init__(self, token, username=None): + def __init__( + self, token: str, username: str = None, displayname: str = None + ) -> None: self._validate_token(token) self._token = token self.username = username + self.displayname = displayname @property def username(self) -> str: @@ -76,6 +79,15 @@ def username(self) -> str: def username(self, username: str) -> None: self._username = username + @property + def displayname(self) -> str: + """The displayname associated with this token.""" + return self._displayname + + @displayname.setter + def displayname(self, displayname: str) -> None: + self._displayname = displayname + @property def secret(self) -> str: """The bearer token.""" @@ -86,7 +98,12 @@ def __call__(self, r): return r def __repr__(self): - return f"SynapseAuthTokenCredentials(username='{self.username}', token='{self.secret}')" + return ( + f"SynapseAuthTokenCredentials(" + f"username='{self.username}', " + f"displayname='{self.displayname}', " + f"token='{self.secret}')" + ) # a class that just contains args passed form synapse client login diff --git a/synapseclient/core/credentials/credential_provider.py b/synapseclient/core/credentials/credential_provider.py index 60609df4c..ced18e4e9 100644 --- a/synapseclient/core/credentials/credential_provider.py +++ b/synapseclient/core/credentials/credential_provider.py @@ -77,6 +77,7 @@ def _create_synapse_credential( profile = syn.restGET("/userProfile", auth=credentials) profile_username = profile.get("userName") profile_emails = profile.get("emails", []) + profile_displayname = profile.get("displayName") if username and ( username != profile_username and username not in profile_emails @@ -88,8 +89,9 @@ def _create_synapse_credential( "username/email and auth_token both provided but username does not " "match token profile" ) - credentials.username = profile_username + credentials.displayname = profile_displayname + return credentials return None diff --git a/tests/unit/synapseclient/core/credentials/unit_test_cred_data.py b/tests/unit/synapseclient/core/credentials/unit_test_cred_data.py index b40204447..e733cbbb0 100644 --- a/tests/unit/synapseclient/core/credentials/unit_test_cred_data.py +++ b/tests/unit/synapseclient/core/credentials/unit_test_cred_data.py @@ -12,8 +12,9 @@ class TestSynapseAuthTokenCredentials: def setup_method(self): self.username = "ahhhhhhhhhhhhhh" self.auth_token = "opensesame" + self.displayname = "hhhhhaaaa" self.credentials = SynapseAuthTokenCredentials( - self.auth_token, username=self.username + self.auth_token, username=self.username, displayname=self.displayname ) self.KEYRING_NAME = "SYNAPSE.ORG_CLIENT_AUTH_TOKEN" @@ -26,6 +27,15 @@ def test_username_setter(self): credentials.username = self.username assert credentials.username is self.username + def test_displayname(self): + assert self.displayname == self.credentials.displayname + + def test_displayname_setter(self): + credentials = SynapseAuthTokenCredentials(self.auth_token) + assert credentials.displayname is None + credentials.displayname = self.displayname + assert credentials.displayname is self.displayname + def test_secret(self): assert self.credentials.secret == self.auth_token @@ -44,8 +54,10 @@ def test_call(self): def test_repr(self): assert ( - f"SynapseAuthTokenCredentials(username='{self.username}', token='{self.auth_token}')" - == repr(self.credentials) + f"SynapseAuthTokenCredentials(" + f"username='{self.username}', " + f"displayname='{self.displayname}', " + f"token='{self.auth_token}')" == repr(self.credentials) ) def test_tokens_validated(self, mocker): diff --git a/tests/unit/synapseclient/core/credentials/unit_test_cred_provider.py b/tests/unit/synapseclient/core/credentials/unit_test_cred_provider.py index bf47a3eee..717c602dc 100644 --- a/tests/unit/synapseclient/core/credentials/unit_test_cred_provider.py +++ b/tests/unit/synapseclient/core/credentials/unit_test_cred_provider.py @@ -62,6 +62,7 @@ def test_get_credentials__multiple_providers(self) -> None: cred_provider2.get_synapse_credentials.return_value = ( SynapseAuthTokenCredentials( username="asdf", + displayname="aaaa", token="ghjk", ) ) @@ -174,13 +175,14 @@ def test_create_synapse_credential_username_not_None_auth_token_is_not_None( assert creds is mock_creds @pytest.mark.parametrize( - "login_username,profile_username,profile_emails", + "login_username,profile_username,profile_emails,profile_displayname", ( - ("foo", "foo", ["foo@bar.com"]), # username matches + ("foo", "foo", ["foo@bar.com"], "foo"), # username matches ( "foo@bar.com", "foo", ["1@2.com", "foo@bar.com", "3@4.com"], + "foo", ), # email matches ), ) @@ -190,6 +192,7 @@ def test_create_synapse_credential__username_auth_token_match( login_username, profile_username, profile_emails, + profile_displayname, ) -> None: """Verify that if both a username/email and a auth token are provided, the login is successful if the token matches either the username or a profile email address.""" @@ -198,6 +201,7 @@ def test_create_synapse_credential__username_auth_token_match( mock_rest_get.return_value = { "userName": profile_username, "emails": profile_emails, + "displayName": profile_displayname, } cred = self.provider._create_synapse_credential( @@ -205,6 +209,7 @@ def test_create_synapse_credential__username_auth_token_match( ) assert cred.secret == self.auth_token assert cred.username == profile_username + assert cred.displayname == profile_displayname def test_create_synapse_credential__username_auth_token_mismatch( self, mocker @@ -217,6 +222,7 @@ def test_create_synapse_credential__username_auth_token_mismatch( mock_rest_get.return_value = { "userName": "foo", "emails": ["foo@bar.com", "bar@baz.com"], + "displayName": "foo", } with pytest.raises(SynapseAuthenticationError) as ex: diff --git a/tests/unit/synapseclient/unit_test_client.py b/tests/unit/synapseclient/unit_test_client.py index edb22a0fc..145aeb3d9 100644 --- a/tests/unit/synapseclient/unit_test_client.py +++ b/tests/unit/synapseclient/unit_test_client.py @@ -100,7 +100,9 @@ def setup_method(self) -> None: auth_token="hunter2", username="AzureDiamond" ) self.synapse_creds = SynapseAuthTokenCredentials( - token="hunter2", username="AzureDiamond" + token="hunter2", + displayname="Azure Diamond", + username="AzureDiamond", ) self.mocked_credential_chain = create_autospec(SynapseCredentialsProviderChain) @@ -139,9 +141,7 @@ def test_login_credentials_returned(self) -> None: assert self.synapse_creds == self.syn.credentials def test_login_silent_is_false(self) -> None: - with patch.object(self.syn, "getUserProfile"), patch.object( - self.syn, "logger" - ) as mocked_logger: + with patch.object(self.syn, "logger") as mocked_logger: # method under test self.syn.login(silent=False, **self.login_args)