From dff7dbfb17f7718c918373a5287fd34f92b2ee5e Mon Sep 17 00:00:00 2001 From: Celina Hanouti Date: Wed, 23 Oct 2024 19:13:47 +0200 Subject: [PATCH 1/6] Add user CLI unit tests (#2628) --- tests/test_auth_cli.py | 165 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 tests/test_auth_cli.py diff --git a/tests/test_auth_cli.py b/tests/test_auth_cli.py new file mode 100644 index 0000000000..d9013b44ff --- /dev/null +++ b/tests/test_auth_cli.py @@ -0,0 +1,165 @@ +import logging +import os +import tempfile +from unittest.mock import patch + +import pytest +from pytest import CaptureFixture, LogCaptureFixture + +from huggingface_hub import constants +from huggingface_hub.commands.user import AuthListCommand, AuthSwitchCommand, LoginCommand, LogoutCommand + +from .testing_constants import ENDPOINT_STAGING + + +# fixtures & constants + +MOCK_TOKEN = "hf_1234" + + +@pytest.fixture(autouse=True) +def use_tmp_file_paths(): + """ + Fixture to temporarily override HF_TOKEN_PATH, HF_STORED_TOKENS_PATH, and ENDPOINT. + """ + with tempfile.TemporaryDirectory() as tmp_hf_home: + hf_token_path = os.path.join(tmp_hf_home, "token") + hf_stored_tokens_path = os.path.join(tmp_hf_home, "stored_tokens") + with patch.multiple( + constants, + HF_TOKEN_PATH=hf_token_path, + HF_STORED_TOKENS_PATH=hf_stored_tokens_path, + ENDPOINT=ENDPOINT_STAGING, + ): + yield + + +@pytest.fixture +def mock_whoami_api_call(): + MOCK_WHOAMI_RESPONSE = { + "auth": { + "accessToken": { + "displayName": "test_token", + "role": "write", + "createdAt": "2024-01-01T00:00:00.000Z", + } + } + } + with patch("huggingface_hub.hf_api.whoami", return_value=MOCK_WHOAMI_RESPONSE): + yield + + +@pytest.fixture +def mock_stored_tokens(): + """Mock stored tokens.""" + stored_tokens = { + "token1": "hf_1234", + "token2": "hf_5678", + "active_token": "hf_9012", + } + with patch("huggingface_hub._login.get_stored_tokens", return_value=stored_tokens), patch( + "huggingface_hub.utils._auth.get_stored_tokens", return_value=stored_tokens + ): + yield stored_tokens + + +def assert_in_logs(caplog: LogCaptureFixture, expected_output): + """Helper to check if a message appears in logs.""" + log_text = "\n".join(record.message for record in caplog.records) + assert expected_output in log_text, f"Expected '{expected_output}' not found in logs" + + +def test_login_command_basic(mock_whoami_api_call, caplog: LogCaptureFixture): + """Test basic login command execution.""" + caplog.set_level(logging.INFO) + + args = type("Args", (), {"token": MOCK_TOKEN, "add_to_git_credential": False})() + cmd = LoginCommand(args) + cmd.run() + + assert_in_logs(caplog, "Login successful") + assert_in_logs(caplog, "Token is valid") + assert_in_logs(caplog, "The current active token is: `test_token`") + + +def test_login_command_with_git(mock_whoami_api_call, caplog: LogCaptureFixture): + """Test login command with git credential option.""" + caplog.set_level(logging.INFO) + + args = type("Args", (), {"token": MOCK_TOKEN, "add_to_git_credential": True})() + cmd = LoginCommand(args) + + with patch("huggingface_hub._login._is_git_credential_helper_configured", return_value=True), patch( + "huggingface_hub.utils.set_git_credential" + ): + cmd.run() + + assert_in_logs(caplog, "Login successful") + assert_in_logs(caplog, "Your token has been saved in your configured git credential helpers") + + +def test_logout_specific_token(mock_stored_tokens, caplog: LogCaptureFixture): + """Test logout command for a specific token.""" + caplog.set_level(logging.INFO) + + args = type("Args", (), {"token_name": "token1"})() + cmd = LogoutCommand(args) + cmd.run() + + assert_in_logs(caplog, "Successfully logged out from access token: token1") + + +def test_logout_active_token(mock_stored_tokens, caplog: LogCaptureFixture): + """Test logout command for active token.""" + caplog.set_level(logging.INFO) + + with patch("huggingface_hub._login._get_token_from_file", return_value="hf_9012"): + args = type("Args", (), {"token_name": "active_token"})() + cmd = LogoutCommand(args) + cmd.run() + + assert_in_logs(caplog, "Successfully logged out from access token: active_token") + assert_in_logs(caplog, "Active token 'active_token' has been deleted") + + +def test_logout_all_tokens(mock_stored_tokens, caplog: LogCaptureFixture): + """Test logout command for all tokens.""" + caplog.set_level(logging.INFO) + + args = type("Args", (), {"token_name": None})() + cmd = LogoutCommand(args) + cmd.run() + + assert_in_logs(caplog, "Successfully logged out from all access tokens") + + +def test_switch_token(mock_stored_tokens, caplog: LogCaptureFixture): + """Test switching between tokens.""" + caplog.set_level(logging.INFO) + + args = type("Args", (), {"token_name": "token1", "add_to_git_credential": False})() + cmd = AuthSwitchCommand(args) + cmd.run() + + assert_in_logs(caplog, "The current active token is: token1") + + +def test_switch_nonexistent_token(mock_stored_tokens): + """Test switching to a non-existent token.""" + args = type("Args", (), {"token_name": "nonexistent", "add_to_git_credential": False})() + cmd = AuthSwitchCommand(args) + + with pytest.raises(ValueError, match="Access token nonexistent not found"): + cmd.run() + + +def test_list_tokens(mock_stored_tokens, capsys: CaptureFixture): + """Test listing tokens command.""" + args = type("Args", (), {})() + cmd = AuthListCommand(args) + cmd.run() + + captured = capsys.readouterr() + assert "token1" in captured.out + assert "hf_****1234" in captured.out + assert "token2" in captured.out From 7709178059425cac78c53ddf5855890b222cd74f Mon Sep 17 00:00:00 2001 From: Lucain Date: Thu, 24 Oct 2024 11:16:44 +0200 Subject: [PATCH 2/6] Fix download local dir edge case (remove lru_cache) (#2629) --- src/huggingface_hub/_local_folder.py | 4 ---- tests/test_local_folder.py | 34 ++++++++++++++++------------ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/huggingface_hub/_local_folder.py b/src/huggingface_hub/_local_folder.py index 049394af1d..6fd05f053a 100644 --- a/src/huggingface_hub/_local_folder.py +++ b/src/huggingface_hub/_local_folder.py @@ -53,7 +53,6 @@ import os import time from dataclasses import dataclass -from functools import lru_cache from pathlib import Path from typing import Optional @@ -179,7 +178,6 @@ def save(self, paths: LocalUploadFilePaths) -> None: self.timestamp = new_timestamp -@lru_cache(maxsize=128) # ensure singleton def get_local_download_paths(local_dir: Path, filename: str) -> LocalDownloadFilePaths: """Compute paths to the files related to a download process. @@ -220,7 +218,6 @@ def get_local_download_paths(local_dir: Path, filename: str) -> LocalDownloadFil return LocalDownloadFilePaths(file_path=file_path, lock_path=lock_path, metadata_path=metadata_path) -@lru_cache(maxsize=128) # ensure singleton def get_local_upload_paths(local_dir: Path, filename: str) -> LocalUploadFilePaths: """Compute paths to the files related to an upload process. @@ -404,7 +401,6 @@ def write_download_metadata(local_dir: Path, filename: str, commit_hash: str, et f.write(f"{commit_hash}\n{etag}\n{time.time()}\n") -@lru_cache() def _huggingface_dir(local_dir: Path) -> Path: """Return the path to the `.cache/huggingface` directory in a local directory.""" # Wrap in lru_cache to avoid overwriting the .gitignore file if called multiple times diff --git a/tests/test_local_folder.py b/tests/test_local_folder.py index 76a0c444db..9d19f2f4db 100644 --- a/tests/test_local_folder.py +++ b/tests/test_local_folder.py @@ -74,14 +74,17 @@ def test_local_download_paths(tmp_path: Path): assert paths.incomplete_path("etag123").parent.is_dir() -def test_local_download_paths_are_cached(tmp_path: Path): - """Test local download paths are cached.""" - # No need for an exact singleton here. - # We just want to avoid recreating the dataclass on consecutive calls (happens often - # in the process). +def test_local_download_paths_are_recreated_each_time(tmp_path: Path): paths1 = get_local_download_paths(tmp_path, "path/in/repo.txt") + assert paths1.file_path.parent.is_dir() + assert paths1.metadata_path.parent.is_dir() + + paths1.file_path.parent.rmdir() + paths1.metadata_path.parent.rmdir() + paths2 = get_local_download_paths(tmp_path, "path/in/repo.txt") - assert paths1 is paths2 + assert paths2.file_path.parent.is_dir() + assert paths2.metadata_path.parent.is_dir() @pytest.mark.skipif(os.name != "nt", reason="Windows-specific test.") @@ -198,14 +201,17 @@ def test_local_upload_paths(tmp_path: Path): assert paths.lock_path.parent.is_dir() -def test_local_upload_paths_are_cached(tmp_path: Path): - """Test local upload paths are cached.""" - # No need for an exact singleton here. - # We just want to avoid recreating the dataclass on consecutive calls (happens often - # in the process). - paths1 = get_local_download_paths(tmp_path, "path/in/repo.txt") - paths2 = get_local_download_paths(tmp_path, "path/in/repo.txt") - assert paths1 is paths2 +def test_local_upload_paths_are_recreated_each_time(tmp_path: Path): + paths1 = get_local_upload_paths(tmp_path, "path/in/repo.txt") + assert paths1.file_path.parent.is_dir() + assert paths1.metadata_path.parent.is_dir() + + paths1.file_path.parent.rmdir() + paths1.metadata_path.parent.rmdir() + + paths2 = get_local_upload_paths(tmp_path, "path/in/repo.txt") + assert paths2.file_path.parent.is_dir() + assert paths2.metadata_path.parent.is_dir() @pytest.mark.skipif(os.name != "nt", reason="Windows-specific test.") From 6ac7aef4761328b1922e16c13e2b16c29ac3b47c Mon Sep 17 00:00:00 2001 From: Tom Aarsen <37621491+tomaarsen@users.noreply.github.com> Date: Thu, 24 Oct 2024 15:13:46 +0200 Subject: [PATCH 3/6] Add utf8 encoding to read_text to avoid Windows charmap crash (#2627) Co-authored-by: Lucain --- src/huggingface_hub/hf_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/huggingface_hub/hf_api.py b/src/huggingface_hub/hf_api.py index f1cae45b30..b92c16401b 100644 --- a/src/huggingface_hub/hf_api.py +++ b/src/huggingface_hub/hf_api.py @@ -9165,7 +9165,7 @@ def _prepare_upload_folder_additions( # It's better to fail early than to fail after all the files have been hashed. if "README.md" in filtered_repo_objects: self._validate_yaml( - content=relpath_to_abspath["README.md"].read_text(), + content=relpath_to_abspath["README.md"].read_text(encoding="utf8"), repo_type=repo_type, token=token, ) From ab87526b067b1c078a58cb6bd4ff3850c00840e4 Mon Sep 17 00:00:00 2001 From: Lucain Date: Thu, 24 Oct 2024 15:43:07 +0200 Subject: [PATCH 4/6] Fix and deprecate get_token_permission (#2631) --- src/huggingface_hub/hf_api.py | 26 ++++++++++++++++++++++---- tests/test_hf_api.py | 11 +++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/huggingface_hub/hf_api.py b/src/huggingface_hub/hf_api.py index b92c16401b..5ab1aa0ebb 100644 --- a/src/huggingface_hub/hf_api.py +++ b/src/huggingface_hub/hf_api.py @@ -1661,10 +1661,28 @@ def whoami(self, token: Union[bool, str, None] = None) -> Dict: ) from e return r.json() - def get_token_permission(self, token: Union[bool, str, None] = None) -> Literal["read", "write", None]: + @_deprecate_method( + version="1.0", + message=( + "Permissions are more complex than when `get_token_permission` was first introduced. " + "OAuth and fine-grain tokens allows for more detailed permissions. " + "If you need to know the permissions associated with a token, please use `whoami` and check the `'auth'` key." + ), + ) + def get_token_permission( + self, token: Union[bool, str, None] = None + ) -> Literal["read", "write", "fineGrained", None]: """ Check if a given `token` is valid and return its permissions. + + + This method is deprecated and will be removed in version 1.0. Permissions are more complex than when + `get_token_permission` was first introduced. OAuth and fine-grain tokens allows for more detailed permissions. + If you need to know the permissions associated with a token, please use `whoami` and check the `'auth'` key. + + + For more details about tokens, please refer to https://huggingface.co/docs/hub/security-tokens#what-are-user-access-tokens. Args: @@ -1675,12 +1693,12 @@ def get_token_permission(self, token: Union[bool, str, None] = None) -> Literal[ To disable authentication, pass `False`. Returns: - `Literal["read", "write", None]`: Permission granted by the token ("read" or "write"). Returns `None` if no - token passed or token is invalid. + `Literal["read", "write", "fineGrained", None]`: Permission granted by the token ("read" or "write"). Returns `None` if no + token passed, if token is invalid or if role is not returned by the server. This typically happens when the token is an OAuth token. """ try: return self.whoami(token=token)["auth"]["accessToken"]["role"] - except (LocalTokenNotFoundError, HTTPError): + except (LocalTokenNotFoundError, HTTPError, KeyError): return None def get_model_tags(self) -> Dict: diff --git a/tests/test_hf_api.py b/tests/test_hf_api.py index 185aa48cbd..a2ba07b8c1 100644 --- a/tests/test_hf_api.py +++ b/tests/test_hf_api.py @@ -298,6 +298,17 @@ def test_update_dataset_repo_settings(self, repo_url: RepoUrl): assert info.gated == gated_value assert info.private == private_value + @expect_deprecation("get_token_permission") + def test_get_token_permission_on_oauth_token(self): + whoami = { + "type": "user", + "auth": {"type": "oauth", "expiresAt": "2024-10-24T19:43:43.000Z"}, + # ... + # other values are ignored as we only need to check the "auth" value + } + with patch.object(self._api, "whoami", return_value=whoami): + assert self._api.get_token_permission() is None + class CommitApiTest(HfApiCommonTest): def setUp(self) -> None: From 80352561fae571c8c05b70ccfda2b8c1d0a93a5f Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Fri, 25 Oct 2024 10:49:24 +0200 Subject: [PATCH 5/6] Fix typos (#2634) * fix typos * fix typo * fix typos * fix typo * fix typos * fix typo * fix typo * fix typo * fix typo * fix typo * fix typos * fix typos * fix typos --- docs/source/cn/concepts/git_vs_http.md | 2 +- docs/source/cn/guides/repository.md | 2 +- docs/source/cn/index.md | 2 +- docs/source/cn/installation.md | 2 +- docs/source/cn/quick-start.md | 2 +- docs/source/de/concepts/git_vs_http.md | 2 +- docs/source/de/guides/community.md | 2 +- docs/source/de/guides/download.md | 2 +- docs/source/de/guides/hf_file_system.md | 2 +- docs/source/de/guides/inference.md | 2 +- docs/source/de/guides/integrations.md | 2 +- docs/source/de/guides/manage-cache.md | 2 +- docs/source/de/guides/manage-spaces.md | 2 +- docs/source/de/guides/model-cards.md | 2 +- docs/source/de/guides/overview.md | 2 +- docs/source/de/guides/repository.md | 2 +- docs/source/de/guides/search.md | 2 +- docs/source/de/guides/upload.md | 2 +- docs/source/de/guides/webhooks_server.md | 2 +- docs/source/de/index.md | 2 +- docs/source/de/installation.md | 2 +- docs/source/de/quick-start.md | 2 +- docs/source/en/concepts/git_vs_http.md | 4 ++-- docs/source/en/guides/cli.md | 4 ++-- docs/source/en/guides/collections.md | 6 +++--- docs/source/en/guides/community.md | 4 ++-- docs/source/en/guides/download.md | 2 +- docs/source/en/guides/hf_file_system.md | 4 ++-- docs/source/en/guides/inference.md | 10 +++++----- docs/source/en/guides/integrations.md | 6 +++--- docs/source/en/guides/manage-cache.md | 6 +++--- docs/source/en/guides/manage-spaces.md | 2 +- docs/source/en/guides/model-cards.md | 2 +- docs/source/en/guides/overview.md | 2 +- docs/source/en/guides/repository.md | 2 +- docs/source/en/guides/search.md | 2 +- docs/source/en/guides/upload.md | 2 +- docs/source/en/guides/webhooks.md | 2 +- docs/source/en/index.md | 2 +- docs/source/en/installation.md | 4 ++-- docs/source/en/package_reference/authentication.md | 2 +- docs/source/en/package_reference/cache.md | 2 +- docs/source/en/package_reference/cards.md | 2 +- docs/source/en/package_reference/collections.md | 2 +- docs/source/en/package_reference/community.md | 2 +- .../en/package_reference/environment_variables.md | 2 +- docs/source/en/package_reference/file_download.md | 2 +- docs/source/en/package_reference/hf_api.md | 2 +- docs/source/en/package_reference/hf_file_system.md | 2 +- docs/source/en/package_reference/inference_client.md | 2 +- docs/source/en/package_reference/inference_types.md | 2 +- docs/source/en/package_reference/mixins.md | 2 +- docs/source/en/package_reference/overview.md | 2 +- docs/source/en/package_reference/repository.md | 2 +- docs/source/en/package_reference/serialization.md | 2 +- docs/source/en/package_reference/space_runtime.md | 2 +- docs/source/en/package_reference/tensorboard.md | 2 +- docs/source/en/package_reference/utilities.md | 2 +- docs/source/en/package_reference/webhooks_server.md | 2 +- docs/source/en/quick-start.md | 2 +- docs/source/fr/concepts/git_vs_http.md | 2 +- docs/source/fr/guides/integrations.md | 2 +- docs/source/fr/index.md | 2 +- docs/source/fr/installation.md | 2 +- docs/source/fr/quick-start.md | 2 +- docs/source/hi/index.md | 2 +- docs/source/hi/installation.md | 2 +- docs/source/hi/quick-start.md | 2 +- docs/source/ko/concepts/git_vs_http.md | 2 +- docs/source/ko/guides/cli.md | 2 +- docs/source/ko/guides/collections.md | 2 +- docs/source/ko/guides/community.md | 2 +- docs/source/ko/guides/download.md | 2 +- docs/source/ko/guides/hf_file_system.md | 2 +- docs/source/ko/guides/inference.md | 2 +- docs/source/ko/guides/integrations.md | 2 +- docs/source/ko/guides/manage-cache.md | 2 +- docs/source/ko/guides/manage-spaces.md | 2 +- docs/source/ko/guides/model-cards.md | 2 +- docs/source/ko/guides/overview.md | 4 ++-- docs/source/ko/guides/repository.md | 2 +- docs/source/ko/guides/search.md | 2 +- docs/source/ko/guides/upload.md | 2 +- docs/source/ko/guides/webhooks_server.md | 2 +- docs/source/ko/index.md | 2 +- docs/source/ko/installation.md | 2 +- docs/source/ko/package_reference/cache.md | 2 +- docs/source/ko/package_reference/collections.md | 2 +- docs/source/ko/package_reference/community.md | 2 +- .../ko/package_reference/environment_variables.md | 2 +- docs/source/ko/package_reference/file_download.md | 2 +- docs/source/ko/package_reference/hf_api.md | 2 +- docs/source/ko/package_reference/hf_file_system.md | 2 +- docs/source/ko/package_reference/inference_client.md | 2 +- docs/source/ko/package_reference/inference_types.md | 2 +- docs/source/ko/package_reference/login.md | 2 +- docs/source/ko/package_reference/mixins.md | 2 +- docs/source/ko/package_reference/overview.md | 2 +- docs/source/ko/package_reference/repository.md | 2 +- docs/source/ko/package_reference/serialization.md | 2 +- docs/source/ko/package_reference/space_runtime.md | 2 +- docs/source/ko/package_reference/tensorboard.md | 2 +- docs/source/ko/package_reference/utilities.md | 2 +- docs/source/ko/package_reference/webhooks_server.md | 2 +- docs/source/ko/quick-start.md | 2 +- docs/source/tm/index.md | 2 +- src/huggingface_hub/inference/_common.py | 4 ++-- utils/generate_async_inference_client.py | 2 +- utils/generate_inference_types.py | 4 ++-- 109 files changed, 127 insertions(+), 127 deletions(-) diff --git a/docs/source/cn/concepts/git_vs_http.md b/docs/source/cn/concepts/git_vs_http.md index 8509309b76..b582b5f991 100644 --- a/docs/source/cn/concepts/git_vs_http.md +++ b/docs/source/cn/concepts/git_vs_http.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/cn/guides/repository.md b/docs/source/cn/guides/repository.md index aa1f3b3dff..0b5b294d45 100644 --- a/docs/source/cn/guides/repository.md +++ b/docs/source/cn/guides/repository.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/cn/index.md b/docs/source/cn/index.md index 1944c08f48..9a7d8db6a8 100644 --- a/docs/source/cn/index.md +++ b/docs/source/cn/index.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/cn/installation.md b/docs/source/cn/installation.md index c46de7ce52..2b3003e977 100644 --- a/docs/source/cn/installation.md +++ b/docs/source/cn/installation.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/cn/quick-start.md b/docs/source/cn/quick-start.md index 861973a6f7..4a4a809a79 100644 --- a/docs/source/cn/quick-start.md +++ b/docs/source/cn/quick-start.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/concepts/git_vs_http.md b/docs/source/de/concepts/git_vs_http.md index 799cb974b2..978123762a 100644 --- a/docs/source/de/concepts/git_vs_http.md +++ b/docs/source/de/concepts/git_vs_http.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/community.md b/docs/source/de/guides/community.md index a2026436c2..c492330f5a 100644 --- a/docs/source/de/guides/community.md +++ b/docs/source/de/guides/community.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/download.md b/docs/source/de/guides/download.md index afd2d9d4f7..ec195d4035 100644 --- a/docs/source/de/guides/download.md +++ b/docs/source/de/guides/download.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/hf_file_system.md b/docs/source/de/guides/hf_file_system.md index 6afd8a705c..e33cc97cd4 100644 --- a/docs/source/de/guides/hf_file_system.md +++ b/docs/source/de/guides/hf_file_system.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/inference.md b/docs/source/de/guides/inference.md index dc6e35921f..e34103ac34 100644 --- a/docs/source/de/guides/inference.md +++ b/docs/source/de/guides/inference.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/integrations.md b/docs/source/de/guides/integrations.md index 3482ae6eac..d8f036ec4d 100644 --- a/docs/source/de/guides/integrations.md +++ b/docs/source/de/guides/integrations.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/manage-cache.md b/docs/source/de/guides/manage-cache.md index 2f8c029f8e..779c34b683 100644 --- a/docs/source/de/guides/manage-cache.md +++ b/docs/source/de/guides/manage-cache.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/manage-spaces.md b/docs/source/de/guides/manage-spaces.md index 3caab0f5ed..57a45e9e11 100644 --- a/docs/source/de/guides/manage-spaces.md +++ b/docs/source/de/guides/manage-spaces.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/model-cards.md b/docs/source/de/guides/model-cards.md index bcba30866c..01858c41b8 100644 --- a/docs/source/de/guides/model-cards.md +++ b/docs/source/de/guides/model-cards.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/overview.md b/docs/source/de/guides/overview.md index 7f761839a1..785689b989 100644 --- a/docs/source/de/guides/overview.md +++ b/docs/source/de/guides/overview.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/repository.md b/docs/source/de/guides/repository.md index b2f492717e..6e4187ae8e 100644 --- a/docs/source/de/guides/repository.md +++ b/docs/source/de/guides/repository.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/search.md b/docs/source/de/guides/search.md index 0cafd4e7b3..c40d91b9b8 100644 --- a/docs/source/de/guides/search.md +++ b/docs/source/de/guides/search.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/upload.md b/docs/source/de/guides/upload.md index e591afcb52..38db944c7e 100644 --- a/docs/source/de/guides/upload.md +++ b/docs/source/de/guides/upload.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/guides/webhooks_server.md b/docs/source/de/guides/webhooks_server.md index 223ff8ca31..d2214d6b72 100644 --- a/docs/source/de/guides/webhooks_server.md +++ b/docs/source/de/guides/webhooks_server.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/index.md b/docs/source/de/index.md index 320f098ab0..3514dcf384 100644 --- a/docs/source/de/index.md +++ b/docs/source/de/index.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/installation.md b/docs/source/de/installation.md index 0a00c15d10..8cb6ae3f31 100644 --- a/docs/source/de/installation.md +++ b/docs/source/de/installation.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/de/quick-start.md b/docs/source/de/quick-start.md index f78fa55e75..83ce0a24e0 100644 --- a/docs/source/de/quick-start.md +++ b/docs/source/de/quick-start.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/concepts/git_vs_http.md b/docs/source/en/concepts/git_vs_http.md index f581f1678b..e6eb755af5 100644 --- a/docs/source/en/concepts/git_vs_http.md +++ b/docs/source/en/concepts/git_vs_http.md @@ -1,11 +1,11 @@ - # Git vs HTTP paradigm The `huggingface_hub` library is a library for interacting with the Hugging Face Hub, which is a -collections of git-based repositories (models, datasets or Spaces). There are two main +collection of git-based repositories (models, datasets or Spaces). There are two main ways to access the Hub using `huggingface_hub`. The first approach, the so-called "git-based" approach, is led by the [`Repository`] class. diff --git a/docs/source/en/guides/cli.md b/docs/source/en/guides/cli.md index 9fb355ae9d..35dc861ab4 100644 --- a/docs/source/en/guides/cli.md +++ b/docs/source/en/guides/cli.md @@ -1,4 +1,4 @@ - @@ -139,7 +139,7 @@ If you are not logged in, an error message will be printed. ## huggingface-cli logout -This commands logs you out. In practice, it will delete all tokens stored on your machine. If you want to remove a specific token, you can specify the token name as an argument. +This command logs you out. In practice, it will delete all tokens stored on your machine. If you want to remove a specific token, you can specify the token name as an argument. This command will not log you out if you are logged in using the `HF_TOKEN` environment variable (see [reference](../package_reference/environment_variables#hftoken)). If that is the case, you must unset the environment variable in your machine configuration. diff --git a/docs/source/en/guides/collections.md b/docs/source/en/guides/collections.md index 1fc1cd8da8..2a70f1dd94 100644 --- a/docs/source/en/guides/collections.md +++ b/docs/source/en/guides/collections.md @@ -1,4 +1,4 @@ - @@ -6,7 +6,7 @@ rendered properly in your Markdown viewer. A collection is a group of related items on the Hub (models, datasets, Spaces, papers) that are organized together on the same page. Collections are useful for creating your own portfolio, bookmarking content in categories, or presenting a curated list of items you want to share. Check out this [guide](https://huggingface.co/docs/hub/collections) to understand in more detail what collections are and how they look on the Hub. -You can directly manage collections in the browser, but in this guide, we will focus on how to manage it programmatically. +You can directly manage collections in the browser, but in this guide, we will focus on how to manage them programmatically. ## Fetch a collection @@ -115,7 +115,7 @@ Now that we know how to get a [`Collection`], let's create our own! Use [`create ... ) ``` -It will return a [`Collection`] object with the high-level metadata (title, description, owner, etc.) and an empty list of items. You will now be able to refer to this collection using it's `slug`. +It will return a [`Collection`] object with the high-level metadata (title, description, owner, etc.) and an empty list of items. You will now be able to refer to this collection using its `slug`. ```py >>> collection.slug diff --git a/docs/source/en/guides/community.md b/docs/source/en/guides/community.md index df4a2a28bb..8f55a761c4 100644 --- a/docs/source/en/guides/community.md +++ b/docs/source/en/guides/community.md @@ -1,4 +1,4 @@ - @@ -80,7 +80,7 @@ with more detailed information about the Discussion or Pull Request. Information and renames of the Discussion via [`DiscussionWithDetails.events`]. In case of a Pull Request, you can retrieve the raw git diff with [`DiscussionWithDetails.diff`]. All the commits of the -Pull Request are listed in [`DiscussionWithDetails.events`]. +Pull Requests are listed in [`DiscussionWithDetails.events`]. ## Create and edit a Discussion or Pull Request programmatically diff --git a/docs/source/en/guides/download.md b/docs/source/en/guides/download.md index 1eb8250d20..254c72d165 100644 --- a/docs/source/en/guides/download.md +++ b/docs/source/en/guides/download.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/guides/hf_file_system.md b/docs/source/en/guides/hf_file_system.md index 504a0db836..d0b96a2bd4 100644 --- a/docs/source/en/guides/hf_file_system.md +++ b/docs/source/en/guides/hf_file_system.md @@ -1,10 +1,10 @@ - # Interact with the Hub through the Filesystem API -In addition to the [`HfApi`], the `huggingface_hub` library provides [`HfFileSystem`], a pythonic [fsspec-compatible](https://filesystem-spec.readthedocs.io/en/latest/) file interface to the Hugging Face Hub. The [`HfFileSystem`] builds of top of the [`HfApi`] and offers typical filesystem style operations like `cp`, `mv`, `ls`, `du`, `glob`, `get_file`, and `put_file`. +In addition to the [`HfApi`], the `huggingface_hub` library provides [`HfFileSystem`], a pythonic [fsspec-compatible](https://filesystem-spec.readthedocs.io/en/latest/) file interface to the Hugging Face Hub. The [`HfFileSystem`] builds on top of the [`HfApi`] and offers typical filesystem style operations like `cp`, `mv`, `ls`, `du`, `glob`, `get_file`, and `put_file`. ## Usage diff --git a/docs/source/en/guides/inference.md b/docs/source/en/guides/inference.md index 92207658cd..07a5ca5014 100644 --- a/docs/source/en/guides/inference.md +++ b/docs/source/en/guides/inference.md @@ -1,4 +1,4 @@ - @@ -77,7 +77,7 @@ ChatCompletionOutput( ) ``` -In this example, we specified which model we want to use (`"meta-llama/Meta-Llama-3-8B-Instruct"`). You can find a list of compatible models [on this page](https://huggingface.co/models?other=conversational&sort=likes). We then gave a list of messages to complete (here, a single question) and passed an additional parameter to API (`max_token=100`). The output is a `ChatCompletionOutput` object that follows the OpenAI specification. The generated content can be access with `output.choices[0].message.content`. For more details, check out the [`~InferenceClient.chat_completion`] documentation. +In this example, we specified which model we want to use (`"meta-llama/Meta-Llama-3-8B-Instruct"`). You can find a list of compatible models [on this page](https://huggingface.co/models?other=conversational&sort=likes). We then gave a list of messages to complete (here, a single question) and passed an additional parameter to API (`max_token=100`). The output is a `ChatCompletionOutput` object that follows the OpenAI specification. The generated content can be accessed with `output.choices[0].message.content`. For more details, check out the [`~InferenceClient.chat_completion`] documentation. @@ -176,7 +176,7 @@ for chunk in output: print(chunk.choices[0].delta.content) ``` -And that's it! The only required changes are to replace `from openai import OpenAI` by `from huggingface_hub import InferenceClient` and `client = OpenAI(...)` by `client = InferenceClient(...)`. You can chose any LLM model from the Hugging Face Hub by passing its model id as `model` parameter. [Here is a list](https://huggingface.co/models?pipeline_tag=text-generation&other=conversational,text-generation-inference&sort=trending) of supported models. For authentication, you should pass a valid [User Access Token](https://huggingface.co/settings/tokens) as `api_key` or authenticate using `huggingface_hub` (see the [authentication guide](https://huggingface.co/docs/huggingface_hub/quick-start#authentication)). +And that's it! The only required changes are to replace `from openai import OpenAI` by `from huggingface_hub import InferenceClient` and `client = OpenAI(...)` by `client = InferenceClient(...)`. You can choose any LLM model from the Hugging Face Hub by passing its model id as `model` parameter. [Here is a list](https://huggingface.co/models?pipeline_tag=text-generation&other=conversational,text-generation-inference&sort=trending) of supported models. For authentication, you should pass a valid [User Access Token](https://huggingface.co/settings/tokens) as `api_key` or authenticate using `huggingface_hub` (see the [authentication guide](https://huggingface.co/docs/huggingface_hub/quick-start#authentication)). All input parameters and output format are strictly the same. In particular, you can pass `stream=True` to receive tokens as they are generated. You can also use the [`AsyncInferenceClient`] to run inference using `asyncio`: @@ -201,7 +201,7 @@ asyncio.run(main()) ``` You might wonder why using [`InferenceClient`] instead of OpenAI's client? There are a few reasons for that: -1. [`InferenceClient`] is configured for Hugging Face services. You don't need to provide a `base_url` to run models on the serverless Inference API. You also don't need to provide a `token` or `api_key` if you machine is already correctly logged in. +1. [`InferenceClient`] is configured for Hugging Face services. You don't need to provide a `base_url` to run models on the serverless Inference API. You also don't need to provide a `token` or `api_key` if your machine is already correctly logged in. 2. [`InferenceClient`] is tailored for both Text-Generation-Inference (TGI) and `transformers` frameworks, meaning you are assured it will always be on-par with the latest updates. 3. [`InferenceClient`] is integrated with our Inference Endpoints service, making it easier to launch an Inference Endpoint, check its status and run inference on it. Check out the [Inference Endpoints](./inference_endpoints.md) guide for more details. @@ -285,7 +285,7 @@ After installation all async API endpoints are available via [`AsyncInferenceCli strictly the same as the sync-only version. ```py -# Code must be run in a asyncio concurrent context. +# Code must be run in an asyncio concurrent context. # $ python -m asyncio >>> from huggingface_hub import AsyncInferenceClient >>> client = AsyncInferenceClient() diff --git a/docs/source/en/guides/integrations.md b/docs/source/en/guides/integrations.md index 1b7a8080c2..26018356c5 100644 --- a/docs/source/en/guides/integrations.md +++ b/docs/source/en/guides/integrations.md @@ -1,4 +1,4 @@ - @@ -39,7 +39,7 @@ Implementation can differ between libraries, but the workflow is often similar. ### from_pretrained -This is how a `from_pretrained` method usually look like: +This is how a `from_pretrained` method usually looks like: ```python def from_pretrained(model_id: str) -> MyModelClass: @@ -390,7 +390,7 @@ class VoiceCraft(nn.Module): ... ``` -One solution can be to update the `__init__` signature to `def __init__(self, pattern: str, hidden_size: int)` and update all snippets that instantiates your class. This is a perfectly valid way to fix it but it might break downstream applications using your library. +One solution can be to update the `__init__` signature to `def __init__(self, pattern: str, hidden_size: int)` and update all snippets that instantiate your class. This is a perfectly valid way to fix it but it might break downstream applications using your library. Another solution is to provide a simple encoder/decoder to convert `argparse.Namespace` to a dictionary. diff --git a/docs/source/en/guides/manage-cache.md b/docs/source/en/guides/manage-cache.md index aad3be96c8..521a50b21f 100644 --- a/docs/source/en/guides/manage-cache.md +++ b/docs/source/en/guides/manage-cache.md @@ -1,4 +1,4 @@ - @@ -101,13 +101,13 @@ on the Hub. Its structure is the same as the `snapshots` folder with 1 subfolder Unlike the `snapshots` folder, files are simple empty files (no symlinks). In this example, the file `"config_that_does_not_exist.json"` does not exist on the Hub for the revision `"aaaaaa"`. -As it only stores empty files, this folder is neglectable is term of disk usage. +As it only stores empty files, this folder is neglectable in term of disk usage. So now you might wonder, why is this information even relevant? In some cases, a framework tries to load optional files for a model. Saving the non-existence of optional files makes it faster to load a model as it saves 1 HTTP call per possible optional file. This is for example the case in `transformers` where each tokenizer can support additional files. -The first time you load the tokenizer on your machine, it will cache which optional files exists (and +The first time you load the tokenizer on your machine, it will cache which optional files exist (and which doesn't) to make the loading time faster for the next initializations. To test if a file is cached locally (without making any HTTP request), you can use the [`try_to_load_from_cache`] diff --git a/docs/source/en/guides/manage-spaces.md b/docs/source/en/guides/manage-spaces.md index 898c8b1fb5..8890101fbb 100644 --- a/docs/source/en/guides/manage-spaces.md +++ b/docs/source/en/guides/manage-spaces.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/guides/model-cards.md b/docs/source/en/guides/model-cards.md index e1638e3f3a..0c9f52a2cc 100644 --- a/docs/source/en/guides/model-cards.md +++ b/docs/source/en/guides/model-cards.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/guides/overview.md b/docs/source/en/guides/overview.md index dd2813ea8d..501fa78d37 100644 --- a/docs/source/en/guides/overview.md +++ b/docs/source/en/guides/overview.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/guides/repository.md b/docs/source/en/guides/repository.md index adfc881298..6426fd136a 100644 --- a/docs/source/en/guides/repository.md +++ b/docs/source/en/guides/repository.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/guides/search.md b/docs/source/en/guides/search.md index e5e50e0c29..ce0f6c0bdc 100644 --- a/docs/source/en/guides/search.md +++ b/docs/source/en/guides/search.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/guides/upload.md b/docs/source/en/guides/upload.md index b2658f5c68..d12ff09990 100644 --- a/docs/source/en/guides/upload.md +++ b/docs/source/en/guides/upload.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/guides/webhooks.md b/docs/source/en/guides/webhooks.md index 3d9856c920..064a6cfa99 100644 --- a/docs/source/en/guides/webhooks.md +++ b/docs/source/en/guides/webhooks.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/index.md b/docs/source/en/index.md index 0095c26700..900d26b346 100644 --- a/docs/source/en/index.md +++ b/docs/source/en/index.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/installation.md b/docs/source/en/installation.md index c769d75fbe..89ddaff0d9 100644 --- a/docs/source/en/installation.md +++ b/docs/source/en/installation.md @@ -1,4 +1,4 @@ - @@ -145,7 +145,7 @@ encounter any undocumented problem by opening [an issue on Github](https://githu - `huggingface_hub`'s cache system relies on symlinks to efficiently cache files downloaded from the Hub. On Windows, you must activate developer mode or run your script as admin to -enable symlinks. If they are not activated, the cache-system still works but in an non-optimized +enable symlinks. If they are not activated, the cache-system still works but in a non-optimized manner. Please read [the cache limitations](./guides/manage-cache#limitations) section for more details. - Filepaths on the Hub can have special characters (e.g. `"path/to?/my/file"`). Windows is more restrictive on [special characters](https://learn.microsoft.com/en-us/windows/win32/intl/character-sets-used-in-file-names) diff --git a/docs/source/en/package_reference/authentication.md b/docs/source/en/package_reference/authentication.md index 1577b5bc29..84c7344d22 100644 --- a/docs/source/en/package_reference/authentication.md +++ b/docs/source/en/package_reference/authentication.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/cache.md b/docs/source/en/package_reference/cache.md index ea8cad29c7..83bb1b956a 100644 --- a/docs/source/en/package_reference/cache.md +++ b/docs/source/en/package_reference/cache.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/cards.md b/docs/source/en/package_reference/cards.md index 99fc1196d2..c3ccfbe1ad 100644 --- a/docs/source/en/package_reference/cards.md +++ b/docs/source/en/package_reference/cards.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/collections.md b/docs/source/en/package_reference/collections.md index 8b54d5a744..1678a88d0c 100644 --- a/docs/source/en/package_reference/collections.md +++ b/docs/source/en/package_reference/collections.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/community.md b/docs/source/en/package_reference/community.md index d41d45c8a6..50ae75e054 100644 --- a/docs/source/en/package_reference/community.md +++ b/docs/source/en/package_reference/community.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/environment_variables.md b/docs/source/en/package_reference/environment_variables.md index 15fe3ad3b8..2930a462fa 100644 --- a/docs/source/en/package_reference/environment_variables.md +++ b/docs/source/en/package_reference/environment_variables.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/file_download.md b/docs/source/en/package_reference/file_download.md index 1bc5b21478..26a033c5f1 100644 --- a/docs/source/en/package_reference/file_download.md +++ b/docs/source/en/package_reference/file_download.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/hf_api.md b/docs/source/en/package_reference/hf_api.md index 38c8990469..4c77b44aaa 100644 --- a/docs/source/en/package_reference/hf_api.md +++ b/docs/source/en/package_reference/hf_api.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/hf_file_system.md b/docs/source/en/package_reference/hf_file_system.md index 097c798fa7..89fcf23887 100644 --- a/docs/source/en/package_reference/hf_file_system.md +++ b/docs/source/en/package_reference/hf_file_system.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/inference_client.md b/docs/source/en/package_reference/inference_client.md index 2a6b37c61b..5cfef6be0d 100644 --- a/docs/source/en/package_reference/inference_client.md +++ b/docs/source/en/package_reference/inference_client.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/inference_types.md b/docs/source/en/package_reference/inference_types.md index aa63c64b68..368a716cf3 100644 --- a/docs/source/en/package_reference/inference_types.md +++ b/docs/source/en/package_reference/inference_types.md @@ -1,5 +1,5 @@ - diff --git a/docs/source/en/package_reference/mixins.md b/docs/source/en/package_reference/mixins.md index 04e66c8f2d..42c253e710 100644 --- a/docs/source/en/package_reference/mixins.md +++ b/docs/source/en/package_reference/mixins.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/overview.md b/docs/source/en/package_reference/overview.md index 1265c1efef..1bb51ac910 100644 --- a/docs/source/en/package_reference/overview.md +++ b/docs/source/en/package_reference/overview.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/repository.md b/docs/source/en/package_reference/repository.md index 0a8ebf284c..de7851d6a9 100644 --- a/docs/source/en/package_reference/repository.md +++ b/docs/source/en/package_reference/repository.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/serialization.md b/docs/source/en/package_reference/serialization.md index 841d9d3011..0149855e02 100644 --- a/docs/source/en/package_reference/serialization.md +++ b/docs/source/en/package_reference/serialization.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/space_runtime.md b/docs/source/en/package_reference/space_runtime.md index 75fac898fd..364c43be35 100644 --- a/docs/source/en/package_reference/space_runtime.md +++ b/docs/source/en/package_reference/space_runtime.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/tensorboard.md b/docs/source/en/package_reference/tensorboard.md index 20fa4a3885..14addbb5ba 100644 --- a/docs/source/en/package_reference/tensorboard.md +++ b/docs/source/en/package_reference/tensorboard.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/utilities.md b/docs/source/en/package_reference/utilities.md index 5ea9d56b46..80fe3148ff 100644 --- a/docs/source/en/package_reference/utilities.md +++ b/docs/source/en/package_reference/utilities.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/package_reference/webhooks_server.md b/docs/source/en/package_reference/webhooks_server.md index 3d6847a3e0..a9115cbb03 100644 --- a/docs/source/en/package_reference/webhooks_server.md +++ b/docs/source/en/package_reference/webhooks_server.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/en/quick-start.md b/docs/source/en/quick-start.md index dbbe0d2a91..b8a2b67005 100644 --- a/docs/source/en/quick-start.md +++ b/docs/source/en/quick-start.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/fr/concepts/git_vs_http.md b/docs/source/fr/concepts/git_vs_http.md index 8a4829b8ff..8ccc31b69c 100644 --- a/docs/source/fr/concepts/git_vs_http.md +++ b/docs/source/fr/concepts/git_vs_http.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/fr/guides/integrations.md b/docs/source/fr/guides/integrations.md index 5813707f90..3adcc8f9f7 100644 --- a/docs/source/fr/guides/integrations.md +++ b/docs/source/fr/guides/integrations.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/fr/index.md b/docs/source/fr/index.md index e0ddf64ae5..51a19a3ea3 100644 --- a/docs/source/fr/index.md +++ b/docs/source/fr/index.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/fr/installation.md b/docs/source/fr/installation.md index a06a838a95..219808f823 100644 --- a/docs/source/fr/installation.md +++ b/docs/source/fr/installation.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/fr/quick-start.md b/docs/source/fr/quick-start.md index f11d5412c3..1a99d830d7 100644 --- a/docs/source/fr/quick-start.md +++ b/docs/source/fr/quick-start.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/hi/index.md b/docs/source/hi/index.md index e2f83b7d56..99cd7aeccb 100644 --- a/docs/source/hi/index.md +++ b/docs/source/hi/index.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/hi/installation.md b/docs/source/hi/installation.md index d154d0fc5a..4587838950 100644 --- a/docs/source/hi/installation.md +++ b/docs/source/hi/installation.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/hi/quick-start.md b/docs/source/hi/quick-start.md index 88cf26f02f..3ce8a78a7a 100644 --- a/docs/source/hi/quick-start.md +++ b/docs/source/hi/quick-start.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/concepts/git_vs_http.md b/docs/source/ko/concepts/git_vs_http.md index ac9761ec7c..7f2bd9933f 100644 --- a/docs/source/ko/concepts/git_vs_http.md +++ b/docs/source/ko/concepts/git_vs_http.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/cli.md b/docs/source/ko/guides/cli.md index 6dbd0fd3ef..13c4352235 100644 --- a/docs/source/ko/guides/cli.md +++ b/docs/source/ko/guides/cli.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/collections.md b/docs/source/ko/guides/collections.md index bb7db4bb36..69e75b92cf 100644 --- a/docs/source/ko/guides/collections.md +++ b/docs/source/ko/guides/collections.md @@ -1,4 +1,4 @@ - # Collections[[collections]] diff --git a/docs/source/ko/guides/community.md b/docs/source/ko/guides/community.md index 1affc7861e..76ecb23e25 100644 --- a/docs/source/ko/guides/community.md +++ b/docs/source/ko/guides/community.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/download.md b/docs/source/ko/guides/download.md index e4d52d5cca..ac658dde4e 100644 --- a/docs/source/ko/guides/download.md +++ b/docs/source/ko/guides/download.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/hf_file_system.md b/docs/source/ko/guides/hf_file_system.md index e3f9b9a521..74a02f71f5 100644 --- a/docs/source/ko/guides/hf_file_system.md +++ b/docs/source/ko/guides/hf_file_system.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/inference.md b/docs/source/ko/guides/inference.md index f59f2b52b8..04ac68ad41 100644 --- a/docs/source/ko/guides/inference.md +++ b/docs/source/ko/guides/inference.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/integrations.md b/docs/source/ko/guides/integrations.md index f251785a07..f0946bc298 100644 --- a/docs/source/ko/guides/integrations.md +++ b/docs/source/ko/guides/integrations.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/manage-cache.md b/docs/source/ko/guides/manage-cache.md index 9e5c1a674f..7b54c7eaab 100644 --- a/docs/source/ko/guides/manage-cache.md +++ b/docs/source/ko/guides/manage-cache.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/manage-spaces.md b/docs/source/ko/guides/manage-spaces.md index 7ee3ccde21..f629d121e0 100644 --- a/docs/source/ko/guides/manage-spaces.md +++ b/docs/source/ko/guides/manage-spaces.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/model-cards.md b/docs/source/ko/guides/model-cards.md index 15bdd320fc..41bc4f1317 100644 --- a/docs/source/ko/guides/model-cards.md +++ b/docs/source/ko/guides/model-cards.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/overview.md b/docs/source/ko/guides/overview.md index 318f933c4d..9e171c97f0 100644 --- a/docs/source/ko/guides/overview.md +++ b/docs/source/ko/guides/overview.md @@ -1,4 +1,4 @@ - @@ -118,4 +118,4 @@ rendered properly in your Markdown viewer. - + diff --git a/docs/source/ko/guides/repository.md b/docs/source/ko/guides/repository.md index 56328b419c..ab6e7bea34 100644 --- a/docs/source/ko/guides/repository.md +++ b/docs/source/ko/guides/repository.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/search.md b/docs/source/ko/guides/search.md index e5e37e7c68..ef739d4bde 100644 --- a/docs/source/ko/guides/search.md +++ b/docs/source/ko/guides/search.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/upload.md b/docs/source/ko/guides/upload.md index e097870b01..fd704d0ba6 100644 --- a/docs/source/ko/guides/upload.md +++ b/docs/source/ko/guides/upload.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/guides/webhooks_server.md b/docs/source/ko/guides/webhooks_server.md index adc94e1877..39049e160a 100644 --- a/docs/source/ko/guides/webhooks_server.md +++ b/docs/source/ko/guides/webhooks_server.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/index.md b/docs/source/ko/index.md index 53785d8fe3..b5428b6a7c 100644 --- a/docs/source/ko/index.md +++ b/docs/source/ko/index.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/installation.md b/docs/source/ko/installation.md index 346189835a..b70808b3b7 100644 --- a/docs/source/ko/installation.md +++ b/docs/source/ko/installation.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/cache.md b/docs/source/ko/package_reference/cache.md index 2e155c7f63..53c6d358ee 100644 --- a/docs/source/ko/package_reference/cache.md +++ b/docs/source/ko/package_reference/cache.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/collections.md b/docs/source/ko/package_reference/collections.md index 3b7bec4826..d8276953b0 100644 --- a/docs/source/ko/package_reference/collections.md +++ b/docs/source/ko/package_reference/collections.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/community.md b/docs/source/ko/package_reference/community.md index 264af6fba5..9e598efc77 100644 --- a/docs/source/ko/package_reference/community.md +++ b/docs/source/ko/package_reference/community.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/environment_variables.md b/docs/source/ko/package_reference/environment_variables.md index 455e5e49ab..a4d26123e4 100644 --- a/docs/source/ko/package_reference/environment_variables.md +++ b/docs/source/ko/package_reference/environment_variables.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/file_download.md b/docs/source/ko/package_reference/file_download.md index 82e67a83c6..b3b36f5659 100644 --- a/docs/source/ko/package_reference/file_download.md +++ b/docs/source/ko/package_reference/file_download.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/hf_api.md b/docs/source/ko/package_reference/hf_api.md index 2efe5c965a..f3363fce61 100644 --- a/docs/source/ko/package_reference/hf_api.md +++ b/docs/source/ko/package_reference/hf_api.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/hf_file_system.md b/docs/source/ko/package_reference/hf_file_system.md index fb27660d8b..bebbeda1f1 100644 --- a/docs/source/ko/package_reference/hf_file_system.md +++ b/docs/source/ko/package_reference/hf_file_system.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/inference_client.md b/docs/source/ko/package_reference/inference_client.md index d3ecfcaa87..2ccab6366f 100644 --- a/docs/source/ko/package_reference/inference_client.md +++ b/docs/source/ko/package_reference/inference_client.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/inference_types.md b/docs/source/ko/package_reference/inference_types.md index 393481e10f..6ae2736fba 100644 --- a/docs/source/ko/package_reference/inference_types.md +++ b/docs/source/ko/package_reference/inference_types.md @@ -1,5 +1,5 @@ - diff --git a/docs/source/ko/package_reference/login.md b/docs/source/ko/package_reference/login.md index 8ab39c2208..dbfa8a0650 100644 --- a/docs/source/ko/package_reference/login.md +++ b/docs/source/ko/package_reference/login.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/mixins.md b/docs/source/ko/package_reference/mixins.md index 53aaf9303a..4a4a84ad9e 100644 --- a/docs/source/ko/package_reference/mixins.md +++ b/docs/source/ko/package_reference/mixins.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/overview.md b/docs/source/ko/package_reference/overview.md index 87fcb99ea1..f55369302b 100644 --- a/docs/source/ko/package_reference/overview.md +++ b/docs/source/ko/package_reference/overview.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/repository.md b/docs/source/ko/package_reference/repository.md index b513137cc9..fc70e3e203 100644 --- a/docs/source/ko/package_reference/repository.md +++ b/docs/source/ko/package_reference/repository.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/serialization.md b/docs/source/ko/package_reference/serialization.md index d026052eda..25901237bf 100644 --- a/docs/source/ko/package_reference/serialization.md +++ b/docs/source/ko/package_reference/serialization.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/space_runtime.md b/docs/source/ko/package_reference/space_runtime.md index 8f22a5361f..03bc46cd13 100644 --- a/docs/source/ko/package_reference/space_runtime.md +++ b/docs/source/ko/package_reference/space_runtime.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/tensorboard.md b/docs/source/ko/package_reference/tensorboard.md index 395a733756..77f87e5ea0 100644 --- a/docs/source/ko/package_reference/tensorboard.md +++ b/docs/source/ko/package_reference/tensorboard.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/utilities.md b/docs/source/ko/package_reference/utilities.md index 592092f64a..a76e9d474b 100644 --- a/docs/source/ko/package_reference/utilities.md +++ b/docs/source/ko/package_reference/utilities.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/package_reference/webhooks_server.md b/docs/source/ko/package_reference/webhooks_server.md index 9712c6c0be..8764fb2f7f 100644 --- a/docs/source/ko/package_reference/webhooks_server.md +++ b/docs/source/ko/package_reference/webhooks_server.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/ko/quick-start.md b/docs/source/ko/quick-start.md index 9a6eb23b5a..30e07331e3 100644 --- a/docs/source/ko/quick-start.md +++ b/docs/source/ko/quick-start.md @@ -1,4 +1,4 @@ - diff --git a/docs/source/tm/index.md b/docs/source/tm/index.md index 4b524eed3e..a4fdc5e4b9 100644 --- a/docs/source/tm/index.md +++ b/docs/source/tm/index.md @@ -1,4 +1,4 @@ - diff --git a/src/huggingface_hub/inference/_common.py b/src/huggingface_hub/inference/_common.py index a19636a506..a5d80f282a 100644 --- a/src/huggingface_hub/inference/_common.py +++ b/src/huggingface_hub/inference/_common.py @@ -81,7 +81,7 @@ @dataclass class ModelStatus: """ - This Dataclass represents the the model status in the Hugging Face Inference API. + This Dataclass represents the model status in the Hugging Face Inference API. Args: loaded (`bool`): @@ -213,7 +213,7 @@ def _open_as_binary(content: Optional[ContentT]) -> Generator[Optional[BinaryT], def _b64_encode(content: ContentT) -> str: - """Encode a raw file (image, audio) into base64. Can be byes, an opened file, a path or a URL.""" + """Encode a raw file (image, audio) into base64. Can be bytes, an opened file, a path or a URL.""" with _open_as_binary(content) as data: data_as_bytes = data if isinstance(data, bytes) else data.read() return base64.b64encode(data_as_bytes).decode() diff --git a/utils/generate_async_inference_client.py b/utils/generate_async_inference_client.py index 832049ad5d..a4b92f1d64 100644 --- a/utils/generate_async_inference_client.py +++ b/utils/generate_async_inference_client.py @@ -102,7 +102,7 @@ def check_async_client(update: bool) -> NoReturn: else: print( "❌ Expected content mismatch in `./src/huggingface_hub/inference/_generated/_async_client.py`.\n It" - " is most likely that you modified some InferenceClient code and did not update the the" + " is most likely that you modified some InferenceClient code and did not update the" " AsyncInferenceClient one.\n Please run `make style` or `python" " utils/generate_async_inference_client.py --update`." ) diff --git a/utils/generate_inference_types.py b/utils/generate_inference_types.py index 23ab7c7b9c..5f9675d60a 100644 --- a/utils/generate_inference_types.py +++ b/utils/generate_inference_types.py @@ -98,7 +98,7 @@ ] REFERENCE_PACKAGE_EN_CONTENT = """ - @@ -119,7 +119,7 @@ """ REFERENCE_PACKAGE_KO_CONTENT = """ - From c547c839dbbe0163e3ca422d017daad7c7f9361f Mon Sep 17 00:00:00 2001 From: Lucain Date: Fri, 25 Oct 2024 11:19:35 +0200 Subject: [PATCH 6/6] Deprecate is_write_action and write_permission=True when login (#2632) * Deprecate is_write_action and write_permission=True when login * fix mypy --- src/huggingface_hub/_login.py | 92 ++++++++----------- src/huggingface_hub/file_download.py | 12 +-- src/huggingface_hub/hf_api.py | 2 - src/huggingface_hub/inference/_client.py | 4 +- .../inference/_generated/_async_client.py | 4 +- src/huggingface_hub/utils/_headers.py | 34 ++----- tests/test_auth.py | 16 ---- tests/test_utils_headers.py | 13 --- 8 files changed, 59 insertions(+), 118 deletions(-) diff --git a/src/huggingface_hub/_login.py b/src/huggingface_hub/_login.py index 2901437752..b14702201d 100644 --- a/src/huggingface_hub/_login.py +++ b/src/huggingface_hub/_login.py @@ -15,7 +15,6 @@ import os import subprocess -from functools import partial from getpass import getpass from pathlib import Path from typing import Optional @@ -42,6 +41,7 @@ _save_token, get_stored_tokens, ) +from .utils._deprecation import _deprecate_arguments, _deprecate_positional_args logger = logging.get_logger(__name__) @@ -55,8 +55,15 @@ """ +@_deprecate_arguments( + version="1.0", + deprecated_args="write_permission", + custom_message="Fine-grained tokens added complexity to the permissions, making it irrelevant to check if a token has 'write' access.", +) +@_deprecate_positional_args(version="1.0") def login( token: Optional[str] = None, + *, add_to_git_credential: bool = False, new_session: bool = True, write_permission: bool = False, @@ -97,8 +104,8 @@ def login( to the end user. new_session (`bool`, defaults to `True`): If `True`, will request a token even if one is already saved on the machine. - write_permission (`bool`, defaults to `False`): - If `True`, requires a token with write permission. + write_permission (`bool`): + Ignored and deprecated argument. Raises: [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) If an organization token is passed. Only personal account tokens are valid @@ -116,11 +123,11 @@ def login( "`--add-to-git-credential` if using via `huggingface-cli` if " "you want to set the git credential as well." ) - _login(token, add_to_git_credential=add_to_git_credential, write_permission=write_permission) + _login(token, add_to_git_credential=add_to_git_credential) elif is_notebook(): - notebook_login(new_session=new_session, write_permission=write_permission) + notebook_login(new_session=new_session) else: - interpreter_login(new_session=new_session, write_permission=write_permission) + interpreter_login(new_session=new_session) def logout(token_name: Optional[str] = None) -> None: @@ -235,7 +242,13 @@ def auth_list() -> None: ### -def interpreter_login(new_session: bool = True, write_permission: bool = False) -> None: +@_deprecate_arguments( + version="1.0", + deprecated_args="write_permission", + custom_message="Fine-grained tokens added complexity to the permissions, making it irrelevant to check if a token has 'write' access.", +) +@_deprecate_positional_args(version="1.0") +def interpreter_login(*, new_session: bool = True, write_permission: bool = False) -> None: """ Displays a prompt to log in to the HF website and store the token. @@ -248,11 +261,10 @@ def interpreter_login(new_session: bool = True, write_permission: bool = False) Args: new_session (`bool`, defaults to `True`): If `True`, will request a token even if one is already saved on the machine. - write_permission (`bool`, defaults to `False`): - If `True`, requires a token with write permission. - + write_permission (`bool`): + Ignored and deprecated argument. """ - if not new_session and _current_token_okay(write_permission=write_permission): + if not new_session and get_token() is not None: logger.info("User is already logged in.") return @@ -275,11 +287,7 @@ def interpreter_login(new_session: bool = True, write_permission: bool = False) token = getpass("Enter your token (input will not be visible): ") add_to_git_credential = _ask_for_confirmation_no_tui("Add token as git credential?") - _login( - token=token, - add_to_git_credential=add_to_git_credential, - write_permission=write_permission, - ) + _login(token=token, add_to_git_credential=add_to_git_credential) ### @@ -306,7 +314,13 @@ def interpreter_login(new_session: bool = True, write_permission: bool = False) notebooks. """ -def notebook_login(new_session: bool = True, write_permission: bool = False) -> None: +@_deprecate_arguments( + version="1.0", + deprecated_args="write_permission", + custom_message="Fine-grained tokens added complexity to the permissions, making it irrelevant to check if a token has 'write' access.", +) +@_deprecate_positional_args(version="1.0") +def notebook_login(*, new_session: bool = True, write_permission: bool = False) -> None: """ Displays a widget to log in to the HF website and store the token. @@ -319,8 +333,8 @@ def notebook_login(new_session: bool = True, write_permission: bool = False) -> Args: new_session (`bool`, defaults to `True`): If `True`, will request a token even if one is already saved on the machine. - write_permission (`bool`, defaults to `False`): - If `True`, requires a token with write permission. + write_permission (`bool`): + Ignored and deprecated argument. """ try: import ipywidgets.widgets as widgets # type: ignore @@ -330,7 +344,7 @@ def notebook_login(new_session: bool = True, write_permission: bool = False) -> "The `notebook_login` function can only be used in a notebook (Jupyter or" " Colab) and you need the `ipywidgets` module: `pip install ipywidgets`." ) - if not new_session and _current_token_okay(write_permission=write_permission): + if not new_session and get_token() is not None: logger.info("User is already logged in.") return @@ -353,14 +367,8 @@ def notebook_login(new_session: bool = True, write_permission: bool = False) -> display(login_token_widget) # On click events - def login_token_event(t, write_permission: bool = False): - """ - Event handler for the login button. - - Args: - write_permission (`bool`, defaults to `False`): - If `True`, requires a token with write permission. - """ + def login_token_event(t): + """Event handler for the login button.""" token = token_widget.value add_to_git_credential = git_checkbox_widget.value # Erase token and clear value to make sure it's not saved in the notebook. @@ -369,14 +377,14 @@ def login_token_event(t, write_permission: bool = False): login_token_widget.children = [widgets.Label("Connecting...")] try: with capture_output() as captured: - _login(token, add_to_git_credential=add_to_git_credential, write_permission=write_permission) + _login(token, add_to_git_credential=add_to_git_credential) message = captured.getvalue() except Exception as error: message = str(error) # Print result (success message or error) login_token_widget.children = [widgets.Label(line) for line in message.split("\n") if line.strip()] - token_finish_button.on_click(partial(login_token_event, write_permission=write_permission)) + token_finish_button.on_click(login_token_event) ### @@ -387,7 +395,6 @@ def login_token_event(t, write_permission: bool = False): def _login( token: str, add_to_git_credential: bool, - write_permission: bool = False, ) -> None: from .hf_api import whoami # avoid circular import @@ -396,11 +403,6 @@ def _login( token_info = whoami(token) permission = token_info["auth"]["accessToken"]["role"] - if write_permission and permission != "write": - raise ValueError( - "Token is valid but is 'read-only' and a 'write' token is required.\nPlease provide a new token with" - " correct permission." - ) logger.info(f"Token is valid (permission: {permission}).") token_name = token_info["auth"]["accessToken"]["displayName"] @@ -469,24 +471,6 @@ def _set_active_token( logger.info(f"Your token has been saved to {constants.HF_TOKEN_PATH}") -def _current_token_okay(write_permission: bool = False): - """Check if the current token is valid. - - Args: - write_permission (`bool`, defaults to `False`): - If `True`, requires a token with write permission. - - Returns: - `bool`: `True` if the current token is valid, `False` otherwise. - """ - from .hf_api import get_token_permission # avoid circular import - - permission = get_token_permission() - if permission is None or (write_permission and permission != "write"): - return False - return True - - def _is_git_credential_helper_configured() -> bool: """Check if a git credential helper is configured. diff --git a/src/huggingface_hub/file_download.py b/src/huggingface_hub/file_download.py index def44b3a34..46d5ccaead 100644 --- a/src/huggingface_hub/file_download.py +++ b/src/huggingface_hub/file_download.py @@ -821,7 +821,7 @@ def hf_hub_download( if repo_type not in constants.REPO_TYPES: raise ValueError(f"Invalid repo type: {repo_type}. Accepted repo types are: {str(constants.REPO_TYPES)}") - headers = build_hf_headers( + hf_headers = build_hf_headers( token=token, library_name=library_name, library_version=library_version, @@ -850,7 +850,7 @@ def hf_hub_download( # HTTP info endpoint=endpoint, etag_timeout=etag_timeout, - headers=headers, + headers=hf_headers, proxies=proxies, token=token, # Additional options @@ -870,7 +870,7 @@ def hf_hub_download( # HTTP info endpoint=endpoint, etag_timeout=etag_timeout, - headers=headers, + headers=hf_headers, proxies=proxies, token=token, # Additional options @@ -1283,20 +1283,20 @@ def get_hf_file_metadata( A [`HfFileMetadata`] object containing metadata such as location, etag, size and commit_hash. """ - headers = build_hf_headers( + hf_headers = build_hf_headers( token=token, library_name=library_name, library_version=library_version, user_agent=user_agent, headers=headers, ) - headers["Accept-Encoding"] = "identity" # prevent any compression => we want to know the real size of the file + hf_headers["Accept-Encoding"] = "identity" # prevent any compression => we want to know the real size of the file # Retrieve metadata r = _request_wrapper( method="HEAD", url=url, - headers=headers, + headers=hf_headers, allow_redirects=False, follow_relative_redirects=True, proxies=proxies, diff --git a/src/huggingface_hub/hf_api.py b/src/huggingface_hub/hf_api.py index 5ab1aa0ebb..0b53fc877d 100644 --- a/src/huggingface_hub/hf_api.py +++ b/src/huggingface_hub/hf_api.py @@ -9082,7 +9082,6 @@ def delete_webhook(self, webhook_id: str, *, token: Union[bool, str, None] = Non def _build_hf_headers( self, token: Union[bool, str, None] = None, - is_write_action: bool = False, library_name: Optional[str] = None, library_version: Optional[str] = None, user_agent: Union[Dict, str, None] = None, @@ -9096,7 +9095,6 @@ def _build_hf_headers( token = self.token return build_hf_headers( token=token, - is_write_action=is_write_action, library_name=library_name or self.library_name, library_version=library_version or self.library_version, user_agent=user_agent or self.user_agent, diff --git a/src/huggingface_hub/inference/_client.py b/src/huggingface_hub/inference/_client.py index 8d5a8e6a38..ed473e6d11 100644 --- a/src/huggingface_hub/inference/_client.py +++ b/src/huggingface_hub/inference/_client.py @@ -178,7 +178,9 @@ def __init__( self.model: Optional[str] = model self.token: Union[str, bool, None] = token if token is not None else api_key - self.headers = CaseInsensitiveDict(build_hf_headers(token=self.token)) # 'authorization' + 'user-agent' + self.headers: CaseInsensitiveDict[str] = CaseInsensitiveDict( + build_hf_headers(token=self.token) # 'authorization' + 'user-agent' + ) if headers is not None: self.headers.update(headers) self.cookies = cookies diff --git a/src/huggingface_hub/inference/_generated/_async_client.py b/src/huggingface_hub/inference/_generated/_async_client.py index 5c3a8044fc..74888bc0b8 100644 --- a/src/huggingface_hub/inference/_generated/_async_client.py +++ b/src/huggingface_hub/inference/_generated/_async_client.py @@ -170,7 +170,9 @@ def __init__( self.model: Optional[str] = model self.token: Union[str, bool, None] = token if token is not None else api_key - self.headers = CaseInsensitiveDict(build_hf_headers(token=self.token)) # 'authorization' + 'user-agent' + self.headers: CaseInsensitiveDict[str] = CaseInsensitiveDict( + build_hf_headers(token=self.token) # 'authorization' + 'user-agent' + ) if headers is not None: self.headers.update(headers) self.cookies = cookies diff --git a/src/huggingface_hub/utils/_headers.py b/src/huggingface_hub/utils/_headers.py index 8b05e939db..300e6b4e9c 100644 --- a/src/huggingface_hub/utils/_headers.py +++ b/src/huggingface_hub/utils/_headers.py @@ -20,6 +20,7 @@ from .. import constants from ._auth import get_token +from ._deprecation import _deprecate_arguments from ._runtime import ( get_fastai_version, get_fastcore_version, @@ -35,15 +36,20 @@ from ._validators import validate_hf_hub_args +@_deprecate_arguments( + version="1.0", + deprecated_args="is_write_action", + custom_message="This argument is ignored and we let the server handle the permission error instead (if any).", +) @validate_hf_hub_args def build_hf_headers( *, token: Optional[Union[bool, str]] = None, - is_write_action: bool = False, library_name: Optional[str] = None, library_version: Optional[str] = None, user_agent: Union[Dict, str, None] = None, headers: Optional[Dict[str, str]] = None, + is_write_action: bool = False, ) -> Dict[str, str]: """ Build headers dictionary to send in a HF Hub call. @@ -68,9 +74,6 @@ def build_hf_headers( - if `False`, authorization header is not set - if `None`, the token is read from the machine only except if `HF_HUB_DISABLE_IMPLICIT_TOKEN` env variable is set. - is_write_action (`bool`, default to `False`): - Set to True if the API call requires a write access. If `True`, the token - will be validated (cannot be `None`, cannot start by `"api_org***"`). library_name (`str`, *optional*): The name of the library that is making the HTTP request. Will be added to the user-agent header. @@ -83,6 +86,8 @@ def build_hf_headers( headers (`dict`, *optional*): Additional headers to include in the request. Those headers take precedence over the ones generated by this function. + is_write_action (`bool`): + Ignored and deprecated argument. Returns: A `Dict` of headers to pass in your API call. @@ -105,9 +110,6 @@ def build_hf_headers( >>> build_hf_headers() # token is not sent {"user-agent": ...} - >>> build_hf_headers(token="api_org_***", is_write_action=True) - ValueError: You must use your personal account token for write-access methods. - >>> build_hf_headers(library_name="transformers", library_version="1.2.3") {"authorization": ..., "user-agent": "transformers/1.2.3; hf_hub/0.10.2; python/3.10.4; tensorflow/1.55"} ``` @@ -122,7 +124,6 @@ def build_hf_headers( """ # Get auth token to send token_to_send = get_token_to_send(token) - _validate_token_to_send(token_to_send, is_write_action=is_write_action) # Combine headers hf_headers = { @@ -171,23 +172,6 @@ def get_token_to_send(token: Optional[Union[bool, str]]) -> Optional[str]: return cached_token -def _validate_token_to_send(token: Optional[str], is_write_action: bool) -> None: - if is_write_action: - if token is None: - raise ValueError( - "Token is required (write-access action) but no token found. You need" - " to provide a token or be logged in to Hugging Face with" - " `huggingface-cli login` or `huggingface_hub.login`. See" - " https://huggingface.co/settings/tokens." - ) - if token.startswith("api_org"): - raise ValueError( - "You must use your personal account token for write-access methods. To" - " generate a write-access token, go to" - " https://huggingface.co/settings/tokens" - ) - - def _http_user_agent( *, library_name: Optional[str] = None, diff --git a/tests/test_auth.py b/tests/test_auth.py index fd1a18f641..457b9342ef 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -88,22 +88,6 @@ def test_login_success(self, mock_whoami): assert _get_token_by_name("test_token") == TOKEN assert _get_token_from_file() == TOKEN - @patch( - "huggingface_hub.hf_api.whoami", - return_value={ - "auth": { - "accessToken": { - "displayName": "test_token", - "role": "read", - "createdAt": "2024-01-01T00:00:00.000Z", - } - } - }, - ) - def test_login_errors(self, mock_whoami): - with pytest.raises(ValueError, match=r"Token is valid but is 'read-only' and a 'write' token is required.*"): - _login(TOKEN, add_to_git_credential=False, write_permission=True) - class TestLogout: def test_logout_deletes_files(self): diff --git a/tests/test_utils_headers.py b/tests/test_utils_headers.py index 89cce741c3..202f4283b0 100644 --- a/tests/test_utils_headers.py +++ b/tests/test_utils_headers.py @@ -46,19 +46,6 @@ def test_use_auth_token_none_no_cached_token(self, mock_get_token: Mock) -> None def test_use_auth_token_none_has_cached_token(self, mock_get_token: Mock) -> None: self.assertEqual(build_hf_headers(), FAKE_TOKEN_HEADER) - def test_write_action_org_token(self) -> None: - with self.assertRaises(ValueError): - build_hf_headers(use_auth_token=FAKE_TOKEN_ORG, is_write_action=True) - - @patch("huggingface_hub.utils._headers.get_token", return_value=None) - def test_write_action_none_token(self, mock_get_token: Mock) -> None: - with self.assertRaises(ValueError): - build_hf_headers(is_write_action=True) - - def test_write_action_use_auth_token_false(self) -> None: - with self.assertRaises(ValueError): - build_hf_headers(use_auth_token=False, is_write_action=True) - @patch("huggingface_hub.utils._headers.get_token", return_value=FAKE_TOKEN) def test_implicit_use_disabled(self, mock_get_token: Mock) -> None: with patch( # not as decorator to avoid friction with @handle_injection