From c75ce82ac8be7dcb842571aaa287b55e4cbd7d8f Mon Sep 17 00:00:00 2001 From: narugo1992 Date: Sun, 5 Oct 2025 17:55:45 +0800 Subject: [PATCH 1/7] dev(narugo): add hf_site_info function --- .gitignore | 3 +- docs/source/api_doc/meta/index.rst | 13 +++++ docs/source/api_doc/meta/version.rst | 23 ++++++++ docs/source/index.rst | 1 + hfutils/meta/__init__.py | 1 + hfutils/meta/version.py | 80 ++++++++++++++++++++++++++++ test/meta/__init__.py | 0 test/meta/test_version.py | 42 +++++++++++++++ 8 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 docs/source/api_doc/meta/index.rst create mode 100644 docs/source/api_doc/meta/version.rst create mode 100644 hfutils/meta/__init__.py create mode 100644 hfutils/meta/version.py create mode 100644 test/meta/__init__.py create mode 100644 test/meta/test_version.py diff --git a/.gitignore b/.gitignore index 6880c5f7f7d..c551ebbe3f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1225,4 +1225,5 @@ fabric.properties /YOLOv8 .benchmarks !/hfutils/utils/irregular_repo.json -/venv* \ No newline at end of file +/venv* +/.env* \ No newline at end of file diff --git a/docs/source/api_doc/meta/index.rst b/docs/source/api_doc/meta/index.rst new file mode 100644 index 00000000000..d17ed44d647 --- /dev/null +++ b/docs/source/api_doc/meta/index.rst @@ -0,0 +1,13 @@ +hfutils.meta +===================== + +.. currentmodule:: hfutils.meta + +.. automodule:: hfutils.meta + + +.. toctree:: + :maxdepth: 3 + + version + diff --git a/docs/source/api_doc/meta/version.rst b/docs/source/api_doc/meta/version.rst new file mode 100644 index 00000000000..41412a76302 --- /dev/null +++ b/docs/source/api_doc/meta/version.rst @@ -0,0 +1,23 @@ +hfutils.meta.version +=================================== + +.. currentmodule:: hfutils.meta.version + +.. automodule:: hfutils.meta.version + + +HfSiteInfo +---------------------------------------------------------- + +.. autoclass:: HfSiteInfo + :members: site,version + + + +hf_site_info +---------------------------------------------------------- + +.. autofunction:: hf_site_info + + + diff --git a/docs/source/index.rst b/docs/source/index.rst index 0083002d67b..71b555d3f70 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -32,6 +32,7 @@ Overview api_doc/config/index api_doc/entry/index api_doc/index/index + api_doc/meta/index api_doc/operate/index api_doc/repository/index api_doc/utils/index diff --git a/hfutils/meta/__init__.py b/hfutils/meta/__init__.py new file mode 100644 index 00000000000..cf460fce99f --- /dev/null +++ b/hfutils/meta/__init__.py @@ -0,0 +1 @@ +from .version import hf_site_info, HfSiteInfo diff --git a/hfutils/meta/version.py b/hfutils/meta/version.py new file mode 100644 index 00000000000..65a84554024 --- /dev/null +++ b/hfutils/meta/version.py @@ -0,0 +1,80 @@ +""" +This module provides functionality to retrieve information about Hugging Face sites and their versions. + +It contains utilities to identify whether a site is the official Hugging Face hub or a custom +deployment, along with version information when available. +""" + +from dataclasses import dataclass +from typing import Optional + +from huggingface_hub.constants import ENDPOINT +from huggingface_hub.utils import get_session, build_hf_headers, hf_raise_for_status + + +@dataclass +class HfSiteInfo: + """ + Data class containing information about a Hugging Face site. + + This class holds metadata about a Hugging Face deployment, including + the site identifier and version information. + + :param site: The site identifier (e.g., 'huggingface' for official hub) + :type site: str + :param version: The version of the site deployment, if available + :type version: Optional[str] + + Example:: + + >>> site_info = HfSiteInfo(site='huggingface') + >>> print(site_info.site) + huggingface + >>> site_info = HfSiteInfo(site='custom-hub', version='1.2.3') + >>> print(f"{site_info.site} v{site_info.version}") + custom-hub v1.2.3 + """ + site: str + version: Optional[str] = None + + +def hf_site_info(endpoint: Optional[str] = None, hf_token: Optional[str] = None) -> HfSiteInfo: + """ + Retrieve information about a Hugging Face site deployment. + + This function queries the version API endpoint to determine if the target + is the official Hugging Face hub or a custom deployment. For custom + deployments, it also retrieves version information. + + :param endpoint: The API endpoint URL. If None, uses the default Hugging Face endpoint + :type endpoint: Optional[str] + :param hf_token: The Hugging Face authentication token for private endpoints + :type hf_token: Optional[str] + + :return: Site information including site identifier and version + :rtype: HfSiteInfo + :raises requests.HTTPError: If the API request fails (except for 404 on official hub) + + Example:: + + >>> # Query official Hugging Face hub + >>> info = hf_site_info() + >>> print(info.site) + huggingface + + >>> # Query custom deployment + >>> info = hf_site_info(endpoint='https://my-custom-hub.com') + >>> print(f"{info.site} v{info.version}") + my-custom-hub v2.1.0 + """ + r = get_session().post( + f"{endpoint or ENDPOINT}/api/version", + headers=build_hf_headers(token=hf_token), + ) + if r.status_code == 404: + # this is huggingface official site + return HfSiteInfo(site='huggingface') + else: + hf_raise_for_status(r) + meta_info = r.json() + return HfSiteInfo(site=meta_info['site'], version=meta_info['version']) diff --git a/test/meta/__init__.py b/test/meta/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/meta/test_version.py b/test/meta/test_version.py new file mode 100644 index 00000000000..9516c245e61 --- /dev/null +++ b/test/meta/test_version.py @@ -0,0 +1,42 @@ +from unittest.mock import MagicMock, patch + +import pytest + +from hfutils.meta import hf_site_info, HfSiteInfo + + +@pytest.fixture +def mock_non_404_response(): + mock_response = MagicMock() + mock_response.status_code = 200 + mock_response.json.return_value = {'site': 'custom_site', 'version': '1.0.0'} + return mock_response + + +@pytest.fixture +def mock_404_response(): + mock_response = MagicMock() + mock_response.status_code = 404 + return mock_response + + +@pytest.mark.unittest +class TestMetaVersion: + def test_hf_site_info(self): + assert hf_site_info() == HfSiteInfo(site='huggingface') + + @patch('hfutils.meta.version.get_session') + def test_hf_site_info_404_response(self, mock_get_session, mock_404_response): + mock_session = MagicMock() + mock_session.post.return_value = mock_404_response + mock_get_session.return_value = mock_session + + assert hf_site_info() == HfSiteInfo(site='huggingface') + + @patch('hfutils.meta.version.get_session') + def test_hf_site_info_non_404_response(self, mock_get_session, mock_non_404_response): + mock_session = MagicMock() + mock_session.post.return_value = mock_non_404_response + mock_get_session.return_value = mock_session + + assert hf_site_info() == HfSiteInfo(site='custom_site', version='1.0.0') From 7ddeb8f1a9668498499075ff7e9ea654145fc517 Mon Sep 17 00:00:00 2001 From: narugo1992 Date: Sun, 5 Oct 2025 18:03:48 +0800 Subject: [PATCH 2/7] dev(narugo): optimize this function --- hfutils/meta/version.py | 63 ++++++++++++++++++++++++++++----------- test/meta/test_version.py | 12 ++++++-- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/hfutils/meta/version.py b/hfutils/meta/version.py index 65a84554024..1c7590fae0b 100644 --- a/hfutils/meta/version.py +++ b/hfutils/meta/version.py @@ -1,8 +1,16 @@ """ This module provides functionality to retrieve information about Hugging Face sites and their versions. -It contains utilities to identify whether a site is the official Hugging Face hub or a custom -deployment, along with version information when available. +It contains utilities to identify whether a site is the official Hugging Face hub, a Hugging Face +enterprise deployment, or a custom self-hosted deployment that maintains API compatibility with +Hugging Face. The module distinguishes between: + +- Official Hugging Face (huggingface.co): The main public hub +- Hugging Face Enterprise: Custom deployments supported by Hugging Face but not the official site +- Self-hosted compatible projects: Open source projects that implement HF-compatible APIs + +The identification mechanism works by checking the /api/version endpoint. Official huggingface.co +returns 404 for this endpoint, while enterprise and self-hosted deployments return site metadata. """ from dataclasses import dataclass @@ -10,6 +18,7 @@ from huggingface_hub.constants import ENDPOINT from huggingface_hub.utils import get_session, build_hf_headers, hf_raise_for_status +from urlobject import URLObject @dataclass @@ -18,33 +27,46 @@ class HfSiteInfo: Data class containing information about a Hugging Face site. This class holds metadata about a Hugging Face deployment, including - the site identifier and version information. + the site identifier and version information. It can represent: - :param site: The site identifier (e.g., 'huggingface' for official hub) + - Official Hugging Face hub (site='huggingface', version='official') + - Hugging Face enterprise deployments (site='huggingface', version='custom') + - Self-hosted compatible projects (site=custom_name, version=custom_version) + + :param site: The site identifier (e.g., 'huggingface' for official hub or enterprise) :type site: str - :param version: The version of the site deployment, if available - :type version: Optional[str] + :param version: The version of the site deployment ('official', 'custom', or specific version) + :type version: str Example:: - >>> site_info = HfSiteInfo(site='huggingface') - >>> print(site_info.site) - huggingface + >>> # Official Hugging Face hub + >>> site_info = HfSiteInfo(site='huggingface', version='official') + >>> print(f"{site_info.site} ({site_info.version})") + huggingface (official) + + >>> # Self-hosted project >>> site_info = HfSiteInfo(site='custom-hub', version='1.2.3') >>> print(f"{site_info.site} v{site_info.version}") custom-hub v1.2.3 """ site: str - version: Optional[str] = None + version: str def hf_site_info(endpoint: Optional[str] = None, hf_token: Optional[str] = None) -> HfSiteInfo: """ Retrieve information about a Hugging Face site deployment. - This function queries the version API endpoint to determine if the target - is the official Hugging Face hub or a custom deployment. For custom - deployments, it also retrieves version information. + This function queries the /api/version endpoint to determine the type of deployment: + + 1. Official Hugging Face (huggingface.co): Returns 404 for /api/version, identified as 'official' + 2. Hugging Face Enterprise: Returns site metadata with site='huggingface' but version='custom' + 3. Self-hosted compatible projects: Returns custom site name and version information + + The identification mechanism relies on the fact that the official huggingface.co does not + expose a /api/version endpoint (returns 404), while enterprise deployments and self-hosted + projects that maintain API compatibility do provide this endpoint with site metadata. :param endpoint: The API endpoint URL. If None, uses the default Hugging Face endpoint :type endpoint: Optional[str] @@ -59,21 +81,28 @@ def hf_site_info(endpoint: Optional[str] = None, hf_token: Optional[str] = None) >>> # Query official Hugging Face hub >>> info = hf_site_info() - >>> print(info.site) - huggingface + >>> print(f"{info.site} ({info.version})") + huggingface (official) + + >>> # Query Hugging Face enterprise deployment + >>> info = hf_site_info(endpoint='https://company.huggingface.co') + >>> print(f"{info.site} ({info.version})") + huggingface (custom) - >>> # Query custom deployment + >>> # Query self-hosted compatible project >>> info = hf_site_info(endpoint='https://my-custom-hub.com') >>> print(f"{info.site} v{info.version}") my-custom-hub v2.1.0 """ + endpoint = endpoint or ENDPOINT + is_huggingface_official = URLObject(endpoint).hostname == 'huggingface.co' r = get_session().post( f"{endpoint or ENDPOINT}/api/version", headers=build_hf_headers(token=hf_token), ) if r.status_code == 404: # this is huggingface official site - return HfSiteInfo(site='huggingface') + return HfSiteInfo(site='huggingface', version='official' if is_huggingface_official else 'custom') else: hf_raise_for_status(r) meta_info = r.json() diff --git a/test/meta/test_version.py b/test/meta/test_version.py index 9516c245e61..aa4deb731a4 100644 --- a/test/meta/test_version.py +++ b/test/meta/test_version.py @@ -23,7 +23,7 @@ def mock_404_response(): @pytest.mark.unittest class TestMetaVersion: def test_hf_site_info(self): - assert hf_site_info() == HfSiteInfo(site='huggingface') + assert hf_site_info() == HfSiteInfo(site='huggingface', version='official') @patch('hfutils.meta.version.get_session') def test_hf_site_info_404_response(self, mock_get_session, mock_404_response): @@ -31,7 +31,15 @@ def test_hf_site_info_404_response(self, mock_get_session, mock_404_response): mock_session.post.return_value = mock_404_response mock_get_session.return_value = mock_session - assert hf_site_info() == HfSiteInfo(site='huggingface') + assert hf_site_info() == HfSiteInfo(site='huggingface', version='official') + + @patch('hfutils.meta.version.get_session') + def test_hf_site_info_404_response_custom(self, mock_get_session, mock_404_response): + mock_session = MagicMock() + mock_session.post.return_value = mock_404_response + mock_get_session.return_value = mock_session + + assert hf_site_info(endpoint='https://hf.custom.co') == HfSiteInfo(site='huggingface', version='custom') @patch('hfutils.meta.version.get_session') def test_hf_site_info_non_404_response(self, mock_get_session, mock_non_404_response): From 5125b6a1cdc14a3c350a189546f22a36b956e60f Mon Sep 17 00:00:00 2001 From: narugo1992 Date: Sun, 5 Oct 2025 19:23:56 +0800 Subject: [PATCH 3/7] dev(narugo): fix issue due to the new apis --- .github/workflows/ir_repos.yml | 4 ++-- hfutils/meta/version.py | 42 ++++++++++++++++++++++---------- test/meta/test_version.py | 44 +++++++++++++++++++++++----------- 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/.github/workflows/ir_repos.yml b/.github/workflows/ir_repos.yml index 7d0507112da..b36d08039cc 100644 --- a/.github/workflows/ir_repos.yml +++ b/.github/workflows/ir_repos.yml @@ -3,8 +3,8 @@ name: Irregular Repos on: workflow_dispatch: - schedule: - - cron: '0 12 * * 0' +# schedule: +# - cron: '0 12 * * 0' jobs: check_irregular_repo: diff --git a/hfutils/meta/version.py b/hfutils/meta/version.py index 1c7590fae0b..38a8b53055c 100644 --- a/hfutils/meta/version.py +++ b/hfutils/meta/version.py @@ -33,6 +33,8 @@ class HfSiteInfo: - Hugging Face enterprise deployments (site='huggingface', version='custom') - Self-hosted compatible projects (site=custom_name, version=custom_version) + :param name: The human-readable name of the site deployment + :type name: str :param site: The site identifier (e.g., 'huggingface' for official hub or enterprise) :type site: str :param version: The version of the site deployment ('official', 'custom', or specific version) @@ -41,15 +43,16 @@ class HfSiteInfo: Example:: >>> # Official Hugging Face hub - >>> site_info = HfSiteInfo(site='huggingface', version='official') + >>> site_info = HfSiteInfo(name='HuggingFace (Official)', site='huggingface', version='official') >>> print(f"{site_info.site} ({site_info.version})") huggingface (official) >>> # Self-hosted project - >>> site_info = HfSiteInfo(site='custom-hub', version='1.2.3') + >>> site_info = HfSiteInfo(name='Custom Hub (1.2.3)', site='custom-hub', version='1.2.3') >>> print(f"{site_info.site} v{site_info.version}") custom-hub v1.2.3 """ + name: str site: str version: str @@ -60,13 +63,13 @@ def hf_site_info(endpoint: Optional[str] = None, hf_token: Optional[str] = None) This function queries the /api/version endpoint to determine the type of deployment: - 1. Official Hugging Face (huggingface.co): Returns 404 for /api/version, identified as 'official' - 2. Hugging Face Enterprise: Returns site metadata with site='huggingface' but version='custom' + 1. Official Hugging Face (huggingface.co): Returns 401 for /api/version, identified as 'official' + 2. Hugging Face Enterprise: Returns 401 for /api/version but not on official domain, identified as 'custom' 3. Self-hosted compatible projects: Returns custom site name and version information - The identification mechanism relies on the fact that the official huggingface.co does not - expose a /api/version endpoint (returns 404), while enterprise deployments and self-hosted - projects that maintain API compatibility do provide this endpoint with site metadata. + The identification mechanism relies on the fact that the official huggingface.co and enterprise + deployments return 401 for the /api/version endpoint without proper authentication, while + self-hosted projects that maintain API compatibility provide this endpoint with site metadata. :param endpoint: The API endpoint URL. If None, uses the default Hugging Face endpoint :type endpoint: Optional[str] @@ -75,7 +78,7 @@ def hf_site_info(endpoint: Optional[str] = None, hf_token: Optional[str] = None) :return: Site information including site identifier and version :rtype: HfSiteInfo - :raises requests.HTTPError: If the API request fails (except for 404 on official hub) + :raises requests.HTTPError: If the API request fails (except for 401 on Hugging Face deployments) Example:: @@ -96,14 +99,29 @@ def hf_site_info(endpoint: Optional[str] = None, hf_token: Optional[str] = None) """ endpoint = endpoint or ENDPOINT is_huggingface_official = URLObject(endpoint).hostname == 'huggingface.co' - r = get_session().post( + r = get_session().get( f"{endpoint or ENDPOINT}/api/version", headers=build_hf_headers(token=hf_token), ) - if r.status_code == 404: + if r.status_code == 401: # this is huggingface official site - return HfSiteInfo(site='huggingface', version='official' if is_huggingface_official else 'custom') + if is_huggingface_official: + return HfSiteInfo( + name='HuggingFace (Official)', + site='huggingface', + version='official', + ) + else: + return HfSiteInfo( + name='HuggingFace (Custom Enterprise)', + site='huggingface', + version='custom', + ) else: hf_raise_for_status(r) meta_info = r.json() - return HfSiteInfo(site=meta_info['site'], version=meta_info['version']) + return HfSiteInfo( + name=meta_info.get('name') or f'{meta_info["site"].capitalize()} ({meta_info["version"]})', + site=meta_info['site'], + version=meta_info['version'], + ) diff --git a/test/meta/test_version.py b/test/meta/test_version.py index aa4deb731a4..44fa254f3ec 100644 --- a/test/meta/test_version.py +++ b/test/meta/test_version.py @@ -6,45 +6,61 @@ @pytest.fixture -def mock_non_404_response(): +def mock_non_401_response(): mock_response = MagicMock() mock_response.status_code = 200 - mock_response.json.return_value = {'site': 'custom_site', 'version': '1.0.0'} + mock_response.json.return_value = {'name': 'MyCustomSite LOL', 'site': 'custom_site', 'version': '1.0.0'} return mock_response @pytest.fixture -def mock_404_response(): +def mock_401_response(): mock_response = MagicMock() - mock_response.status_code = 404 + mock_response.status_code = 401 return mock_response @pytest.mark.unittest class TestMetaVersion: def test_hf_site_info(self): - assert hf_site_info() == HfSiteInfo(site='huggingface', version='official') + assert hf_site_info() == HfSiteInfo( + name='HuggingFace (Official)', + site='huggingface', + version='official', + ) @patch('hfutils.meta.version.get_session') - def test_hf_site_info_404_response(self, mock_get_session, mock_404_response): + def test_hf_site_info_401_response(self, mock_get_session, mock_401_response): mock_session = MagicMock() - mock_session.post.return_value = mock_404_response + mock_session.get.return_value = mock_401_response mock_get_session.return_value = mock_session - assert hf_site_info() == HfSiteInfo(site='huggingface', version='official') + assert hf_site_info() == HfSiteInfo( + name='HuggingFace (Official)', + site='huggingface', + version='official', + ) @patch('hfutils.meta.version.get_session') - def test_hf_site_info_404_response_custom(self, mock_get_session, mock_404_response): + def test_hf_site_info_401_response_custom(self, mock_get_session, mock_401_response): mock_session = MagicMock() - mock_session.post.return_value = mock_404_response + mock_session.get.return_value = mock_401_response mock_get_session.return_value = mock_session - assert hf_site_info(endpoint='https://hf.custom.co') == HfSiteInfo(site='huggingface', version='custom') + assert hf_site_info(endpoint='https://hf.custom.co') == HfSiteInfo( + name='HuggingFace (Custom Enterprise)', + site='huggingface', + version='custom', + ) @patch('hfutils.meta.version.get_session') - def test_hf_site_info_non_404_response(self, mock_get_session, mock_non_404_response): + def test_hf_site_info_non_401_response(self, mock_get_session, mock_non_401_response): mock_session = MagicMock() - mock_session.post.return_value = mock_non_404_response + mock_session.get.return_value = mock_non_401_response mock_get_session.return_value = mock_session - assert hf_site_info() == HfSiteInfo(site='custom_site', version='1.0.0') + assert hf_site_info() == HfSiteInfo( + name='MyCustomSite LOL', + site='custom_site', + version='1.0.0', + ) From 7d8894df074ac82645a615152746e0c4f5f0566d Mon Sep 17 00:00:00 2001 From: narugo1992 Date: Sun, 5 Oct 2025 19:31:38 +0800 Subject: [PATCH 4/7] dev(narugo): add max-parallel --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 448950d5b61..eb795ae5653 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,6 +12,7 @@ jobs: if: ${{ !contains(github.event.head_commit.message, 'ci skip') && !contains(github.event.head_commit.message, 'test skip') }} strategy: fail-fast: false + max-parallel: 3 matrix: os: - 'ubuntu-latest' From 3379cbd1402da09d8f087ae23e8da212df6c32d7 Mon Sep 17 00:00:00 2001 From: narugo1992 Date: Sun, 5 Oct 2025 20:00:01 +0800 Subject: [PATCH 5/7] dev(narugo): add max-parallel to 2 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eb795ae5653..6ea14d3f3a6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: if: ${{ !contains(github.event.head_commit.message, 'ci skip') && !contains(github.event.head_commit.message, 'test skip') }} strategy: fail-fast: false - max-parallel: 3 + max-parallel: 2 matrix: os: - 'ubuntu-latest' From 4277810285e4755e5e45ac910f49bff1b271b056 Mon Sep 17 00:00:00 2001 From: narugo1992 Date: Sun, 5 Oct 2025 20:27:29 +0800 Subject: [PATCH 6/7] dev(narugo): update the name --- hfutils/meta/version.py | 28 ++++++++++++++-------------- test/meta/test_version.py | 10 +++++----- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/hfutils/meta/version.py b/hfutils/meta/version.py index 38a8b53055c..c1d85cf55d1 100644 --- a/hfutils/meta/version.py +++ b/hfutils/meta/version.py @@ -35,25 +35,25 @@ class HfSiteInfo: :param name: The human-readable name of the site deployment :type name: str - :param site: The site identifier (e.g., 'huggingface' for official hub or enterprise) - :type site: str + :param api: The site identifier (e.g., 'huggingface' for official hub or enterprise) + :type api: str :param version: The version of the site deployment ('official', 'custom', or specific version) :type version: str Example:: >>> # Official Hugging Face hub - >>> site_info = HfSiteInfo(name='HuggingFace (Official)', site='huggingface', version='official') - >>> print(f"{site_info.site} ({site_info.version})") + >>> site_info = HfSiteInfo(name='HuggingFace (Official)', api='huggingface', version='official') + >>> print(f"{site_info.api} ({site_info.version})") huggingface (official) >>> # Self-hosted project - >>> site_info = HfSiteInfo(name='Custom Hub (1.2.3)', site='custom-hub', version='1.2.3') - >>> print(f"{site_info.site} v{site_info.version}") + >>> site_info = HfSiteInfo(name='Custom Hub (1.2.3)', api='custom-hub', version='1.2.3') + >>> print(f"{site_info.api} v{site_info.version}") custom-hub v1.2.3 """ name: str - site: str + api: str version: str @@ -84,17 +84,17 @@ def hf_site_info(endpoint: Optional[str] = None, hf_token: Optional[str] = None) >>> # Query official Hugging Face hub >>> info = hf_site_info() - >>> print(f"{info.site} ({info.version})") + >>> print(f"{info.api} ({info.version})") huggingface (official) >>> # Query Hugging Face enterprise deployment >>> info = hf_site_info(endpoint='https://company.huggingface.co') - >>> print(f"{info.site} ({info.version})") + >>> print(f"{info.api} ({info.version})") huggingface (custom) >>> # Query self-hosted compatible project >>> info = hf_site_info(endpoint='https://my-custom-hub.com') - >>> print(f"{info.site} v{info.version}") + >>> print(f"{info.api} v{info.version}") my-custom-hub v2.1.0 """ endpoint = endpoint or ENDPOINT @@ -108,20 +108,20 @@ def hf_site_info(endpoint: Optional[str] = None, hf_token: Optional[str] = None) if is_huggingface_official: return HfSiteInfo( name='HuggingFace (Official)', - site='huggingface', + api='huggingface', version='official', ) else: return HfSiteInfo( name='HuggingFace (Custom Enterprise)', - site='huggingface', + api='huggingface', version='custom', ) else: hf_raise_for_status(r) meta_info = r.json() return HfSiteInfo( - name=meta_info.get('name') or f'{meta_info["site"].capitalize()} ({meta_info["version"]})', - site=meta_info['site'], + name=meta_info.get('name') or f'{meta_info["api"].capitalize()} ({meta_info["version"]})', + api=meta_info['api'], version=meta_info['version'], ) diff --git a/test/meta/test_version.py b/test/meta/test_version.py index 44fa254f3ec..1640474c532 100644 --- a/test/meta/test_version.py +++ b/test/meta/test_version.py @@ -9,7 +9,7 @@ def mock_non_401_response(): mock_response = MagicMock() mock_response.status_code = 200 - mock_response.json.return_value = {'name': 'MyCustomSite LOL', 'site': 'custom_site', 'version': '1.0.0'} + mock_response.json.return_value = {'name': 'MyCustomSite LOL', 'api': 'custom_site', 'version': '1.0.0'} return mock_response @@ -25,7 +25,7 @@ class TestMetaVersion: def test_hf_site_info(self): assert hf_site_info() == HfSiteInfo( name='HuggingFace (Official)', - site='huggingface', + api='huggingface', version='official', ) @@ -37,7 +37,7 @@ def test_hf_site_info_401_response(self, mock_get_session, mock_401_response): assert hf_site_info() == HfSiteInfo( name='HuggingFace (Official)', - site='huggingface', + api='huggingface', version='official', ) @@ -49,7 +49,7 @@ def test_hf_site_info_401_response_custom(self, mock_get_session, mock_401_respo assert hf_site_info(endpoint='https://hf.custom.co') == HfSiteInfo( name='HuggingFace (Custom Enterprise)', - site='huggingface', + api='huggingface', version='custom', ) @@ -61,6 +61,6 @@ def test_hf_site_info_non_401_response(self, mock_get_session, mock_non_401_resp assert hf_site_info() == HfSiteInfo( name='MyCustomSite LOL', - site='custom_site', + api='custom_site', version='1.0.0', ) From e4ec30ef68e85ad4c445577c7f46af5a0174fd8b Mon Sep 17 00:00:00 2001 From: narugo1992 Date: Sun, 5 Oct 2025 22:04:01 +0800 Subject: [PATCH 7/7] dev(narugo): add endpoint --- hfutils/meta/version.py | 12 +++++++++--- test/meta/test_version.py | 10 ++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/hfutils/meta/version.py b/hfutils/meta/version.py index c1d85cf55d1..92fa27aa156 100644 --- a/hfutils/meta/version.py +++ b/hfutils/meta/version.py @@ -10,7 +10,7 @@ - Self-hosted compatible projects: Open source projects that implement HF-compatible APIs The identification mechanism works by checking the /api/version endpoint. Official huggingface.co -returns 404 for this endpoint, while enterprise and self-hosted deployments return site metadata. +returns 401 for this endpoint, while enterprise and self-hosted deployments return site metadata. """ from dataclasses import dataclass @@ -39,22 +39,25 @@ class HfSiteInfo: :type api: str :param version: The version of the site deployment ('official', 'custom', or specific version) :type version: str + :param endpoint: The API endpoint URL of the site + :type endpoint: str Example:: >>> # Official Hugging Face hub - >>> site_info = HfSiteInfo(name='HuggingFace (Official)', api='huggingface', version='official') + >>> site_info = HfSiteInfo(name='HuggingFace (Official)', api='huggingface', version='official', endpoint='https://huggingface.co') >>> print(f"{site_info.api} ({site_info.version})") huggingface (official) >>> # Self-hosted project - >>> site_info = HfSiteInfo(name='Custom Hub (1.2.3)', api='custom-hub', version='1.2.3') + >>> site_info = HfSiteInfo(name='Custom Hub (1.2.3)', api='custom-hub', version='1.2.3', endpoint='https://my-hub.com') >>> print(f"{site_info.api} v{site_info.version}") custom-hub v1.2.3 """ name: str api: str version: str + endpoint: str def hf_site_info(endpoint: Optional[str] = None, hf_token: Optional[str] = None) -> HfSiteInfo: @@ -110,12 +113,14 @@ def hf_site_info(endpoint: Optional[str] = None, hf_token: Optional[str] = None) name='HuggingFace (Official)', api='huggingface', version='official', + endpoint=endpoint, ) else: return HfSiteInfo( name='HuggingFace (Custom Enterprise)', api='huggingface', version='custom', + endpoint=endpoint, ) else: hf_raise_for_status(r) @@ -124,4 +129,5 @@ def hf_site_info(endpoint: Optional[str] = None, hf_token: Optional[str] = None) name=meta_info.get('name') or f'{meta_info["api"].capitalize()} ({meta_info["version"]})', api=meta_info['api'], version=meta_info['version'], + endpoint=endpoint, ) diff --git a/test/meta/test_version.py b/test/meta/test_version.py index 1640474c532..cfe3cef0bdc 100644 --- a/test/meta/test_version.py +++ b/test/meta/test_version.py @@ -27,6 +27,7 @@ def test_hf_site_info(self): name='HuggingFace (Official)', api='huggingface', version='official', + endpoint='https://huggingface.co', ) @patch('hfutils.meta.version.get_session') @@ -39,6 +40,7 @@ def test_hf_site_info_401_response(self, mock_get_session, mock_401_response): name='HuggingFace (Official)', api='huggingface', version='official', + endpoint='https://huggingface.co', ) @patch('hfutils.meta.version.get_session') @@ -51,6 +53,7 @@ def test_hf_site_info_401_response_custom(self, mock_get_session, mock_401_respo name='HuggingFace (Custom Enterprise)', api='huggingface', version='custom', + endpoint='https://hf.custom.co', ) @patch('hfutils.meta.version.get_session') @@ -63,4 +66,11 @@ def test_hf_site_info_non_401_response(self, mock_get_session, mock_non_401_resp name='MyCustomSite LOL', api='custom_site', version='1.0.0', + endpoint='https://huggingface.co', + ) + assert hf_site_info(endpoint='https://hf.custom.co') == HfSiteInfo( + name='MyCustomSite LOL', + api='custom_site', + version='1.0.0', + endpoint='https://hf.custom.co', )