From 8a47eec0592dd3be778f5fe8fa3450ff90b75d96 Mon Sep 17 00:00:00 2001 From: panchicore Date: Wed, 29 Jul 2026 11:05:13 -0500 Subject: [PATCH] [SC-17529] Treat broken torch installs as "not a PyTorch model" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit is_pytorch_model() only caught ImportError, but a broken torch install can raise other errors on import — e.g. OSError WinError 1114 when c10.dll fails to load on Windows — which crashed vm.init_model() even for non-torch models like sklearn LogisticRegression (ZD 741). Co-Authored-By: Claude Fable 5 --- tests/test_model.py | 55 ++++++++++++++++++++++++++++++++++++ validmind/vm_models/model.py | 6 ++-- 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 tests/test_model.py diff --git a/tests/test_model.py b/tests/test_model.py new file mode 100644 index 000000000..31c84c5ef --- /dev/null +++ b/tests/test_model.py @@ -0,0 +1,55 @@ +# Copyright © 2023-2026 ValidMind Inc. All rights reserved. +# Refer to the LICENSE file in the root of this repository for details. +# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial + +""" +Unit tests for model type detection in validmind.vm_models.model +""" + +import sys +import unittest + +from sklearn.linear_model import LogisticRegression + +from validmind.vm_models.model import is_pytorch_model + + +class BrokenTorchFinder: + """Simulates a broken torch install where importing torch raises an + error other than ImportError (e.g. OSError WinError 1114 when c10.dll + fails to load on Windows).""" + + def find_spec(self, fullname, path=None, target=None): + if fullname == "torch" or fullname.startswith("torch."): + raise OSError( + "[WinError 1114] A dynamic link library (DLL) initialization " + "routine failed. Error loading c10.dll" + ) + return None + + +class TestIsPyTorchModel(unittest.TestCase): + def test_non_torch_model_returns_false(self): + self.assertFalse(is_pytorch_model(LogisticRegression())) + + def test_broken_torch_install_returns_false(self): + saved_modules = { + name: module + for name, module in sys.modules.items() + if name == "torch" or name.startswith("torch.") + } + for name in saved_modules: + del sys.modules[name] + + finder = BrokenTorchFinder() + sys.meta_path.insert(0, finder) + + try: + self.assertFalse(is_pytorch_model(LogisticRegression())) + finally: + sys.meta_path.remove(finder) + sys.modules.update(saved_modules) + + +if __name__ == "__main__": + unittest.main() diff --git a/validmind/vm_models/model.py b/validmind/vm_models/model.py index debc9c5c3..508c8c4db 100644 --- a/validmind/vm_models/model.py +++ b/validmind/vm_models/model.py @@ -187,10 +187,12 @@ def is_pytorch_model(model): Checks if the model is a PyTorch model. Need to extend this method to check for all ways a PyTorch model can be created """ - # if we can't import torch, then it's not a PyTorch model + # if we can't import torch, then it's not a PyTorch model. Broken torch + # installs can fail with errors other than ImportError (e.g. OSError + # WinError 1114 when a native DLL fails to load on Windows) try: import torch.nn as nn - except ImportError: + except Exception: return False # return False