From 5bf3c8d20303b10544bd51e03345ae65cc5071a0 Mon Sep 17 00:00:00 2001 From: Mark Paronyan Date: Mon, 28 Sep 2026 05:09:43 +0000 Subject: [PATCH 1/3] fix(typing): resolve mypy errors in utils.http_client --- gns3server/utils/http_client.py | 17 ++++++++++++----- pyproject.toml | 1 - 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/gns3server/utils/http_client.py b/gns3server/utils/http_client.py index 505073cf5..a6b032a82 100644 --- a/gns3server/utils/http_client.py +++ b/gns3server/utils/http_client.py @@ -16,6 +16,7 @@ # along with this program. If not, see . import aiohttp +from pydantic import SecretStr import socket import logging @@ -28,7 +29,7 @@ class HTTPClient: HTTP client for request to computes and external services. """ - _aiohttp_client: aiohttp.ClientSession = None + _aiohttp_client: aiohttp.ClientSession | None = None @classmethod def get_client(cls, ssl_context=None) -> aiohttp.ClientSession: @@ -44,15 +45,21 @@ class HTTPClient: cls._aiohttp_client = None @classmethod - def request(cls, method: str, url: str, user: str = None, password: str = None, ssl_context=None, **kwargs): + def request( + cls, + method: str, + url: str, + user: str | None = None, + password: SecretStr | None = None, + ssl_context=None, + **kwargs, + ): client = cls.get_client(ssl_context=ssl_context) basic_auth = None if user: - if not password: - password = "" try: - basic_auth = aiohttp.BasicAuth(user, password.get_secret_value(), "utf-8") + basic_auth = aiohttp.BasicAuth(user, password.get_secret_value() if password else "", "utf-8") except ValueError as e: log.error(f"Basic authentication set-up error: {e}") diff --git a/pyproject.toml b/pyproject.toml index 258447eb6..53da2cea5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -399,7 +399,6 @@ module = [ "gns3server.services.templates", # 18 "gns3server.utils.asyncio.aiozipstream", # 8 "gns3server.utils.encryption", # 2 - "gns3server.utils.http_client", # 4 "gns3server.utils.images", # 4 "gns3server.utils.packet_filter_validation", # 16 "gns3server.utils.websocket_to_websocket", # 12 From 1772c7380e6c884de22ffaf79c33363ac65bb6c4 Mon Sep 17 00:00:00 2001 From: Mark Paronyan Date: Mon, 28 Sep 2026 06:16:28 +0000 Subject: [PATCH 2/3] fix(typing): resolve mypy errors in utils.websocket_to_websocket --- gns3server/utils/websocket_to_websocket.py | 47 +++++++++------------- pyproject.toml | 1 - 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/gns3server/utils/websocket_to_websocket.py b/gns3server/utils/websocket_to_websocket.py index 88efdbfd2..12e410ce2 100644 --- a/gns3server/utils/websocket_to_websocket.py +++ b/gns3server/utils/websocket_to_websocket.py @@ -25,7 +25,6 @@ Similar pattern to VNC console implementation in base_node.py: import asyncio import logging -import sys from typing import Optional import aiohttp @@ -39,7 +38,7 @@ log = logging.getLogger(__name__) async def websocket_proxy( client_ws: WebSocket, target_url: str, - requested_protocols: list = None, + requested_protocols: Optional[list] = None, buffer_size: int = 65536, timeout: Optional[float] = None, ) -> None: @@ -59,7 +58,7 @@ async def websocket_proxy( Raises: aiohttp.ClientError: If connection to target fails """ - client_info = f"{client_ws.client.host}:{client_ws.client.port}" + client_info = f"{client_ws.client.host}:{client_ws.client.port}" if client_ws.client else "unknown" async def forward_client_to_target(target_ws): """Client → Target: Forward binary WebSocket data.""" @@ -101,25 +100,20 @@ async def websocket_proxy( subprotocols = requested_protocols or ["binary"] log.info(f"Client requested subprotocols: {subprotocols}") - timeout_config = {} - if timeout: - timeout_config = {"timeout": aiohttp.ClientTimeout(total=timeout)} + session_timeout = aiohttp.ClientTimeout(total=timeout) if timeout else None - async with aiohttp.ClientSession() as session: - async with session.ws_connect(target_url, protocols=subprotocols, **timeout_config) as target_ws: + async with aiohttp.ClientSession(timeout=session_timeout) as session: + async with session.ws_connect(target_url, protocols=subprotocols) as target_ws: negotiated_protocol = target_ws.protocol log.info(f"Target WebSocket negotiated protocol: {negotiated_protocol}") log.info(f"WebSocket proxy established: {client_info} → {target_url}") # Run both forwarding tasks in parallel # Similar pattern to base_node.py VNC implementation - if sys.version_info >= (3, 11, 0): - aws = [ - asyncio.create_task(forward_client_to_target(target_ws)), - asyncio.create_task(forward_target_to_client(target_ws)), - ] - else: - aws = [forward_client_to_target(target_ws), forward_target_to_client(target_ws)] + aws = [ + asyncio.create_task(forward_client_to_target(target_ws)), + asyncio.create_task(forward_target_to_client(target_ws)), + ] try: done, pending = await asyncio.wait(aws, return_when=asyncio.FIRST_COMPLETED) @@ -146,7 +140,7 @@ async def websocket_proxy( async def websocket_proxy_with_manual_accept( client_ws: StarletteWebSocket, target_url: str, - requested_protocols: list = None, + requested_protocols: Optional[list] = None, buffer_size: int = 65536, timeout: Optional[float] = None, ) -> None: @@ -167,7 +161,7 @@ async def websocket_proxy_with_manual_accept( Raises: aiohttp.ClientError: If connection to target fails """ - client_info = f"{client_ws.client.host}:{client_ws.client.port}" if hasattr(client_ws, "client") else "unknown" + client_info = f"{client_ws.client.host}:{client_ws.client.port}" if client_ws.client else "unknown" async def forward_client_to_target(target_ws): """Client → Target: Forward binary WebSocket data.""" @@ -213,13 +207,11 @@ async def websocket_proxy_with_manual_accept( subprotocols = requested_protocols or ["binary"] log.info(f"Client requested subprotocols: {subprotocols}") - timeout_config = {} - if timeout: - timeout_config = {"timeout": aiohttp.ClientTimeout(total=timeout)} + session_timeout = aiohttp.ClientTimeout(total=timeout) if timeout else None - async with aiohttp.ClientSession() as session: + async with aiohttp.ClientSession(timeout=session_timeout) as session: log.info(f"About to ws_connect to {target_url}") - ws_conn = session.ws_connect(target_url, protocols=subprotocols, **timeout_config) + ws_conn = session.ws_connect(target_url, protocols=subprotocols) log.info("ws_connect coroutine created, about to enter") async with ws_conn as target_ws: negotiated_protocol = target_ws.protocol @@ -235,13 +227,10 @@ async def websocket_proxy_with_manual_accept( log.info(f"WebSocket proxy established: {client_info} → {target_url}") # Run both forwarding tasks in parallel - if sys.version_info >= (3, 11, 0): - aws = [ - asyncio.create_task(forward_client_to_target(target_ws)), - asyncio.create_task(forward_target_to_client(target_ws)), - ] - else: - aws = [forward_client_to_target(target_ws), forward_target_to_client(target_ws)] + aws = [ + asyncio.create_task(forward_client_to_target(target_ws)), + asyncio.create_task(forward_target_to_client(target_ws)), + ] log.info(f"About to call asyncio.wait with {len(aws)} tasks") try: diff --git a/pyproject.toml b/pyproject.toml index 53da2cea5..d40ba58b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -401,7 +401,6 @@ module = [ "gns3server.utils.encryption", # 2 "gns3server.utils.images", # 4 "gns3server.utils.packet_filter_validation", # 16 - "gns3server.utils.websocket_to_websocket", # 12 "gns3server.utils.zipfile_zstd._patcher", # 1 ] ignore_errors = true From 128470125346696f3e056ecabe3a3cbeb8b0111a Mon Sep 17 00:00:00 2001 From: Mark Paronyan Date: Mon, 28 Sep 2026 04:58:21 +0000 Subject: [PATCH 3/3] fix(typing): resolve mypy errors in utils.zipfile_zstd._patcher --- gns3server/utils/zipfile_zstd/_patcher.py | 3 ++- pyproject.toml | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gns3server/utils/zipfile_zstd/_patcher.py b/gns3server/utils/zipfile_zstd/_patcher.py index ee2d19812..fc97d3645 100644 --- a/gns3server/utils/zipfile_zstd/_patcher.py +++ b/gns3server/utils/zipfile_zstd/_patcher.py @@ -1,8 +1,9 @@ import functools +from typing import Any class patch: - originals = {} + originals: dict[str, Any] = {} def __init__(self, host, name): self.host = host diff --git a/pyproject.toml b/pyproject.toml index d40ba58b3..01aaf9959 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -401,6 +401,5 @@ module = [ "gns3server.utils.encryption", # 2 "gns3server.utils.images", # 4 "gns3server.utils.packet_filter_validation", # 16 - "gns3server.utils.zipfile_zstd._patcher", # 1 ] ignore_errors = true