Skip to content

Commit aa8dbf1

Browse files
Add get username util function (#53)
1 parent 11854bb commit aa8dbf1

2 files changed

Lines changed: 64 additions & 0 deletions

File tree

src/modelscope_hub/_openapi.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,28 @@ def get_current_user(self) -> JSON:
388388
"""``GET /users/me`` — fetch the authenticated user profile."""
389389
return self._request("GET", "/users/me")
390390

391+
def get_current_username(self) -> str:
392+
"""The authenticated account handle, or ``""`` when unresolvable.
393+
394+
Callers need the handle to build repo paths (``<owner>/<repo>``), and
395+
the field it arrives in has changed: the endpoint now answers with
396+
OIDC-style claims (``preferred_username`` / ``name``) where it used to
397+
return ModelScope's own ``Username``. Reading only the old key yielded
398+
an empty owner, which then produced confusing downstream failures
399+
(``path is required`` on create, then a ``//`` URL 404 on commit).
400+
401+
Keys are tried in handle-before-display-name order so a server that
402+
populates both still gives the login handle rather than a full name.
403+
"""
404+
data = self.get_current_user()
405+
if not isinstance(data, dict):
406+
return ""
407+
for key in ("Username", "username", "preferred_username", "name"):
408+
value = data.get(key)
409+
if value:
410+
return str(value)
411+
return ""
412+
391413
# ==================================================================
392414
# Models
393415
# ==================================================================

tests/cli/test_openapi.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,45 @@ def test_foreign_host_absolute_url_strips_auth_and_cookies(self, client):
379379
assert call_kwargs["cookies"] == {}
380380
# Caller-supplied headers (not credentials) must still be sent.
381381
assert call_kwargs["headers"]["Content-Type"] == "application/octet-stream"
382+
383+
384+
class TestCurrentUsernameFieldCompat:
385+
"""``/users/me`` moved from ``Username`` to OIDC claims; both must work.
386+
387+
Reading only the old key silently produced an empty owner, which surfaced
388+
much later as ``path is required`` on repo creation and a ``//`` URL 404 on
389+
commit -- so each accepted shape is pinned here.
390+
"""
391+
392+
@pytest.mark.parametrize(
393+
("payload", "expected"),
394+
[
395+
# Shape observed on the server today: OIDC claims, handle in ``name``
396+
# while ``preferred_username`` comes back empty.
397+
(
398+
{
399+
"name": "tastelikefeet",
400+
"preferred_username": "",
401+
"description": "",
402+
"avatar": "",
403+
"email": "user@example.com",
404+
},
405+
"tastelikefeet",
406+
),
407+
# Legacy ModelScope shapes still deployed elsewhere.
408+
({"Username": "alice", "Email": "a@b.c"}, "alice"),
409+
({"username": "bob"}, "bob"),
410+
# A server populating both must yield the login handle, not the
411+
# human-readable display name.
412+
({"preferred_username": "carol", "name": "Carol Smith"}, "carol"),
413+
({"Username": "dave", "name": "Dave X"}, "dave"),
414+
# Unresolvable responses degrade to "" so callers can report it.
415+
({}, ""),
416+
({"name": ""}, ""),
417+
(None, ""),
418+
("not-a-dict", ""),
419+
],
420+
)
421+
def test_username_resolved_from_any_known_field(self, client, payload, expected):
422+
with patch.object(OpenAPIClient, "get_current_user", return_value=payload):
423+
assert client.get_current_username() == expected

0 commit comments

Comments
 (0)