gui: updated core.gui to not use deprecated type hinting

This commit is contained in:
Blake Harnden 2023-04-13 15:53:16 -07:00
parent 69f05a6712
commit e7351b594d
40 changed files with 268 additions and 257 deletions

View file

@ -3,7 +3,7 @@ import math
import tkinter as tk
from tkinter import PhotoImage, font, messagebox, ttk
from tkinter.ttk import Progressbar
from typing import Any, Dict, Optional, Type
from typing import Any, Optional
import grpc
@ -45,7 +45,7 @@ class Application(ttk.Frame):
self.show_infobar: tk.BooleanVar = tk.BooleanVar(value=False)
# fonts
self.fonts_size: Dict[str, int] = {}
self.fonts_size: dict[str, int] = {}
self.icon_text_font: Optional[font.Font] = None
self.edge_font: Optional[font.Font] = None
@ -145,7 +145,7 @@ class Application(ttk.Frame):
self.statusbar = StatusBar(self.right_frame, self)
self.statusbar.grid(sticky=tk.EW, columnspan=2)
def display_info(self, frame_class: Type[InfoFrameBase], **kwargs: Any) -> None:
def display_info(self, frame_class: type[InfoFrameBase], **kwargs: Any) -> None:
if not self.show_infobar.get():
return
self.clear_info()

View file

@ -1,7 +1,7 @@
import os
import shutil
from pathlib import Path
from typing import Dict, List, Optional, Type
from typing import Optional
import yaml
@ -26,7 +26,7 @@ LOCAL_XMLS_PATH: Path = DATA_PATH.joinpath("xmls").absolute()
LOCAL_MOBILITY_PATH: Path = DATA_PATH.joinpath("mobility").absolute()
# configuration data
TERMINALS: Dict[str, str] = {
TERMINALS: dict[str, str] = {
"xterm": "xterm -e",
"aterm": "aterm -e",
"eterm": "eterm -e",
@ -36,7 +36,7 @@ TERMINALS: Dict[str, str] = {
"xfce4-terminal": "xfce4-terminal -x",
"gnome-terminal": "gnome-terminal --window --",
}
EDITORS: List[str] = ["$EDITOR", "vim", "emacs", "gedit", "nano", "vi"]
EDITORS: list[str] = ["$EDITOR", "vim", "emacs", "gedit", "nano", "vi"]
class IndentDumper(yaml.Dumper):
@ -46,17 +46,17 @@ class IndentDumper(yaml.Dumper):
class CustomNode(yaml.YAMLObject):
yaml_tag: str = "!CustomNode"
yaml_loader: Type[yaml.SafeLoader] = yaml.SafeLoader
yaml_loader: type[yaml.SafeLoader] = yaml.SafeLoader
def __init__(self, name: str, image: str, services: List[str]) -> None:
def __init__(self, name: str, image: str, services: list[str]) -> None:
self.name: str = name
self.image: str = image
self.services: List[str] = services
self.services: list[str] = services
class CoreServer(yaml.YAMLObject):
yaml_tag: str = "!CoreServer"
yaml_loader: Type[yaml.SafeLoader] = yaml.SafeLoader
yaml_loader: type[yaml.SafeLoader] = yaml.SafeLoader
def __init__(self, name: str, address: str) -> None:
self.name: str = name
@ -65,7 +65,7 @@ class CoreServer(yaml.YAMLObject):
class Observer(yaml.YAMLObject):
yaml_tag: str = "!Observer"
yaml_loader: Type[yaml.SafeLoader] = yaml.SafeLoader
yaml_loader: type[yaml.SafeLoader] = yaml.SafeLoader
def __init__(self, name: str, cmd: str) -> None:
self.name: str = name
@ -74,7 +74,7 @@ class Observer(yaml.YAMLObject):
class PreferencesConfig(yaml.YAMLObject):
yaml_tag: str = "!PreferencesConfig"
yaml_loader: Type[yaml.SafeLoader] = yaml.SafeLoader
yaml_loader: type[yaml.SafeLoader] = yaml.SafeLoader
def __init__(
self,
@ -95,7 +95,7 @@ class PreferencesConfig(yaml.YAMLObject):
class LocationConfig(yaml.YAMLObject):
yaml_tag: str = "!LocationConfig"
yaml_loader: Type[yaml.SafeLoader] = yaml.SafeLoader
yaml_loader: type[yaml.SafeLoader] = yaml.SafeLoader
def __init__(
self,
@ -118,17 +118,17 @@ class LocationConfig(yaml.YAMLObject):
class IpConfigs(yaml.YAMLObject):
yaml_tag: str = "!IpConfigs"
yaml_loader: Type[yaml.SafeLoader] = yaml.SafeLoader
yaml_loader: type[yaml.SafeLoader] = yaml.SafeLoader
def __init__(self, **kwargs) -> None:
self.__setstate__(kwargs)
def __setstate__(self, kwargs):
self.ip4s: List[str] = kwargs.get(
self.ip4s: list[str] = kwargs.get(
"ip4s", ["10.0.0.0", "192.168.0.0", "172.16.0.0"]
)
self.ip4: str = kwargs.get("ip4", self.ip4s[0])
self.ip6s: List[str] = kwargs.get("ip6s", ["2001::", "2002::", "a::"])
self.ip6s: list[str] = kwargs.get("ip6s", ["2001::", "2002::", "a::"])
self.ip6: str = kwargs.get("ip6", self.ip6s[0])
self.enable_ip4: bool = kwargs.get("enable_ip4", True)
self.enable_ip6: bool = kwargs.get("enable_ip6", True)
@ -136,16 +136,16 @@ class IpConfigs(yaml.YAMLObject):
class GuiConfig(yaml.YAMLObject):
yaml_tag: str = "!GuiConfig"
yaml_loader: Type[yaml.SafeLoader] = yaml.SafeLoader
yaml_loader: type[yaml.SafeLoader] = yaml.SafeLoader
def __init__(
self,
preferences: PreferencesConfig = None,
location: LocationConfig = None,
servers: List[CoreServer] = None,
nodes: List[CustomNode] = None,
recentfiles: List[str] = None,
observers: List[Observer] = None,
servers: list[CoreServer] = None,
nodes: list[CustomNode] = None,
recentfiles: list[str] = None,
observers: list[Observer] = None,
scale: float = 1.0,
ips: IpConfigs = None,
mac: str = "00:00:00:aa:00:00",
@ -158,16 +158,16 @@ class GuiConfig(yaml.YAMLObject):
self.location: LocationConfig = location
if servers is None:
servers = []
self.servers: List[CoreServer] = servers
self.servers: list[CoreServer] = servers
if nodes is None:
nodes = []
self.nodes: List[CustomNode] = nodes
self.nodes: list[CustomNode] = nodes
if recentfiles is None:
recentfiles = []
self.recentfiles: List[str] = recentfiles
self.recentfiles: list[str] = recentfiles
if observers is None:
observers = []
self.observers: List[Observer] = observers
self.observers: list[Observer] = observers
self.scale: float = scale
if ips is None:
ips = IpConfigs()

View file

@ -6,9 +6,10 @@ import json
import logging
import os
import tkinter as tk
from collections.abc import Iterable
from pathlib import Path
from tkinter import messagebox
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Tuple
from typing import TYPE_CHECKING, Optional
import grpc
@ -55,7 +56,7 @@ GUI_SOURCE = "gui"
CPU_USAGE_DELAY = 3
def to_dict(config: Dict[str, ConfigOption]) -> Dict[str, str]:
def to_dict(config: dict[str, ConfigOption]) -> dict[str, str]:
return {x: y.value for x, y in config.items()}
@ -74,26 +75,26 @@ class CoreClient:
self.show_throughputs: tk.BooleanVar = tk.BooleanVar(value=False)
# global service settings
self.services: Dict[str, Set[str]] = {}
self.config_services_groups: Dict[str, Set[str]] = {}
self.config_services: Dict[str, ConfigService] = {}
self.services: dict[str, set[str]] = {}
self.config_services_groups: dict[str, set[str]] = {}
self.config_services: dict[str, ConfigService] = {}
# loaded configuration data
self.emane_models: List[str] = []
self.servers: Dict[str, CoreServer] = {}
self.custom_nodes: Dict[str, NodeDraw] = {}
self.custom_observers: Dict[str, Observer] = {}
self.emane_models: list[str] = []
self.servers: dict[str, CoreServer] = {}
self.custom_nodes: dict[str, NodeDraw] = {}
self.custom_observers: dict[str, Observer] = {}
self.read_config()
# helpers
self.iface_to_edge: Dict[Tuple[int, ...], CanvasEdge] = {}
self.iface_to_edge: dict[tuple[int, ...], CanvasEdge] = {}
self.ifaces_manager: InterfaceManager = InterfaceManager(self.app)
self.observer: Optional[str] = None
# session data
self.mobility_players: Dict[int, MobilityPlayer] = {}
self.canvas_nodes: Dict[int, CanvasNode] = {}
self.links: Dict[str, CanvasEdge] = {}
self.mobility_players: dict[int, MobilityPlayer] = {}
self.canvas_nodes: dict[int, CanvasNode] = {}
self.links: dict[str, CanvasEdge] = {}
self.handling_throughputs: Optional[grpc.Future] = None
self.handling_cpu_usage: Optional[grpc.Future] = None
self.handling_events: Optional[grpc.Future] = None
@ -372,7 +373,7 @@ class CoreClient:
# existing session
sessions = self.client.get_sessions()
if session_id:
session_ids = set(x.id for x in sessions)
session_ids = {x.id for x in sessions}
if session_id not in session_ids:
self.app.show_error(
"Join Session Error",
@ -401,7 +402,7 @@ class CoreClient:
except grpc.RpcError as e:
self.app.show_grpc_exception("Edit Node Error", e)
def get_links(self, definition: bool = False) -> List[Link]:
def get_links(self, definition: bool = False) -> list[Link]:
if not definition:
self.ifaces_manager.set_macs([x.link for x in self.links.values()])
links = []
@ -419,7 +420,7 @@ class CoreClient:
links.append(edge.asymmetric_link)
return links
def start_session(self, definition: bool = False) -> Tuple[bool, List[str]]:
def start_session(self, definition: bool = False) -> tuple[bool, list[str]]:
self.session.links = self.get_links(definition)
self.session.metadata = self.get_metadata()
self.session.servers.clear()
@ -461,7 +462,7 @@ class CoreClient:
self.mobility_players[node.id] = mobility_player
mobility_player.show()
def get_metadata(self) -> Dict[str, str]:
def get_metadata(self) -> dict[str, str]:
# create canvas data
canvas_config = self.app.manager.get_metadata()
canvas_config = json.dumps(canvas_config)
@ -652,7 +653,7 @@ class CoreClient:
self.session.nodes[node.id] = node
return node
def deleted_canvas_nodes(self, canvas_nodes: List[CanvasNode]) -> None:
def deleted_canvas_nodes(self, canvas_nodes: list[CanvasNode]) -> None:
"""
remove the nodes selected by the user and anything related to that node
such as link, configurations, interfaces
@ -680,7 +681,7 @@ class CoreClient:
dst_iface_id = edge.link.iface2.id
self.iface_to_edge[(dst_node.id, dst_iface_id)] = edge
def get_wlan_configs(self) -> List[Tuple[int, Dict[str, str]]]:
def get_wlan_configs(self) -> list[tuple[int, dict[str, str]]]:
configs = []
for node in self.session.nodes.values():
if node.type != NodeType.WIRELESS_LAN:
@ -691,7 +692,7 @@ class CoreClient:
configs.append((node.id, config))
return configs
def get_mobility_configs(self) -> List[Tuple[int, Dict[str, str]]]:
def get_mobility_configs(self) -> list[tuple[int, dict[str, str]]]:
configs = []
for node in self.session.nodes.values():
if not nutils.is_mobility(node):
@ -702,7 +703,7 @@ class CoreClient:
configs.append((node.id, config))
return configs
def get_emane_model_configs(self) -> List[EmaneModelConfig]:
def get_emane_model_configs(self) -> list[EmaneModelConfig]:
configs = []
for node in self.session.nodes.values():
for key, config in node.emane_model_configs.items():
@ -716,7 +717,7 @@ class CoreClient:
configs.append(config)
return configs
def get_service_configs(self) -> List[ServiceConfig]:
def get_service_configs(self) -> list[ServiceConfig]:
configs = []
for node in self.session.nodes.values():
if not nutils.is_container(node):
@ -736,7 +737,7 @@ class CoreClient:
configs.append(config)
return configs
def get_service_file_configs(self) -> List[ServiceFileConfig]:
def get_service_file_configs(self) -> list[ServiceFileConfig]:
configs = []
for node in self.session.nodes.values():
if not nutils.is_container(node):
@ -749,12 +750,12 @@ class CoreClient:
configs.append(config)
return configs
def get_config_service_rendered(self, node_id: int, name: str) -> Dict[str, str]:
def get_config_service_rendered(self, node_id: int, name: str) -> dict[str, str]:
return self.client.get_config_service_rendered(self.session.id, node_id, name)
def get_config_service_configs_proto(
self,
) -> List[configservices_pb2.ConfigServiceConfig]:
) -> list[configservices_pb2.ConfigServiceConfig]:
config_service_protos = []
for node in self.session.nodes.values():
if not nutils.is_container(node):
@ -776,7 +777,7 @@ class CoreClient:
_, output = self.client.node_command(self.session.id, node_id, self.observer)
return output
def get_wlan_config(self, node_id: int) -> Dict[str, ConfigOption]:
def get_wlan_config(self, node_id: int) -> dict[str, ConfigOption]:
config = self.client.get_wlan_config(self.session.id, node_id)
logger.debug(
"get wlan configuration from node %s, result configuration: %s",
@ -785,10 +786,10 @@ class CoreClient:
)
return config
def get_wireless_config(self, node_id: int) -> Dict[str, ConfigOption]:
def get_wireless_config(self, node_id: int) -> dict[str, ConfigOption]:
return self.client.get_wireless_config(self.session.id, node_id)
def get_mobility_config(self, node_id: int) -> Dict[str, ConfigOption]:
def get_mobility_config(self, node_id: int) -> dict[str, ConfigOption]:
config = self.client.get_mobility_config(self.session.id, node_id)
logger.debug(
"get mobility config from node %s, result configuration: %s",
@ -799,7 +800,7 @@ class CoreClient:
def get_emane_model_config(
self, node_id: int, model: str, iface_id: int = None
) -> Dict[str, ConfigOption]:
) -> dict[str, ConfigOption]:
if iface_id is None:
iface_id = -1
config = self.client.get_emane_model_config(

View file

@ -3,7 +3,7 @@ check engine light
"""
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, Dict, Optional
from typing import TYPE_CHECKING, Optional
from core.api.grpc.wrappers import ExceptionEvent, ExceptionLevel
from core.gui.dialogs.dialog import Dialog
@ -19,7 +19,7 @@ class AlertsDialog(Dialog):
super().__init__(app, "Alerts")
self.tree: Optional[ttk.Treeview] = None
self.codetext: Optional[CodeText] = None
self.alarm_map: Dict[int, ExceptionEvent] = {}
self.alarm_map: dict[int, ExceptionEvent] = {}
self.draw()
def draw(self) -> None:

View file

@ -4,7 +4,7 @@ set wallpaper
import logging
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, List, Optional
from typing import TYPE_CHECKING, Optional
from core.gui import images
from core.gui.appconfig import BACKGROUNDS_PATH
@ -32,7 +32,7 @@ class CanvasWallpaperDialog(Dialog):
)
self.filename: tk.StringVar = tk.StringVar(value=self.canvas.wallpaper_file)
self.image_label: Optional[ttk.Label] = None
self.options: List[ttk.Radiobutton] = []
self.options: list[ttk.Radiobutton] = []
self.draw()
def draw(self) -> None:

View file

@ -3,7 +3,7 @@ custom color picker
"""
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, Optional, Tuple
from typing import TYPE_CHECKING, Optional
from core.gui import validation
from core.gui.dialogs.dialog import Dialog
@ -66,7 +66,9 @@ class ColorPickerDialog(Dialog):
)
scale.grid(row=0, column=2, sticky=tk.EW, padx=PADX)
self.red_label = ttk.Label(
frame, background="#%02x%02x%02x" % (self.red.get(), 0, 0), width=5
frame,
background="#{:02x}{:02x}{:02x}".format(self.red.get(), 0, 0),
width=5,
)
self.red_label.grid(row=0, column=3, sticky=tk.EW)
@ -89,7 +91,9 @@ class ColorPickerDialog(Dialog):
)
scale.grid(row=0, column=2, sticky=tk.EW, padx=PADX)
self.green_label = ttk.Label(
frame, background="#%02x%02x%02x" % (0, self.green.get(), 0), width=5
frame,
background="#{:02x}{:02x}{:02x}".format(0, self.green.get(), 0),
width=5,
)
self.green_label.grid(row=0, column=3, sticky=tk.EW)
@ -112,7 +116,9 @@ class ColorPickerDialog(Dialog):
)
scale.grid(row=0, column=2, sticky=tk.EW, padx=PADX)
self.blue_label = ttk.Label(
frame, background="#%02x%02x%02x" % (0, 0, self.blue.get()), width=5
frame,
background="#{:02x}{:02x}{:02x}".format(0, 0, self.blue.get()),
width=5,
)
self.blue_label.grid(row=0, column=3, sticky=tk.EW)
@ -157,7 +163,7 @@ class ColorPickerDialog(Dialog):
red = self.red_entry.get()
blue = self.blue_entry.get()
green = self.green_entry.get()
return "#%02x%02x%02x" % (int(red), int(green), int(blue))
return "#{:02x}{:02x}{:02x}".format(int(red), int(green), int(blue))
def current_focus(self, focus: str) -> None:
self.focus = focus
@ -169,7 +175,7 @@ class ColorPickerDialog(Dialog):
green = self.green_entry.get()
self.set_scale(red, green, blue)
if red and blue and green:
hex_code = "#%02x%02x%02x" % (int(red), int(green), int(blue))
hex_code = "#{:02x}{:02x}{:02x}".format(int(red), int(green), int(blue))
self.hex.set(hex_code)
self.display.config(background=hex_code)
self.set_label(red, green, blue)
@ -200,11 +206,17 @@ class ColorPickerDialog(Dialog):
self.blue.set(blue)
def set_label(self, red: str, green: str, blue: str) -> None:
self.red_label.configure(background="#%02x%02x%02x" % (int(red), 0, 0))
self.green_label.configure(background="#%02x%02x%02x" % (0, int(green), 0))
self.blue_label.configure(background="#%02x%02x%02x" % (0, 0, int(blue)))
self.red_label.configure(
background="#{:02x}{:02x}{:02x}".format(int(red), 0, 0)
)
self.green_label.configure(
background="#{:02x}{:02x}{:02x}".format(0, int(green), 0)
)
self.blue_label.configure(
background="#{:02x}{:02x}{:02x}".format(0, 0, int(blue))
)
def get_rgb(self, hex_code: str) -> Tuple[int, int, int]:
def get_rgb(self, hex_code: str) -> tuple[int, int, int]:
"""
convert a valid hex code to RGB values
"""

View file

@ -4,7 +4,7 @@ Service configuration dialog
import logging
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, Dict, List, Optional, Set
from typing import TYPE_CHECKING, Optional
import grpc
@ -35,22 +35,22 @@ class ConfigServiceConfigDialog(Dialog):
self.node: Node = node
self.service_name: str = service_name
self.radiovar: tk.IntVar = tk.IntVar(value=2)
self.directories: List[str] = []
self.templates: List[str] = []
self.rendered: Dict[str, str] = {}
self.dependencies: List[str] = []
self.executables: List[str] = []
self.startup_commands: List[str] = []
self.validation_commands: List[str] = []
self.shutdown_commands: List[str] = []
self.default_startup: List[str] = []
self.default_validate: List[str] = []
self.default_shutdown: List[str] = []
self.directories: list[str] = []
self.templates: list[str] = []
self.rendered: dict[str, str] = {}
self.dependencies: list[str] = []
self.executables: list[str] = []
self.startup_commands: list[str] = []
self.validation_commands: list[str] = []
self.shutdown_commands: list[str] = []
self.default_startup: list[str] = []
self.default_validate: list[str] = []
self.default_shutdown: list[str] = []
self.validation_mode: Optional[ServiceValidationMode] = None
self.validation_time: Optional[int] = None
self.validation_period: tk.DoubleVar = tk.DoubleVar()
self.modes: List[str] = []
self.mode_configs: Dict[str, Dict[str, str]] = {}
self.modes: list[str] = []
self.mode_configs: dict[str, dict[str, str]] = {}
self.notebook: Optional[ttk.Notebook] = None
self.templates_combobox: Optional[ttk.Combobox] = None
self.modes_combobox: Optional[ttk.Combobox] = None
@ -62,12 +62,12 @@ class ConfigServiceConfigDialog(Dialog):
self.template_text: Optional[CodeText] = None
self.rendered_text: Optional[CodeText] = None
self.validation_period_entry: Optional[ttk.Entry] = None
self.original_service_files: Dict[str, str] = {}
self.temp_service_files: Dict[str, str] = {}
self.modified_files: Set[str] = set()
self.original_service_files: dict[str, str] = {}
self.temp_service_files: dict[str, str] = {}
self.modified_files: set[str] = set()
self.config_frame: Optional[ConfigFrame] = None
self.default_config: Dict[str, str] = {}
self.config: Dict[str, ConfigOption] = {}
self.default_config: dict[str, str] = {}
self.config: dict[str, ConfigOption] = {}
self.has_error: bool = False
self.load()
if not self.has_error:
@ -405,7 +405,7 @@ class ConfigServiceConfigDialog(Dialog):
pass
def append_commands(
self, commands: List[str], listbox: tk.Listbox, to_add: List[str]
self, commands: list[str], listbox: tk.Listbox, to_add: list[str]
) -> None:
for cmd in to_add:
commands.append(cmd)

View file

@ -4,7 +4,7 @@ copy service config dialog
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, Dict, Optional
from typing import TYPE_CHECKING, Optional
from core.gui.dialogs.dialog import Dialog
from core.gui.themes import PADX, PADY
@ -29,7 +29,7 @@ class CopyServiceConfigDialog(Dialog):
self.service: str = service
self.file_name: str = file_name
self.listbox: Optional[tk.Listbox] = None
self.nodes: Dict[str, int] = {}
self.nodes: dict[str, int] = {}
self.draw()
def draw(self) -> None:

View file

@ -2,7 +2,7 @@ import logging
import tkinter as tk
from pathlib import Path
from tkinter import ttk
from typing import TYPE_CHECKING, Optional, Set
from typing import TYPE_CHECKING, Optional
from PIL.ImageTk import PhotoImage
@ -21,13 +21,13 @@ if TYPE_CHECKING:
class ServicesSelectDialog(Dialog):
def __init__(
self, master: tk.BaseWidget, app: "Application", current_services: Set[str]
self, master: tk.BaseWidget, app: "Application", current_services: set[str]
) -> None:
super().__init__(app, "Node Config Services", master=master)
self.groups: Optional[ListboxScroll] = None
self.services: Optional[CheckboxList] = None
self.current: Optional[ListboxScroll] = None
self.current_services: Set[str] = current_services
self.current_services: set[str] = current_services
self.draw()
def draw(self) -> None:
@ -114,7 +114,7 @@ class CustomNodesDialog(Dialog):
self.image_button: Optional[ttk.Button] = None
self.image: Optional[PhotoImage] = None
self.image_file: Optional[str] = None
self.services: Set[str] = set()
self.services: set[str] = set()
self.selected: Optional[str] = None
self.selected_index: Optional[int] = None
self.draw()

View file

@ -4,7 +4,7 @@ emane configuration
import tkinter as tk
import webbrowser
from tkinter import ttk
from typing import TYPE_CHECKING, Dict, List, Optional
from typing import TYPE_CHECKING, Optional
import grpc
@ -43,7 +43,7 @@ class EmaneModelDialog(Dialog):
config = self.app.core.get_emane_model_config(
self.node.id, self.model, self.iface_id
)
self.config: Dict[str, ConfigOption] = config
self.config: dict[str, ConfigOption] = config
self.draw()
except grpc.RpcError as e:
self.app.show_grpc_exception("Get EMANE Config Error", e)
@ -82,7 +82,7 @@ class EmaneConfigDialog(Dialog):
self.node: Node = node
self.radiovar: tk.IntVar = tk.IntVar()
self.radiovar.set(1)
self.emane_models: List[str] = [
self.emane_models: list[str] = [
x.split("_")[1] for x in self.app.core.emane_models
]
model = self.node.emane.split("_")[1]

View file

@ -1,6 +1,6 @@
import tkinter as tk
from tkinter import messagebox, ttk
from typing import TYPE_CHECKING, List, Optional
from typing import TYPE_CHECKING, Optional
import netaddr
@ -17,8 +17,8 @@ class IpConfigDialog(Dialog):
super().__init__(app, "IP Configuration")
self.ip4: str = self.app.guiconfig.ips.ip4
self.ip6: str = self.app.guiconfig.ips.ip6
self.ip4s: List[str] = self.app.guiconfig.ips.ip4s
self.ip6s: List[str] = self.app.guiconfig.ips.ip6s
self.ip4s: list[str] = self.app.guiconfig.ips.ip4s
self.ip6s: list[str] = self.app.guiconfig.ips.ip6s
self.ip4_entry: Optional[ttk.Entry] = None
self.ip4_listbox: Optional[ListboxScroll] = None
self.ip6_entry: Optional[ttk.Entry] = None

View file

@ -3,7 +3,7 @@ mobility configuration
"""
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, Dict, Optional
from typing import TYPE_CHECKING, Optional
import grpc
@ -26,7 +26,7 @@ class MobilityConfigDialog(Dialog):
config = self.node.mobility_config
if not config:
config = self.app.core.get_mobility_config(self.node.id)
self.config: Dict[str, ConfigOption] = config
self.config: dict[str, ConfigOption] = config
self.draw()
except grpc.RpcError as e:
self.app.show_grpc_exception("Get Mobility Config Error", e)

View file

@ -2,7 +2,7 @@ import logging
import tkinter as tk
from functools import partial
from tkinter import messagebox, ttk
from typing import TYPE_CHECKING, Dict, Optional
from typing import TYPE_CHECKING, Optional
import netaddr
from PIL.ImageTk import PhotoImage
@ -190,7 +190,7 @@ class NodeConfigDialog(Dialog):
if self.node.server:
server = self.node.server
self.server: tk.StringVar = tk.StringVar(value=server)
self.ifaces: Dict[int, InterfaceData] = {}
self.ifaces: dict[int, InterfaceData] = {}
self.draw()
def draw(self) -> None:

View file

@ -4,7 +4,7 @@ core node services
import logging
import tkinter as tk
from tkinter import messagebox, ttk
from typing import TYPE_CHECKING, Optional, Set
from typing import TYPE_CHECKING, Optional
from core.api.grpc.wrappers import Node
from core.gui.dialogs.configserviceconfig import ConfigServiceConfigDialog
@ -20,7 +20,7 @@ if TYPE_CHECKING:
class NodeConfigServiceDialog(Dialog):
def __init__(
self, app: "Application", node: Node, services: Set[str] = None
self, app: "Application", node: Node, services: set[str] = None
) -> None:
title = f"{node.name} Config Services"
super().__init__(app, title)
@ -30,7 +30,7 @@ class NodeConfigServiceDialog(Dialog):
self.current: Optional[ListboxScroll] = None
if services is None:
services = set(node.config_services)
self.current_services: Set[str] = services
self.current_services: set[str] = services
self.protocol("WM_DELETE_WINDOW", self.click_cancel)
self.draw()

View file

@ -3,7 +3,7 @@ core node services
"""
import tkinter as tk
from tkinter import messagebox, ttk
from typing import TYPE_CHECKING, Optional, Set
from typing import TYPE_CHECKING, Optional
from core.api.grpc.wrappers import Node
from core.gui.dialogs.dialog import Dialog
@ -24,7 +24,7 @@ class NodeServiceDialog(Dialog):
self.services: Optional[CheckboxList] = None
self.current: Optional[ListboxScroll] = None
services = set(node.services)
self.current_services: Set[str] = services
self.current_services: set[str] = services
self.protocol("WM_DELETE_WINDOW", self.click_cancel)
self.draw()

View file

@ -1,6 +1,6 @@
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, Dict, Optional
from typing import TYPE_CHECKING, Optional
from core.gui import nodeutils as nutils
from core.gui.dialogs.dialog import Dialog
@ -17,7 +17,7 @@ class RunToolDialog(Dialog):
self.cmd: tk.StringVar = tk.StringVar(value="ps ax")
self.result: Optional[CodeText] = None
self.node_list: Optional[ListboxScroll] = None
self.executable_nodes: Dict[str, int] = {}
self.executable_nodes: dict[str, int] = {}
self.store_nodes()
self.draw()

View file

@ -2,7 +2,7 @@ import logging
import tkinter as tk
from pathlib import Path
from tkinter import filedialog, messagebox, ttk
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple
from typing import TYPE_CHECKING, Optional
import grpc
from PIL.ImageTk import PhotoImage
@ -35,21 +35,21 @@ class ServiceConfigDialog(Dialog):
self.service_name: str = service_name
self.radiovar: tk.IntVar = tk.IntVar(value=2)
self.metadata: str = ""
self.filenames: List[str] = []
self.dependencies: List[str] = []
self.executables: List[str] = []
self.startup_commands: List[str] = []
self.validation_commands: List[str] = []
self.shutdown_commands: List[str] = []
self.default_startup: List[str] = []
self.default_validate: List[str] = []
self.default_shutdown: List[str] = []
self.filenames: list[str] = []
self.dependencies: list[str] = []
self.executables: list[str] = []
self.startup_commands: list[str] = []
self.validation_commands: list[str] = []
self.shutdown_commands: list[str] = []
self.default_startup: list[str] = []
self.default_validate: list[str] = []
self.default_shutdown: list[str] = []
self.validation_mode: Optional[ServiceValidationMode] = None
self.validation_time: Optional[int] = None
self.validation_period: Optional[float] = None
self.directory_entry: Optional[ttk.Entry] = None
self.default_directories: List[str] = []
self.temp_directories: List[str] = []
self.default_directories: list[str] = []
self.temp_directories: list[str] = []
self.documentnew_img: PhotoImage = self.app.get_enum_icon(
ImageEnum.DOCUMENTNEW, width=ICON_SIZE
)
@ -67,10 +67,10 @@ class ServiceConfigDialog(Dialog):
self.validation_mode_entry: Optional[ttk.Entry] = None
self.service_file_data: Optional[CodeText] = None
self.validation_period_entry: Optional[ttk.Entry] = None
self.original_service_files: Dict[str, str] = {}
self.original_service_files: dict[str, str] = {}
self.default_config: Optional[NodeServiceData] = None
self.temp_service_files: Dict[str, str] = {}
self.modified_files: Set[str] = set()
self.temp_service_files: dict[str, str] = {}
self.modified_files: set[str] = set()
self.has_error: bool = False
self.load()
if not self.has_error:
@ -558,13 +558,13 @@ class ServiceConfigDialog(Dialog):
@classmethod
def append_commands(
cls, commands: List[str], listbox: tk.Listbox, to_add: List[str]
cls, commands: list[str], listbox: tk.Listbox, to_add: list[str]
) -> None:
for cmd in to_add:
commands.append(cmd)
listbox.insert(tk.END, cmd)
def get_commands(self) -> Tuple[List[str], List[str], List[str]]:
def get_commands(self) -> tuple[list[str], list[str], list[str]]:
startup = self.startup_commands_listbox.get(0, "end")
shutdown = self.shutdown_commands_listbox.get(0, "end")
validate = self.validate_commands_listbox.get(0, "end")

View file

@ -1,7 +1,7 @@
import logging
import tkinter as tk
from tkinter import messagebox, ttk
from typing import TYPE_CHECKING, List, Optional
from typing import TYPE_CHECKING, Optional
import grpc
@ -30,7 +30,7 @@ class SessionsDialog(Dialog):
self.protocol("WM_DELETE_WINDOW", self.on_closing)
self.draw()
def get_sessions(self) -> List[SessionSummary]:
def get_sessions(self) -> list[SessionSummary]:
try:
sessions = self.app.core.client.get_sessions()
logger.info("sessions: %s", sessions)

View file

@ -3,7 +3,7 @@ shape input dialog
"""
import tkinter as tk
from tkinter import font, ttk
from typing import TYPE_CHECKING, List, Optional, Union
from typing import TYPE_CHECKING, Optional, Union
from core.gui.dialogs.colorpicker import ColorPickerDialog
from core.gui.dialogs.dialog import Dialog
@ -16,8 +16,8 @@ if TYPE_CHECKING:
from core.gui.graph.graph import CanvasGraph
from core.gui.graph.shape import Shape
FONT_SIZES: List[int] = [8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72]
BORDER_WIDTH: List[int] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
FONT_SIZES: list[int] = [8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72]
BORDER_WIDTH: list[int] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
class ShapeDialog(Dialog):
@ -168,7 +168,7 @@ class ShapeDialog(Dialog):
self.add_text()
self.destroy()
def make_font(self) -> List[Union[int, str]]:
def make_font(self) -> list[Union[int, str]]:
"""
create font for text or shape label
"""

View file

@ -1,6 +1,6 @@
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, Dict, Optional
from typing import TYPE_CHECKING, Optional
import grpc
@ -19,12 +19,12 @@ class WirelessConfigDialog(Dialog):
super().__init__(app, f"Wireless Configuration - {canvas_node.core_node.name}")
self.node: Node = canvas_node.core_node
self.config_frame: Optional[ConfigFrame] = None
self.config: Dict[str, ConfigOption] = {}
self.config: dict[str, ConfigOption] = {}
try:
config = self.node.wireless_config
if not config:
config = self.app.core.get_wireless_config(self.node.id)
self.config: Dict[str, ConfigOption] = config
self.config: dict[str, ConfigOption] = config
self.draw()
except grpc.RpcError as e:
self.app.show_grpc_exception("Wireless Config Error", e)

View file

@ -1,6 +1,6 @@
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, Dict, Optional
from typing import TYPE_CHECKING, Optional
import grpc
@ -27,13 +27,13 @@ class WlanConfigDialog(Dialog):
self.config_frame: Optional[ConfigFrame] = None
self.range_entry: Optional[ttk.Entry] = None
self.has_error: bool = False
self.ranges: Dict[int, int] = {}
self.ranges: dict[int, int] = {}
self.positive_int: int = self.app.master.register(self.validate_and_update)
try:
config = self.node.wlan_config
if not config:
config = self.app.core.get_wlan_config(self.node.id)
self.config: Dict[str, ConfigOption] = config
self.config: dict[str, ConfigOption] = config
self.init_draw_range()
self.draw()
except grpc.RpcError as e:

View file

@ -2,7 +2,7 @@ import functools
import logging
import math
import tkinter as tk
from typing import TYPE_CHECKING, Optional, Tuple, Union
from typing import TYPE_CHECKING, Optional, Union
from core.api.grpc.wrappers import Interface, Link
from core.gui import nodeutils, themes
@ -54,7 +54,7 @@ def create_edge_token(link: Link) -> str:
def node_label_positions(
src_x: int, src_y: int, dst_x: int, dst_y: int
) -> Tuple[Tuple[float, float], Tuple[float, float]]:
) -> tuple[tuple[float, float], tuple[float, float]]:
v_x, v_y = dst_x - src_x, dst_y - src_y
v_len = math.sqrt(v_x**2 + v_y**2)
if v_len == 0:
@ -128,8 +128,8 @@ class Edge:
return self.width * self.app.app_scale
def _get_arcpoint(
self, src_pos: Tuple[float, float], dst_pos: Tuple[float, float]
) -> Tuple[float, float]:
self, src_pos: tuple[float, float], dst_pos: tuple[float, float]
) -> tuple[float, float]:
src_x, src_y = src_pos
dst_x, dst_y = dst_pos
mp_x = (src_x + dst_x) / 2
@ -317,7 +317,7 @@ class Edge:
if self.dst_label2:
self.dst.canvas.itemconfig(self.dst_label2, text=text)
def drawing(self, pos: Tuple[float, float]) -> None:
def drawing(self, pos: tuple[float, float]) -> None:
src_x, src_y, _, _, _, _ = self.src.canvas.coords(self.id)
src_pos = src_x, src_y
self.moved(src_pos, pos)
@ -368,7 +368,7 @@ class Edge:
dst_pos = dst_x, dst_y
self.moved(self.src.position(), dst_pos)
def moved(self, src_pos: Tuple[float, float], dst_pos: Tuple[float, float]) -> None:
def moved(self, src_pos: tuple[float, float], dst_pos: tuple[float, float]) -> None:
arc_pos = self._get_arcpoint(src_pos, dst_pos)
self.src.canvas.coords(self.id, *src_pos, *arc_pos, *dst_pos)
if self.middle_label:
@ -381,7 +381,7 @@ class Edge:
self.src.canvas.coords(self.dst_label, *dst_pos)
def moved2(
self, src_pos: Tuple[float, float], dst_pos: Tuple[float, float]
self, src_pos: tuple[float, float], dst_pos: tuple[float, float]
) -> None:
arc_pos = self._get_arcpoint(src_pos, dst_pos)
self.dst.canvas.coords(self.id2, *src_pos, *arc_pos, *dst_pos)
@ -568,7 +568,7 @@ class CanvasEdge(Edge):
label += f"{iface.ip6}/{iface.ip6_mask}"
return label
def create_node_labels(self) -> Tuple[str, str]:
def create_node_labels(self) -> tuple[str, str]:
label1 = None
if self.link.iface1:
label1 = self.iface_label(self.link.iface1)

View file

@ -2,7 +2,7 @@ import logging
import tkinter as tk
from copy import deepcopy
from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Tuple
from typing import TYPE_CHECKING, Any, Optional
from PIL import Image
from PIL.ImageTk import PhotoImage
@ -27,8 +27,8 @@ if TYPE_CHECKING:
ZOOM_IN: float = 1.1
ZOOM_OUT: float = 0.9
MOVE_NODE_MODES: Set[GraphMode] = {GraphMode.NODE, GraphMode.SELECT}
MOVE_SHAPE_MODES: Set[GraphMode] = {GraphMode.ANNOTATION, GraphMode.SELECT}
MOVE_NODE_MODES: set[GraphMode] = {GraphMode.NODE, GraphMode.SELECT}
MOVE_SHAPE_MODES: set[GraphMode] = {GraphMode.ANNOTATION, GraphMode.SELECT}
BACKGROUND_COLOR: str = "#cccccc"
@ -40,32 +40,32 @@ class CanvasGraph(tk.Canvas):
manager: "CanvasManager",
core: "CoreClient",
_id: int,
dimensions: Tuple[int, int],
dimensions: tuple[int, int],
) -> None:
super().__init__(master, highlightthickness=0, background=BACKGROUND_COLOR)
self.id: int = _id
self.app: "Application" = app
self.manager: "CanvasManager" = manager
self.core: "CoreClient" = core
self.selection: Dict[int, int] = {}
self.selection: dict[int, int] = {}
self.select_box: Optional[Shape] = None
self.selected: Optional[int] = None
self.nodes: Dict[int, CanvasNode] = {}
self.shadow_nodes: Dict[int, ShadowNode] = {}
self.shapes: Dict[int, Shape] = {}
self.shadow_core_nodes: Dict[int, ShadowNode] = {}
self.nodes: dict[int, CanvasNode] = {}
self.shadow_nodes: dict[int, ShadowNode] = {}
self.shapes: dict[int, Shape] = {}
self.shadow_core_nodes: dict[int, ShadowNode] = {}
# map wireless/EMANE node to the set of MDRs connected to that node
self.wireless_network: Dict[int, Set[int]] = {}
self.wireless_network: dict[int, set[int]] = {}
self.drawing_edge: Optional[CanvasEdge] = None
self.rect: Optional[int] = None
self.shape_drawing: bool = False
self.current_dimensions: Tuple[int, int] = dimensions
self.current_dimensions: tuple[int, int] = dimensions
self.ratio: float = 1.0
self.offset: Tuple[int, int] = (0, 0)
self.cursor: Tuple[int, int] = (0, 0)
self.to_copy: List[CanvasNode] = []
self.offset: tuple[int, int] = (0, 0)
self.cursor: tuple[int, int] = (0, 0)
self.to_copy: list[CanvasNode] = []
# background related
self.wallpaper_id: Optional[int] = None
@ -82,7 +82,7 @@ class CanvasGraph(tk.Canvas):
self.draw_canvas()
self.draw_grid()
def draw_canvas(self, dimensions: Tuple[int, int] = None) -> None:
def draw_canvas(self, dimensions: tuple[int, int] = None) -> None:
if self.rect is not None:
self.delete(self.rect)
if not dimensions:
@ -126,23 +126,23 @@ class CanvasGraph(tk.Canvas):
shadow_node = ShadowNode(self.app, self, node)
return shadow_node
def get_actual_coords(self, x: float, y: float) -> Tuple[float, float]:
def get_actual_coords(self, x: float, y: float) -> tuple[float, float]:
actual_x = (x - self.offset[0]) / self.ratio
actual_y = (y - self.offset[1]) / self.ratio
return actual_x, actual_y
def get_scaled_coords(self, x: float, y: float) -> Tuple[float, float]:
def get_scaled_coords(self, x: float, y: float) -> tuple[float, float]:
scaled_x = (x * self.ratio) + self.offset[0]
scaled_y = (y * self.ratio) + self.offset[1]
return scaled_x, scaled_y
def inside_canvas(self, x: float, y: float) -> Tuple[bool, bool]:
def inside_canvas(self, x: float, y: float) -> tuple[bool, bool]:
x1, y1, x2, y2 = self.bbox(self.rect)
valid_x = x1 <= x <= x2
valid_y = y1 <= y <= y2
return valid_x and valid_y
def valid_position(self, x1: int, y1: int, x2: int, y2: int) -> Tuple[bool, bool]:
def valid_position(self, x1: int, y1: int, x2: int, y2: int) -> tuple[bool, bool]:
valid_topleft = self.inside_canvas(x1, y1)
valid_bottomright = self.inside_canvas(x2, y2)
return valid_topleft and valid_bottomright
@ -161,7 +161,7 @@ class CanvasGraph(tk.Canvas):
self.tag_lower(tags.GRIDLINE)
self.tag_lower(self.rect)
def canvas_xy(self, event: tk.Event) -> Tuple[float, float]:
def canvas_xy(self, event: tk.Event) -> tuple[float, float]:
"""
Convert window coordinate to canvas coordinate
"""
@ -516,7 +516,7 @@ class CanvasGraph(tk.Canvas):
self.nodes[node.id] = node
self.core.set_canvas_node(core_node, node)
def width_and_height(self) -> Tuple[int, int]:
def width_and_height(self) -> tuple[int, int]:
"""
retrieve canvas width and height in pixels
"""
@ -601,7 +601,7 @@ class CanvasGraph(tk.Canvas):
self.redraw_canvas((image.width(), image.height()))
self.draw_wallpaper(image)
def redraw_canvas(self, dimensions: Tuple[int, int] = None) -> None:
def redraw_canvas(self, dimensions: tuple[int, int] = None) -> None:
logger.debug("redrawing canvas to dimensions: %s", dimensions)
# reset scale and move back to original position
@ -814,7 +814,7 @@ class CanvasGraph(tk.Canvas):
for edge_id in self.find_withtag(tags.EDGE):
self.itemconfig(edge_id, width=int(EDGE_WIDTH * self.app.app_scale))
def get_metadata(self) -> Dict[str, Any]:
def get_metadata(self) -> dict[str, Any]:
wallpaper_path = None
if self.wallpaper_file:
wallpaper = Path(self.wallpaper_file)
@ -830,7 +830,7 @@ class CanvasGraph(tk.Canvas):
dimensions=self.current_dimensions,
)
def parse_metadata(self, config: Dict[str, Any]) -> None:
def parse_metadata(self, config: dict[str, Any]) -> None:
fit_image = config.get("fit_image", False)
self.adjust_to_dim.set(fit_image)
wallpaper_style = config.get("wallpaper_style", 1)

View file

@ -1,9 +1,10 @@
import json
import logging
import tkinter as tk
from collections.abc import ValuesView
from copy import deepcopy
from tkinter import BooleanVar, messagebox, ttk
from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, ValuesView
from typing import TYPE_CHECKING, Any, Optional
from core.api.grpc.wrappers import Link, LinkType, Node, Session, ThroughputsEvent
from core.gui import nodeutils as nutils
@ -78,14 +79,14 @@ class CanvasManager:
self.mode: GraphMode = GraphMode.SELECT
self.annotation_type: Optional[ShapeType] = None
self.node_draw: Optional[NodeDraw] = None
self.canvases: Dict[int, CanvasGraph] = {}
self.canvases: dict[int, CanvasGraph] = {}
# global edge management
self.edges: Dict[str, CanvasEdge] = {}
self.wireless_edges: Dict[str, CanvasWirelessEdge] = {}
self.edges: dict[str, CanvasEdge] = {}
self.wireless_edges: dict[str, CanvasWirelessEdge] = {}
# global canvas settings
self.default_dimensions: Tuple[int, int] = (
self.default_dimensions: tuple[int, int] = (
self.app.guiconfig.preferences.width,
self.app.guiconfig.preferences.height,
)
@ -111,8 +112,8 @@ class CanvasManager:
# widget
self.notebook: Optional[ttk.Notebook] = None
self.canvas_ids: Dict[str, int] = {}
self.unique_ids: Dict[int, str] = {}
self.canvas_ids: dict[str, int] = {}
self.unique_ids: dict[int, str] = {}
self.draw()
self.setup_bindings()
@ -273,17 +274,17 @@ class CanvasManager:
if not self.canvases:
self.add_canvas()
def redraw_canvas(self, dimensions: Tuple[int, int]) -> None:
def redraw_canvas(self, dimensions: tuple[int, int]) -> None:
canvas = self.current()
canvas.redraw_canvas(dimensions)
if canvas.wallpaper:
canvas.redraw_wallpaper()
def get_metadata(self) -> Dict[str, Any]:
def get_metadata(self) -> dict[str, Any]:
canvases = [x.get_metadata() for x in self.all()]
return dict(gridlines=self.show_grid.get(), canvases=canvases)
def parse_metadata_canvas(self, metadata: Dict[str, Any]) -> None:
def parse_metadata_canvas(self, metadata: dict[str, Any]) -> None:
# canvas setting
canvas_config = metadata.get("canvas")
logger.debug("canvas metadata: %s", canvas_config)
@ -303,7 +304,7 @@ class CanvasManager:
canvas = self.get(canvas_id)
canvas.parse_metadata(canvas_config)
def parse_metadata_shapes(self, metadata: Dict[str, Any]) -> None:
def parse_metadata_shapes(self, metadata: dict[str, Any]) -> None:
# load saved shapes
shapes_config = metadata.get("shapes")
if not shapes_config:
@ -313,7 +314,7 @@ class CanvasManager:
logger.debug("loading shape: %s", shape_config)
Shape.from_metadata(self.app, shape_config)
def parse_metadata_edges(self, metadata: Dict[str, Any]) -> None:
def parse_metadata_edges(self, metadata: dict[str, Any]) -> None:
# load edges config
edges_config = metadata.get("edges")
if not edges_config:
@ -330,7 +331,7 @@ class CanvasManager:
else:
logger.warning("invalid edge token to configure: %s", edge_token)
def parse_metadata_hidden(self, metadata: Dict[str, Any]) -> None:
def parse_metadata_hidden(self, metadata: dict[str, Any]) -> None:
# read hidden nodes
hidden_config = metadata.get("hidden")
if not hidden_config:

View file

@ -2,7 +2,7 @@ import functools
import logging
import tkinter as tk
from pathlib import Path
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple
from typing import TYPE_CHECKING, Optional
import grpc
from PIL.ImageTk import PhotoImage
@ -62,17 +62,17 @@ class CanvasNode:
state=self.app.manager.show_node_labels.state(),
)
self.tooltip: CanvasTooltip = CanvasTooltip(self.canvas)
self.edges: Set[CanvasEdge] = set()
self.ifaces: Dict[int, Interface] = {}
self.wireless_edges: Set[CanvasWirelessEdge] = set()
self.antennas: List[int] = []
self.antenna_images: Dict[int, PhotoImage] = {}
self.edges: set[CanvasEdge] = set()
self.ifaces: dict[int, Interface] = {}
self.wireless_edges: set[CanvasWirelessEdge] = set()
self.antennas: list[int] = []
self.antenna_images: dict[int, PhotoImage] = {}
self.hidden: bool = False
self.setup_bindings()
self.context: tk.Menu = tk.Menu(self.canvas)
themes.style_menu(self.context)
def position(self) -> Tuple[int, int]:
def position(self) -> tuple[int, int]:
return self.canvas.coords(self.id)
def next_iface_id(self) -> int:
@ -543,7 +543,7 @@ class ShadowNode:
self.canvas.shadow_nodes[self.id] = self
self.canvas.shadow_core_nodes[self.node.core_node.id] = self
def position(self) -> Tuple[int, int]:
def position(self) -> tuple[int, int]:
return self.canvas.coords(self.id)
def should_delete(self) -> bool:

View file

@ -1,5 +1,5 @@
import logging
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
from typing import TYPE_CHECKING, Any, Optional, Union
from core.gui.dialogs.shapemod import ShapeDialog
from core.gui.graph import tags
@ -72,7 +72,7 @@ class Shape:
self.draw()
@classmethod
def from_metadata(cls, app: "Application", config: Dict[str, Any]) -> None:
def from_metadata(cls, app: "Application", config: dict[str, Any]) -> None:
shape_type = config["type"]
try:
shape_type = ShapeType(shape_type)
@ -144,7 +144,7 @@ class Shape:
logger.error("unknown shape type: %s", self.shape_type)
self.created = True
def get_font(self) -> List[Union[int, str]]:
def get_font(self) -> list[Union[int, str]]:
font = [self.shape_data.font, self.shape_data.font_size]
if self.shape_data.bold:
font.append("bold")
@ -198,7 +198,7 @@ class Shape:
self.canvas.delete(self.id)
self.canvas.delete(self.text_id)
def metadata(self) -> Dict[str, Union[str, int, bool]]:
def metadata(self) -> dict[str, Union[str, int, bool]]:
coords = self.canvas.coords(self.id)
# update coords to actual positions
if len(coords) == 4:

View file

@ -1,5 +1,4 @@
import enum
from typing import Set
class ShapeType(enum.Enum):
@ -9,7 +8,7 @@ class ShapeType(enum.Enum):
TEXT = "text"
SHAPES: Set[ShapeType] = {ShapeType.OVAL, ShapeType.RECTANGLE}
SHAPES: set[ShapeType] = {ShapeType.OVAL, ShapeType.RECTANGLE}
def is_draw_shape(shape_type: ShapeType) -> bool:

View file

@ -1,5 +1,3 @@
from typing import List
ANNOTATION: str = "annotation"
GRIDLINE: str = "gridline"
SHAPE: str = "shape"
@ -15,7 +13,7 @@ WALLPAPER: str = "wallpaper"
SELECTION: str = "selectednodes"
MARKER: str = "marker"
HIDDEN: str = "hidden"
ORGANIZE_TAGS: List[str] = [
ORGANIZE_TAGS: list[str] = [
WALLPAPER,
GRIDLINE,
SHAPE,
@ -29,7 +27,7 @@ ORGANIZE_TAGS: List[str] = [
SELECTION,
MARKER,
]
RESET_TAGS: List[str] = [
RESET_TAGS: list[str] = [
EDGE,
NODE,
NODE_LABEL,

View file

@ -1,6 +1,6 @@
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, Optional, Tuple
from typing import TYPE_CHECKING, Optional
from core.gui.themes import Styles
@ -27,7 +27,7 @@ class CanvasTooltip:
self,
canvas: "CanvasGraph",
*,
pad: Tuple[int, int, int, int] = (5, 3, 5, 3),
pad: tuple[int, int, int, int] = (5, 3, 5, 3),
waittime: int = 400,
wraplength: int = 600
) -> None:
@ -37,7 +37,7 @@ class CanvasTooltip:
self.wraplength: int = wraplength
self.canvas: "CanvasGraph" = canvas
self.text: tk.StringVar = tk.StringVar()
self.pad: Tuple[int, int, int, int] = pad
self.pad: tuple[int, int, int, int] = pad
self.id: Optional[str] = None
self.tw: Optional[tk.Toplevel] = None
@ -63,8 +63,8 @@ class CanvasTooltip:
canvas: "CanvasGraph",
label: ttk.Label,
*,
tip_delta: Tuple[int, int] = (10, 5),
pad: Tuple[int, int, int, int] = (5, 3, 5, 3)
tip_delta: tuple[int, int] = (10, 5),
pad: tuple[int, int, int, int] = (5, 3, 5, 3)
):
c = canvas
s_width, s_height = c.winfo_screenwidth(), c.winfo_screenheight()

View file

@ -1,5 +1,5 @@
from enum import Enum
from typing import Dict, Optional, Tuple
from typing import Optional
from PIL import Image
from PIL.ImageTk import PhotoImage
@ -12,7 +12,7 @@ ANTENNA_SIZE: int = 32
BUTTON_SIZE: int = 16
ERROR_SIZE: int = 24
DIALOG_SIZE: int = 16
IMAGES: Dict[str, str] = {}
IMAGES: dict[str, str] = {}
def load_all() -> None:
@ -87,7 +87,7 @@ class ImageEnum(Enum):
SHADOW = "shadow"
TYPE_MAP: Dict[Tuple[NodeType, str], ImageEnum] = {
TYPE_MAP: dict[tuple[NodeType, str], ImageEnum] = {
(NodeType.DEFAULT, "router"): ImageEnum.ROUTER,
(NodeType.DEFAULT, "PC"): ImageEnum.PC,
(NodeType.DEFAULT, "host"): ImageEnum.HOST,

View file

@ -1,5 +1,5 @@
import logging
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Tuple
from typing import TYPE_CHECKING, Any, Optional
import netaddr
from netaddr import EUI, IPNetwork
@ -43,7 +43,7 @@ class Subnets:
def __hash__(self) -> int:
return hash(self.key())
def key(self) -> Tuple[IPNetwork, IPNetwork]:
def key(self) -> tuple[IPNetwork, IPNetwork]:
return self.ip4, self.ip6
def next(self) -> "Subnets":
@ -61,8 +61,8 @@ class InterfaceManager:
self.mac: EUI = EUI(mac, dialect=netaddr.mac_unix_expanded)
self.current_mac: Optional[EUI] = None
self.current_subnets: Optional[Subnets] = None
self.used_subnets: Dict[Tuple[IPNetwork, IPNetwork], Subnets] = {}
self.used_macs: Set[str] = set()
self.used_subnets: dict[tuple[IPNetwork, IPNetwork], Subnets] = {}
self.used_macs: set[str] = set()
def update_ips(self, ip4: str, ip6: str) -> None:
self.reset()
@ -91,7 +91,7 @@ class InterfaceManager:
self.current_subnets = None
self.used_subnets.clear()
def removed(self, links: List[Link]) -> None:
def removed(self, links: list[Link]) -> None:
# get remaining subnets
remaining_subnets = set()
for edge in self.app.core.links.values():
@ -121,7 +121,7 @@ class InterfaceManager:
subnets.used_indexes.discard(index)
self.current_subnets = None
def set_macs(self, links: List[Link]) -> None:
def set_macs(self, links: list[Link]) -> None:
self.current_mac = self.mac
self.used_macs.clear()
for link in links:
@ -130,7 +130,7 @@ class InterfaceManager:
if link.iface2:
self.used_macs.add(link.iface2.mac)
def joined(self, links: List[Link]) -> None:
def joined(self, links: list[Link]) -> None:
ifaces = []
for link in links:
if link.iface1:
@ -208,7 +208,7 @@ class InterfaceManager:
logger.info("ignoring subnet change for link between network nodes")
def find_subnets(
self, canvas_node: CanvasNode, visited: Set[int] = None
self, canvas_node: CanvasNode, visited: set[int] = None
) -> Optional[IPNetwork]:
logger.info("finding subnet for node: %s", canvas_node.core_node.name)
subnets = None

View file

@ -1,5 +1,5 @@
import logging
from typing import TYPE_CHECKING, List, Optional, Set
from typing import TYPE_CHECKING, Optional
from PIL.ImageTk import PhotoImage
@ -13,22 +13,22 @@ logger = logging.getLogger(__name__)
if TYPE_CHECKING:
from core.gui.app import Application
NODES: List["NodeDraw"] = []
NETWORK_NODES: List["NodeDraw"] = []
NODES: list["NodeDraw"] = []
NETWORK_NODES: list["NodeDraw"] = []
NODE_ICONS = {}
CONTAINER_NODES: Set[NodeType] = {NodeType.DEFAULT, NodeType.DOCKER, NodeType.LXC}
IMAGE_NODES: Set[NodeType] = {NodeType.DOCKER, NodeType.LXC}
WIRELESS_NODES: Set[NodeType] = {
CONTAINER_NODES: set[NodeType] = {NodeType.DEFAULT, NodeType.DOCKER, NodeType.LXC}
IMAGE_NODES: set[NodeType] = {NodeType.DOCKER, NodeType.LXC}
WIRELESS_NODES: set[NodeType] = {
NodeType.WIRELESS_LAN,
NodeType.EMANE,
NodeType.WIRELESS,
}
RJ45_NODES: Set[NodeType] = {NodeType.RJ45}
BRIDGE_NODES: Set[NodeType] = {NodeType.HUB, NodeType.SWITCH}
IGNORE_NODES: Set[NodeType] = {NodeType.CONTROL_NET}
MOBILITY_NODES: Set[NodeType] = {NodeType.WIRELESS_LAN, NodeType.EMANE}
NODE_MODELS: Set[str] = {"router", "PC", "mdr", "prouter"}
ROUTER_NODES: Set[str] = {"router", "mdr"}
RJ45_NODES: set[NodeType] = {NodeType.RJ45}
BRIDGE_NODES: set[NodeType] = {NodeType.HUB, NodeType.SWITCH}
IGNORE_NODES: set[NodeType] = {NodeType.CONTROL_NET}
MOBILITY_NODES: set[NodeType] = {NodeType.WIRELESS_LAN, NodeType.EMANE}
NODE_MODELS: set[str] = {"router", "PC", "mdr", "prouter"}
ROUTER_NODES: set[str] = {"router", "mdr"}
ANTENNA_ICON: Optional[PhotoImage] = None
@ -106,7 +106,7 @@ def is_iface_node(node: Node) -> bool:
return is_container(node) or is_bridge(node)
def get_custom_services(gui_config: GuiConfig, name: str) -> List[str]:
def get_custom_services(gui_config: GuiConfig, name: str) -> list[str]:
for custom_node in gui_config.nodes:
if custom_node.name == name:
return custom_node.services
@ -154,7 +154,7 @@ class NodeDraw:
self.image_file: Optional[str] = None
self.node_type: Optional[NodeType] = None
self.model: Optional[str] = None
self.services: Set[str] = set()
self.services: set[str] = set()
self.label: Optional[str] = None
@classmethod

View file

@ -1,13 +1,13 @@
import tkinter as tk
from functools import partial
from typing import TYPE_CHECKING, Dict
from typing import TYPE_CHECKING
from core.gui.dialogs.observers import ObserverDialog
if TYPE_CHECKING:
from core.gui.app import Application
OBSERVERS: Dict[str, str] = {
OBSERVERS: dict[str, str] = {
"List Processes": "ps",
"Show Interfaces": "ip address",
"IPV4 Routes": "ip -4 route",

View file

@ -3,7 +3,7 @@ status bar
"""
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, List, Optional
from typing import TYPE_CHECKING, Optional
from core.api.grpc.wrappers import ExceptionEvent, ExceptionLevel
from core.gui.dialogs.alerts import AlertsDialog
@ -24,7 +24,7 @@ class StatusBar(ttk.Frame):
self.alerts_button: Optional[ttk.Button] = None
self.alert_style = Styles.no_alert
self.running: bool = False
self.core_alarms: List[ExceptionEvent] = []
self.core_alarms: list[ExceptionEvent] = []
self.draw()
def draw(self) -> None:

View file

@ -2,7 +2,7 @@ import logging
import threading
import time
import tkinter as tk
from typing import TYPE_CHECKING, Any, Callable, Optional, Tuple
from typing import TYPE_CHECKING, Any, Callable, Optional
logger = logging.getLogger(__name__)
@ -17,7 +17,7 @@ class ProgressTask:
title: str,
task: Callable,
callback: Callable = None,
args: Tuple[Any] = None,
args: tuple[Any] = None,
):
self.app: "Application" = app
self.title: str = title
@ -25,7 +25,7 @@ class ProgressTask:
self.callback: Callable = callback
if args is None:
args = ()
self.args: Tuple[Any] = args
self.args: tuple[Any] = args
self.time: Optional[float] = None
def start(self) -> None:

View file

@ -1,10 +1,9 @@
import tkinter as tk
from tkinter import font, ttk
from typing import Dict, Tuple
THEME_DARK: str = "black"
PADX: Tuple[int, int] = (0, 5)
PADY: Tuple[int, int] = (0, 5)
PADX: tuple[int, int] = (0, 5)
PADY: tuple[int, int] = (0, 5)
FRAME_PAD: int = 5
DIALOG_PAD: int = 5
@ -201,7 +200,7 @@ def theme_change(event: tk.Event) -> None:
_alert_style(style, Styles.red_alert, "red")
def scale_fonts(fonts_size: Dict[str, int], scale: float) -> None:
def scale_fonts(fonts_size: dict[str, int], scale: float) -> None:
for name in font.names():
f = font.nametofont(name)
if name in fonts_size:

View file

@ -3,7 +3,7 @@ import tkinter as tk
from enum import Enum
from functools import partial
from tkinter import ttk
from typing import TYPE_CHECKING, Callable, List, Optional
from typing import TYPE_CHECKING, Callable, Optional
from PIL.ImageTk import PhotoImage
@ -90,7 +90,7 @@ class ButtonBar(ttk.Frame):
def __init__(self, master: tk.Widget, app: "Application") -> None:
super().__init__(master)
self.app: "Application" = app
self.radio_buttons: List[ttk.Button] = []
self.radio_buttons: list[ttk.Button] = []
def create_button(
self, image_enum: ImageEnum, func: Callable, tooltip: str, radio: bool = False
@ -303,7 +303,7 @@ class Toolbar(ttk.Frame):
)
task.start()
def start_callback(self, result: bool, exceptions: List[str]) -> None:
def start_callback(self, result: bool, exceptions: list[str]) -> None:
self.set_runtime()
self.app.core.show_mobility_players()
if not result and exceptions:

View file

@ -5,7 +5,7 @@ from typing import Optional
from core.gui.themes import Styles
class Tooltip(object):
class Tooltip:
"""
Create tool tip for a given widget
"""

View file

@ -3,8 +3,9 @@ input validation
"""
import re
import tkinter as tk
from re import Pattern
from tkinter import ttk
from typing import Any, Optional, Pattern
from typing import Any, Optional
SMALLEST_SCALE: float = 0.5
LARGEST_SCALE: float = 5.0

View file

@ -3,7 +3,7 @@ import tkinter as tk
from functools import partial
from pathlib import Path
from tkinter import filedialog, font, ttk
from typing import TYPE_CHECKING, Any, Callable, Dict, Set, Type
from typing import TYPE_CHECKING, Any, Callable
from core.api.grpc.wrappers import ConfigOption, ConfigOptionType
from core.gui import appconfig, themes, validation
@ -15,7 +15,7 @@ logger = logging.getLogger(__name__)
if TYPE_CHECKING:
from core.gui.app import Application
INT_TYPES: Set[ConfigOptionType] = {
INT_TYPES: set[ConfigOptionType] = {
ConfigOptionType.UINT8,
ConfigOptionType.UINT16,
ConfigOptionType.UINT32,
@ -40,7 +40,7 @@ class FrameScroll(ttk.Frame):
self,
master: tk.Widget,
app: "Application",
_cls: Type[ttk.Frame] = ttk.Frame,
_cls: type[ttk.Frame] = ttk.Frame,
**kw: Any
) -> None:
super().__init__(master, **kw)
@ -86,14 +86,14 @@ class ConfigFrame(ttk.Notebook):
self,
master: tk.Widget,
app: "Application",
config: Dict[str, ConfigOption],
config: dict[str, ConfigOption],
enabled: bool = True,
**kw: Any
) -> None:
super().__init__(master, **kw)
self.app: "Application" = app
self.config: Dict[str, ConfigOption] = config
self.values: Dict[str, tk.StringVar] = {}
self.config: dict[str, ConfigOption] = config
self.values: dict[str, tk.StringVar] = {}
self.enabled: bool = enabled
def draw_config(self) -> None:
@ -166,7 +166,7 @@ class ConfigFrame(ttk.Notebook):
logger.error("unhandled config option type: %s", option.type)
self.values[option.name] = value
def parse_config(self) -> Dict[str, str]:
def parse_config(self) -> dict[str, str]:
for key in self.config:
option = self.config[key]
value = self.values[key]
@ -180,7 +180,7 @@ class ConfigFrame(ttk.Notebook):
option.value = config_value
return {x: self.config[x].value for x in self.config}
def set_values(self, config: Dict[str, str]) -> None:
def set_values(self, config: dict[str, str]) -> None:
for name, data in config.items():
option = self.config[name]
value = self.values[name]