Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add list_repo_likers method to HfApi #1715

Merged
merged 5 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/source/en/package_reference/hf_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ models = hf_api.list_models()

[[autodoc]] huggingface_hub.hf_api.SpaceInfo

### User

[[autodoc]] huggingface_hub.hf_api.User

### UserLikes

[[autodoc]] huggingface_hub.hf_api.UserLikes
Expand Down
4 changes: 4 additions & 0 deletions src/huggingface_hub/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
"HfApi",
"ModelSearchArguments",
"RepoUrl",
"User",
"UserLikes",
"add_collection_item",
"add_space_secret",
Expand Down Expand Up @@ -188,6 +189,7 @@
"list_models",
"list_repo_commits",
"list_repo_files",
"list_repo_likers",
"list_repo_refs",
"list_spaces",
"merge_pull_request",
Expand Down Expand Up @@ -462,6 +464,7 @@ def __dir__():
HfApi, # noqa: F401
ModelSearchArguments, # noqa: F401
RepoUrl, # noqa: F401
User, # noqa: F401
UserLikes, # noqa: F401
add_collection_item, # noqa: F401
add_space_secret, # noqa: F401
Expand Down Expand Up @@ -507,6 +510,7 @@ def __dir__():
list_models, # noqa: F401
list_repo_commits, # noqa: F401
list_repo_files, # noqa: F401
list_repo_likers, # noqa: F401
list_repo_refs, # noqa: F401
list_spaces, # noqa: F401
merge_pull_request, # noqa: F401
Expand Down
71 changes: 71 additions & 0 deletions src/huggingface_hub/hf_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,26 @@ class UserLikes:
spaces: List[str]


@dataclass
class User:
"""
Contains information about a user on the Hub.

Args:
avatar_url (`str`):
URL of the user's avatar.
username (`str`):
Name of the user on the Hub (unique).
fullname (`str`):
User's full name.
"""

# Metadata
avatar_url: str
username: str
fullname: str


def future_compatible(fn: CallableT) -> CallableT:
"""Wrap a method of `HfApi` to handle `run_as_future=True`.

Expand Down Expand Up @@ -1730,6 +1750,56 @@ def list_liked_repos(
spaces=[like["repo"]["name"] for like in likes if like["repo"]["type"] == "space"],
)

@validate_hf_hub_args
def list_repo_likers(
self,
repo_id: str,
*,
repo_type: Optional[str] = None,
token: Optional[str] = None,
) -> List[User]:
"""
List all users who liked a given repo on the hugging Face Hub.

See also [`like`] and [`list_liked_repos`].

Args:
repo_id (`str`):
The repository to retrieve . Example: `"user/my-cool-model"`.

token (`str`, *optional*):
Authentication token. Will default to the stored token.

repo_type (`str`, *optional*):
Set to `"dataset"` or `"space"` if uploading to a dataset or
space, `None` or `"model"` if uploading to a model. Default is
`None`.

Returns:
`List[User]`: a list of [`User`] objects.
"""

# Construct the API endpoint
if repo_type is None:
repo_type = REPO_TYPE_MODEL
path = f"{self.endpoint}/api/{repo_type}s/{repo_id}/likers"
headers = self._build_hf_headers(token=token)

# Make the request
response = get_session().get(path, headers=headers)
hf_raise_for_status(response)

# Parse the results into User objects
likers_data = response.json()
return [
User(
username=user_data["user"],
fullname=user_data["fullname"],
avatar_url=user_data["avatarUrl"],
)
for user_data in likers_data
]

@validate_hf_hub_args
def model_info(
self,
Expand Down Expand Up @@ -6475,6 +6545,7 @@ def _parse_revision_from_pr_url(pr_url: str) -> str:

# Activity API
list_liked_repos = api.list_liked_repos
list_repo_likers = api.list_repo_likers
like = api.like
unlike = api.unlike

Expand Down
16 changes: 16 additions & 0 deletions tests/test_hf_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2467,6 +2467,22 @@ def test_list_likes_repos_auth_and_explicit_user(self) -> None:
likes = self.api.list_liked_repos(user="__DUMMY_DATASETS_SERVER_USER__", token=TOKEN)
self.assertEqual(likes.user, "__DUMMY_DATASETS_SERVER_USER__")

def test_list_repo_likers(self) -> None:
# Create a repo + like
repo_id = self.api.create_repo(repo_name(), token=TOKEN).repo_id
self.api.like(repo_id, token=TOKEN)

# Use list_repo_likers to get the list of users who liked this repo
likers = self.api.list_repo_likers(repo_id, token=TOKEN)

# Check if the test user is in the list of likers
liker_usernames = [user.username for user in likers]
self.assertGreater(len(likers), 0)
self.assertIn(USER, liker_usernames)

# Cleanup
self.api.delete_repo(repo_id, token=TOKEN)

@with_production_testing
def test_list_likes_on_production(self) -> None:
# Test julien-c likes a lot of repos !
Expand Down
Loading