chore: ruff cleanup — fix 7 long-standing lint findings
Mechanical, no behavior change. `ruff check src/ tests/` now passes with zero findings. - cli.py:147 (SIM105) — replace `try/except SynologyError/pass` around the cleanup logout with `contextlib.suppress(SynologyError)`. - compose.py:271 (B007) — drop the unused `i` from the env_list preview-detection loop (the apply loop below still uses enumerate). - compose.py:329 (E501) — extract `verb = "Updated" if … else "Added"` into a local before the return so the f-string fits in 100 cols. - images.py:237 (E501) — extract `stopped_name = in_use_stopped[0]` before the return and split the message across two f-strings. - test_auth.py:38, 127, 140 (SIM117) — combine nested `with patch(…):` / `with pytest.raises(…):` into single parenthesised with-statements. 236 tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import contextlib
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
@@ -144,10 +145,8 @@ async def _run_setup() -> None:
|
|||||||
client.sid = sid
|
client.sid = sid
|
||||||
click.echo(click.style("Login successful!", fg="green"))
|
click.echo(click.style("Login successful!", fg="green"))
|
||||||
# Logout cleanly
|
# Logout cleanly
|
||||||
try:
|
with contextlib.suppress(SynologyError):
|
||||||
await client.request("SYNO.API.Auth", "logout", version=6, params={})
|
await client.request("SYNO.API.Auth", "logout", version=6, params={})
|
||||||
except SynologyError:
|
|
||||||
pass
|
|
||||||
else:
|
else:
|
||||||
click.echo(click.style("Login failed: no session ID returned.", fg="red"), err=True)
|
click.echo(click.style("Login failed: no session ID returned.", fg="red"), err=True)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ def register_compose(mcp: FastMCP, config: AppConfig, client: DsmClient) -> None
|
|||||||
# Determine previous value and build description
|
# Determine previous value and build description
|
||||||
old_value: str | None = None
|
old_value: str | None = None
|
||||||
if isinstance(env_list, list):
|
if isinstance(env_list, list):
|
||||||
for i, entry in enumerate(env_list):
|
for entry in env_list:
|
||||||
if isinstance(entry, str) and entry.startswith(f"{var_name}="):
|
if isinstance(entry, str) and entry.startswith(f"{var_name}="):
|
||||||
old_value = entry.split("=", 1)[1]
|
old_value = entry.split("=", 1)[1]
|
||||||
break
|
break
|
||||||
@@ -325,8 +325,9 @@ def register_compose(mcp: FastMCP, config: AppConfig, client: DsmClient) -> None
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return f"Error writing compose file: {e}"
|
return f"Error writing compose file: {e}"
|
||||||
|
|
||||||
|
verb = "Updated" if action == "update" else "Added"
|
||||||
return (
|
return (
|
||||||
f"{'Updated' if action == 'update' else 'Added'} env var in '{service_name}' ({project_name}):\n"
|
f"{verb} env var in '{service_name}' ({project_name}):\n"
|
||||||
f" {var_name}={var_value}\n\n"
|
f" {var_name}={var_value}\n\n"
|
||||||
f"Tip: Run redeploy_project('{project_name}', confirmed=True) to apply the change."
|
f"Tip: Run redeploy_project('{project_name}', confirmed=True) to apply the change."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -233,8 +233,10 @@ def register_images(mcp: FastMCP, config: AppConfig, client: DsmClient) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if in_use_stopped:
|
if in_use_stopped:
|
||||||
|
stopped_name = in_use_stopped[0]
|
||||||
return (
|
return (
|
||||||
f"Cannot delete '{display_name}': image is used by stopped container '{in_use_stopped[0]}'.\n"
|
f"Cannot delete '{display_name}': image is used by stopped container "
|
||||||
|
f"'{stopped_name}'.\n"
|
||||||
f"Delete the container first or run system_prune to clean up stopped containers."
|
f"Delete the container first or run system_prune to clean up stopped containers."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+15
-9
@@ -35,9 +35,11 @@ def test_resolve_credentials_no_credentials(monkeypatch):
|
|||||||
config = make_config()
|
config = make_config()
|
||||||
auth = AuthManager(config)
|
auth = AuthManager(config)
|
||||||
|
|
||||||
with patch("keyring.get_password", return_value=None):
|
with (
|
||||||
with pytest.raises(AuthenticationError, match="No credentials found"):
|
patch("keyring.get_password", return_value=None),
|
||||||
auth.resolve_credentials()
|
pytest.raises(AuthenticationError, match="No credentials found"),
|
||||||
|
):
|
||||||
|
auth.resolve_credentials()
|
||||||
|
|
||||||
|
|
||||||
def test_resolve_credentials_from_keyring(monkeypatch):
|
def test_resolve_credentials_from_keyring(monkeypatch):
|
||||||
@@ -124,9 +126,11 @@ async def test_login_2fa_required():
|
|||||||
mock_client = AsyncMock()
|
mock_client = AsyncMock()
|
||||||
mock_client.request.side_effect = SynologyError("2FA required", code=403)
|
mock_client.request.side_effect = SynologyError("2FA required", code=403)
|
||||||
|
|
||||||
with patch.object(auth, "resolve_credentials", return_value=("user", "pass", None)):
|
with (
|
||||||
with pytest.raises(AuthenticationError, match="2FA is required"):
|
patch.object(auth, "resolve_credentials", return_value=("user", "pass", None)),
|
||||||
await auth.login(mock_client)
|
pytest.raises(AuthenticationError, match="2FA is required"),
|
||||||
|
):
|
||||||
|
await auth.login(mock_client)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -137,9 +141,11 @@ async def test_login_no_sid_returned():
|
|||||||
mock_client = AsyncMock()
|
mock_client = AsyncMock()
|
||||||
mock_client.request.return_value = {} # No 'sid' key
|
mock_client.request.return_value = {} # No 'sid' key
|
||||||
|
|
||||||
with patch.object(auth, "resolve_credentials", return_value=("user", "pass", None)):
|
with (
|
||||||
with pytest.raises(AuthenticationError, match="no session ID"):
|
patch.object(auth, "resolve_credentials", return_value=("user", "pass", None)),
|
||||||
await auth.login(mock_client)
|
pytest.raises(AuthenticationError, match="no session ID"),
|
||||||
|
):
|
||||||
|
await auth.login(mock_client)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
|||||||
Reference in New Issue
Block a user