diff --git a/src/sas/qtgui/Utilities/NewVersion/NewVersionAvailable.py b/src/sas/qtgui/Utilities/NewVersion/NewVersionAvailable.py index db721a1abc..340da0b098 100644 --- a/src/sas/qtgui/Utilities/NewVersion/NewVersionAvailable.py +++ b/src/sas/qtgui/Utilities/NewVersion/NewVersionAvailable.py @@ -2,8 +2,7 @@ import webbrowser from copy import copy -import requests -from packaging.version import Version, parse +from packaging.version import parse from PySide6.QtCore import QSize from PySide6.QtGui import QIcon from PySide6.QtWidgets import ( @@ -19,8 +18,8 @@ ) from sas import config -from sas.system import web from sas.system.version import __version__ as current_version_string +from sas.system.web import get_current_release_version logger = logging.getLogger("NewVersionAvailable") @@ -83,27 +82,6 @@ def cancel(self): self.close() -def get_current_release_version() -> tuple[str, str, Version] | None: - """ Get the current version from the server """ - try: - response = requests.get(web.update_url, timeout=config.UPDATE_TIMEOUT) - # Will throw Exception if the HTTP status code returned isn't success - # (2xx) - response.raise_for_status() - version_info = response.json() - logger.info("Connected to www.sasview.org. Received: %s", version_info) - - version_string = version_info["version"] - url = version_info["download_url"] - - return version_string, url, parse(version_string) - - except Exception as ex: - logger.info("Failed to get version number %s", ex) - return None - - - def maybe_prompt_new_version_download() -> QDialog | None: """ If a new version is available, and Show a dialog prompting the user to download """ diff --git a/src/sas/system/_help.py b/src/sas/system/_help.py index 086a62b5de..49ebad4952 100644 --- a/src/sas/system/_help.py +++ b/src/sas/system/_help.py @@ -2,6 +2,8 @@ import webbrowser from pathlib import Path +from sas.system.web import get_current_release_version + logger = logging.getLogger(__name__) @@ -75,8 +77,15 @@ def _online_url(self, relative_path: Path, fragment: str = "") -> str: """Construct the online documentation URL for the current version.""" from sas.system.version import __version__ - version = _release_version(__version__) - base = f"https://www.sasview.org/docs/v{version}" + release_version = get_current_release_version() + active_version = _release_version(__version__) + + # The base URL is different for the latest version of docs. + if release_version == active_version: + base = "https://www.sasview.org/docs/" + else: + base = f"https://www.sasview.org/docs/old_docs/{active_version}" + url = f"{base}/{relative_path.as_posix()}" if fragment: url += "#" + fragment diff --git a/src/sas/system/web.py b/src/sas/system/web.py index 6384367681..5def212827 100644 --- a/src/sas/system/web.py +++ b/src/sas/system/web.py @@ -1,3 +1,12 @@ +import logging + +import requests +from packaging.version import Version, parse + +from sas.system import config + +logger = logging.getLogger("Web Configuration") + class WebLinks: def __init__(self): self.nist_url = "https://www.nist.gov/ncnr" @@ -22,5 +31,26 @@ def __init__(self): self.help_email = "help@sasview.org" + +def get_current_release_version() -> tuple[str, str, Version] | None: + """ Get the current version from the server """ + try: + response = requests.get(web.update_url, timeout=config.UPDATE_TIMEOUT) + # Will throw Exception if the HTTP status code returned isn't success + # (2xx) + response.raise_for_status() + version_info = response.json() + logger.info("Connected to www.sasview.org. Received: %s", version_info) + + version_string = version_info["version"] + url = version_info["download_url"] + + return version_string, url, parse(version_string) + + except Exception as ex: + logger.info("Failed to get version number %s", ex) + return None + + web = WebLinks() diff --git a/test/system/utest_help.py b/test/system/utest_help.py index d56453397c..509a53b42a 100644 --- a/test/system/utest_help.py +++ b/test/system/utest_help.py @@ -5,6 +5,8 @@ from sas.system._help import _HelpSystem, _release_version +TEST_VERSION = '4.2.2' + class PosixTestPath(PurePosixPath): """Pure POSIX path with the minimal filesystem API used by _HelpSystem.""" @@ -38,26 +40,26 @@ def setup_method(self): @patch("sas.system._help.HELP_SYSTEM") def test_online_url_basic(self, _mock): - with patch("sas.system.version.__version__", "6.1.2"): + with patch("sas.system.version.__version__", TEST_VERSION): url = self.hs._online_url( Path("user/qtgui/Perspectives/Fitting/fitting_help.html") ) assert url == ( - "https://www.sasview.org/docs/v6.1.2" + f"https://www.sasview.org/docs/old_docs/{TEST_VERSION}" "/user/qtgui/Perspectives/Fitting/fitting_help.html" ) def test_online_url_dev_version(self): - with patch("sas.system.version.__version__", "6.1.2.dev159+g77be83657"): + with patch("sas.system.version.__version__", f"{TEST_VERSION}.dev159+g77be83657"): url = self.hs._online_url( Path("user/qtgui/Perspectives/Fitting/fitting_help.html") ) - assert url.startswith("https://www.sasview.org/docs/v6.1.2/") + assert url.startswith(f"https://www.sasview.org/docs/old_docs/{TEST_VERSION}/") assert "+g77be83657" not in url assert ".dev159" not in url def test_online_url_with_fragment(self): - with patch("sas.system.version.__version__", "6.1.2"): + with patch("sas.system.version.__version__", TEST_VERSION): url = self.hs._online_url( Path("user/qtgui/Perspectives/Fitting/fitting_help.html"), "simultaneous-fits", @@ -65,7 +67,7 @@ def test_online_url_with_fragment(self): assert url.endswith("fitting_help.html#simultaneous-fits") def test_online_url_uses_posix_separators(self): - with patch("sas.system.version.__version__", "6.1.2"): + with patch("sas.system.version.__version__", TEST_VERSION): url = self.hs._online_url( Path("user") / "qtgui" / "Perspectives" / "Fitting" / "fitting_help.html" ) @@ -110,19 +112,19 @@ def test_local_docs_with_fragment(self, mock_wb, tmp_path): def test_online_fallback_when_local_missing(self, mock_wb, tmp_path): """When local docs don't exist, fall back to online URL.""" self.hs.path = tmp_path # empty dir — no docs - with patch("sas.system.version.__version__", "6.1.2"): + with patch("sas.system.version.__version__", TEST_VERSION): self.hs.show_help("user/fitting.html") opened_url = mock_wb.open.call_args[0][0] assert opened_url == ( - "https://www.sasview.org/docs/v6.1.2/user/fitting.html" + f"https://www.sasview.org/docs/old_docs/{TEST_VERSION}/user/fitting.html" ) @patch("sas.system._help.webbrowser") def test_online_fallback_no_absolute_path_leak(self, mock_wb, tmp_path): """The online URL must never contain the local filesystem path.""" self.hs.path = tmp_path - with patch("sas.system.version.__version__", "6.1.2"): + with patch("sas.system.version.__version__", TEST_VERSION): self.hs.show_help("user/fitting.html") opened_url = mock_wb.open.call_args[0][0] @@ -134,11 +136,11 @@ def test_online_fallback_no_absolute_path_leak(self, mock_wb, tmp_path): def test_online_fallback_when_path_is_none(self, mock_wb): """When HELP_SYSTEM.path is None, fall back to online.""" self.hs.path = None - with patch("sas.system.version.__version__", "6.1.2"): + with patch("sas.system.version.__version__", TEST_VERSION): self.hs.show_help("user/fitting.html") opened_url = mock_wb.open.call_args[0][0] - assert opened_url.startswith("https://www.sasview.org/docs/v6.1.2/") + assert opened_url.startswith(f"https://www.sasview.org/docs/old_docs/{TEST_VERSION}/") @patch("sas.system._help.webbrowser") def test_absolute_path_stripped_for_online(self, mock_wb, tmp_path): @@ -146,12 +148,12 @@ def test_absolute_path_stripped_for_online(self, mock_wb, tmp_path): root should be stripped when building the online fallback URL.""" self.hs.path = tmp_path # empty — no local docs absolute_url = tmp_path / "user" / "fitting.html" - with patch("sas.system.version.__version__", "6.1.2"): + with patch("sas.system.version.__version__", TEST_VERSION): self.hs.show_help(str(absolute_url)) opened_url = mock_wb.open.call_args[0][0] assert opened_url == ( - "https://www.sasview.org/docs/v6.1.2/user/fitting.html" + f"https://www.sasview.org/docs/old_docs/{TEST_VERSION}/user/fitting.html" ) @patch("sas.system._help.webbrowser") @@ -161,12 +163,12 @@ def test_posix_absolute_path_stripped_for_online(self, mock_wb): absolute_url = "/tmp/sasview-docs/user/fitting.html" with patch("sas.system._help.Path", PosixTestPath): - with patch("sas.system.version.__version__", "6.1.2"): + with patch("sas.system.version.__version__", TEST_VERSION): self.hs.show_help(absolute_url) opened_url = mock_wb.open.call_args[0][0] assert opened_url == ( - "https://www.sasview.org/docs/v6.1.2/user/fitting.html" + f"https://www.sasview.org/docs/old_docs/{TEST_VERSION}/user/fitting.html" ) @patch("sas.system._help.webbrowser")