-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is a partial copy of the outdated PR of @HarmvZ who laid the foundations. However, it now also checks the latest supported version. The original PR had some problems with double running the check and the new check needed access to the `base_url` anyway. So I decided put the checking in the `ClientBase` initialisation but keep it in a separate httpx Client. --------- Co-authored-by: HarmvZ <[email protected]> Co-authored-by: James Meakin <[email protected]>
- Loading branch information
1 parent
b063078
commit ad9f6ff
Showing
7 changed files
with
162 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import warnings | ||
from importlib.metadata import version as get_version | ||
|
||
import httpx | ||
from packaging import version | ||
|
||
|
||
class UnsupportedVersionError(Exception): | ||
pass | ||
|
||
|
||
def check_version(base_url): | ||
package_name = "gcapi" | ||
|
||
current_version = get_version(package_name) | ||
|
||
with httpx.Client() as client: | ||
response = client.get(f"{base_url}/gcapi/") | ||
|
||
api_data = response.json() | ||
|
||
latest_version = api_data["latest_version"] | ||
lowest_supported_version = api_data["lowest_supported_version"] | ||
|
||
current_version_v = version.parse(current_version) | ||
latest_version_v = version.parse(latest_version) | ||
lowest_supported_version_v = version.parse(lowest_supported_version) | ||
|
||
if current_version_v < lowest_supported_version_v: | ||
raise UnsupportedVersionError( | ||
f"You are using {package_name} version {current_version}. " | ||
f"However, the platform only supports {lowest_supported_version} " | ||
"or newer. Upgrade via `pip install --upgrade {package_name}`", | ||
) | ||
|
||
if current_version_v < latest_version_v: | ||
warnings.warn( | ||
f"You are using {package_name} version {current_version}. " | ||
f"However, version {latest_version} is available. You should consider" | ||
f" upgrading via `pip install --upgrade {package_name}`", | ||
UserWarning, | ||
stacklevel=0, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import warnings | ||
from contextlib import nullcontext | ||
from unittest.mock import MagicMock, patch | ||
|
||
import pytest | ||
|
||
from gcapi import AsyncClient, Client | ||
from gcapi.check_version import UnsupportedVersionError, check_version | ||
|
||
|
||
@pytest.fixture | ||
def mock_get_version(): | ||
with patch("gcapi.check_version.get_version") as mock: | ||
yield mock | ||
|
||
|
||
@pytest.fixture | ||
def mock_httpx_client(): | ||
with patch("gcapi.check_version.httpx.Client") as mock: | ||
yield mock | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"current,latest,lowest,should_warn,expected_context", | ||
[ | ||
# Normal operations | ||
("1.0.0", "1.0.0", "0.0.0", False, nullcontext()), | ||
# Newer versions | ||
("1.0.0", "1.0.1", "0.0.0", True, nullcontext()), | ||
("1.0.0", "1.1.0", "0.0.0", True, nullcontext()), | ||
("1.0.0", "2.0.0", "0.0.0", True, nullcontext()), | ||
("1.0.1", "1.0.0", "0.0.0", False, nullcontext()), | ||
("1.1.0", "1.0.0", "0.0.0", False, nullcontext()), | ||
("2.0.0", "1.0.0", "0.0.0", False, nullcontext()), | ||
# Lower supported versions | ||
( | ||
"1.0.0", | ||
"0.0.0", | ||
"2.0.0", | ||
False, | ||
pytest.raises(UnsupportedVersionError), | ||
), | ||
( | ||
"1.0.0", | ||
"3.0.0", # Even if there is a newer version: error out | ||
"2.0.0", | ||
False, | ||
pytest.raises(UnsupportedVersionError), | ||
), | ||
], | ||
) | ||
def test_check_version_comparisons( | ||
mock_get_version, | ||
mock_httpx_client, | ||
current, | ||
latest, | ||
lowest, | ||
should_warn, | ||
expected_context, | ||
): | ||
mock_get_version.return_value = current | ||
mock_response = MagicMock() | ||
mock_response.json.return_value = { | ||
"latest_version": latest, | ||
"lowest_supported_version": lowest, | ||
} | ||
mock_httpx_client.return_value.__enter__.return_value.get.return_value = ( | ||
mock_response | ||
) | ||
|
||
with warnings.catch_warnings(record=True) as w: | ||
with expected_context: | ||
check_version(base_url="https://example.test/") | ||
|
||
if should_warn: | ||
assert ( | ||
len(w) == 1 | ||
), f"A warning should be issued for version {current} < {latest}" | ||
assert f"You are using gcapi version {current}" in str(w[0].message) | ||
else: | ||
assert ( | ||
len(w) == 0 | ||
), f"No warning should be issued for version {current} >= {latest}" | ||
|
||
|
||
@pytest.mark.parametrize("client", [Client, AsyncClient]) | ||
def test_check_version_calling(client, mock_check_version): | ||
mock_check_version.assert_not_called() # Sanity | ||
client(token="Foo") | ||
mock_check_version.assert_called_once() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters