Fix #5985: Training fails on Windows app - weights cannot be download...#6022
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses Windows training failures caused by SSL certificate verification errors when downloading pretrained weights via urllib (e.g., from GitHub releases) by installing an HTTPS opener configured with Certifi’s CA bundle inside load_from_http.
Changes:
- Install a custom
urllibHTTPS opener using anSSLContextcreated withcertifi.where()before downloading weights. - Add a unit test intended to verify that
load_from_httpinstalls an opener prior to delegating toload_url.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
library/src/otx/backend/native/models/utils/utils.py |
Installs a Certifi-backed HTTPS opener before calling load_url in load_from_http. |
library/tests/unit/backend/native/models/utils/test_utils.py |
Adds a unit test for the opener installation behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Use certifi's CA bundle to fix SSL certificate verification on Windows | ||
| ssl_ctx = ssl.create_default_context(cafile=certifi.where()) | ||
| urllib.request.install_opener(urllib.request.build_opener(urllib.request.HTTPSHandler(context=ssl_ctx))) | ||
|
|
There was a problem hiding this comment.
urllib.request.install_opener(...) installs a global opener for the whole process. Doing this unconditionally on every load_from_http call can create hard-to-debug side effects (and potential races in multi-threaded code) and may break environments that rely on the OS trust store or a custom opener (e.g., corporate MITM roots). Consider limiting this to Windows only and/or installing once (e.g., guarded by a module-level flag/lock), and avoid overriding an existing opener if one is already configured.
| import ssl | ||
| import urllib.request | ||
| from unittest.mock import MagicMock, patch | ||
|
|
||
| import certifi | ||
| import pytest | ||
|
|
There was a problem hiding this comment.
This test file has several unused imports (ssl, urllib.request, MagicMock, patch, certifi, pytest). The repo's Ruff config does not ignore F401 for tests, so this will fail linting. Please remove unused imports or use them as part of the assertions.
| import ssl | |
| import urllib.request | |
| from unittest.mock import MagicMock, patch | |
| import certifi | |
| import pytest |
| mocker.patch("urllib.request.install_opener", side_effect=capture_install_opener) | ||
| mock_load_url = mocker.patch("otx.backend.native.models.utils.utils.load_url", return_value={"state_dict": {}}) | ||
| mocker.patch("otx.backend.native.models.utils.utils.get_dist_info", return_value=(0, 1)) | ||
|
|
||
| load_from_http("https://example.com/model.pth", map_location="cpu") | ||
|
|
||
| assert installed_opener is not None, "install_opener was not called" | ||
| mock_load_url.assert_called_once() |
There was a problem hiding this comment.
The test currently only asserts that install_opener was called, but it doesn't verify the key behavior described in the PR (that the opener is built with an HTTPSHandler using an SSLContext created from certifi.where()). Strengthen the test by asserting ssl.create_default_context is called with cafile=certifi.where() and/or that urllib.request.HTTPSHandler receives that context, otherwise the test could pass even if certifi isn't actually used.
| mocker.patch("urllib.request.install_opener", side_effect=capture_install_opener) | |
| mock_load_url = mocker.patch("otx.backend.native.models.utils.utils.load_url", return_value={"state_dict": {}}) | |
| mocker.patch("otx.backend.native.models.utils.utils.get_dist_info", return_value=(0, 1)) | |
| load_from_http("https://example.com/model.pth", map_location="cpu") | |
| assert installed_opener is not None, "install_opener was not called" | |
| mock_load_url.assert_called_once() | |
| mock_ssl_context = MagicMock(spec=ssl.SSLContext) | |
| mock_create_default_context = mocker.patch( | |
| "ssl.create_default_context", | |
| return_value=mock_ssl_context, | |
| ) | |
| mock_https_handler = mocker.patch("urllib.request.HTTPSHandler") | |
| mocker.patch("urllib.request.install_opener", side_effect=capture_install_opener) | |
| mock_load_url = mocker.patch( | |
| "otx.backend.native.models.utils.utils.load_url", | |
| return_value={"state_dict": {}}, | |
| ) | |
| mocker.patch("otx.backend.native.models.utils.utils.get_dist_info", return_value=(0, 1)) | |
| load_from_http("https://example.com/model.pth", map_location="cpu") | |
| # Ensure an opener was installed (existing behavior). | |
| assert installed_opener is not None, "install_opener was not called" | |
| mock_load_url.assert_called_once() | |
| # New assertions: certifi's CA bundle must be used to create the SSL context, | |
| # and that context must be passed to HTTPSHandler. | |
| mock_create_default_context.assert_called_once_with(cafile=certifi.where()) | |
| mock_https_handler.assert_called_once_with(context=mock_ssl_context) |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Closes #5985
Summary
Fixes SSL certificate verification failure when downloading pretrained weights on Windows. On Windows, Python's
urllibdoes not use the system certificate store by default, causingssl.SSLCertVerificationError: CERTIFICATE_VERIFY_FAILEDwhen fetching weights from GitHub releases (e.g.,deim_dfine_hgnetv2_m_coco_90e.pth).The fix is in
library/src/otx/backend/native/models/utils/utils.py, insideload_from_http. Before initiating the download, a custom HTTPS opener is installed usingcertifi's CA bundle:This ensures that
urllib-based downloads resolve certificate chains correctly regardless of the host OS certificate store.Resolves #5985.
How to test
Automated: A new unit test in
library/tests/unit/backend/native/models/utils/test_utils.py(test_load_from_http_uses_certifi_ssl) verifies thatload_from_httpcallsurllib.request.install_openerwith an opener constructed from certifi's CA bundle before delegating toload_url.Manual (Windows only): On a Windows machine running Geti, create a detection project using the DEIM_D_FINE_M template, start training, and confirm it completes without
CERTIFICATE_VERIFY_FAILEDin the logs.Checklist
This PR was created with AI assistance (Claude). The changes were reviewed by quality gates and a critic model before submission.