diff --git a/contrib/spacy/test_spacy.py b/contrib/spacy/test_spacy.py index 5420219dbe..00d4c9b671 100644 --- a/contrib/spacy/test_spacy.py +++ b/contrib/spacy/test_spacy.py @@ -3,7 +3,7 @@ from spacy_huggingface_hub import push from huggingface_hub import delete_repo, hf_hub_download, model_info -from huggingface_hub.utils import HfHubHTTPError +from huggingface_hub.errors import HfHubHTTPError from ..utils import production_endpoint diff --git a/src/huggingface_hub/_commit_api.py b/src/huggingface_hub/_commit_api.py index ba0cfce238..229c19026f 100644 --- a/src/huggingface_hub/_commit_api.py +++ b/src/huggingface_hub/_commit_api.py @@ -16,11 +16,11 @@ from tqdm.contrib.concurrent import thread_map from .constants import ENDPOINT, HF_HUB_ENABLE_HF_TRANSFER +from .errors import EntryNotFoundError from .file_download import hf_hub_url from .lfs import UploadInfo, lfs_upload, post_lfs_batch_info from .utils import ( FORBIDDEN_FOLDERS, - EntryNotFoundError, chunk_iterable, get_session, hf_raise_for_status, diff --git a/src/huggingface_hub/_snapshot_download.py b/src/huggingface_hub/_snapshot_download.py index 7968c0a00b..6fbdce7b0c 100644 --- a/src/huggingface_hub/_snapshot_download.py +++ b/src/huggingface_hub/_snapshot_download.py @@ -13,14 +13,11 @@ HF_HUB_ENABLE_HF_TRANSFER, REPO_TYPES, ) +from .errors import GatedRepoError, LocalEntryNotFoundError, RepositoryNotFoundError, RevisionNotFoundError from .file_download import REGEX_COMMIT_HASH, hf_hub_download, repo_folder_name from .hf_api import DatasetInfo, HfApi, ModelInfo, SpaceInfo from .utils import ( - GatedRepoError, - LocalEntryNotFoundError, OfflineModeIsEnabled, - RepositoryNotFoundError, - RevisionNotFoundError, filter_repo_objects, logging, validate_hf_hub_args, diff --git a/src/huggingface_hub/_tensorboard_logger.py b/src/huggingface_hub/_tensorboard_logger.py index dee2c581a9..792dc7c4df 100644 --- a/src/huggingface_hub/_tensorboard_logger.py +++ b/src/huggingface_hub/_tensorboard_logger.py @@ -17,8 +17,9 @@ from typing import TYPE_CHECKING, List, Optional, Union from ._commit_scheduler import CommitScheduler +from .errors import EntryNotFoundError from .repocard import ModelCard -from .utils import EntryNotFoundError, experimental +from .utils import experimental # Depending on user's setup, SummaryWriter can come either from 'tensorboardX' diff --git a/src/huggingface_hub/commands/tag.py b/src/huggingface_hub/commands/tag.py index 7c6e9b2b7a..c3beab90a0 100644 --- a/src/huggingface_hub/commands/tag.py +++ b/src/huggingface_hub/commands/tag.py @@ -40,7 +40,7 @@ ) from huggingface_hub.hf_api import HfApi -from ..utils import HfHubHTTPError, RepositoryNotFoundError, RevisionNotFoundError +from ..errors import HfHubHTTPError, RepositoryNotFoundError, RevisionNotFoundError from ._cli_utils import ANSI diff --git a/src/huggingface_hub/commands/upload.py b/src/huggingface_hub/commands/upload.py index a42dd0f882..c5db1118e3 100644 --- a/src/huggingface_hub/commands/upload.py +++ b/src/huggingface_hub/commands/upload.py @@ -53,8 +53,9 @@ from huggingface_hub._commit_scheduler import CommitScheduler from huggingface_hub.commands import BaseHuggingfaceCLICommand from huggingface_hub.constants import HF_HUB_ENABLE_HF_TRANSFER +from huggingface_hub.errors import RevisionNotFoundError from huggingface_hub.hf_api import HfApi -from huggingface_hub.utils import RevisionNotFoundError, disable_progress_bars, enable_progress_bars +from huggingface_hub.utils import disable_progress_bars, enable_progress_bars logger = logging.get_logger(__name__) diff --git a/src/huggingface_hub/errors.py b/src/huggingface_hub/errors.py index 3ddca2c0d6..b583a1268f 100644 --- a/src/huggingface_hub/errors.py +++ b/src/huggingface_hub/errors.py @@ -1,6 +1,8 @@ """Contains all custom errors.""" -from requests import HTTPError +from typing import Optional + +from requests import HTTPError, Response # HEADERS ERRORS @@ -17,6 +19,91 @@ class OfflineModeIsEnabled(ConnectionError): """Raised when a request is made but `HF_HUB_OFFLINE=1` is set as environment variable.""" +class HfHubHTTPError(HTTPError): + """ + HTTPError to inherit from for any custom HTTP Error raised in HF Hub. + + Any HTTPError is converted at least into a `HfHubHTTPError`. If some information is + sent back by the server, it will be added to the error message. + + Added details: + - Request id from "X-Request-Id" header if exists. + - Server error message from the header "X-Error-Message". + - Server error message if we can found one in the response body. + + Example: + ```py + import requests + from huggingface_hub.utils import get_session, hf_raise_for_status, HfHubHTTPError + + response = get_session().post(...) + try: + hf_raise_for_status(response) + except HfHubHTTPError as e: + print(str(e)) # formatted message + e.request_id, e.server_message # details returned by server + + # Complete the error message with additional information once it's raised + e.append_to_message("\n`create_commit` expects the repository to exist.") + raise + ``` + """ + + request_id: Optional[str] = None + server_message: Optional[str] = None + + def __init__(self, message: str, response: Optional[Response] = None): + # Parse server information if any. + if response is not None: + # Import here to avoid circular import + from .utils._fixes import JSONDecodeError + + self.request_id = response.headers.get("X-Request-Id") + try: + server_data = response.json() + except JSONDecodeError: + server_data = {} + + # Retrieve server error message from multiple sources + server_message_from_headers = response.headers.get("X-Error-Message") + server_message_from_body = server_data.get("error") + server_multiple_messages_from_body = "\n".join( + error["message"] for error in server_data.get("errors", []) if "message" in error + ) + + # Concatenate error messages + _server_message = "" + if server_message_from_headers is not None: # from headers + _server_message += server_message_from_headers + "\n" + if server_message_from_body is not None: # from body "error" + if isinstance(server_message_from_body, list): + server_message_from_body = "\n".join(server_message_from_body) + if server_message_from_body not in _server_message: + _server_message += server_message_from_body + "\n" + if server_multiple_messages_from_body is not None: # from body "errors" + if server_multiple_messages_from_body not in _server_message: + _server_message += server_multiple_messages_from_body + "\n" + _server_message = _server_message.strip() + + # Set message to `HfHubHTTPError` (if any) + if _server_message != "": + self.server_message = _server_message + + super().__init__( + _format_error_message( + message, + request_id=self.request_id, + server_message=self.server_message, + ), + response=response, # type: ignore + request=response.request if response is not None else None, # type: ignore + ) + + def append_to_message(self, additional_message: str) -> None: + """Append additional information to the `HfHubHTTPError` initial message.""" + self.args = (self.args[0] + additional_message,) + self.args[1:] + + # INFERENCE CLIENT ERRORS @@ -94,3 +181,181 @@ class HFValidationError(ValueError): Inherits from [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError). """ + + +# FILE METADATA ERRORS + + +class FileMetadataError(OSError): + """Error triggered when the metadata of a file on the Hub cannot be retrieved (missing ETag or commit_hash). + + Inherits from `OSError` for backward compatibility. + """ + + +# REPOSIORY ERRORS + + +class RepositoryNotFoundError(HfHubHTTPError): + """ + Raised when trying to access a hf.co URL with an invalid repository name, or + with a private repo name the user does not have access to. + + Example: + + ```py + >>> from huggingface_hub import model_info + >>> model_info("") + (...) + huggingface_hub.utils._errors.RepositoryNotFoundError: 401 Client Error. (Request ID: PvMw_VjBMjVdMz53WKIzP) + + Repository Not Found for url: https://huggingface.co/api/models/%3Cnon_existent_repository%3E. + Please make sure you specified the correct `repo_id` and `repo_type`. + If the repo is private, make sure you are authenticated. + Invalid username or password. + ``` + """ + + +class GatedRepoError(RepositoryNotFoundError): + """ + Raised when trying to access a gated repository for which the user is not on the + authorized list. + + Note: derives from `RepositoryNotFoundError` to ensure backward compatibility. + + Example: + + ```py + >>> from huggingface_hub import model_info + >>> model_info("") + (...) + huggingface_hub.utils._errors.GatedRepoError: 403 Client Error. (Request ID: ViT1Bf7O_026LGSQuVqfa) + + Cannot access gated repo for url https://huggingface.co/api/models/ardent-figment/gated-model. + Access to model ardent-figment/gated-model is restricted and you are not in the authorized list. + Visit https://huggingface.co/ardent-figment/gated-model to ask for access. + ``` + """ + + +class DisabledRepoError(HfHubHTTPError): + """ + Raised when trying to access a repository that has been disabled by its author. + + Example: + + ```py + >>> from huggingface_hub import dataset_info + >>> dataset_info("laion/laion-art") + (...) + huggingface_hub.utils._errors.DisabledRepoError: 403 Client Error. (Request ID: Root=1-659fc3fa-3031673e0f92c71a2260dbe2;bc6f4dfb-b30a-4862-af0a-5cfe827610d8) + + Cannot access repository for url https://huggingface.co/api/datasets/laion/laion-art. + Access to this resource is disabled. + ``` + """ + + +# REVISION ERROR + + +class RevisionNotFoundError(HfHubHTTPError): + """ + Raised when trying to access a hf.co URL with a valid repository but an invalid + revision. + + Example: + + ```py + >>> from huggingface_hub import hf_hub_download + >>> hf_hub_download('bert-base-cased', 'config.json', revision='') + (...) + huggingface_hub.utils._errors.RevisionNotFoundError: 404 Client Error. (Request ID: Mwhe_c3Kt650GcdKEFomX) + + Revision Not Found for url: https://huggingface.co/bert-base-cased/resolve/%3Cnon-existent-revision%3E/config.json. + ``` + """ + + +# ENTRY ERRORS +class EntryNotFoundError(HfHubHTTPError): + """ + Raised when trying to access a hf.co URL with a valid repository and revision + but an invalid filename. + + Example: + + ```py + >>> from huggingface_hub import hf_hub_download + >>> hf_hub_download('bert-base-cased', '') + (...) + huggingface_hub.utils._errors.EntryNotFoundError: 404 Client Error. (Request ID: 53pNl6M0MxsnG5Sw8JA6x) + + Entry Not Found for url: https://huggingface.co/bert-base-cased/resolve/main/%3Cnon-existent-file%3E. + ``` + """ + + +class LocalEntryNotFoundError(EntryNotFoundError, FileNotFoundError, ValueError): + """ + Raised when trying to access a file or snapshot that is not on the disk when network is + disabled or unavailable (connection issue). The entry may exist on the Hub. + + Note: `ValueError` type is to ensure backward compatibility. + Note: `LocalEntryNotFoundError` derives from `HTTPError` because of `EntryNotFoundError` + even when it is not a network issue. + + Example: + + ```py + >>> from huggingface_hub import hf_hub_download + >>> hf_hub_download('bert-base-cased', '', local_files_only=True) + (...) + huggingface_hub.utils._errors.LocalEntryNotFoundError: Cannot find the requested files in the disk cache and outgoing traffic has been disabled. To enable hf.co look-ups and downloads online, set 'local_files_only' to False. + ``` + """ + + def __init__(self, message: str): + super().__init__(message, response=None) + + +# REQUEST ERROR +class BadRequestError(HfHubHTTPError, ValueError): + """ + Raised by `hf_raise_for_status` when the server returns a HTTP 400 error. + + Example: + + ```py + >>> resp = requests.post("hf.co/api/check", ...) + >>> hf_raise_for_status(resp, endpoint_name="check") + huggingface_hub.utils._errors.BadRequestError: Bad request for check endpoint: {details} (Request ID: XXX) + ``` + """ + + +def _format_error_message(message: str, request_id: Optional[str], server_message: Optional[str]) -> str: + """ + Format the `HfHubHTTPError` error message based on initial message and information + returned by the server. + + Used when initializing `HfHubHTTPError`. + """ + # Add message from response body + if server_message is not None and len(server_message) > 0 and server_message.lower() not in message.lower(): + if "\n\n" in message: + message += "\n" + server_message + else: + message += "\n\n" + server_message + + # Add Request ID + if request_id is not None and str(request_id).lower() not in message.lower(): + request_id_message = f" (Request ID: {request_id})" + if "\n" in message: + newline_index = message.index("\n") + message = message[:newline_index] + request_id_message + message[newline_index:] + else: + message += request_id_message + + return message diff --git a/src/huggingface_hub/file_download.py b/src/huggingface_hub/file_download.py index f85193e37c..52bfdd2c73 100644 --- a/src/huggingface_hub/file_download.py +++ b/src/huggingface_hub/file_download.py @@ -45,14 +45,16 @@ REPO_TYPES, REPO_TYPES_URL_PREFIXES, ) -from .utils import ( +from .errors import ( EntryNotFoundError, FileMetadataError, GatedRepoError, LocalEntryNotFoundError, - OfflineModeIsEnabled, RepositoryNotFoundError, RevisionNotFoundError, +) +from .utils import ( + OfflineModeIsEnabled, SoftTemporaryDirectory, WeakFileLock, build_hf_headers, diff --git a/src/huggingface_hub/hf_api.py b/src/huggingface_hub/hf_api.py index f1b95f85a0..e1f595facd 100644 --- a/src/huggingface_hub/hf_api.py +++ b/src/huggingface_hub/hf_api.py @@ -102,19 +102,21 @@ DiscussionStatusFilter, DiscussionTypeFilter, ) +from .errors import ( + BadRequestError, + EntryNotFoundError, + GatedRepoError, + HfHubHTTPError, + RepositoryNotFoundError, + RevisionNotFoundError, +) from .file_download import HfFileMetadata, get_hf_file_metadata, hf_hub_url from .repocard_data import DatasetCardData, ModelCardData, SpaceCardData from .utils import ( DEFAULT_IGNORE_PATTERNS, - BadRequestError, - EntryNotFoundError, - GatedRepoError, HfFolder, # noqa: F401 # kept for backward compatibility - HfHubHTTPError, LocalTokenNotFoundError, NotASafetensorsRepoError, - RepositoryNotFoundError, - RevisionNotFoundError, SafetensorsFileMetadata, SafetensorsParsingError, SafetensorsRepoMetadata, diff --git a/src/huggingface_hub/hf_file_system.py b/src/huggingface_hub/hf_file_system.py index 660f51225f..1b0e971787 100644 --- a/src/huggingface_hub/hf_file_system.py +++ b/src/huggingface_hub/hf_file_system.py @@ -25,13 +25,11 @@ REPO_TYPES_MAPPING, REPO_TYPES_URL_PREFIXES, ) +from .errors import EntryNotFoundError, RepositoryNotFoundError, RevisionNotFoundError from .file_download import hf_hub_url, http_get from .hf_api import HfApi, LastCommitInfo, RepoFile from .utils import ( - EntryNotFoundError, HFValidationError, - RepositoryNotFoundError, - RevisionNotFoundError, hf_raise_for_status, http_backoff, ) diff --git a/src/huggingface_hub/hub_mixin.py b/src/huggingface_hub/hub_mixin.py index 75715dfed8..85b29331ee 100644 --- a/src/huggingface_hub/hub_mixin.py +++ b/src/huggingface_hub/hub_mixin.py @@ -18,12 +18,11 @@ ) from .constants import CONFIG_NAME, PYTORCH_WEIGHTS_NAME, SAFETENSORS_SINGLE_FILE +from .errors import EntryNotFoundError, HfHubHTTPError from .file_download import hf_hub_download from .hf_api import HfApi from .repocard import ModelCard, ModelCardData from .utils import ( - EntryNotFoundError, - HfHubHTTPError, SoftTemporaryDirectory, is_jsonable, is_safetensors_available, diff --git a/src/huggingface_hub/inference/_client.py b/src/huggingface_hub/inference/_client.py index 3b66105605..4dfe6e9de8 100644 --- a/src/huggingface_hub/inference/_client.py +++ b/src/huggingface_hub/inference/_client.py @@ -53,7 +53,7 @@ from requests.structures import CaseInsensitiveDict from huggingface_hub.constants import ALL_INFERENCE_API_FRAMEWORKS, INFERENCE_ENDPOINT, MAIN_INFERENCE_API_FRAMEWORKS -from huggingface_hub.errors import InferenceTimeoutError +from huggingface_hub.errors import BadRequestError, InferenceTimeoutError from huggingface_hub.inference._common import ( TASKS_EXPECTING_IMAGES, ContentT, @@ -101,7 +101,6 @@ ZeroShotImageClassificationOutputElement, ) from huggingface_hub.utils import ( - BadRequestError, build_hf_headers, get_session, hf_raise_for_status, diff --git a/src/huggingface_hub/inference/_templating.py b/src/huggingface_hub/inference/_templating.py index dc913b91e5..954b203908 100644 --- a/src/huggingface_hub/inference/_templating.py +++ b/src/huggingface_hub/inference/_templating.py @@ -1,9 +1,8 @@ from functools import lru_cache from typing import Callable, Dict, List, Optional, Union -from huggingface_hub.errors import TemplateError - -from ..utils import HfHubHTTPError, RepositoryNotFoundError, is_minijinja_available +from ..errors import HfHubHTTPError, RepositoryNotFoundError, TemplateError +from ..utils import is_minijinja_available def _import_minijinja(): diff --git a/src/huggingface_hub/repocard.py b/src/huggingface_hub/repocard.py index 2ea7fc136c..0a767e6303 100644 --- a/src/huggingface_hub/repocard.py +++ b/src/huggingface_hub/repocard.py @@ -20,7 +20,8 @@ from huggingface_hub.utils import get_session, is_jinja_available, yaml_dump from .constants import REPOCARD_NAME -from .utils import EntryNotFoundError, SoftTemporaryDirectory, logging, validate_hf_hub_args +from .errors import EntryNotFoundError +from .utils import SoftTemporaryDirectory, logging, validate_hf_hub_args logger = logging.get_logger(__name__) diff --git a/src/huggingface_hub/utils/__init__.py b/src/huggingface_hub/utils/__init__.py index 305d8e78e2..7dd6fecb2d 100644 --- a/src/huggingface_hub/utils/__init__.py +++ b/src/huggingface_hub/utils/__init__.py @@ -16,10 +16,19 @@ # ruff: noqa: F401 from huggingface_hub.errors import ( + BadRequestError, + DisabledRepoError, + EntryNotFoundError, + FileMetadataError, + GatedRepoError, + HfHubHTTPError, HFValidationError, + LocalEntryNotFoundError, LocalTokenNotFoundError, NotASafetensorsRepoError, OfflineModeIsEnabled, + RepositoryNotFoundError, + RevisionNotFoundError, SafetensorsParsingError, ) @@ -38,15 +47,6 @@ from ._chunk_utils import chunk_iterable from ._datetime import parse_datetime from ._errors import ( - BadRequestError, - DisabledRepoError, - EntryNotFoundError, - FileMetadataError, - GatedRepoError, - HfHubHTTPError, - LocalEntryNotFoundError, - RepositoryNotFoundError, - RevisionNotFoundError, hf_raise_for_status, ) from ._experimental import experimental diff --git a/src/huggingface_hub/utils/_errors.py b/src/huggingface_hub/utils/_errors.py index 338b622ef4..a467427087 100644 --- a/src/huggingface_hub/utils/_errors.py +++ b/src/huggingface_hub/utils/_errors.py @@ -3,7 +3,15 @@ from requests import HTTPError, Response -from ._fixes import JSONDecodeError +from ..errors import ( + BadRequestError, + DisabledRepoError, + EntryNotFoundError, + GatedRepoError, + HfHubHTTPError, + RepositoryNotFoundError, + RevisionNotFoundError, +) REPO_API_REGEX = re.compile( @@ -22,229 +30,6 @@ ) -class FileMetadataError(OSError): - """Error triggered when the metadata of a file on the Hub cannot be retrieved (missing ETag or commit_hash). - - Inherits from `OSError` for backward compatibility. - """ - - -class HfHubHTTPError(HTTPError): - """ - HTTPError to inherit from for any custom HTTP Error raised in HF Hub. - - Any HTTPError is converted at least into a `HfHubHTTPError`. If some information is - sent back by the server, it will be added to the error message. - - Added details: - - Request id from "X-Request-Id" header if exists. - - Server error message from the header "X-Error-Message". - - Server error message if we can found one in the response body. - - Example: - ```py - import requests - from huggingface_hub.utils import get_session, hf_raise_for_status, HfHubHTTPError - - response = get_session().post(...) - try: - hf_raise_for_status(response) - except HfHubHTTPError as e: - print(str(e)) # formatted message - e.request_id, e.server_message # details returned by server - - # Complete the error message with additional information once it's raised - e.append_to_message("\n`create_commit` expects the repository to exist.") - raise - ``` - """ - - request_id: Optional[str] = None - server_message: Optional[str] = None - - def __init__(self, message: str, response: Optional[Response] = None): - # Parse server information if any. - if response is not None: - self.request_id = response.headers.get("X-Request-Id") - try: - server_data = response.json() - except JSONDecodeError: - server_data = {} - - # Retrieve server error message from multiple sources - server_message_from_headers = response.headers.get("X-Error-Message") - server_message_from_body = server_data.get("error") - server_multiple_messages_from_body = "\n".join( - error["message"] for error in server_data.get("errors", []) if "message" in error - ) - - # Concatenate error messages - _server_message = "" - if server_message_from_headers is not None: # from headers - _server_message += server_message_from_headers + "\n" - if server_message_from_body is not None: # from body "error" - if isinstance(server_message_from_body, list): - server_message_from_body = "\n".join(server_message_from_body) - if server_message_from_body not in _server_message: - _server_message += server_message_from_body + "\n" - if server_multiple_messages_from_body is not None: # from body "errors" - if server_multiple_messages_from_body not in _server_message: - _server_message += server_multiple_messages_from_body + "\n" - _server_message = _server_message.strip() - - # Set message to `HfHubHTTPError` (if any) - if _server_message != "": - self.server_message = _server_message - - super().__init__( - _format_error_message( - message, - request_id=self.request_id, - server_message=self.server_message, - ), - response=response, # type: ignore - request=response.request if response is not None else None, # type: ignore - ) - - def append_to_message(self, additional_message: str) -> None: - """Append additional information to the `HfHubHTTPError` initial message.""" - self.args = (self.args[0] + additional_message,) + self.args[1:] - - -class RepositoryNotFoundError(HfHubHTTPError): - """ - Raised when trying to access a hf.co URL with an invalid repository name, or - with a private repo name the user does not have access to. - - Example: - - ```py - >>> from huggingface_hub import model_info - >>> model_info("") - (...) - huggingface_hub.utils._errors.RepositoryNotFoundError: 401 Client Error. (Request ID: PvMw_VjBMjVdMz53WKIzP) - - Repository Not Found for url: https://huggingface.co/api/models/%3Cnon_existent_repository%3E. - Please make sure you specified the correct `repo_id` and `repo_type`. - If the repo is private, make sure you are authenticated. - Invalid username or password. - ``` - """ - - -class GatedRepoError(RepositoryNotFoundError): - """ - Raised when trying to access a gated repository for which the user is not on the - authorized list. - - Note: derives from `RepositoryNotFoundError` to ensure backward compatibility. - - Example: - - ```py - >>> from huggingface_hub import model_info - >>> model_info("") - (...) - huggingface_hub.utils._errors.GatedRepoError: 403 Client Error. (Request ID: ViT1Bf7O_026LGSQuVqfa) - - Cannot access gated repo for url https://huggingface.co/api/models/ardent-figment/gated-model. - Access to model ardent-figment/gated-model is restricted and you are not in the authorized list. - Visit https://huggingface.co/ardent-figment/gated-model to ask for access. - ``` - """ - - -class DisabledRepoError(HfHubHTTPError): - """ - Raised when trying to access a repository that has been disabled by its author. - - Example: - - ```py - >>> from huggingface_hub import dataset_info - >>> dataset_info("laion/laion-art") - (...) - huggingface_hub.utils._errors.DisabledRepoError: 403 Client Error. (Request ID: Root=1-659fc3fa-3031673e0f92c71a2260dbe2;bc6f4dfb-b30a-4862-af0a-5cfe827610d8) - - Cannot access repository for url https://huggingface.co/api/datasets/laion/laion-art. - Access to this resource is disabled. - ``` - """ - - -class RevisionNotFoundError(HfHubHTTPError): - """ - Raised when trying to access a hf.co URL with a valid repository but an invalid - revision. - - Example: - - ```py - >>> from huggingface_hub import hf_hub_download - >>> hf_hub_download('bert-base-cased', 'config.json', revision='') - (...) - huggingface_hub.utils._errors.RevisionNotFoundError: 404 Client Error. (Request ID: Mwhe_c3Kt650GcdKEFomX) - - Revision Not Found for url: https://huggingface.co/bert-base-cased/resolve/%3Cnon-existent-revision%3E/config.json. - ``` - """ - - -class EntryNotFoundError(HfHubHTTPError): - """ - Raised when trying to access a hf.co URL with a valid repository and revision - but an invalid filename. - - Example: - - ```py - >>> from huggingface_hub import hf_hub_download - >>> hf_hub_download('bert-base-cased', '') - (...) - huggingface_hub.utils._errors.EntryNotFoundError: 404 Client Error. (Request ID: 53pNl6M0MxsnG5Sw8JA6x) - - Entry Not Found for url: https://huggingface.co/bert-base-cased/resolve/main/%3Cnon-existent-file%3E. - ``` - """ - - -class LocalEntryNotFoundError(EntryNotFoundError, FileNotFoundError, ValueError): - """ - Raised when trying to access a file or snapshot that is not on the disk when network is - disabled or unavailable (connection issue). The entry may exist on the Hub. - - Note: `ValueError` type is to ensure backward compatibility. - Note: `LocalEntryNotFoundError` derives from `HTTPError` because of `EntryNotFoundError` - even when it is not a network issue. - - Example: - - ```py - >>> from huggingface_hub import hf_hub_download - >>> hf_hub_download('bert-base-cased', '', local_files_only=True) - (...) - huggingface_hub.utils._errors.LocalEntryNotFoundError: Cannot find the requested files in the disk cache and outgoing traffic has been disabled. To enable hf.co look-ups and downloads online, set 'local_files_only' to False. - ``` - """ - - def __init__(self, message: str): - super().__init__(message, response=None) - - -class BadRequestError(HfHubHTTPError, ValueError): - """ - Raised by `hf_raise_for_status` when the server returns a HTTP 400 error. - - Example: - - ```py - >>> resp = requests.post("hf.co/api/check", ...) - >>> hf_raise_for_status(resp, endpoint_name="check") - huggingface_hub.utils._errors.BadRequestError: Bad request for check endpoint: {details} (Request ID: XXX) - ``` - """ - - def hf_raise_for_status(response: Response, endpoint_name: Optional[str] = None) -> None: """ Internal version of `response.raise_for_status()` that will refine a @@ -253,6 +38,7 @@ def hf_raise_for_status(response: Response, endpoint_name: Optional[str] = None) This helper is meant to be the unique method to raise_for_status when making a call to the Hugging Face Hub. + Example: ```py import requests @@ -374,29 +160,3 @@ def hf_raise_for_status(response: Response, endpoint_name: Optional[str] = None) # Convert `HTTPError` into a `HfHubHTTPError` to display request information # as well (request id and/or server error message) raise HfHubHTTPError(str(e), response=response) from e - - -def _format_error_message(message: str, request_id: Optional[str], server_message: Optional[str]) -> str: - """ - Format the `HfHubHTTPError` error message based on initial message and information - returned by the server. - - Used when initializing `HfHubHTTPError`. - """ - # Add message from response body - if server_message is not None and len(server_message) > 0 and server_message.lower() not in message.lower(): - if "\n\n" in message: - message += "\n" + server_message - else: - message += "\n\n" + server_message - - # Add Request ID - if request_id is not None and str(request_id).lower() not in message.lower(): - request_id_message = f" (Request ID: {request_id})" - if "\n" in message: - newline_index = message.index("\n") - message = message[:newline_index] + request_id_message + message[newline_index:] - else: - message += request_id_message - - return message diff --git a/tests/test_cache_layout.py b/tests/test_cache_layout.py index accd8183fc..388d3cdaa0 100644 --- a/tests/test_cache_layout.py +++ b/tests/test_cache_layout.py @@ -4,8 +4,8 @@ from io import BytesIO from huggingface_hub import HfApi, hf_hub_download, snapshot_download +from huggingface_hub.errors import EntryNotFoundError from huggingface_hub.utils import SoftTemporaryDirectory, logging -from huggingface_hub.utils._errors import EntryNotFoundError from .testing_constants import ENDPOINT_STAGING, TOKEN from .testing_utils import ( diff --git a/tests/test_cli.py b/tests/test_cli.py index 4850da8766..88e1350454 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -13,7 +13,8 @@ from huggingface_hub.commands.scan_cache import ScanCacheCommand from huggingface_hub.commands.tag import TagCommands from huggingface_hub.commands.upload import UploadCommand -from huggingface_hub.utils import RevisionNotFoundError, SoftTemporaryDirectory, capture_output +from huggingface_hub.errors import RevisionNotFoundError +from huggingface_hub.utils import SoftTemporaryDirectory, capture_output from .testing_utils import DUMMY_MODEL_ID diff --git a/tests/test_file_download.py b/tests/test_file_download.py index a7d5a5043b..e2aafde3c9 100644 --- a/tests/test_file_download.py +++ b/tests/test_file_download.py @@ -36,6 +36,13 @@ PYTORCH_WEIGHTS_NAME, REPO_TYPE_DATASET, ) +from huggingface_hub.errors import ( + EntryNotFoundError, + GatedRepoError, + LocalEntryNotFoundError, + RepositoryNotFoundError, + RevisionNotFoundError, +) from huggingface_hub.file_download import ( _CACHED_NO_EXIST, HfFileMetadata, @@ -53,11 +60,6 @@ try_to_load_from_cache, ) from huggingface_hub.utils import ( - EntryNotFoundError, - GatedRepoError, - LocalEntryNotFoundError, - RepositoryNotFoundError, - RevisionNotFoundError, SoftTemporaryDirectory, get_session, hf_raise_for_status, diff --git a/tests/test_hf_api.py b/tests/test_hf_api.py index 07a6dd68b5..233b2677e3 100644 --- a/tests/test_hf_api.py +++ b/tests/test_hf_api.py @@ -49,6 +49,13 @@ REPO_TYPE_SPACE, SPACES_SDK_TYPES, ) +from huggingface_hub.errors import ( + BadRequestError, + EntryNotFoundError, + HfHubHTTPError, + RepositoryNotFoundError, + RevisionNotFoundError, +) from huggingface_hub.file_download import hf_hub_download from huggingface_hub.hf_api import ( AccessRequest, @@ -70,12 +77,7 @@ ) from huggingface_hub.repocard_data import DatasetCardData, ModelCardData from huggingface_hub.utils import ( - BadRequestError, - EntryNotFoundError, - HfHubHTTPError, NotASafetensorsRepoError, - RepositoryNotFoundError, - RevisionNotFoundError, SafetensorsFileMetadata, SafetensorsParsingError, SafetensorsRepoMetadata, diff --git a/tests/test_hf_file_system.py b/tests/test_hf_file_system.py index d0037d37a6..ec4ffd5ba1 100644 --- a/tests/test_hf_file_system.py +++ b/tests/test_hf_file_system.py @@ -12,8 +12,8 @@ import pytest from huggingface_hub import hf_file_system +from huggingface_hub.errors import RepositoryNotFoundError, RevisionNotFoundError from huggingface_hub.hf_file_system import HfFileSystem, HfFileSystemFile, HfFileSystemStreamFile -from huggingface_hub.utils import RepositoryNotFoundError, RevisionNotFoundError from .testing_constants import ENDPOINT_STAGING, TOKEN from .testing_utils import repo_name diff --git a/tests/test_hub_mixin_pytorch.py b/tests/test_hub_mixin_pytorch.py index 9b19eb5926..b8f2ffc85c 100644 --- a/tests/test_hub_mixin_pytorch.py +++ b/tests/test_hub_mixin_pytorch.py @@ -11,8 +11,9 @@ from huggingface_hub import HfApi, ModelCard, hf_hub_download from huggingface_hub.constants import PYTORCH_WEIGHTS_NAME +from huggingface_hub.errors import EntryNotFoundError, HfHubHTTPError from huggingface_hub.hub_mixin import ModelHubMixin, PyTorchModelHubMixin -from huggingface_hub.utils import EntryNotFoundError, HfHubHTTPError, SoftTemporaryDirectory, is_torch_available +from huggingface_hub.utils import SoftTemporaryDirectory, is_torch_available from .testing_constants import ENDPOINT_STAGING, TOKEN, USER from .testing_utils import repo_name, requires diff --git a/tests/test_inference_client.py b/tests/test_inference_client.py index af461511e5..d09d97d6ff 100644 --- a/tests/test_inference_client.py +++ b/tests/test_inference_client.py @@ -46,12 +46,13 @@ hf_hub_download, ) from huggingface_hub.constants import ALL_INFERENCE_API_FRAMEWORKS, MAIN_INFERENCE_API_FRAMEWORKS +from huggingface_hub.errors import HfHubHTTPError from huggingface_hub.inference._client import _open_as_binary from huggingface_hub.inference._common import ( _stream_chat_completion_response, _stream_text_generation_response, ) -from huggingface_hub.utils import HfHubHTTPError, build_hf_headers +from huggingface_hub.utils import build_hf_headers from .testing_utils import with_production_testing diff --git a/tests/test_repocard.py b/tests/test_repocard.py index fe19d7c9cb..204c6ed9a7 100644 --- a/tests/test_repocard.py +++ b/tests/test_repocard.py @@ -37,11 +37,12 @@ metadata_update, ) from huggingface_hub.constants import REPOCARD_NAME +from huggingface_hub.errors import EntryNotFoundError from huggingface_hub.file_download import hf_hub_download from huggingface_hub.hf_api import HfApi from huggingface_hub.repocard import REGEX_YAML_BLOCK from huggingface_hub.repocard_data import CardData -from huggingface_hub.utils import EntryNotFoundError, SoftTemporaryDirectory, is_jinja_available +from huggingface_hub.utils import SoftTemporaryDirectory, is_jinja_available from .testing_constants import ( ENDPOINT_STAGING, diff --git a/tests/test_snapshot_download.py b/tests/test_snapshot_download.py index e3a3698d5b..17f4c561b3 100644 --- a/tests/test_snapshot_download.py +++ b/tests/test_snapshot_download.py @@ -4,7 +4,8 @@ from unittest.mock import patch from huggingface_hub import CommitOperationAdd, HfApi, snapshot_download -from huggingface_hub.utils import LocalEntryNotFoundError, RepositoryNotFoundError, SoftTemporaryDirectory +from huggingface_hub.errors import LocalEntryNotFoundError, RepositoryNotFoundError +from huggingface_hub.utils import SoftTemporaryDirectory from .testing_constants import TOKEN from .testing_utils import OfflineSimulationMode, offline, repo_name diff --git a/tests/test_utils_errors.py b/tests/test_utils_errors.py index 2ecc018df8..5b6e443558 100644 --- a/tests/test_utils_errors.py +++ b/tests/test_utils_errors.py @@ -3,16 +3,15 @@ import pytest from requests.models import PreparedRequest, Response -from huggingface_hub.utils._errors import ( - REPO_API_REGEX, +from huggingface_hub.errors import ( BadRequestError, DisabledRepoError, EntryNotFoundError, HfHubHTTPError, RepositoryNotFoundError, RevisionNotFoundError, - hf_raise_for_status, ) +from huggingface_hub.utils._errors import REPO_API_REGEX, hf_raise_for_status class TestErrorUtils(unittest.TestCase):