From 25125567707c49a4426281297924526a427717d2 Mon Sep 17 00:00:00 2001 From: Mark Paronyan Date: Mon, 28 Sep 2026 04:42:58 +0000 Subject: [PATCH 1/7] fix(typing): resolve mypy errors in config --- gns3server/config.py | 8 ++++++-- pyproject.toml | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/gns3server/config.py b/gns3server/config.py index 0baf2fe2f..ed1507f4e 100644 --- a/gns3server/config.py +++ b/gns3server/config.py @@ -48,6 +48,10 @@ class ConfigConflictError(Exception): LIST_OPTION_SEPARATORS = {"additional_images_paths": ";"} +def parser_sections(parser: configparser.ConfigParser) -> dict[str, dict[str, str]]: + return {section: dict(parser[section]) for section in parser.sections()} + + class Config: """ Configuration file management using configparser. @@ -328,7 +332,7 @@ class Config: changed.append(f"{section}.{option}") # validate the merged settings before touching the file on disk - ServerConfig(**merged_parser._sections) + ServerConfig(**parser_sections(merged_parser)) directory_name = os.path.dirname(main_config_file) if directory_name: @@ -414,7 +418,7 @@ class Config: self._watched_files[file] = os.stat(file).st_mtime try: - self._settings = ServerConfig(**config._sections) + self._settings = ServerConfig(**parser_sections(config)) except ValidationError as e: log.critical(f"Could not validate configuration file settings: {e}") raise diff --git a/pyproject.toml b/pyproject.toml index 21c8a9ba6..74a32a924 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -372,7 +372,6 @@ module = [ "gns3server.compute.virtualbox.virtualbox_vm", # 1 "gns3server.compute.vmware.vmware_vm", # 1 "gns3server.compute.vpcs.vpcs_vm", # 2 - "gns3server.config", # 1 "gns3server.controller.appliance", # 2 "gns3server.controller.appliance_manager", # 5 "gns3server.controller.compute", # 2 From f858ae23a6e283f03e41f555db01ff8e6bde63dc Mon Sep 17 00:00:00 2001 From: Mark Paronyan Date: Mon, 28 Sep 2026 04:41:54 +0000 Subject: [PATCH 2/7] fix(typing): resolve mypy errors in api.routes.index --- gns3server/api/routes/index.py | 2 +- pyproject.toml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/gns3server/api/routes/index.py b/gns3server/api/routes/index.py index 365840b8c..23e859bc2 100644 --- a/gns3server/api/routes/index.py +++ b/gns3server/api/routes/index.py @@ -36,7 +36,7 @@ async def root(): @router.get("/debug", response_class=HTMLResponse, deprecated=True, include_in_schema=False) def debug(request: Request): - kwargs = {"gns3_version": __version__, "gns3_host": request.client.host} + kwargs = {"gns3_version": __version__, "gns3_host": request.client.host if request.client else None} return templates.TemplateResponse(request=request, name="index.html", context=kwargs) diff --git a/pyproject.toml b/pyproject.toml index 21c8a9ba6..8da681384 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -359,7 +359,6 @@ module = [ "gns3server.api.routes.controller.snapshots", # 1 "gns3server.api.routes.controller.templates", # 10 "gns3server.api.routes.controller.users", # 14 - "gns3server.api.routes.index", # 1 "gns3server.api.server", # 2 "gns3server.compute.docker.docker_vm", # 3 "gns3server.compute.docker.iol_docker_vm", # 3 From b8ae84031eee359aac0ba03c5d6e68ad3a1cb1d1 Mon Sep 17 00:00:00 2001 From: Mark Paronyan Date: Mon, 28 Sep 2026 04:45:19 +0000 Subject: [PATCH 3/7] fix(typing): resolve mypy errors in compute.docker vm modules --- gns3server/compute/docker/docker_vm.py | 20 +++++++++++++------- gns3server/compute/docker/iol_docker_vm.py | 20 +++++++++++++++----- pyproject.toml | 2 -- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/gns3server/compute/docker/docker_vm.py b/gns3server/compute/docker/docker_vm.py index 7d557dff2..08559b990 100644 --- a/gns3server/compute/docker/docker_vm.py +++ b/gns3server/compute/docker/docker_vm.py @@ -227,7 +227,11 @@ class DockerVM(BaseNode): return display display += 1 - @BaseNode.name.setter + @property + def name(self): + return self._name + + @name.setter def name(self, new_name): """ Sets the name of this Qemu VM. @@ -737,13 +741,15 @@ class DockerVM(BaseNode): params["Env"].append("{}={}".format(var_name, formatted)) if self._environment: - for e in self._environment.strip().split("\n"): - e = e.strip() - if e.split("=")[0] == "": - self.project.emit("log.warning", {"message": f"{self.name} has invalid environment variable: {e}"}) + for env in self._environment.strip().split("\n"): + env = env.strip() + if env.split("=")[0] == "": + self.project.emit( + "log.warning", {"message": f"{self.name} has invalid environment variable: {env}"} + ) continue - if not e.startswith("GNS3_"): - formatted = self._format_env(variables, e) + if not env.startswith("GNS3_"): + formatted = self._format_env(variables, env) vm_name = self._name.replace(",", ",,") project_path = self.project.path.replace(",", ",,") formatted = formatted.replace("%vm-name%", '"' + vm_name.replace('"', '\\"') + '"') diff --git a/gns3server/compute/docker/iol_docker_vm.py b/gns3server/compute/docker/iol_docker_vm.py index ff0ab2b00..070195e6b 100644 --- a/gns3server/compute/docker/iol_docker_vm.py +++ b/gns3server/compute/docker/iol_docker_vm.py @@ -92,8 +92,8 @@ class IOLDockerVM(VendorDockerVM): # controller-allocated application id (MACs would flip to the fallback # hash, colliding with the allocation pool) and any pending # startup-config delivered by a PUT. - _application_id = None - _startup_config_content = None + _application_id: int | None = None + _startup_config_content: str | None = None _startup_config_dirty = False def _parse_vendor_environment(self): @@ -119,7 +119,7 @@ class IOLDockerVM(VendorDockerVM): pass @property - def application_id(self) -> int: + def application_id(self) -> int | None: """ IOL application ID: drives interface MACs (aabb.cc{app}{iface}) and the NVRAM file name. Allocated by the controller from the IOL Docker @@ -178,6 +178,8 @@ class IOLDockerVM(VendorDockerVM): initial configuration dialog. """ + if self._startup_config_content is None: + return content = self._startup_config_content.replace("%h", self._name) nvram_file = self._iol_nvram_file() os.makedirs(os.path.dirname(nvram_file), exist_ok=True) @@ -189,7 +191,11 @@ class IOLDockerVM(VendorDockerVM): raise DockerError(f"Could not write IOL startup-config to NVRAM of container '{self._name}': {e}") log.debug("IOL container '%s': startup-config written to %s", self._name, nvram_file) - @DockerVM.name.setter + @property + def name(self): + return self._name + + @name.setter def name(self, new_name): """ Override: keep the hostname line inside the NVRAM in sync with the @@ -228,7 +234,11 @@ class IOLDockerVM(VendorDockerVM): result["startup_config_content"] = self._startup_config_content return result - @DockerVM.adapters.setter + @property + def adapters(self): + return len(self._ethernet_adapters) + + @adapters.setter def adapters(self, adapters): """ Override: one IOL adapter is a 4-port unit — the IOU model. The diff --git a/pyproject.toml b/pyproject.toml index 21c8a9ba6..4b0d7a76c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -361,8 +361,6 @@ module = [ "gns3server.api.routes.controller.users", # 14 "gns3server.api.routes.index", # 1 "gns3server.api.server", # 2 - "gns3server.compute.docker.docker_vm", # 3 - "gns3server.compute.docker.iol_docker_vm", # 3 "gns3server.compute.dynamips.nodes.router", # 2 "gns3server.compute.iou.iou_vm", # 4 "gns3server.compute.iou.utils.iou_export", # 2 From 667b0531f6feff818527c0c8113eb81476e6da96 Mon Sep 17 00:00:00 2001 From: Mark Paronyan Date: Mon, 28 Sep 2026 04:41:28 +0000 Subject: [PATCH 4/7] fix(typing): resolve mypy errors in compute.project --- gns3server/compute/project.py | 2 +- pyproject.toml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/gns3server/compute/project.py b/gns3server/compute/project.py index 6f683d5bc..8e6ef7648 100644 --- a/gns3server/compute/project.py +++ b/gns3server/compute/project.py @@ -466,7 +466,7 @@ class Project: ) # Non-recursive: list only the current directory level - files = [] + files: list[dict] = [] try: scandir_iter = os.scandir(target_path) except PermissionError: diff --git a/pyproject.toml b/pyproject.toml index 21c8a9ba6..cbf8d4d6a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -367,7 +367,6 @@ module = [ "gns3server.compute.iou.iou_vm", # 4 "gns3server.compute.iou.utils.iou_export", # 2 "gns3server.compute.iou.utils.iou_import", # 2 - "gns3server.compute.project", # 1 "gns3server.compute.qemu.qemu_vm", # 2 "gns3server.compute.virtualbox.virtualbox_vm", # 1 "gns3server.compute.vmware.vmware_vm", # 1 From fdfb2d559192e0dcba474e3616c6a7e8dd1bded3 Mon Sep 17 00:00:00 2001 From: Mark Paronyan Date: Mon, 28 Sep 2026 04:43:42 +0000 Subject: [PATCH 5/7] fix(typing): resolve mypy errors in compute.vmware.vmware_vm --- gns3server/compute/vmware/vmware_vm.py | 6 +++++- pyproject.toml | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gns3server/compute/vmware/vmware_vm.py b/gns3server/compute/vmware/vmware_vm.py index d36074f0b..b56b420a2 100644 --- a/gns3server/compute/vmware/vmware_vm.py +++ b/gns3server/compute/vmware/vmware_vm.py @@ -952,7 +952,11 @@ class VMwareVM(BaseNode): await self._stop_remote_console() await self._start_console() - @BaseNode.console_type.setter + @property + def console_type(self): + return self._console_type + + @console_type.setter def console_type(self, new_console_type): """ Sets the console type for this VMware VM. diff --git a/pyproject.toml b/pyproject.toml index 21c8a9ba6..d12703ee3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -370,7 +370,6 @@ module = [ "gns3server.compute.project", # 1 "gns3server.compute.qemu.qemu_vm", # 2 "gns3server.compute.virtualbox.virtualbox_vm", # 1 - "gns3server.compute.vmware.vmware_vm", # 1 "gns3server.compute.vpcs.vpcs_vm", # 2 "gns3server.config", # 1 "gns3server.controller.appliance", # 2 From d1df96e0a62550d84851dd26e57d686cb9632a7f Mon Sep 17 00:00:00 2001 From: Mark Paronyan Date: Mon, 28 Sep 2026 04:43:20 +0000 Subject: [PATCH 6/7] fix(typing): resolve mypy errors in utils.asyncio.embed_shell --- gns3server/utils/asyncio/embed_shell.py | 5 ++--- pyproject.toml | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/gns3server/utils/asyncio/embed_shell.py b/gns3server/utils/asyncio/embed_shell.py index 3efd0bdbc..7059c9e29 100644 --- a/gns3server/utils/asyncio/embed_shell.py +++ b/gns3server/utils/asyncio/embed_shell.py @@ -236,12 +236,11 @@ class ShellConnection(TelnetConnection): async def disconnected(self): pass - @asyncio.coroutine - def window_size_changed(self, columns, rows): + async def window_size_changed(self, columns, rows): self._size = Size(rows=rows, columns=columns) self._cb.terminal_size_changed() if self._window_size_changed_callback: - yield from self._window_size_changed_callback(columns, rows) + await self._window_size_changed_callback(columns, rows) async def feed(self, data): data = data.decode() diff --git a/pyproject.toml b/pyproject.toml index 21c8a9ba6..f85a8ea85 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -421,7 +421,6 @@ module = [ "gns3server.services.computes", # 4 "gns3server.services.templates", # 18 "gns3server.utils.asyncio.aiozipstream", # 8 - "gns3server.utils.asyncio.embed_shell", # 1 "gns3server.utils.encryption", # 2 "gns3server.utils.http_client", # 4 "gns3server.utils.images", # 4 From 21643fe89d4a0fabfabd1f71aa96df515cb78c42 Mon Sep 17 00:00:00 2001 From: Mark Paronyan Date: Mon, 28 Sep 2026 04:56:59 +0000 Subject: [PATCH 7/7] fix(typing): resolve mypy errors in controller.compute --- gns3server/controller/compute.py | 14 +++++++------- pyproject.toml | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index 6c22d16b2..f42f2e3a0 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -216,6 +216,13 @@ class Compute: """ return self._host + @host.setter + def host(self, host): + self._host = host + self._host_ip_cache = None # invalidate; re-resolve on next access + if self._console_host is None: + self._console_host = host + @property def host_ip(self): """ @@ -228,13 +235,6 @@ class Compute: self._host_ip_cache = "0.0.0.0" return self._host_ip_cache - @host.setter - def host(self, host): - self._host = host - self._host_ip_cache = None # invalidate; re-resolve on next access - if self._console_host is None: - self._console_host = host - @property def console_host(self): return self._console_host diff --git a/pyproject.toml b/pyproject.toml index 21c8a9ba6..51eaeee42 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -375,7 +375,6 @@ module = [ "gns3server.config", # 1 "gns3server.controller.appliance", # 2 "gns3server.controller.appliance_manager", # 5 - "gns3server.controller.compute", # 2 "gns3server.controller.project", # 2 "gns3server.controller.topology", # 1 "gns3server.db.models.acl", # 1