Fix custom tqdm_class silently broken in non-TTY environments#4056
Fix custom tqdm_class silently broken in non-TTY environments#4056hanouticelina merged 5 commits intomainfrom
tqdm_class silently broken in non-TTY environments#4056Conversation
| pbar.close() | ||
|
|
||
|
|
||
| def _create_progress_bar(*, cls: type[old_tqdm], log_level: int, name: str | None = None, **kwargs) -> old_tqdm: |
There was a problem hiding this comment.
added this private helper to centralize how we initialize the tqdm progress bar. is_tqdm_disabled is no longer needed internally but kept it since it's exposed in huggingface_hub.utils module
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
|
Thanks for the fix @hanouticelina! There's a related but distinct tqdm bug that this PR's tqdm crashes with multiprocessing lock errors when used in threaded contexts such as Textual TUI worker threads, some web server setups, etc. The error looks like: or This happens because tqdm internally initializes multiprocessing locks during def _create_progress_bar(*, cls, log_level, name=None, **kwargs):
# ... existing logic ...
try:
return cls(disable=disable, name=name, **kwargs)
except (OSError, ValueError):
# tqdm multiprocessing lock init can fail in threaded contexts
# (Textual workers, some web servers). Fall back to disabled bar.
logger.warning(
"Progress bar could not be initialized in this environment. "
"Download will continue without progress reporting. "
"Set HF_HUB_DISABLE_PROGRESS_BARS=1 to silence this warning."
)
return cls(disable=True, **kwargs)Right now users can work around this by setting This crash was initial root motivation behind #4051 and I feel it might as well be addressed here. The non-TTY silencing was a secondary symptom, but the primary crash was tqdm's multiprocessing lock failing in worker threads. My suggestion is to add this try/except and add a test case before merging. This way a separate fix/pr can be avoided and this is a great defensive measure. |
| disable = False | ||
| else: | ||
| disable = None | ||
| return cls(disable=disable, name=name, **kwargs) # type: ignore[return-value] |
There was a problem hiding this comment.
_create_progress_bar should wrap instantiation in try/except (OSError, ValueError), log a warning, and fall back to a no-op. A progress bar failing to init shouldn't crash the download.
See #4056 (comment)
Wauplin
left a comment
There was a problem hiding this comment.
I'm fine with this fix 👍
Approving but could you still address comment before merging?
Also could you mention explicitly in the PR description that this is a breaking change so we pick it up for the next release notes (it's a breaking change since we change the default behavior of custom tqdm classes)
Co-authored-by: célina <[email protected]>
|
@Wauplin updated the PR description and addressed your comment, thanks! |
|
@Wauplin @hanouticelina this is the second time my concerns were ignored or dismissed silently. My feedback on this PR was completely ignored which is troublesome. If my concerns are wrong or invalid, then they should be acknowledged and resolved and not ignored. If I'm in the wrong place, I should be told this as well. I would have never put in the effort had I known it wouldn't even be read. I put a large amounts of effort into providing exhaustive amounts of information, reproducing bugs, creating detailed descriptions, creating a fix and they just got completely dismissed with zero acknowledgement which isn't great. Nobody should be ignored like this. A simple acknowledgement would have been sufficient. A culture of ignoring is just not cool, especially if the concerns are warranted and valid. All I asked for was to roll in a defensive measure here, and what got merged in will crash specifically in the contexts I mentioned. If my approach isn't good, then say so and be direct. My ego isn't big and I'm always prepared to be wrong about something. Could simply suggest opening a separate PR or you can tell me that my approach is bad, but the silence is why I'm raising an alarm. It started here: #4051 my bug reports, granularity concerns, all dismissed and not acknowledged. I understand my implementation not being merged in, but all the concerns in this PR were just completely either not read or just not appreciated at all. My implementation was deemed "too complicated" but it also was a completely backwards compatible additive not breaking change and that was my philosophy. The code here is a deliberate breaking change and something I was trying to avoid introducing as an outsider to the org. I understand it not being merged in due to the complexity, but the surrounding concerns of the crash and the progress granularity being ignored is what is unsettling. A change request could have also been an option and I would have happily made the change Most importantly, the crash concern got completely ignored in this pr. I expect similar communication patterns with my followup If someone puts significant effort into something, the general rule that we all should stand by is acknowledging their concerns. In that previous PR, i identified two serious bugs, and the response was along the lines of "this is too complicated and not worth it" and I get it but there were other issues flagged in this PR that got dismissed completely which is what concerns me. This is poor communication. Suggesting a different implementation and acknowledging the issues I flagged is what I was hoping for. You can say something like "Create a separate issue", or "this concern will be addressed in a separate PR" or "thanks for the report, but we'll be doing this differently" or even in the case of this PR, just an emoji reaction would be sufficient, but instead it got completely ignored and now I feel less compelled to report any bugs in the future. Ignoring is not acceptable and an improvement in communication is needed. I normally do not create noise like this, but I obviously do not like being ignored and I apologize for the wall of text. My goal is to help make this library as good as it can be and work well for everyone. When serious concerns are raised and ignored, it's just baffling to me. I really appreciate this library and I can't help but call out this behavior in an effort to improve communication with those outside of the org. Like I said before, being ignored makes me not want to report these bugs anymore, so I really hope this communication issue gets addressed. |

Fixes #4050.
when passing a custom
tqdm_classtohf_hub_download()orsnapshot_download(), progress tracking is broken. this is because all tqdm classes are instantiated identically. When a user passes a customtqdm_class, they take full control of progress bar behavior. The library should not inject HF-specific kwargs (name) or override display logic (disable). the custom class is responsible for its own configuration.Here is a small reproducible:
this causes two bugs depending on the environment:
In TTY:
disable=None->isatty()returnsTrue-> tqdm continues__init__-> hits the unknown kwargs check →TqdmKeyErroronname:In non-TTY:
is_tqdm_disabled()returnsNone. Vanilla tqdm interpretsdisable=Noneas "checksys.stderr.isatty()" →Falsein non-TTY → setsself.disable = True→update()becomes a no-op. No crash, but progress is silently lost:tqdm_classinstances no longer receive thenamekwarg ordisablevalue, the custom class is fully responsible for its own configuration.Note
Low Risk
Low risk: change is isolated to progress bar instantiation logic and adds regression tests; main behavior change only affects callers providing a custom
tqdm_class, especially in non-TTY environments.Overview
Fixes progress reporting when callers pass a custom
tqdm_classby centralizing progress-bar creation in_create_progress_barand only applying Hugging Face–specific kwargs (name) and disable/TTY logic for the HFtqdmsubclass.Updates both
_get_progress_bar_contextandsnapshot_downloadto use this helper, and adds regression tests to ensure group-based disabling still works for HF bars while vanilla/custom tqdm classes are neither force-disabled in non-TTY nor passed the unsupportednamekwarg.Reviewed by Cursor Bugbot for commit d5d3eba. Bugbot is set up for automated code reviews on this repo. Configure here.