From c055b58e638cbf3fc392c6eec372342a0c0cc329 Mon Sep 17 00:00:00 2001 From: Michele Dolfi Date: Tue, 5 Aug 2025 14:23:04 +0200 Subject: [PATCH 1/4] fix: make utils.tqdm thread-safe Signed-off-by: Michele Dolfi --- src/huggingface_hub/utils/tqdm.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/huggingface_hub/utils/tqdm.py b/src/huggingface_hub/utils/tqdm.py index 4c1fcef4be..c7bd40d221 100644 --- a/src/huggingface_hub/utils/tqdm.py +++ b/src/huggingface_hub/utils/tqdm.py @@ -211,7 +211,22 @@ def is_tqdm_disabled(log_level: int) -> Optional[bool]: return None -class tqdm(old_tqdm): +class SafeDelLockMeta(type): + """ + Class for fixing `del tqdm_class._lock`: https://github.com/huggingface/datasets/issues/7660 + """ + + def __delattr__(cls, name): + if name == "_lock": + try: + super().__delattr__(name) + except AttributeError: + pass + else: + super().__delattr__(name) + + +class tqdm(old_tqdm, metaclass=SafeDelLockMeta): """ Class to override `disable` argument in case progress bars are globally disabled. @@ -219,19 +234,10 @@ class tqdm(old_tqdm): """ def __init__(self, *args, **kwargs): - name = kwargs.pop("name", None) # do not pass `name` to `tqdm` - if are_progress_bars_disabled(name): + if are_progress_bars_disabled(): kwargs["disable"] = True super().__init__(*args, **kwargs) - def __delattr__(self, attr: str) -> None: - """Fix for https://github.com/huggingface/huggingface_hub/issues/1603""" - try: - super().__delattr__(attr) - except AttributeError: - if attr != "_lock": - raise - @contextmanager def tqdm_stream_file(path: Union[Path, str]) -> Iterator[io.BufferedReader]: From 5f8cbc34d664f04b60cffbcdb6138e46e17d5230 Mon Sep 17 00:00:00 2001 From: Michele Dolfi Date: Wed, 6 Aug 2025 17:38:39 +0200 Subject: [PATCH 2/4] restore original __init__ and __delattr Signed-off-by: Michele Dolfi --- src/huggingface_hub/utils/tqdm.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/huggingface_hub/utils/tqdm.py b/src/huggingface_hub/utils/tqdm.py index c7bd40d221..e4d11c7f8d 100644 --- a/src/huggingface_hub/utils/tqdm.py +++ b/src/huggingface_hub/utils/tqdm.py @@ -234,10 +234,18 @@ class tqdm(old_tqdm, metaclass=SafeDelLockMeta): """ def __init__(self, *args, **kwargs): - if are_progress_bars_disabled(): + name = kwargs.pop("name", None) # do not pass `name` to `tqdm` + if are_progress_bars_disabled(name): kwargs["disable"] = True super().__init__(*args, **kwargs) + def __delattr__(self, attr: str) -> None: + """Fix for https://github.com/huggingface/huggingface_hub/issues/1603""" + try: + super().__delattr__(attr) + except AttributeError: + if attr != "_lock": + raise @contextmanager def tqdm_stream_file(path: Union[Path, str]) -> Iterator[io.BufferedReader]: From a2c84b52896976c8230034d809b3bdcaecab197a Mon Sep 17 00:00:00 2001 From: Michele Dolfi Date: Thu, 7 Aug 2025 15:01:01 +0200 Subject: [PATCH 3/4] make quality and style Signed-off-by: Michele Dolfi --- src/huggingface_hub/utils/tqdm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/huggingface_hub/utils/tqdm.py b/src/huggingface_hub/utils/tqdm.py index e4d11c7f8d..f02dc94185 100644 --- a/src/huggingface_hub/utils/tqdm.py +++ b/src/huggingface_hub/utils/tqdm.py @@ -247,6 +247,7 @@ def __delattr__(self, attr: str) -> None: if attr != "_lock": raise + @contextmanager def tqdm_stream_file(path: Union[Path, str]) -> Iterator[io.BufferedReader]: """ From 2dff57343e5b82389108c6c11972d9ded13ab27c Mon Sep 17 00:00:00 2001 From: Michele Dolfi Date: Thu, 7 Aug 2025 18:46:55 +0200 Subject: [PATCH 4/4] handle case with progressbar enabled Signed-off-by: Michele Dolfi --- src/huggingface_hub/utils/tqdm.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/huggingface_hub/utils/tqdm.py b/src/huggingface_hub/utils/tqdm.py index f02dc94185..586353de31 100644 --- a/src/huggingface_hub/utils/tqdm.py +++ b/src/huggingface_hub/utils/tqdm.py @@ -83,6 +83,7 @@ import io import logging import os +import threading import warnings from contextlib import contextmanager, nullcontext from pathlib import Path @@ -227,18 +228,32 @@ def __delattr__(cls, name): class tqdm(old_tqdm, metaclass=SafeDelLockMeta): + # class tqdm(old_tqdm): """ Class to override `disable` argument in case progress bars are globally disabled. Taken from https://github.com/tqdm/tqdm/issues/619#issuecomment-619639324. """ + _lock = threading.RLock() # fallback, just in case + + @classmethod + def get_lock(cls): + if not hasattr(cls, "_lock") or cls._lock is None: + cls._lock = threading.RLock() + return cls._lock + def __init__(self, *args, **kwargs): name = kwargs.pop("name", None) # do not pass `name` to `tqdm` if are_progress_bars_disabled(name): kwargs["disable"] = True super().__init__(*args, **kwargs) + def update(self, n=1): + # Always get a valid lock + with self.get_lock(): + super().update(n) + def __delattr__(self, attr: str) -> None: """Fix for https://github.com/huggingface/huggingface_hub/issues/1603""" try: