Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.13"]
python-version: ["3.9", "3.14"]
test_name: ["Everything else", "Inference only", "Xet only"]
include:
- python-version: "3.13" # LFS not ran on 3.9
- python-version: "3.14" # LFS not ran on 3.9
test_name: "lfs"
- python-version: "3.9"
test_name: "fastai"
Expand All @@ -34,6 +34,8 @@ jobs:
test_name: "Python 3.9, torch_1.11"
- python-version: "3.12" # test torch latest on python 3.12 only.
test_name: "torch_latest"
- python-version: "3.13" # gradio not supported on 3.14 -> test it on 3.13
test_name: "gradio"
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
Expand Down Expand Up @@ -69,6 +71,10 @@ jobs:
uv pip install "huggingface_hub[fastai] @ ."
;;

gradio)
uv pip install "huggingface_hub[gradio] @ ."
;;

torch_latest)
uv pip install "huggingface_hub[torch] @ ."
uv pip install --upgrade torch
Expand Down Expand Up @@ -117,6 +123,10 @@ jobs:
eval "$PYTEST ../tests/test_fastai*"
;;

gradio)
eval "$PYTEST ../tests/test_webhooks_server.py"
;;

"Python 3.9, torch_1.11" | torch_latest)
eval "$PYTEST ../tests/test_hub_mixin*"
eval "$PYTEST ../tests/test_serialization.py"
Expand Down Expand Up @@ -148,7 +158,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.11"]
python-version: ["3.9", "3.14"]
test_name: ["Everything else", "Xet only"]

steps:
Expand Down
8 changes: 5 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ def get_version() -> str:
"urllib3<2.0", # VCR.py broken with urllib3 2.0 (see https://urllib3.readthedocs.io/en/stable/v2-migration-guide.html)
"soundfile",
"Pillow",
"requests", # for gradio
"numpy", # for embeddings
"fastapi", # To build the documentation
]
Expand All @@ -74,8 +73,10 @@ def get_version() -> str:
if sys.version_info >= (3, 10):
# We need gradio to test webhooks server
# But gradio 5.0+ only supports python 3.10+ so we don't want to test earlier versions
extras["testing"].append("gradio>=5.0.0")
extras["testing"].append("requests") # see https://github.com/gradio-app/gradio/pull/11830
extras["gradio"] = [
"gradio>=5.0.0",
"requests", # see https://github.com/gradio-app/gradio/pull/11830
]

# Typing extra dependencies list is duplicated in `.pre-commit-config.yaml`
# Please make sure to update the list there when adding a new typing dependency.
Expand Down Expand Up @@ -135,6 +136,7 @@ def get_version() -> str:
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
],
include_package_data=True,
Expand Down
23 changes: 17 additions & 6 deletions src/huggingface_hub/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,7 @@ def validate_typed_dict(schema: type[TypedDictType], data: dict) -> None:
@lru_cache
def _build_strict_cls_from_typed_dict(schema: type[TypedDictType]) -> Type:
# Extract type hints from the TypedDict class
type_hints = {
# We do not use `get_type_hints` here to avoid evaluating ForwardRefs (which might fail).
# ForwardRefs are not validated by @strict anyway.
name: value if value is not None else type(None)
for name, value in schema.__dict__.get("__annotations__", {}).items()
}
type_hints = _get_typed_dict_annotations(schema)

# If the TypedDict is not total, wrap fields as NotRequired (unless explicitly Required or NotRequired)
if not getattr(schema, "__total__", True):
Expand Down Expand Up @@ -338,6 +333,22 @@ def _build_strict_cls_from_typed_dict(schema: type[TypedDictType]) -> Type:
return strict(make_dataclass(schema.__name__, fields))


def _get_typed_dict_annotations(schema: type[TypedDictType]) -> dict[str, Any]:
"""Extract type annotations from a TypedDict class."""
try:
# Available in Python 3.14+
import annotationlib

return annotationlib.get_annotations(schema)
except ImportError:
return {
# We do not use `get_type_hints` here to avoid evaluating ForwardRefs (which might fail).
# ForwardRefs are not validated by @strict anyway.
name: value if value is not None else type(None)
for name, value in schema.__dict__.get("__annotations__", {}).items()
}


def validated_field(
validator: Union[list[Validator_T], Validator_T],
default: Union[Any, _MISSING_TYPE] = MISSING,
Expand Down
20 changes: 0 additions & 20 deletions tests/test_utils_http.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import os
import threading
import time
import unittest
from http.server import BaseHTTPRequestHandler, HTTPServer
from multiprocessing import Process, Queue
from typing import Generator, Optional
from unittest.mock import Mock, call, patch
from urllib.parse import urlparse
Expand Down Expand Up @@ -222,24 +220,6 @@ def _get_session_in_thread(index: int) -> None:
for j in range(N):
self.assertIs(clients[i], clients[j])

@unittest.skipIf(os.name == "nt", "Works differently on Windows.")
def test_get_session_in_forked_process(self):
# Get main process client
main_client = get_session()

def _child_target():
# Put `repr(client)` in queue because putting the `Client` object directly would duplicate it.
# Repr looks like this: "<httpx.Client object at 0x7f5adcc41e40>"
process_queue.put(repr(get_session()))

# Fork a new process and get client in it
process_queue = Queue()
Process(target=_child_target).start()
child_client = process_queue.get()

# Check clients are the same instance
self.assertEqual(repr(main_client), child_client)


class OfflineModeSessionTest(unittest.TestCase):
def tearDown(self) -> None:
Expand Down
Loading