Skip to content

Commit bc46199

Browse files
authored
[SYNPY-1436] avoid duplicate user profile call during login (#1124)
* add diaplayname to SynapseAuthTokenCredentials * simplify display_name creation
1 parent 52aa513 commit bc46199

File tree

6 files changed

+64
-24
lines changed

6 files changed

+64
-24
lines changed

synapseclient/client.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
The `Synapse` object encapsulates a connection to the Synapse service and is used for building projects, uploading and
33
retrieving data, and recording provenance of data analysis.
44
"""
5+
56
import asyncio
67
import collections
78
import collections.abc
@@ -770,12 +771,7 @@ def login(
770771
raise SynapseNoCredentialsError("No credentials provided.")
771772

772773
if not silent:
773-
profile = self.getUserProfile()
774-
display_name = (
775-
profile["displayName"]
776-
if "displayName" in profile
777-
else self.credentials.username
778-
)
774+
display_name = self.credentials.displayname or self.credentials.username
779775
self.logger.info(f"Welcome, {display_name}!\n")
780776

781777
if cache_client:
@@ -1958,9 +1954,14 @@ def store(
19581954
upload_file_handle_async(
19591955
self,
19601956
parent_id_for_upload,
1961-
local_state["path"]
1962-
if (synapseStore or local_state_fh.get("externalURL") is None)
1963-
else local_state_fh.get("externalURL"),
1957+
(
1958+
local_state["path"]
1959+
if (
1960+
synapseStore
1961+
or local_state_fh.get("externalURL") is None
1962+
)
1963+
else local_state_fh.get("externalURL")
1964+
),
19641965
synapse_store=synapseStore,
19651966
md5=local_file_md5_hex or local_state_fh.get("contentMd5"),
19661967
file_size=local_state_fh.get("contentSize"),
@@ -3130,9 +3131,11 @@ def _convertProvenanceList(self, usedList: list, limitSearch: str = None) -> lis
31303131
if usedList is None:
31313132
return None
31323133
usedList = [
3133-
self.get(target, limitSearch=limitSearch)
3134-
if (os.path.isfile(target) if isinstance(target, str) else False)
3135-
else target
3134+
(
3135+
self.get(target, limitSearch=limitSearch)
3136+
if (os.path.isfile(target) if isinstance(target, str) else False)
3137+
else target
3138+
)
31363139
for target in usedList
31373140
]
31383141
return usedList

synapseclient/core/credentials/cred_data.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,14 @@ def _validate_token(cls, token):
6161
# ValueError if the split string is not base64 encoded or if the decoded base64 is not json
6262
pass
6363

64-
def __init__(self, token, username=None):
64+
def __init__(
65+
self, token: str, username: str = None, displayname: str = None
66+
) -> None:
6567
self._validate_token(token)
6668

6769
self._token = token
6870
self.username = username
71+
self.displayname = displayname
6972

7073
@property
7174
def username(self) -> str:
@@ -76,6 +79,15 @@ def username(self) -> str:
7679
def username(self, username: str) -> None:
7780
self._username = username
7881

82+
@property
83+
def displayname(self) -> str:
84+
"""The displayname associated with this token."""
85+
return self._displayname
86+
87+
@displayname.setter
88+
def displayname(self, displayname: str) -> None:
89+
self._displayname = displayname
90+
7991
@property
8092
def secret(self) -> str:
8193
"""The bearer token."""
@@ -86,7 +98,12 @@ def __call__(self, r):
8698
return r
8799

88100
def __repr__(self):
89-
return f"SynapseAuthTokenCredentials(username='{self.username}', token='{self.secret}')"
101+
return (
102+
f"SynapseAuthTokenCredentials("
103+
f"username='{self.username}', "
104+
f"displayname='{self.displayname}', "
105+
f"token='{self.secret}')"
106+
)
90107

91108

92109
# a class that just contains args passed form synapse client login

synapseclient/core/credentials/credential_provider.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def _create_synapse_credential(
7777
profile = syn.restGET("/userProfile", auth=credentials)
7878
profile_username = profile.get("userName")
7979
profile_emails = profile.get("emails", [])
80+
profile_displayname = profile.get("displayName")
8081

8182
if username and (
8283
username != profile_username and username not in profile_emails
@@ -88,8 +89,9 @@ def _create_synapse_credential(
8889
"username/email and auth_token both provided but username does not "
8990
"match token profile"
9091
)
91-
9292
credentials.username = profile_username
93+
credentials.displayname = profile_displayname
94+
9395
return credentials
9496

9597
return None

tests/unit/synapseclient/core/credentials/unit_test_cred_data.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ class TestSynapseAuthTokenCredentials:
1212
def setup_method(self):
1313
self.username = "ahhhhhhhhhhhhhh"
1414
self.auth_token = "opensesame"
15+
self.displayname = "hhhhhaaaa"
1516
self.credentials = SynapseAuthTokenCredentials(
16-
self.auth_token, username=self.username
17+
self.auth_token, username=self.username, displayname=self.displayname
1718
)
1819
self.KEYRING_NAME = "SYNAPSE.ORG_CLIENT_AUTH_TOKEN"
1920

@@ -26,6 +27,15 @@ def test_username_setter(self):
2627
credentials.username = self.username
2728
assert credentials.username is self.username
2829

30+
def test_displayname(self):
31+
assert self.displayname == self.credentials.displayname
32+
33+
def test_displayname_setter(self):
34+
credentials = SynapseAuthTokenCredentials(self.auth_token)
35+
assert credentials.displayname is None
36+
credentials.displayname = self.displayname
37+
assert credentials.displayname is self.displayname
38+
2939
def test_secret(self):
3040
assert self.credentials.secret == self.auth_token
3141

@@ -44,8 +54,10 @@ def test_call(self):
4454

4555
def test_repr(self):
4656
assert (
47-
f"SynapseAuthTokenCredentials(username='{self.username}', token='{self.auth_token}')"
48-
== repr(self.credentials)
57+
f"SynapseAuthTokenCredentials("
58+
f"username='{self.username}', "
59+
f"displayname='{self.displayname}', "
60+
f"token='{self.auth_token}')" == repr(self.credentials)
4961
)
5062

5163
def test_tokens_validated(self, mocker):

tests/unit/synapseclient/core/credentials/unit_test_cred_provider.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def test_get_credentials__multiple_providers(self) -> None:
6262
cred_provider2.get_synapse_credentials.return_value = (
6363
SynapseAuthTokenCredentials(
6464
username="asdf",
65+
displayname="aaaa",
6566
token="ghjk",
6667
)
6768
)
@@ -174,13 +175,14 @@ def test_create_synapse_credential_username_not_None_auth_token_is_not_None(
174175
assert creds is mock_creds
175176

176177
@pytest.mark.parametrize(
177-
"login_username,profile_username,profile_emails",
178+
"login_username,profile_username,profile_emails,profile_displayname",
178179
(
179-
("foo", "foo", ["[email protected]"]), # username matches
180+
("foo", "foo", ["[email protected]"], "foo"), # username matches
180181
(
181182
182183
"foo",
183184
185+
"foo",
184186
), # email matches
185187
),
186188
)
@@ -190,6 +192,7 @@ def test_create_synapse_credential__username_auth_token_match(
190192
login_username,
191193
profile_username,
192194
profile_emails,
195+
profile_displayname,
193196
) -> None:
194197
"""Verify that if both a username/email and a auth token are provided, the login is successful
195198
if the token matches either the username or a profile email address."""
@@ -198,13 +201,15 @@ def test_create_synapse_credential__username_auth_token_match(
198201
mock_rest_get.return_value = {
199202
"userName": profile_username,
200203
"emails": profile_emails,
204+
"displayName": profile_displayname,
201205
}
202206

203207
cred = self.provider._create_synapse_credential(
204208
syn=self.syn, username=login_username, auth_token=self.auth_token
205209
)
206210
assert cred.secret == self.auth_token
207211
assert cred.username == profile_username
212+
assert cred.displayname == profile_displayname
208213

209214
def test_create_synapse_credential__username_auth_token_mismatch(
210215
self, mocker
@@ -217,6 +222,7 @@ def test_create_synapse_credential__username_auth_token_mismatch(
217222
mock_rest_get.return_value = {
218223
"userName": "foo",
219224
225+
"displayName": "foo",
220226
}
221227

222228
with pytest.raises(SynapseAuthenticationError) as ex:

tests/unit/synapseclient/unit_test_client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ def setup_method(self) -> None:
100100
auth_token="hunter2", username="AzureDiamond"
101101
)
102102
self.synapse_creds = SynapseAuthTokenCredentials(
103-
token="hunter2", username="AzureDiamond"
103+
token="hunter2",
104+
displayname="Azure Diamond",
105+
username="AzureDiamond",
104106
)
105107

106108
self.mocked_credential_chain = create_autospec(SynapseCredentialsProviderChain)
@@ -139,9 +141,7 @@ def test_login_credentials_returned(self) -> None:
139141
assert self.synapse_creds == self.syn.credentials
140142

141143
def test_login_silent_is_false(self) -> None:
142-
with patch.object(self.syn, "getUserProfile"), patch.object(
143-
self.syn, "logger"
144-
) as mocked_logger:
144+
with patch.object(self.syn, "logger") as mocked_logger:
145145
# method under test
146146
self.syn.login(silent=False, **self.login_args)
147147

0 commit comments

Comments
 (0)