From a4256b89f50570c7f2953e000708bbc252cafad0 Mon Sep 17 00:00:00 2001 From: Raymond Wiker Date: Mon, 10 Aug 2026 12:25:04 +0200 Subject: [PATCH 1/6] feat: add retry to make access to well_known endpoint more robust. --- src/sumo/wrapper/sumo_client.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sumo/wrapper/sumo_client.py b/src/sumo/wrapper/sumo_client.py index b2cf89f..c12ad2d 100644 --- a/src/sumo/wrapper/sumo_client.py +++ b/src/sumo/wrapper/sumo_client.py @@ -74,7 +74,12 @@ def __init__( logger.setLevel(verbosity) global well_known if well_known is None: - well_known = httpx.get(WELL_KNOWN).json() + + def _get(): + return httpx.get(WELL_KNOWN, timeout=timeout) + + retryer = retry_strategy.make_retryer() + well_known = retryer(_get).json() if env not in well_known["envs"]: raise ValueError(f"Invalid environment: {env}") From 65043d2d3927f27df28b5da1185a7a166fe8b2db Mon Sep 17 00:00:00 2001 From: Raymond Wiker Date: Mon, 10 Aug 2026 12:35:18 +0200 Subject: [PATCH 2/6] chore: make ruff happy (or happier). --- src/sumo/wrapper/__init__.py | 2 +- src/sumo/wrapper/_auth_provider.py | 38 ++------------- src/sumo/wrapper/_blob_client.py | 1 - src/sumo/wrapper/_logging.py | 7 +-- src/sumo/wrapper/_retry_strategy.py | 2 - src/sumo/wrapper/sumo_client.py | 72 +++++++++++++---------------- tests/test_sumo_thin_client.py | 2 +- 7 files changed, 38 insertions(+), 86 deletions(-) diff --git a/src/sumo/wrapper/__init__.py b/src/sumo/wrapper/__init__.py index c7714de..08eba2a 100644 --- a/src/sumo/wrapper/__init__.py +++ b/src/sumo/wrapper/__init__.py @@ -8,4 +8,4 @@ except ImportError: __version__ = "0.0.0" -__all__ = ["SumoClient", "RetryStrategy"] +__all__ = ["RetryStrategy", "SumoClient"] diff --git a/src/sumo/wrapper/_auth_provider.py b/src/sumo/wrapper/_auth_provider.py index cc0bc36..cbb6923 100644 --- a/src/sumo/wrapper/_auth_provider.py +++ b/src/sumo/wrapper/_auth_provider.py @@ -5,9 +5,8 @@ import stat import sys import time -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from pathlib import Path -from typing import Dict from urllib.parse import parse_qs import jwt @@ -55,7 +54,6 @@ def __init__(self, resource_id): self._login_timeout_minutes = 5 os.system("") # Ensure color init on all platforms (win10) - return @tn.retry( retry=tn.retry_if_exception(_maybe_nfs_exception), @@ -77,7 +75,7 @@ def get_token(self): # ELSE return result["access_token"] - def get_authorization(self) -> Dict: + def get_authorization(self) -> dict: token = self.get_token() if token is None: return {} @@ -92,7 +90,6 @@ def store_shared_access_key_for_case(self, case_uuid, token): ) as f: f.write(token) protect_token_cache(self._resource_id, ".sharedkey", case_uuid) - return def has_case_token(self, case_uuid): return os.path.exists( @@ -102,14 +99,12 @@ def has_case_token(self, case_uuid): def delete_token(self): return False - pass class AuthProviderNone(AuthProvider): def get_token(self): raise Exception("No valid authorization provider found.") - pass class AuthProviderSilent(AuthProvider): @@ -130,7 +125,6 @@ def __init__(self, access_token): payload = jwt.decode(access_token, options={"verify_signature": False}) self._expires = payload["exp"] self._resource_id = payload["aud"] - return def get_token(self): if time.time() >= self._expires: @@ -138,7 +132,6 @@ def get_token(self): # ELSE return self._access_token - pass class AuthProviderRefreshToken(AuthProvider): @@ -149,9 +142,7 @@ def __init__(self, refresh_token, client_id, authority, resource_id): ) self._scope = scope_for_resource(resource_id) self._app.acquire_token_by_refresh_token(refresh_token, [self._scope]) - return - pass @tn.retry( @@ -186,14 +177,10 @@ def get_token_cache(resource_id, suffix): token = FilePersistence(token_path).load() with open(token_path, "w") as f: f.truncate() - pass encrypted_persistence.save(token) - pass - pass persistence = build_encrypted_persistence(token_path) cache = PersistedTokenCache(persistence) - pass return cache @@ -218,10 +205,7 @@ def protect_token_cache(resource_id, suffix, case_uuid=None): foldermode = stat.filemode(os.stat(folder).st_mode) if foldermode != "drwx------": os.chmod(os.path.dirname(token_path), 0o700) - pass - pass return - pass class AuthProviderInteractive(AuthProvider): @@ -237,8 +221,6 @@ def __init__(self, client_id, authority, resource_id): if self.get_token() is None: self.login() - pass - return @tn.retry( retry=tn.retry_if_exception(_maybe_nfs_exception), @@ -291,7 +273,6 @@ def login(self): ) return - pass class AuthProviderDeviceCode(AuthProvider): @@ -305,8 +286,6 @@ def __init__(self, client_id, authority, resource_id): self._scope = scope_for_resource(resource_id) if self.get_token() is None: self.login() - pass - return @tn.retry( retry=tn.retry_if_exception(_maybe_nfs_exception), @@ -363,7 +342,6 @@ def login(self): return - pass class AuthProviderManaged(AuthProvider): @@ -371,7 +349,6 @@ def __init__(self, resource_id): super().__init__(resource_id) self._app = ManagedIdentityCredential() self._scope = scope_for_resource(resource_id) - return @tn.retry( retry=tn.retry_if_exception(_maybe_nfs_exception), @@ -386,7 +363,6 @@ def __init__(self, resource_id): def get_token(self): return self._app.get_token(self._scope).token - pass class AuthProviderSumoToken(AuthProvider): @@ -407,7 +383,6 @@ def __init__(self, resource_id, case_uuid=None): with open(self.token_path, "r") as f: self._token = f.readline().strip() - return def get_token(self): return self._token @@ -460,7 +435,6 @@ def get_auth_provider( token = auth_silent.get_token() if token is not None: return auth_silent - pass # ELSE if all( os.getenv(x) @@ -484,7 +458,6 @@ def get_auth_provider( "\n\n\033[1mDetected chromium lockfile for different node; using firefox to authenticate.\033[0m" ) os.environ["BROWSER"] = "firefox" - pass return AuthProviderInteractive(client_id, authority, resource_id) # ELSE @@ -511,14 +484,9 @@ def cleanup_shared_keys(): pq = parse_qs(token) se = pq["se"][0] end = datetime.strptime(se, "%Y-%m-%dT%H:%M:%S.%fZ") - now = datetime.now(timezone.utc) + now = datetime.now(UTC) if now.timestamp() > end.timestamp(): os.unlink(ff) - pass - pass - pass except Exception: pass - pass - pass return diff --git a/src/sumo/wrapper/_blob_client.py b/src/sumo/wrapper/_blob_client.py index 3aa38fb..7f29be9 100644 --- a/src/sumo/wrapper/_blob_client.py +++ b/src/sumo/wrapper/_blob_client.py @@ -12,7 +12,6 @@ def __init__(self, client, async_client, timeout, retry_strategy): self._async_client = async_client self._timeout = timeout self._retry_strategy = retry_strategy - return @raise_for_status def upload_blob(self, blob: bytes, url: str): diff --git a/src/sumo/wrapper/_logging.py b/src/sumo/wrapper/_logging.py index 4f32e19..afeda15 100644 --- a/src/sumo/wrapper/_logging.py +++ b/src/sumo/wrapper/_logging.py @@ -1,17 +1,16 @@ import logging -from datetime import datetime, timezone +from datetime import UTC, datetime class LogHandlerSumo(logging.Handler): def __init__(self, sumo_client): logging.Handler.__init__(self) self._sumoClient = sumo_client - return def emit(self, record): try: dt = ( - datetime.now(timezone.utc) + datetime.now(UTC) .replace(microsecond=0, tzinfo=None) .isoformat() + "Z" @@ -36,6 +35,4 @@ def emit(self, record): # Never fail on logging pass - return - pass diff --git a/src/sumo/wrapper/_retry_strategy.py b/src/sumo/wrapper/_retry_strategy.py index 1928dfa..74fd954 100644 --- a/src/sumo/wrapper/_retry_strategy.py +++ b/src/sumo/wrapper/_retry_strategy.py @@ -12,7 +12,6 @@ def _log_retry_info(retry_state): f"Attempts: {retry_state.attempt_number}; " f"Elapsed: {retry_state.seconds_since_start}" ) - return # Define the conditions for retrying based on exception types @@ -49,7 +48,6 @@ def __init__( self._multiplier = multiplier self._exp_base = exp_base self._before_sleep = before_sleep - return def make_retryer(self) -> tn.Retrying: return tn.Retrying( diff --git a/src/sumo/wrapper/sumo_client.py b/src/sumo/wrapper/sumo_client.py index c12ad2d..f6dc118 100644 --- a/src/sumo/wrapper/sumo_client.py +++ b/src/sumo/wrapper/sumo_client.py @@ -4,7 +4,6 @@ import os import re import time -from typing import Dict, Optional, Tuple import httpx import jwt @@ -38,7 +37,7 @@ class SumoClient: def __init__( self, env: str = "prod", - token: Optional[str] = None, + token: str | None = None, interactive: bool = True, devicecode: bool = False, verbosity: str = "CRITICAL", @@ -47,7 +46,7 @@ def __init__( case_uuid=None, http_client=None, async_http_client=None, - client_id: Optional[str] = None, + client_id: str | None = None, ): """Initialize a new Sumo object @@ -133,8 +132,6 @@ def _get(): "treating it as a refresh token" ) refresh_token = token - pass - pass cleanup_shared_keys() self.auth = get_auth_provider( @@ -149,7 +146,6 @@ def _get(): ) self.base_url = base_url - return def __enter__(self): return self @@ -170,19 +166,16 @@ async def __aexit__(self, *_): def __del__(self): if self._client is not None and not self._borrowed_client: self._client.close() - pass if self._async_client is not None and not self._borrowed_async_client: async def closeit(client): await client.aclose() - return try: loop = asyncio.get_running_loop() loop.create_task(closeit(self._async_client)) except RuntimeError: pass - pass def authenticate(self): if self.auth is None: @@ -227,8 +220,8 @@ def _handle_invalid_shared_key(self): def get( self, path: str, - params: Optional[Dict] = None, - retry_strategy: Optional[RetryStrategy] = None, + params: dict | None = None, + retry_strategy: RetryStrategy | None = None, ) -> httpx.Response: """Performs a GET-request to the Sumo API. @@ -266,12 +259,12 @@ def get( follow_redirects = False if ( re.match( - r"^/objects\('[0-9a-fA-F-]{8}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{12}'\)/blob$", # noqa: E501 + r"^/objects\('[0-9a-fA-F-]{8}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{12}'\)/blob$", path, ) is not None or re.match( - r"^/tasks\('[0-9a-fA-F-]{8}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{12}'\)/result$", # noqa: E501 + r"^/tasks\('[0-9a-fA-F-]{8}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{12}'\)/result$", path, ) is not None @@ -296,10 +289,10 @@ def _get(): def post( self, path: str, - blob: Optional[bytes] = None, - json: Optional[dict] = None, - params: Optional[dict] = None, - retry_strategy: Optional[RetryStrategy] = None, + blob: bytes | None = None, + json: dict | None = None, + params: dict | None = None, + retry_strategy: RetryStrategy | None = None, ) -> httpx.Response: """Performs a POST-request to the Sumo API. @@ -374,9 +367,9 @@ def _post(): def put( self, path: str, - blob: Optional[bytes] = None, - json: Optional[dict] = None, - retry_strategy: Optional[RetryStrategy] = None, + blob: bytes | None = None, + json: dict | None = None, + retry_strategy: RetryStrategy | None = None, ) -> httpx.Response: """Performs a PUT-request to the Sumo API. @@ -426,8 +419,8 @@ def _put(): def delete( self, path: str, - params: Optional[dict] = None, - retry_strategy: Optional[RetryStrategy] = None, + params: dict | None = None, + retry_strategy: RetryStrategy | None = None, ) -> httpx.Response: """Performs a DELETE-request to the Sumo API. @@ -467,7 +460,7 @@ def _delete(): return retryer(_delete) - def _get_retry_details(self, response_in) -> Tuple[str, int]: + def _get_retry_details(self, response_in) -> tuple[str, int]: assert response_in.status_code == 202, ( "Incorrect status code; expcted 202" ) @@ -485,7 +478,7 @@ def poll( self, response_in: httpx.Response, timeout=None, - retry_strategy: Optional[RetryStrategy] = None, + retry_strategy: RetryStrategy | None = None, ) -> httpx.Response: """Poll a specific endpoint until a result is obtained. @@ -507,7 +500,6 @@ def poll( "No response within specified timeout." ) location, retry_after = self._get_retry_details(response) - pass def getLogger(self, name): """Gets a logger object that sends log objects into the message_log @@ -526,7 +518,6 @@ def getLogger(self, name): if len(logger.handlers) == 0: handler = LogHandlerSumo(self) logger.addHandler(handler) - pass return logger def create_shared_access_key_for_case(self, case_uuid): @@ -566,8 +557,8 @@ def client_for_case(self, case_uuid, interactive=False): async def get_async( self, path: str, - params: Optional[dict] = None, - retry_strategy: Optional[RetryStrategy] = None, + params: dict | None = None, + retry_strategy: RetryStrategy | None = None, ) -> httpx.Response: """Performs an async GET-request to the Sumo API. @@ -605,12 +596,12 @@ async def get_async( follow_redirects = False if ( re.match( - r"^/objects\('[0-9a-fA-F-]{8}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{12}'\)/blob$", # noqa: E501 + r"^/objects\('[0-9a-fA-F-]{8}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{12}'\)/blob$", path, ) is not None or re.match( - r"^/tasks\('[0-9a-fA-F-]{8}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{12}'\)/result$", # noqa: E501 + r"^/tasks\('[0-9a-fA-F-]{8}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{12}'\)/result$", path, ) is not None @@ -636,10 +627,10 @@ async def _get(): async def post_async( self, path: str, - blob: Optional[bytes] = None, - json: Optional[dict] = None, - params: Optional[dict] = None, - retry_strategy: Optional[RetryStrategy] = None, + blob: bytes | None = None, + json: dict | None = None, + params: dict | None = None, + retry_strategy: RetryStrategy | None = None, ) -> httpx.Response: """Performs an async POST-request to the Sumo API. @@ -715,9 +706,9 @@ async def _post(): async def put_async( self, path: str, - blob: Optional[bytes] = None, - json: Optional[dict] = None, - retry_strategy: Optional[RetryStrategy] = None, + blob: bytes | None = None, + json: dict | None = None, + retry_strategy: RetryStrategy | None = None, ) -> httpx.Response: """Performs an async PUT-request to the Sumo API. @@ -767,8 +758,8 @@ async def _put(): async def delete_async( self, path: str, - params: Optional[dict] = None, - retry_strategy: Optional[RetryStrategy] = None, + params: dict | None = None, + retry_strategy: RetryStrategy | None = None, ) -> httpx.Response: """Performs an async DELETE-request to the Sumo API. @@ -812,7 +803,7 @@ async def poll_async( self, response_in: httpx.Response, timeout=None, - retry_strategy: Optional[RetryStrategy] = None, + retry_strategy: RetryStrategy | None = None, ) -> httpx.Response: """Poll a specific endpoint until a result is obtained. @@ -836,4 +827,3 @@ async def poll_async( "No response within specified timeout." ) location, retry_after = self._get_retry_details(response) - pass diff --git a/tests/test_sumo_thin_client.py b/tests/test_sumo_thin_client.py index 071812f..2d738e2 100644 --- a/tests/test_sumo_thin_client.py +++ b/tests/test_sumo_thin_client.py @@ -10,7 +10,7 @@ sys.path.append(os.path.abspath(os.path.join("src"))) -from sumo.wrapper import SumoClient # noqa: E402 +from sumo.wrapper import SumoClient def _upload_parent_object(conn, json): From 2c7c0d0d5142b01d3bacbc475bbf736446bfe321 Mon Sep 17 00:00:00 2001 From: Raymond Wiker Date: Mon, 10 Aug 2026 13:50:59 +0200 Subject: [PATCH 3/6] chore: make ruff even happier --- pyproject.toml | 2 +- src/sumo/wrapper/_auth_provider.py | 22 +++++++--------------- src/sumo/wrapper/_logging.py | 4 +--- src/sumo/wrapper/sumo_client.py | 4 +++- 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ab48eae..0620af3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,7 @@ exclude = [".env", ".git", ".github", ".venv", "venv"] line-length = 79 [tool.ruff.lint] -ignore = ["E501", "N802"] +ignore = ["E501", "N802", "TRY002", "BLE001"] extend-select = [ "C4", # Flake8-comprehensions diff --git a/src/sumo/wrapper/_auth_provider.py b/src/sumo/wrapper/_auth_provider.py index cbb6923..3ba140a 100644 --- a/src/sumo/wrapper/_auth_provider.py +++ b/src/sumo/wrapper/_auth_provider.py @@ -54,7 +54,6 @@ def __init__(self, resource_id): self._login_timeout_minutes = 5 os.system("") # Ensure color init on all platforms (win10) - @tn.retry( retry=tn.retry_if_exception(_maybe_nfs_exception), stop=tn.stop_after_attempt(6), @@ -100,13 +99,11 @@ def delete_token(self): return False - class AuthProviderNone(AuthProvider): def get_token(self): raise Exception("No valid authorization provider found.") - class AuthProviderSilent(AuthProvider): def __init__(self, client_id, authority, resource_id): super().__init__(resource_id) @@ -133,7 +130,6 @@ def get_token(self): return self._access_token - class AuthProviderRefreshToken(AuthProvider): def __init__(self, refresh_token, client_id, authority, resource_id): super().__init__(resource_id) @@ -144,7 +140,6 @@ def __init__(self, refresh_token, client_id, authority, resource_id): self._app.acquire_token_by_refresh_token(refresh_token, [self._scope]) - @tn.retry( retry=tn.retry_if_exception(_maybe_nfs_exception), stop=tn.stop_after_attempt(6), @@ -244,7 +239,7 @@ def login(self): + "that is before " + str( ( - datetime.now() + datetime.now().astimezone() + timedelta(minutes=self._login_timeout_minutes) ).strftime("%H:%M:%S") ) @@ -274,7 +269,6 @@ def login(self): return - class AuthProviderDeviceCode(AuthProvider): def __init__(self, client_id, authority, resource_id): super().__init__(resource_id) @@ -303,9 +297,10 @@ def login(self): flow = self._app.initiate_device_flow(scopes) if "error" in flow: print( - "\n\n \033[31m" - + "Failed to initiate device-code login. Err: %s\033[0m" - % json.dumps(flow, indent=4) + ( + "\n\n \033[31m" + + "Failed to initiate device-code login. Err: {}\033[0m" + ).format(json.dumps(flow, indent=4)) ) return flow["expires_at"] = ( @@ -343,7 +338,6 @@ def login(self): return - class AuthProviderManaged(AuthProvider): def __init__(self, resource_id): super().__init__(resource_id) @@ -364,7 +358,6 @@ def get_token(self): return self._app.get_token(self._scope).token - class AuthProviderSumoToken(AuthProvider): @tn.retry( retry=tn.retry_if_exception(_maybe_nfs_exception), @@ -383,7 +376,6 @@ def __init__(self, resource_id, case_uuid=None): with open(self.token_path, "r") as f: self._token = f.readline().strip() - def get_token(self): return self._token @@ -483,10 +475,10 @@ def cleanup_shared_keys(): token = file.read() pq = parse_qs(token) se = pq["se"][0] - end = datetime.strptime(se, "%Y-%m-%dT%H:%M:%S.%fZ") + end = datetime.fromisoformat(se) now = datetime.now(UTC) if now.timestamp() > end.timestamp(): os.unlink(ff) - except Exception: + except Exception: # noqa: S110 pass return diff --git a/src/sumo/wrapper/_logging.py b/src/sumo/wrapper/_logging.py index afeda15..97fe5c8 100644 --- a/src/sumo/wrapper/_logging.py +++ b/src/sumo/wrapper/_logging.py @@ -31,8 +31,6 @@ def emit(self, record): json["details"] = record.__dict__.get("details") self._sumoClient.post("/message-log/new", json=json) - except Exception: + except Exception: # noqa: S110 # Never fail on logging pass - - diff --git a/src/sumo/wrapper/sumo_client.py b/src/sumo/wrapper/sumo_client.py index f6dc118..55c3c44 100644 --- a/src/sumo/wrapper/sumo_client.py +++ b/src/sumo/wrapper/sumo_client.py @@ -41,7 +41,7 @@ def __init__( interactive: bool = True, devicecode: bool = False, verbosity: str = "CRITICAL", - retry_strategy=RetryStrategy(), + retry_strategy=None, timeout=DEFAULT_TIMEOUT, case_uuid=None, http_client=None, @@ -70,6 +70,8 @@ def __init__( AZURE_CLIENT_ID from environment variables or the config. Defaults to None. """ + if retry_strategy is None: + retry_strategy = RetryStrategy() logger.setLevel(verbosity) global well_known if well_known is None: From 133bc0c8ccbe8d81e4728fefe55de6b135e3ff0c Mon Sep 17 00:00:00 2001 From: Raymond Wiker Date: Mon, 10 Aug 2026 13:58:54 +0200 Subject: [PATCH 4/6] chore: make ruff happy about tests, too. --- tests/test_sumo_thin_client.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_sumo_thin_client.py b/tests/test_sumo_thin_client.py index 2d738e2..40a507f 100644 --- a/tests/test_sumo_thin_client.py +++ b/tests/test_sumo_thin_client.py @@ -99,7 +99,7 @@ def test_upload_search_delete_ensemble_child(token): ) except Exception as ex: print(ex.response.text) - raise ex + raise assert 200 <= response_surface.status_code <= 202 assert isinstance(response_surface.json(), dict) @@ -169,7 +169,7 @@ def test_fail_on_wrong_metadata(token): Upload a parent object with erroneous metadata, confirm failure """ conn = SumoClient(env="dev", token=token) - with pytest.raises(Exception): + with pytest.raises(AssertionError): assert _upload_parent_object( conn=conn, json={"some field": "some value"} ) @@ -220,7 +220,7 @@ def test_upload_duplicate_ensemble(token): sleep(61) # Search for ensemble - with pytest.raises(Exception): + with pytest.raises(AssertionError): assert _download_object(conn, object_id=case_id2) From c69d89ee990c9fbd327250e7ac5c482b794e301c Mon Sep 17 00:00:00 2001 From: Raymond Wiker Date: Mon, 10 Aug 2026 14:04:37 +0200 Subject: [PATCH 5/6] chore: update github actions. --- .github/workflows/build_docs.yaml | 6 +++--- .github/workflows/linting.yml | 6 +++--- .github/workflows/publish_release.yml | 6 +++--- .github/workflows/pytest.yml | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build_docs.yaml b/.github/workflows/build_docs.yaml index 0213126..b3958bb 100644 --- a/.github/workflows/build_docs.yaml +++ b/.github/workflows/build_docs.yaml @@ -17,14 +17,14 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ["3.11"] + python-version: ["3.12"] os: [ubuntu-latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7.0.0 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6.3.0 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 74d7e37..135a9ae 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -12,11 +12,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7.0.0 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6.3.0 with: - python-version: '3.11' + python-version: '3.12' cache: 'pip' - name: Installing dependencies diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml index 138de02..c99095e 100644 --- a/.github/workflows/publish_release.yml +++ b/.github/workflows/publish_release.yml @@ -13,11 +13,11 @@ jobs: environment: production runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7.0.0 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6.3.0 with: - python-version: "3.11" + python-version: "3.12" - name: build run: | diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 3b84395..db06124 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -14,24 +14,24 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ["3.11", "3.12"] + python-version: ["3.12"] os: [ubuntu-latest, windows-latest, macos-15] permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7.0.0 - name: Azure Login - uses: Azure/login@v2 + uses: Azure/login@v3.0.0 with: client-id: f96c150d-cacf-4257-9cc9-54b2c68ec4ce tenant-id: 3aa4a235-b6e2-48d5-9195-7fcf05b459b0 subscription-id: 87897772-fb27-495f-ae40-486a2df57baa - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6.3.0 with: python-version: ${{ matrix.python-version }} From 5b7580620217c096fadd0ec763228496aa68df35 Mon Sep 17 00:00:00 2001 From: Raymond Wiker Date: Mon, 10 Aug 2026 14:17:47 +0200 Subject: [PATCH 6/6] Catch correct exception in tests. --- tests/test_sumo_thin_client.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/test_sumo_thin_client.py b/tests/test_sumo_thin_client.py index 40a507f..33216b2 100644 --- a/tests/test_sumo_thin_client.py +++ b/tests/test_sumo_thin_client.py @@ -7,6 +7,7 @@ import pytest import yaml +from httpx import HTTPStatusError sys.path.append(os.path.abspath(os.path.join("src"))) @@ -169,10 +170,8 @@ def test_fail_on_wrong_metadata(token): Upload a parent object with erroneous metadata, confirm failure """ conn = SumoClient(env="dev", token=token) - with pytest.raises(AssertionError): - assert _upload_parent_object( - conn=conn, json={"some field": "some value"} - ) + with pytest.raises(HTTPStatusError): + _upload_parent_object(conn=conn, json={"some field": "some value"}) def test_upload_duplicate_ensemble(token): @@ -220,8 +219,8 @@ def test_upload_duplicate_ensemble(token): sleep(61) # Search for ensemble - with pytest.raises(AssertionError): - assert _download_object(conn, object_id=case_id2) + with pytest.raises(HTTPStatusError): + _download_object(conn, object_id=case_id2) def test_poll(token):