Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d02da49
Refactor download_url test into TestDownloadUrl class
e-mny Apr 17, 2026
867287e
Merge branch 'dev' into dev
e-mny Apr 17, 2026
6296784
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 17, 2026
8a6b6f6
Enoch Mok <enochmokny@gmail.com>
e-mny Apr 18, 2026
66af964
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 18, 2026
43f508b
Merge branch 'dev' into dev
e-mny Apr 18, 2026
834a8b4
Validate downloaded file integrity and raise ValueError on hash mismatch
e-mny Apr 18, 2026
51a49b0
Validate downloaded file integrity and raise ValueError on hash misma…
e-mny Apr 18, 2026
98ccecc
amended runtimeerrors -> valueerror
e-mny Apr 18, 2026
29ec2fe
fixing code according to coderabbitai
e-mny Apr 18, 2026
606e7ca
addressed bugs and issues raised in previous commit
e-mny Apr 18, 2026
19ce7f6
Merge branch 'dev' into 8832-hashvalueerror
ericspod Apr 19, 2026
88f8372
addressing Eric's comment in https://github.com/Project-MONAI/MONAI/p…
e-mny Apr 20, 2026
e9861d3
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 20, 2026
453b238
removing duplicate line
e-mny Apr 20, 2026
64b8e09
removed duplicated tests for download_url. updated existing tests for…
e-mny Apr 20, 2026
096c6d0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 20, 2026
e8e1f4b
Merge branch 'dev' into 8832-hashvalueerror
ericspod Apr 29, 2026
5b0b5f4
Apply suggestions from code review
e-mny Jun 3, 2026
3c61005
removed hash checking in a function that checks for download fails
e-mny Jun 4, 2026
44f4d10
Merge branch 'dev' into 8832-hashvalueerror
e-mny Jun 4, 2026
126fcc3
Merge branch 'dev' into 8832-hashvalueerror
ericspod Jun 22, 2026
8974b4d
added HashCheckError
e-mny Jun 25, 2026
32ebca7
refactor(engines): introduce SingleNetworkTrainer and DualNetworkTrai…
e-mny Jun 25, 2026
b014da5
Merge branch 'dev' into 8498-trainerclassabstraction
e-mny Jun 25, 2026
731e0e2
adding according to coderabbit's suggestions
e-mny Jun 25, 2026
54f5f60
adding according to coderabbit's suggestions
e-mny Jun 25, 2026
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
35 changes: 19 additions & 16 deletions monai/apps/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
SUPPORTED_HASH_TYPES = {"md5": hashlib.md5, "sha1": hashlib.sha1, "sha256": hashlib.sha256, "sha512": hashlib.sha512}


class HashCheckError(ValueError):
pass


def get_logger(
module_name: str = "monai.apps",
fmt: str = DEFAULT_FMT,
Expand Down Expand Up @@ -220,18 +224,15 @@ def download_url(
HTTPError: See urllib.request.urlretrieve.
ContentTooShortError: See urllib.request.urlretrieve.
IOError: See urllib.request.urlretrieve.
RuntimeError: When the hash validation of the ``url`` downloaded file fails.

ValueError: When the hash validation of the ``url`` downloaded file fails.
"""
if not filepath:
filepath = Path(".", _basename(url)).resolve()
logger.info(f"Default downloading to '{filepath}'")
filepath = Path(filepath)
if filepath.exists():
if not check_hash(filepath, hash_val, hash_type):
raise RuntimeError(
f"{hash_type} check of existing file failed: filepath={filepath}, expected {hash_type}={hash_val}."
)
raise HashCheckError(f"{hash_type} hash check of existing file failed: {filepath=}, expected {hash_type=}.")
Comment on lines +227 to +235

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the stale Raises contract for existing files.

Line 235 now raises HashCheckError(ValueError) for the pre-existing-file branch too, but the Raises section still advertises RuntimeError for that path. The public contract is now inconsistent.

Suggested diff
-        RuntimeError: When the hash validation of the ``filepath`` existing file fails.
+        ValueError: When the hash validation of the ``filepath`` existing file fails.

As per path instructions, **/*.py: Docstrings should be present for all definition which describe each variable, return value, and raised exception in the appropriate section of the Google-style of docstrings.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@monai/apps/utils.py` around lines 227 - 235, The docstring contract for the
existing-file branch is stale: the filepath/hash-validation path in the download
helper now raises HashCheckError(ValueError), not RuntimeError. Update the
Google-style Raises section in the same helper that checks filepath.exists() and
calls check_hash so it accurately lists HashCheckError for this branch and keeps
the public exception contract aligned with the actual behavior.

Source: Path instructions

logger.info(f"File exists: {filepath}, skipped downloading.")
return
try:
Expand Down Expand Up @@ -260,18 +261,20 @@ def download_url(
raise RuntimeError(
f"Download of file from {url} to {filepath} failed due to network issue or denied permission."
)
if not check_hash(tmp_name, hash_val, hash_type):
raise HashCheckError(
f"{hash_type} hash check of downloaded file failed: {url=}, "
f"{filepath=}, expected {hash_type}={hash_val}, "
f"The file may be corrupted or tampered with. "
"Please retry the download or verify the source."
)
file_dir = filepath.parent
if file_dir:
os.makedirs(file_dir, exist_ok=True)
shutil.move(f"{tmp_name}", f"{filepath}") # copy the downloaded to a user-specified cache.
except (PermissionError, NotADirectoryError): # project-monai/monai issue #3613 #3757 for windows
pass
logger.info(f"Downloaded: {filepath}")
if not check_hash(filepath, hash_val, hash_type):
raise RuntimeError(
f"{hash_type} check of downloaded file failed: URL={url}, "
f"filepath={filepath}, expected {hash_type}={hash_val}."
)


def _extract_zip(filepath, output_dir):
Expand Down Expand Up @@ -325,10 +328,15 @@ def extractall(
be False.

Raises:
RuntimeError: When the hash validation of the ``filepath`` compressed file fails.
ValueError: When the hash validation of the ``filepath`` compressed file fails.
NotImplementedError: When the ``filepath`` file extension is not one of [zip", "tar.gz", "tar"].

"""
filepath = Path(filepath)
if hash_val and not check_hash(filepath, hash_val, hash_type):
raise HashCheckError(
f"{hash_type} hash check of compressed file failed: " f"{filepath=}, expected {hash_type}={hash_val}."
)
if has_base:
# the extracted files will be in this folder
cache_dir = Path(output_dir, _basename(filepath).split(".")[0])
Expand All @@ -337,11 +345,6 @@ def extractall(
if cache_dir.exists() and next(cache_dir.iterdir(), None) is not None:
logger.info(f"Non-empty folder exists in {cache_dir}, skipped extracting.")
return
filepath = Path(filepath)
if hash_val and not check_hash(filepath, hash_val, hash_type):
raise RuntimeError(
f"{hash_type} check of compressed file failed: " f"filepath={filepath}, expected {hash_type}={hash_val}."
)
logger.info(f"Writing into directory: {output_dir}.")
_file_type = file_type.lower().strip()
if filepath.name.endswith("zip") or _file_type == "zip":
Expand Down
6 changes: 4 additions & 2 deletions monai/bundle/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,10 @@
"run_name": None,
# may fill it at runtime
"save_execute_config": True,
"is_not_rank0": ("$torch.distributed.is_available() \
and torch.distributed.is_initialized() and torch.distributed.get_rank() > 0"),
"is_not_rank0": (
"$torch.distributed.is_available() \
and torch.distributed.is_initialized() and torch.distributed.get_rank() > 0"
),
# MLFlowHandler config for the trainer
"trainer": {
"_target_": "MLFlowHandler",
Expand Down
Loading
Loading