diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 8006e898e2..fb040d9492 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.11"] + python-version: ["3.8", "3.11"] test_name: [ "Repository only", @@ -29,13 +29,13 @@ jobs: "torch", ] include: - - python-version: "3.11" # LFS not ran on 3.7 + - python-version: "3.11" # LFS not ran on 3.8 test_name: "lfs" - - python-version: "3.7" + - python-version: "3.8" test_name: "fastai" # fastai not supported on 3.11 -> test it on 3.10 - python-version: "3.10" test_name: "fastai" - - python-version: "3.7" + - python-version: "3.8" test_name: "tensorflow" # Tensorflow not supported on 3.11 -> test it on 3.10 - python-version: "3.10" test_name: "tensorflow" @@ -131,14 +131,14 @@ jobs: build-windows: # (almost) Duplicate config compared to `build-ubuntu` but running on Windows. # Please make sure to keep it updated as well. - # Lighter version of the tests with only 1 test suite running on Python3.7. + # Lighter version of the tests with only 1 test suite running on Python3.8. runs-on: windows-latest env: DISABLE_SYMLINKS_IN_WINDOWS_TESTS: 1 strategy: fail-fast: false matrix: - python-version: ["3.7"] + python-version: ["3.8"] steps: - uses: actions/checkout@v2 diff --git a/docs/source/installation.md b/docs/source/installation.md index 423051e10c..1426f20818 100644 --- a/docs/source/installation.md +++ b/docs/source/installation.md @@ -6,7 +6,7 @@ rendered properly in your Markdown viewer. Before you start, you will need to setup your environment by installing the appropriate packages. -`huggingface_hub` is tested on **Python 3.7+**. +`huggingface_hub` is tested on **Python 3.8+**. ## Install with pip diff --git a/setup.py b/setup.py index 1af9002fd0..a16ed1d8dd 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,6 @@ def get_version() -> str: "tqdm>=4.42.1", "pyyaml>=5.1", "typing-extensions>=3.7.4.3", # to be able to import TypeAlias - "importlib_metadata;python_version<'3.8'", "packaging>=20.9", ] @@ -108,7 +107,7 @@ def get_version() -> str: "console_scripts": ["huggingface-cli=huggingface_hub.commands.huggingface_cli:main"], "fsspec.specs": "hf=huggingface_hub.HfFileSystem", }, - python_requires=">=3.7.0", + python_requires=">=3.8.0", install_requires=install_requires, classifiers=[ "Intended Audience :: Developers", @@ -118,7 +117,6 @@ def get_version() -> str: "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", diff --git a/src/huggingface_hub/__init__.py b/src/huggingface_hub/__init__.py index f2d6490d6e..98b3db2bbd 100644 --- a/src/huggingface_hub/__init__.py +++ b/src/huggingface_hub/__init__.py @@ -46,7 +46,7 @@ from typing import TYPE_CHECKING -__version__ = "0.16.0.dev0" +__version__ = "0.17.0.dev0" # Alphabetical order of definitions is ensured in tests # WARNING: any comment added in this dictionary definition will be lost when diff --git a/src/huggingface_hub/_commit_api.py b/src/huggingface_hub/_commit_api.py index 7cbcc0d765..ae69085b5a 100644 --- a/src/huggingface_hub/_commit_api.py +++ b/src/huggingface_hub/_commit_api.py @@ -10,7 +10,7 @@ from dataclasses import dataclass, field from itertools import groupby from pathlib import Path, PurePosixPath -from typing import TYPE_CHECKING, Any, BinaryIO, Dict, Iterable, Iterator, List, Optional, Tuple, Union +from typing import TYPE_CHECKING, Any, BinaryIO, Dict, Iterable, Iterator, List, Literal, Optional, Tuple, Union from tqdm.contrib.concurrent import thread_map @@ -28,7 +28,6 @@ validate_hf_hub_args, ) from .utils import tqdm as hf_tqdm -from .utils._typing import Literal if TYPE_CHECKING: diff --git a/src/huggingface_hub/_snapshot_download.py b/src/huggingface_hub/_snapshot_download.py index aa85d0f4fe..503ab1c87b 100644 --- a/src/huggingface_hub/_snapshot_download.py +++ b/src/huggingface_hub/_snapshot_download.py @@ -1,6 +1,6 @@ import os from pathlib import Path -from typing import Dict, List, Optional, Union +from typing import Dict, List, Literal, Optional, Union from tqdm.auto import tqdm as base_tqdm from tqdm.contrib.concurrent import thread_map @@ -15,7 +15,6 @@ from .hf_api import HfApi from .utils import filter_repo_objects, logging, validate_hf_hub_args from .utils import tqdm as hf_tqdm -from .utils._typing import Literal logger = logging.get_logger(__name__) diff --git a/src/huggingface_hub/_webhooks_payload.py b/src/huggingface_hub/_webhooks_payload.py index bc9aa7be04..5d66b99643 100644 --- a/src/huggingface_hub/_webhooks_payload.py +++ b/src/huggingface_hub/_webhooks_payload.py @@ -13,12 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. """Contains data structures to parse the webhooks payload.""" -from typing import List, Optional +from typing import List, Literal, Optional from pydantic import BaseModel -from .utils._typing import Literal - # This is an adaptation of the ReportV3 interface implemented in moon-landing. V0, V1 and V2 have been ignored as they # are not in used anymore. To keep in sync when format is updated in diff --git a/src/huggingface_hub/community.py b/src/huggingface_hub/community.py index cadad72591..f5422ca911 100644 --- a/src/huggingface_hub/community.py +++ b/src/huggingface_hub/community.py @@ -6,11 +6,10 @@ """ from dataclasses import dataclass from datetime import datetime -from typing import List, Optional +from typing import List, Literal, Optional from .constants import REPO_TYPE_MODEL from .utils import parse_datetime -from .utils._typing import Literal DiscussionStatus = Literal["open", "closed", "merged", "draft"] diff --git a/src/huggingface_hub/file_download.py b/src/huggingface_hub/file_download.py index c3c7a797c3..fb5beb6a8b 100644 --- a/src/huggingface_hub/file_download.py +++ b/src/huggingface_hub/file_download.py @@ -14,7 +14,7 @@ from functools import partial from hashlib import sha256 from pathlib import Path -from typing import Any, BinaryIO, Dict, Generator, Optional, Tuple, Union +from typing import Any, BinaryIO, Dict, Generator, Literal, Optional, Tuple, Union from urllib.parse import quote, urlparse import requests @@ -64,7 +64,7 @@ ) from .utils._headers import _http_user_agent from .utils._runtime import _PY_VERSION # noqa: F401 # for backward compatibility -from .utils._typing import HTTP_METHOD_T, Literal +from .utils._typing import HTTP_METHOD_T logger = logging.get_logger(__name__) diff --git a/src/huggingface_hub/hf_api.py b/src/huggingface_hub/hf_api.py index 727cbb441e..dab2ceba26 100644 --- a/src/huggingface_hub/hf_api.py +++ b/src/huggingface_hub/hf_api.py @@ -26,7 +26,22 @@ from functools import wraps from itertools import islice from pathlib import Path -from typing import Any, BinaryIO, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, TypeVar, Union, overload +from typing import ( + Any, + BinaryIO, + Callable, + Dict, + Iterable, + Iterator, + List, + Literal, + Optional, + Tuple, + TypedDict, + TypeVar, + Union, + overload, +) from urllib.parse import quote import requests @@ -99,7 +114,7 @@ from .utils._deprecation import ( _deprecate_arguments, ) -from .utils._typing import CallableT, Literal, TypedDict +from .utils._typing import CallableT from .utils.endpoint_helpers import ( AttributeDictionary, DatasetFilter, diff --git a/src/huggingface_hub/inference/_client.py b/src/huggingface_hub/inference/_client.py index 868d1cea5a..8434fdf739 100644 --- a/src/huggingface_hub/inference/_client.py +++ b/src/huggingface_hub/inference/_client.py @@ -43,6 +43,7 @@ Dict, Iterable, List, + Literal, Optional, Union, overload, @@ -80,7 +81,6 @@ get_session, hf_raise_for_status, ) -from huggingface_hub.utils._typing import Literal if TYPE_CHECKING: diff --git a/src/huggingface_hub/inference/_common.py b/src/huggingface_hub/inference/_common.py index 73c3e61dd8..45385fa41e 100644 --- a/src/huggingface_hub/inference/_common.py +++ b/src/huggingface_hub/inference/_common.py @@ -29,6 +29,7 @@ Generator, Iterable, List, + Literal, Optional, Set, Union, @@ -46,7 +47,6 @@ is_numpy_available, is_pillow_available, ) -from ..utils._typing import Literal from ._text_generation import ( TextGenerationStreamResponse, ) diff --git a/src/huggingface_hub/inference/_generated/_async_client.py b/src/huggingface_hub/inference/_generated/_async_client.py index 7a40403abe..2ca84f1c24 100644 --- a/src/huggingface_hub/inference/_generated/_async_client.py +++ b/src/huggingface_hub/inference/_generated/_async_client.py @@ -28,6 +28,7 @@ AsyncIterable, Dict, List, + Literal, Optional, Union, overload, @@ -61,7 +62,6 @@ from huggingface_hub.utils import ( build_hf_headers, ) -from huggingface_hub.utils._typing import Literal from .._common import _async_yield_from, _import_aiohttp diff --git a/src/huggingface_hub/inference/_types.py b/src/huggingface_hub/inference/_types.py index b4691a8cc0..5e52dcbc56 100644 --- a/src/huggingface_hub/inference/_types.py +++ b/src/huggingface_hub/inference/_types.py @@ -12,9 +12,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import TYPE_CHECKING, List - -from ..utils._typing import TypedDict +from typing import TYPE_CHECKING, List, TypedDict if TYPE_CHECKING: diff --git a/src/huggingface_hub/inference_api.py b/src/huggingface_hub/inference_api.py index f5d8d5ec8e..1dd3b36924 100644 --- a/src/huggingface_hub/inference_api.py +++ b/src/huggingface_hub/inference_api.py @@ -4,6 +4,7 @@ from .constants import INFERENCE_ENDPOINT from .hf_api import HfApi from .utils import build_hf_headers, get_session, is_pillow_available, logging, validate_hf_hub_args +from .utils._deprecation import _deprecate_method logger = logging.get_logger(__name__) @@ -90,15 +91,14 @@ class InferenceApi: """ @validate_hf_hub_args - # TODO: add deprecation starting from version v0.16.0 so that we can proactively adapt external scripts. - # @_deprecate_method( - # version="0.18.0", - # message=( - # "`InferenceApi` client is deprecated in favor of the more feature-complete `InferenceClient`. Check out" - # " this guide to learn how to convert your script to use it:" - # " https://huggingface.co/docs/huggingface_hub/guides/inference#legacy-inferenceapi-client." - # ), - # ) + @_deprecate_method( + version="0.19.0", + message=( + "`InferenceApi` client is deprecated in favor of the more feature-complete `InferenceClient`. Check out" + " this guide to learn how to convert your script to use it:" + " https://huggingface.co/docs/huggingface_hub/guides/inference#legacy-inferenceapi-client." + ), + ) def __init__( self, repo_id: str, diff --git a/src/huggingface_hub/lfs.py b/src/huggingface_hub/lfs.py index f2474e2a15..c3c890044d 100644 --- a/src/huggingface_hub/lfs.py +++ b/src/huggingface_hub/lfs.py @@ -22,7 +22,7 @@ from math import ceil from os.path import getsize from pathlib import Path -from typing import TYPE_CHECKING, BinaryIO, Dict, Iterable, List, Optional, Tuple +from typing import TYPE_CHECKING, BinaryIO, Dict, Iterable, List, Optional, Tuple, TypedDict from requests.auth import HTTPBasicAuth @@ -30,7 +30,6 @@ from huggingface_hub.utils import get_session from .utils import get_token_to_send, hf_raise_for_status, http_backoff, logging, validate_hf_hub_args -from .utils._typing import TypedDict from .utils.sha import sha256, sha_fileobj diff --git a/src/huggingface_hub/repocard.py b/src/huggingface_hub/repocard.py index 1c4b976ffa..b8e9dc200c 100644 --- a/src/huggingface_hub/repocard.py +++ b/src/huggingface_hub/repocard.py @@ -1,7 +1,7 @@ import os import re from pathlib import Path -from typing import Any, Dict, Optional, Type, Union +from typing import Any, Dict, Literal, Optional, Type, Union import requests import yaml @@ -21,7 +21,6 @@ from .constants import REPOCARD_NAME from .utils import EntryNotFoundError, SoftTemporaryDirectory, validate_hf_hub_args -from .utils._typing import Literal from .utils.logging import get_logger diff --git a/src/huggingface_hub/repository.py b/src/huggingface_hub/repository.py index 757995870b..d13b287aac 100644 --- a/src/huggingface_hub/repository.py +++ b/src/huggingface_hub/repository.py @@ -6,7 +6,7 @@ import time from contextlib import contextmanager from pathlib import Path -from typing import Callable, Dict, Iterator, List, Optional, Tuple, Union +from typing import Callable, Dict, Iterator, List, Optional, Tuple, TypedDict, Union from urllib.parse import urlparse from huggingface_hub.constants import REPO_TYPES_URL_PREFIXES, REPOCARD_NAME @@ -22,7 +22,6 @@ tqdm, validate_hf_hub_args, ) -from .utils._typing import TypedDict logger = logging.get_logger(__name__) diff --git a/src/huggingface_hub/utils/_cache_manager.py b/src/huggingface_hub/utils/_cache_manager.py index 3e1443a789..674fe27f30 100644 --- a/src/huggingface_hub/utils/_cache_manager.py +++ b/src/huggingface_hub/utils/_cache_manager.py @@ -19,11 +19,10 @@ from collections import defaultdict from dataclasses import dataclass from pathlib import Path -from typing import Dict, FrozenSet, List, Optional, Set, Union +from typing import Dict, FrozenSet, List, Literal, Optional, Set, Union from ..constants import HUGGINGFACE_HUB_CACHE from . import logging -from ._typing import Literal logger = logging.get_logger(__name__) diff --git a/src/huggingface_hub/utils/_http.py b/src/huggingface_hub/utils/_http.py index 835ef648e9..8d349833e8 100644 --- a/src/huggingface_hub/utils/_http.py +++ b/src/huggingface_hub/utils/_http.py @@ -127,7 +127,7 @@ def backend_factory() -> requests.Session: return _get_session_from_cache(thread_ident=threading.get_ident()) -@lru_cache(maxsize=128) # default value for Python>=3.8. Let's keep the same for Python3.7 +@lru_cache def _get_session_from_cache(thread_ident: int) -> requests.Session: """ Create a new session per thread using global factory. Using LRU cache (maxsize 128) to avoid memory leaks when diff --git a/src/huggingface_hub/utils/_runtime.py b/src/huggingface_hub/utils/_runtime.py index f5f95cb57c..969a38e6b1 100644 --- a/src/huggingface_hub/utils/_runtime.py +++ b/src/huggingface_hub/utils/_runtime.py @@ -13,23 +13,16 @@ # See the License for the specific language governing permissions and # limitations under the License. """Check presence of installed packages at runtime.""" +import importlib.metadata import platform import sys from typing import Any, Dict -import packaging.version - from .. import __version__, constants _PY_VERSION: str = sys.version.split()[0].rstrip("+") -if packaging.version.Version(_PY_VERSION) < packaging.version.Version("3.8.0"): - import importlib_metadata # type: ignore -else: - import importlib.metadata as importlib_metadata # type: ignore - - _package_versions = {} _CANDIDATES = { @@ -65,9 +58,9 @@ _package_versions[candidate_name] = "N/A" for name in package_names: try: - _package_versions[candidate_name] = importlib_metadata.version(name) + _package_versions[candidate_name] = importlib.metadata.version(name) break - except importlib_metadata.PackageNotFoundError: + except importlib.metadata.PackageNotFoundError: pass diff --git a/src/huggingface_hub/utils/_typing.py b/src/huggingface_hub/utils/_typing.py index c8885eb1eb..56f2ceed6b 100644 --- a/src/huggingface_hub/utils/_typing.py +++ b/src/huggingface_hub/utils/_typing.py @@ -13,15 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. """Handle typing imports based on system compatibility.""" -import sys -from typing import Callable, TypeVar +from typing import Callable, Literal, TypeVar -if sys.version_info >= (3, 8): - from typing import Literal, TypedDict -else: - from typing_extensions import Literal, TypedDict # noqa: F401 - HTTP_METHOD_T = Literal["GET", "OPTIONS", "HEAD", "POST", "PUT", "PATCH", "DELETE"] # type hint meaning "function signature not changed by decorator" diff --git a/tests/test_inference_api.py b/tests/test_inference_api.py index 42a4a770f1..ec35013d43 100644 --- a/tests/test_inference_api.py +++ b/tests/test_inference_api.py @@ -20,7 +20,7 @@ from huggingface_hub import hf_hub_download from huggingface_hub.inference_api import InferenceApi -from .testing_utils import with_production_testing +from .testing_utils import expect_deprecation, with_production_testing @with_production_testing @@ -34,6 +34,7 @@ def setUpClass(cls) -> None: cls.image_file = hf_hub_download(repo_id="Narsil/image_dummy", repo_type="dataset", filename="lena.png") return super().setUpClass() + @expect_deprecation("huggingface_hub.inference_api") def test_simple_inference(self): api = InferenceApi("bert-base-uncased") inputs = "Hi, I think [MASK] is cool" @@ -45,6 +46,7 @@ def test_simple_inference(self): self.assertTrue("sequence" in result) self.assertTrue("score" in result) + @expect_deprecation("huggingface_hub.inference_api") def test_inference_with_params(self): api = InferenceApi("typeform/distilbert-base-uncased-mnli") inputs = "I bought a device but it is not working and I would like to get reimbursed!" @@ -54,6 +56,7 @@ def test_inference_with_params(self): self.assertTrue("sequence" in result) self.assertTrue("scores" in result) + @expect_deprecation("huggingface_hub.inference_api") def test_inference_with_dict_inputs(self): api = InferenceApi("distilbert-base-cased-distilled-squad") inputs = { @@ -65,6 +68,7 @@ def test_inference_with_dict_inputs(self): self.assertTrue("score" in result) self.assertTrue("answer" in result) + @expect_deprecation("huggingface_hub.inference_api") def test_inference_with_audio(self): api = InferenceApi("facebook/wav2vec2-base-960h") file = hf_hub_download( @@ -77,6 +81,7 @@ def test_inference_with_audio(self): self.assertIsInstance(result, dict) self.assertTrue("text" in result, f"We received {result} instead") + @expect_deprecation("huggingface_hub.inference_api") def test_inference_with_image(self): api = InferenceApi("google/vit-base-patch16-224") data = self.read(self.image_file) @@ -87,6 +92,7 @@ def test_inference_with_image(self): self.assertTrue("score" in classification) self.assertTrue("label" in classification) + @expect_deprecation("huggingface_hub.inference_api") def test_text_to_image(self): api = InferenceApi("stabilityai/stable-diffusion-2-1") with patch("huggingface_hub.inference_api.get_session") as mock: @@ -95,6 +101,7 @@ def test_text_to_image(self): output = api("cat") self.assertIsInstance(output, Image.Image) + @expect_deprecation("huggingface_hub.inference_api") def test_text_to_image_raw_response(self): api = InferenceApi("stabilityai/stable-diffusion-2-1") with patch("huggingface_hub.inference_api.get_session") as mock: @@ -104,6 +111,7 @@ def test_text_to_image_raw_response(self): # Raw response is returned self.assertEqual(output, mock().post.return_value) + @expect_deprecation("huggingface_hub.inference_api") def test_inference_overriding_task(self): api = InferenceApi( "sentence-transformers/paraphrase-albert-small-v2", @@ -113,10 +121,12 @@ def test_inference_overriding_task(self): result = api(inputs) self.assertIsInstance(result, list) + @expect_deprecation("huggingface_hub.inference_api") def test_inference_overriding_invalid_task(self): with self.assertRaises(ValueError, msg="Invalid task invalid-task. Make sure it's valid."): InferenceApi("bert-base-uncased", task="invalid-task") + @expect_deprecation("huggingface_hub.inference_api") def test_inference_missing_input(self): api = InferenceApi("deepset/roberta-base-squad2") result = api({"question": "What's my name?"})