From 0bbec41afa7c5f9f2cf63fe369992d82b05be215 Mon Sep 17 00:00:00 2001 From: BastienGimbert Date: Fri, 10 Oct 2025 17:57:53 +0200 Subject: [PATCH] feat: add organization overview endpoint support - extend Organization dataclass with overview metadata returned by the Hub - expose get_organization_overview on HfApi and top-level package exports - cover the new endpoint with a production UserApi test --- src/huggingface_hub/__init__.py | 5 +++ src/huggingface_hub/hf_api.py | 64 +++++++++++++++++++++++++++++++++ tests/test_hf_api.py | 9 +++++ 3 files changed, 78 insertions(+) diff --git a/src/huggingface_hub/__init__.py b/src/huggingface_hub/__init__.py index 2f1c10a873..f6c5642e10 100644 --- a/src/huggingface_hub/__init__.py +++ b/src/huggingface_hub/__init__.py @@ -159,6 +159,7 @@ "GitRefs", "HfApi", "ModelInfo", + "Organization", "RepoUrl", "SpaceInfo", "User", @@ -212,6 +213,7 @@ "get_full_repo_name", "get_inference_endpoint", "get_model_tags", + "get_organization_overview", "get_paths_info", "get_repo_discussions", "get_safetensors_metadata", @@ -870,6 +872,7 @@ "get_hf_file_metadata", "get_inference_endpoint", "get_model_tags", + "get_organization_overview", "get_paths_info", "get_repo_discussions", "get_safetensors_metadata", @@ -1179,6 +1182,7 @@ def __dir__(): GitRefs, # noqa: F401 HfApi, # noqa: F401 ModelInfo, # noqa: F401 + Organization, # noqa: F401 RepoUrl, # noqa: F401 SpaceInfo, # noqa: F401 User, # noqa: F401 @@ -1232,6 +1236,7 @@ def __dir__(): get_full_repo_name, # noqa: F401 get_inference_endpoint, # noqa: F401 get_model_tags, # noqa: F401 + get_organization_overview, # noqa: F401 get_paths_info, # noqa: F401 get_repo_discussions, # noqa: F401 get_safetensors_metadata, # noqa: F401 diff --git a/src/huggingface_hub/hf_api.py b/src/huggingface_hub/hf_api.py index 600ee9aa4a..6f441e4633 100644 --- a/src/huggingface_hub/hf_api.py +++ b/src/huggingface_hub/hf_api.py @@ -1404,16 +1404,52 @@ class Organization: Name of the organization on the Hub (unique). fullname (`str`): Organization's full name. + id (`str`, *optional*): + Unique identifier of the organization on the Hub. + details (`str`, *optional*): + Organization's description. + is_verified (`bool`, *optional*): + Whether the organization is verified. + is_following (`bool`, *optional*): + Whether the authenticated user follows this organization. + num_users (`int`, *optional*): + Number of members in the organization. + num_models (`int`, *optional*): + Number of models owned by the organization. + num_spaces (`int`, *optional*): + Number of Spaces owned by the organization. + num_datasets (`int`, *optional*): + Number of datasets owned by the organization. + num_followers (`int`, *optional*): + Number of followers of the organization. """ avatar_url: str name: str fullname: str + id: Optional[str] = None + details: Optional[str] = None + is_verified: Optional[bool] = None + is_following: Optional[bool] = None + num_users: Optional[int] = None + num_models: Optional[int] = None + num_spaces: Optional[int] = None + num_datasets: Optional[int] = None + num_followers: Optional[int] = None def __init__(self, **kwargs) -> None: self.avatar_url = kwargs.pop("avatarUrl", "") self.name = kwargs.pop("name", "") self.fullname = kwargs.pop("fullname", "") + self.id = kwargs.pop("_id", None) + self.details = kwargs.pop("details", None) + self.is_verified = kwargs.pop("isVerified", None) + self.is_following = kwargs.pop("isFollowing", None) + self.num_users = kwargs.pop("numUsers", None) + self.num_models = kwargs.pop("numModels", None) + self.num_spaces = kwargs.pop("numSpaces", None) + self.num_datasets = kwargs.pop("numDatasets", None) + self.num_followers = kwargs.pop("numFollowers", None) # forward compatibility self.__dict__.update(**kwargs) @@ -9663,6 +9699,33 @@ def get_user_overview(self, username: str, token: Union[bool, str, None] = None) hf_raise_for_status(r) return User(**r.json()) + @validate_hf_hub_args + def get_organization_overview(self, organization: str, token: Union[bool, str, None] = None) -> Organization: + """ + Get an overview of an organization on the Hub. + + Args: + organization (`str`): + Name of the organization to get an overview of. + token (Union[bool, str, None], optional): + A valid user access token (string). Defaults to the locally saved token, which is the recommended method + for authentication (see https://huggingface.co/docs/huggingface_hub/quick-start#authentication). + To disable authentication, pass `False`. + + Returns: + `Organization`: An [`Organization`] object with the organization's overview. + + Raises: + [`HTTPError`](https://requests.readthedocs.io/en/latest/api/#requests.HTTPError): + HTTP 404 If the organization does not exist on the Hub. + """ + r = get_session().get( + f"{constants.ENDPOINT}/api/organizations/{organization}/overview", + headers=self._build_hf_headers(token=token), + ) + hf_raise_for_status(r) + return Organization(**r.json()) + def list_organization_members(self, organization: str, token: Union[bool, str, None] = None) -> Iterable[User]: """ List of members of an organization on the Hub. @@ -10956,6 +11019,7 @@ def _parse_revision_from_pr_url(pr_url: str) -> str: # User API get_user_overview = api.get_user_overview +get_organization_overview = api.get_organization_overview list_organization_members = api.list_organization_members list_user_followers = api.list_user_followers list_user_following = api.list_user_following diff --git a/tests/test_hf_api.py b/tests/test_hf_api.py index abb2f5e3f0..8ba57d264c 100644 --- a/tests/test_hf_api.py +++ b/tests/test_hf_api.py @@ -4282,6 +4282,15 @@ def test_user_overview(self) -> None: assert overview.num_following > 300 assert overview.num_followers > 1000 + def test_organization_overview(self) -> None: + overview = self.api.get_organization_overview("huggingface") + assert overview.name == "huggingface" + assert overview.fullname == "Hugging Face" + assert overview.avatar_url.startswith("https://") + assert overview.num_users is None or overview.num_users > 10 + assert overview.num_models is None or overview.num_models > 10 + assert overview.num_followers is None or overview.num_followers > 1000 + def test_organization_members(self) -> None: members = self.api.list_organization_members("huggingface") assert len(list(members)) > 1