diff --git a/daemon/core/gui/app.py b/daemon/core/gui/app.py index 72e74e2b..f069e9e1 100644 --- a/daemon/core/gui/app.py +++ b/daemon/core/gui/app.py @@ -1,6 +1,5 @@ import tkinter as tk from tkinter import ttk -from typing import Optional from core.gui import appconfig, themes from core.gui.coreclient import CoreClient @@ -18,7 +17,7 @@ HEIGHT = 800 class Application(tk.Frame): - def __init__(self, master: Optional[tk.Widget] = None): + def __init__(self, master: tk.Widget = None): super().__init__(master) # load node icons NodeUtils.setup() diff --git a/daemon/core/gui/coreclient.py b/daemon/core/gui/coreclient.py index 1e7c3731..9669f58d 100644 --- a/daemon/core/gui/coreclient.py +++ b/daemon/core/gui/coreclient.py @@ -5,7 +5,7 @@ import json import logging import os from pathlib import Path -from typing import Dict, List, Optional +from typing import TYPE_CHECKING, Dict, List, Optional import grpc @@ -22,6 +22,9 @@ from core.gui.graph.shapeutils import ShapeType from core.gui.interface import InterfaceManager from core.gui.nodeutils import NodeDraw, NodeUtils +if TYPE_CHECKING: + from core.gui.app import Application + GUI_SOURCE = "gui" OBSERVERS = { "processes": "ps", @@ -50,7 +53,7 @@ class Observer: class CoreClient: - def __init__(self, app): + def __init__(self, app: "Application"): """ Create a CoreGrpc instance """ @@ -137,7 +140,7 @@ class CoreClient: def handle_events(self, event: core_pb2.Event): if event.session_id != self.session_id: - logging.warn( + logging.warning( "ignoring event session(%s) current(%s)", event.session_id, self.session_id, diff --git a/daemon/core/gui/dialogs/about.py b/daemon/core/gui/dialogs/about.py index 5e6b5d56..bf498bb8 100644 --- a/daemon/core/gui/dialogs/about.py +++ b/daemon/core/gui/dialogs/about.py @@ -35,7 +35,7 @@ THE POSSIBILITY OF SUCH DAMAGE.\ class AboutDialog(Dialog): - def __init__(self, master: tk.Widget, app: "Application"): + def __init__(self, master: "Application", app: "Application"): super().__init__(master, app, "About CORE", modal=True) self.draw() diff --git a/daemon/core/gui/dialogs/alerts.py b/daemon/core/gui/dialogs/alerts.py index 57596f4b..6c07f214 100644 --- a/daemon/core/gui/dialogs/alerts.py +++ b/daemon/core/gui/dialogs/alerts.py @@ -15,7 +15,7 @@ if TYPE_CHECKING: class AlertsDialog(Dialog): - def __init__(self, master: tk.Widget, app: "Application"): + def __init__(self, master: "Application", app: "Application"): super().__init__(master, app, "Alerts", modal=True) self.app = app self.tree = None @@ -124,7 +124,7 @@ class AlertsDialog(Dialog): class DaemonLog(Dialog): - def __init__(self, master, app): + def __init__(self, master: tk.Widget, app: "Application"): super().__init__(master, app, "core-daemon log", modal=True) self.columnconfigure(0, weight=1) self.path = tk.StringVar(value="/var/log/core-daemon.log") diff --git a/daemon/core/gui/dialogs/canvaswallpaper.py b/daemon/core/gui/dialogs/canvaswallpaper.py index 3f79d50b..093d93b0 100644 --- a/daemon/core/gui/dialogs/canvaswallpaper.py +++ b/daemon/core/gui/dialogs/canvaswallpaper.py @@ -17,11 +17,9 @@ if TYPE_CHECKING: class CanvasWallpaperDialog(Dialog): - def __init__(self, master: tk.Widget, app: "Application"): + def __init__(self, master: "Application", app: "Application"): """ create an instance of CanvasWallpaper object - - :param coretk.app.Application app: root application """ super().__init__(master, app, "Canvas Background", modal=True) self.canvas = self.app.canvas diff --git a/daemon/core/gui/dialogs/colorpicker.py b/daemon/core/gui/dialogs/colorpicker.py index 32e0f64b..1c1ffbe5 100644 --- a/daemon/core/gui/dialogs/colorpicker.py +++ b/daemon/core/gui/dialogs/colorpicker.py @@ -4,7 +4,7 @@ custom color picker import logging import tkinter as tk from tkinter import ttk -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Any, Optional from core.gui.dialogs.dialog import Dialog @@ -14,10 +14,7 @@ if TYPE_CHECKING: class ColorPickerDialog(Dialog): def __init__( - self, - master: tk.Widget, - app: "Application", - initcolor: Optional[str] = "#000000", + self, master: Any, app: "Application", initcolor: Optional[str] = "#000000" ): super().__init__(master, app, "color picker", modal=True) self.red_entry = None diff --git a/daemon/core/gui/dialogs/copyserviceconfig.py b/daemon/core/gui/dialogs/copyserviceconfig.py index 207514d5..c56c1575 100644 --- a/daemon/core/gui/dialogs/copyserviceconfig.py +++ b/daemon/core/gui/dialogs/copyserviceconfig.py @@ -5,7 +5,7 @@ copy service config dialog import logging import tkinter as tk from tkinter import ttk -from typing import TYPE_CHECKING, Tuple +from typing import TYPE_CHECKING, Any, Tuple from core.gui.dialogs.dialog import Dialog from core.gui.themes import FRAME_PAD, PADX @@ -13,11 +13,10 @@ from core.gui.widgets import CodeText if TYPE_CHECKING: from core.gui.app import Application - from core.gui.dialogs.serviceconfig import ServiceConfigDialog class CopyServiceConfigDialog(Dialog): - def __init__(self, master: "ServiceConfigDialog", app: "Application", node_id: int): + def __init__(self, master: Any, app: "Application", node_id: int): super().__init__(master, app, f"Copy services to node {node_id}", modal=True) self.parent = master self.app = app @@ -133,6 +132,7 @@ class CopyServiceConfigDialog(Dialog): def click_view(self): selected = self.tree.selection() + data = "" if selected: item = self.tree.item(selected[0]) if "file" in item["tags"]: @@ -161,7 +161,7 @@ class CopyServiceConfigDialog(Dialog): class ViewConfigDialog(Dialog): - def __init__(self, master, app, node_id, data): + def __init__(self, master: Any, app: "Application", node_id: int, data: bytes): super().__init__(master, app, f"n{node_id} config data", modal=True) self.data = data self.service_data = None diff --git a/daemon/core/gui/dialogs/customnodes.py b/daemon/core/gui/dialogs/customnodes.py index ba786491..fe694651 100644 --- a/daemon/core/gui/dialogs/customnodes.py +++ b/daemon/core/gui/dialogs/customnodes.py @@ -2,7 +2,7 @@ import logging import tkinter as tk from pathlib import Path from tkinter import ttk -from typing import TYPE_CHECKING, Set +from typing import TYPE_CHECKING, Any, Set from core.gui import nodeutils from core.gui.appconfig import ICONS_PATH @@ -17,7 +17,7 @@ if TYPE_CHECKING: class ServicesSelectDialog(Dialog): - def __init__(self, master, app: "Application", current_services: Set[str]): + def __init__(self, master: Any, app: "Application", current_services: Set[str]): super().__init__(master, app, "Node Services", modal=True) self.groups = None self.services = None @@ -100,7 +100,7 @@ class ServicesSelectDialog(Dialog): class CustomNodesDialog(Dialog): - def __init__(self, master, app: "Application"): + def __init__(self, master: "Application", app: "Application"): super().__init__(master, app, "Custom Nodes", modal=True) self.edit_button = None self.delete_button = None @@ -245,7 +245,7 @@ class CustomNodesDialog(Dialog): self.nodes_list.listbox.selection_clear(0, tk.END) self.nodes_list.listbox.event_generate("<>") - def handle_node_select(self, event): + def handle_node_select(self, event: tk.Event): selection = self.nodes_list.listbox.curselection() if selection: self.selected_index = selection[0] diff --git a/daemon/core/gui/dialogs/emaneconfig.py b/daemon/core/gui/dialogs/emaneconfig.py index b7c99f02..09ea3cc8 100644 --- a/daemon/core/gui/dialogs/emaneconfig.py +++ b/daemon/core/gui/dialogs/emaneconfig.py @@ -5,7 +5,7 @@ import logging import tkinter as tk import webbrowser from tkinter import ttk -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Any, Optional import grpc @@ -22,7 +22,7 @@ if TYPE_CHECKING: class GlobalEmaneDialog(Dialog): - def __init__(self, master, app: "Application"): + def __init__(self, master: Any, app: "Application"): super().__init__(master, app, "EMANE Configuration", modal=True) self.config_frame = None self.draw() @@ -55,7 +55,7 @@ class GlobalEmaneDialog(Dialog): class EmaneModelDialog(Dialog): def __init__( self, - master, + master: Any, app: "Application", node: core_pb2.Node, model: str, @@ -104,7 +104,9 @@ class EmaneModelDialog(Dialog): class EmaneConfigDialog(Dialog): - def __init__(self, master, app: "Application", canvas_node: "CanvasNode"): + def __init__( + self, master: "Application", app: "Application", canvas_node: "CanvasNode" + ): super().__init__( master, app, f"{canvas_node.core_node.name} EMANE Configuration", modal=True ) diff --git a/daemon/core/gui/dialogs/hooks.py b/daemon/core/gui/dialogs/hooks.py index ec74c525..18cdee42 100644 --- a/daemon/core/gui/dialogs/hooks.py +++ b/daemon/core/gui/dialogs/hooks.py @@ -1,6 +1,6 @@ import tkinter as tk from tkinter import ttk -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Union from core.api.grpc import core_pb2 from core.gui.dialogs.dialog import Dialog @@ -12,7 +12,7 @@ if TYPE_CHECKING: class HookDialog(Dialog): - def __init__(self, master, app: "Application"): + def __init__(self, master: Union[tk.Widget, Dialog], app: "Application"): super().__init__(master, app, "Hook", modal=True) self.name = tk.StringVar() self.codetext = None @@ -88,7 +88,7 @@ class HookDialog(Dialog): class HooksDialog(Dialog): - def __init__(self, master, app: "Application"): + def __init__(self, master: "Application", app: "Application"): super().__init__(master, app, "Hooks", modal=True) self.listbox = None self.edit_button = None diff --git a/daemon/core/gui/dialogs/linkconfig.py b/daemon/core/gui/dialogs/linkconfig.py index e7411182..5f16a586 100644 --- a/daemon/core/gui/dialogs/linkconfig.py +++ b/daemon/core/gui/dialogs/linkconfig.py @@ -13,7 +13,7 @@ from core.gui.themes import PADX, PADY if TYPE_CHECKING: from core.gui.app import Application - from core.gui.graph.edges import CanvasEdge + from core.gui.graph.graph import CanvasGraph, CanvasEdge def get_int(var: tk.StringVar) -> Union[int, None]: @@ -33,7 +33,7 @@ def get_float(var: tk.StringVar) -> Union[float, None]: class LinkConfigurationDialog(Dialog): - def __init__(self, master, app: "Application", edge: "CanvasEdge"): + def __init__(self, master: "CanvasGraph", app: "Application", edge: "CanvasEdge"): super().__init__(master, app, "Link Configuration", modal=True) self.app = app self.edge = edge diff --git a/daemon/core/gui/dialogs/marker.py b/daemon/core/gui/dialogs/marker.py index 2f2ed100..91de3c96 100644 --- a/daemon/core/gui/dialogs/marker.py +++ b/daemon/core/gui/dialogs/marker.py @@ -17,7 +17,10 @@ MARKER_THICKNESS = [3, 5, 8, 10] class MarkerDialog(Dialog): def __init__( - self, master, app: "Application", initcolor: Optional[str] = "#000000" + self, + master: "Application", + app: "Application", + initcolor: Optional[str] = "#000000", ): super().__init__(master, app, "marker tool", modal=False) self.app = app diff --git a/daemon/core/gui/dialogs/mobilityconfig.py b/daemon/core/gui/dialogs/mobilityconfig.py index 91601ae5..18e62a17 100644 --- a/daemon/core/gui/dialogs/mobilityconfig.py +++ b/daemon/core/gui/dialogs/mobilityconfig.py @@ -17,7 +17,9 @@ if TYPE_CHECKING: class MobilityConfigDialog(Dialog): - def __init__(self, master, app: "Application", canvas_node: "CanvasNode"): + def __init__( + self, master: "Application", app: "Application", canvas_node: "CanvasNode" + ): super().__init__( master, app, diff --git a/daemon/core/gui/dialogs/mobilityplayer.py b/daemon/core/gui/dialogs/mobilityplayer.py index cf9a46a8..9b2f1f6b 100644 --- a/daemon/core/gui/dialogs/mobilityplayer.py +++ b/daemon/core/gui/dialogs/mobilityplayer.py @@ -18,7 +18,13 @@ ICON_SIZE = 16 class MobilityPlayer: - def __init__(self, master, app: "Application", canvas_node: "CanvasNode", config): + def __init__( + self, + master: "Application", + app: "Application", + canvas_node: "CanvasNode", + config, + ): self.master = master self.app = app self.canvas_node = canvas_node @@ -62,7 +68,9 @@ class MobilityPlayer: class MobilityPlayerDialog(Dialog): - def __init__(self, master, app, canvas_node, config): + def __init__( + self, master: Dialog, app: "Application", canvas_node: "CanvasNode", config + ): super().__init__( master, app, f"{canvas_node.core_node.name} Mobility Player", modal=False ) diff --git a/daemon/core/gui/dialogs/nodeconfig.py b/daemon/core/gui/dialogs/nodeconfig.py index 4f17b499..cce34520 100644 --- a/daemon/core/gui/dialogs/nodeconfig.py +++ b/daemon/core/gui/dialogs/nodeconfig.py @@ -18,7 +18,7 @@ if TYPE_CHECKING: from core.gui.graph.node import CanvasNode -def mac_auto(is_auto, entry: ttk.Entry): +def mac_auto(is_auto, entry): logging.info("mac auto clicked") if is_auto.get(): logging.info("disabling mac") @@ -38,13 +38,11 @@ class InterfaceData: class NodeConfigDialog(Dialog): - def __init__(self, master, app: "Application", canvas_node: "CanvasNode"): + def __init__( + self, master: "Application", app: "Application", canvas_node: "CanvasNode" + ): """ create an instance of node configuration - - :param master: dialog master - :param coretk.app.Application: main app - :param coretk.graph.CanvasNode canvas_node: canvas node object """ super().__init__( master, app, f"{canvas_node.core_node.name} Configuration", modal=True diff --git a/daemon/core/gui/dialogs/nodeservice.py b/daemon/core/gui/dialogs/nodeservice.py index 768182af..1d0903b1 100644 --- a/daemon/core/gui/dialogs/nodeservice.py +++ b/daemon/core/gui/dialogs/nodeservice.py @@ -3,7 +3,7 @@ core node services """ import tkinter as tk from tkinter import messagebox, ttk -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from core.gui.dialogs.dialog import Dialog from core.gui.dialogs.serviceconfig import ServiceConfigDialog @@ -17,7 +17,7 @@ if TYPE_CHECKING: class NodeServiceDialog(Dialog): def __init__( - self, master, app: "Application", canvas_node: "CanvasNode", services=None + self, master: Any, app: "Application", canvas_node: "CanvasNode", services=None ): title = f"{canvas_node.core_node.name} Services" super().__init__(master, app, title, modal=True) diff --git a/daemon/core/gui/dialogs/observers.py b/daemon/core/gui/dialogs/observers.py index bc244f5c..9fe3f79e 100644 --- a/daemon/core/gui/dialogs/observers.py +++ b/daemon/core/gui/dialogs/observers.py @@ -12,7 +12,7 @@ if TYPE_CHECKING: class ObserverDialog(Dialog): - def __init__(self, master, app: "Application"): + def __init__(self, master: "Application", app: "Application"): super().__init__(master, app, "Observer Widgets", modal=True) self.observers = None self.save_button = None diff --git a/daemon/core/gui/dialogs/preferences.py b/daemon/core/gui/dialogs/preferences.py index 102d49fe..f60da652 100644 --- a/daemon/core/gui/dialogs/preferences.py +++ b/daemon/core/gui/dialogs/preferences.py @@ -12,7 +12,7 @@ if TYPE_CHECKING: class PreferencesDialog(Dialog): - def __init__(self, master, app: "Application"): + def __init__(self, master: "Application", app: "Application"): super().__init__(master, app, "Preferences", modal=True) preferences = self.app.guiconfig["preferences"] self.editor = tk.StringVar(value=preferences["editor"]) diff --git a/daemon/core/gui/dialogs/servers.py b/daemon/core/gui/dialogs/servers.py index 8d46e6de..c57e97d3 100644 --- a/daemon/core/gui/dialogs/servers.py +++ b/daemon/core/gui/dialogs/servers.py @@ -16,7 +16,7 @@ DEFAULT_PORT = 50051 class ServersDialog(Dialog): - def __init__(self, master, app: "Application"): + def __init__(self, master: "Application", app: "Application"): super().__init__(master, app, "CORE Servers", modal=True) self.name = tk.StringVar(value=DEFAULT_NAME) self.address = tk.StringVar(value=DEFAULT_ADDRESS) diff --git a/daemon/core/gui/dialogs/serviceconfig.py b/daemon/core/gui/dialogs/serviceconfig.py index 7171e1a0..804e7e3f 100644 --- a/daemon/core/gui/dialogs/serviceconfig.py +++ b/daemon/core/gui/dialogs/serviceconfig.py @@ -1,7 +1,9 @@ -"Service configuration dialog" +""" +Service configuration dialog +""" import tkinter as tk from tkinter import ttk -from typing import TYPE_CHECKING, List +from typing import TYPE_CHECKING, Any, List import grpc @@ -18,7 +20,9 @@ if TYPE_CHECKING: class ServiceConfigDialog(Dialog): - def __init__(self, master, app: "Application", service_name: str, node_id: int): + def __init__( + self, master: Any, app: "Application", service_name: str, node_id: int + ): title = f"{service_name} Service" super().__init__(master, app, title, modal=True) self.master = master @@ -229,7 +233,7 @@ class ServiceConfigDialog(Dialog): for i in range(3): tab.rowconfigure(i, weight=1) self.notebook.add(tab, text="Startup/Shutdown") - + commands = [] # tab 3 for i in range(3): label_frame = None diff --git a/daemon/core/gui/dialogs/sessionoptions.py b/daemon/core/gui/dialogs/sessionoptions.py index f201674d..ffd61340 100644 --- a/daemon/core/gui/dialogs/sessionoptions.py +++ b/daemon/core/gui/dialogs/sessionoptions.py @@ -14,7 +14,7 @@ if TYPE_CHECKING: class SessionOptionsDialog(Dialog): - def __init__(self, master, app: "Application"): + def __init__(self, master: "Application", app: "Application"): super().__init__(master, app, "Session Options", modal=True) self.config_frame = None self.config = self.get_config() diff --git a/daemon/core/gui/dialogs/sessions.py b/daemon/core/gui/dialogs/sessions.py index d466356e..b40c636d 100644 --- a/daemon/core/gui/dialogs/sessions.py +++ b/daemon/core/gui/dialogs/sessions.py @@ -17,7 +17,7 @@ if TYPE_CHECKING: class SessionsDialog(Dialog): - def __init__(self, master, app: "Application"): + def __init__(self, master: "Application", app: "Application"): super().__init__(master, app, "Sessions", modal=True) self.selected = False self.selected_id = None diff --git a/daemon/core/gui/dialogs/shapemod.py b/daemon/core/gui/dialogs/shapemod.py index ccb9c70b..a1c8c987 100644 --- a/daemon/core/gui/dialogs/shapemod.py +++ b/daemon/core/gui/dialogs/shapemod.py @@ -20,7 +20,7 @@ BORDER_WIDTH = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] class ShapeDialog(Dialog): - def __init__(self, master, app: "Application", shape: "Shape"): + def __init__(self, master: "Application", app: "Application", shape: "Shape"): if is_draw_shape(shape.shape_type): title = "Add Shape" else: diff --git a/daemon/core/gui/dialogs/throughput.py b/daemon/core/gui/dialogs/throughput.py index bb10531e..96aa3bc5 100644 --- a/daemon/core/gui/dialogs/throughput.py +++ b/daemon/core/gui/dialogs/throughput.py @@ -14,7 +14,7 @@ if TYPE_CHECKING: class ThroughputDialog(Dialog): - def __init__(self, master, app: "Application"): + def __init__(self, master: "Application", app: "Application"): super().__init__(master, app, "Throughput Config", modal=False) self.app = app self.canvas = app.canvas diff --git a/daemon/core/gui/dialogs/wlanconfig.py b/daemon/core/gui/dialogs/wlanconfig.py index 525dbc40..264b9e2e 100644 --- a/daemon/core/gui/dialogs/wlanconfig.py +++ b/daemon/core/gui/dialogs/wlanconfig.py @@ -18,7 +18,9 @@ if TYPE_CHECKING: class WlanConfigDialog(Dialog): - def __init__(self, master, app: "Application", canvas_node: "CanvasNode"): + def __init__( + self, master: "Application", app: "Application", canvas_node: "CanvasNode" + ): super().__init__( master, app, f"{canvas_node.core_node.name} Wlan Configuration", modal=True ) diff --git a/daemon/core/gui/errors.py b/daemon/core/gui/errors.py index 51a5ecc8..18e025db 100644 --- a/daemon/core/gui/errors.py +++ b/daemon/core/gui/errors.py @@ -1,9 +1,11 @@ from tkinter import messagebox +from typing import TYPE_CHECKING -import grpc +if TYPE_CHECKING: + import grpc -def show_grpc_error(e: grpc.RpcError): +def show_grpc_error(e: "grpc.RpcError"): title = [x.capitalize() for x in e.code().name.lower().split("_")] title = " ".join(title) title = f"GRPC {title}" diff --git a/daemon/core/gui/graph/edges.py b/daemon/core/gui/graph/edges.py index 197929de..2ca30031 100644 --- a/daemon/core/gui/graph/edges.py +++ b/daemon/core/gui/graph/edges.py @@ -1,13 +1,16 @@ import logging import tkinter as tk from tkinter.font import Font -from typing import Tuple +from typing import TYPE_CHECKING, Any, Tuple from core.gui import themes from core.gui.dialogs.linkconfig import LinkConfigurationDialog from core.gui.graph import tags from core.gui.nodeutils import NodeUtils +if TYPE_CHECKING: + from core.gui.graph.graph import CanvasGraph + TEXT_DISTANCE = 0.30 EDGE_WIDTH = 3 EDGE_COLOR = "#ff0000" @@ -16,11 +19,11 @@ EDGE_COLOR = "#ff0000" class CanvasWirelessEdge: def __init__( self, - token: Tuple[int, int], - position: Tuple[int, int, int, int], + token: Tuple[Any, ...], + position: Tuple[float, float, float, float], src: int, dst: int, - canvas, + canvas: "CanvasGraph", ): self.token = token self.src = src @@ -39,10 +42,17 @@ class CanvasEdge: Canvas edge class """ - def __init__(self, x1: int, y1: int, x2: int, y2: int, src: int, canvas): + def __init__( + self, + x1: float, + y1: float, + x2: float, + y2: float, + src: int, + canvas: "CanvasGraph", + ): """ Create an instance of canvas edge object - :param coretk.graph.graph.GraphCanvas canvas: canvas object """ self.src = src self.dst = None @@ -69,7 +79,7 @@ class CanvasEdge: self.link = link self.draw_labels() - def get_coordinates(self) -> [int, int, int, int]: + def get_coordinates(self) -> [float, float, float, float]: x1, y1, x2, y2 = self.canvas.coords(self.id) v1 = x2 - x1 v2 = y2 - y1 diff --git a/daemon/core/gui/graph/graph.py b/daemon/core/gui/graph/graph.py index d8b752b4..7ab1efab 100644 --- a/daemon/core/gui/graph/graph.py +++ b/daemon/core/gui/graph/graph.py @@ -1,6 +1,6 @@ import logging import tkinter as tk -from typing import List, Optional +from typing import TYPE_CHECKING, List, Optional, Tuple from PIL import Image, ImageTk @@ -16,12 +16,15 @@ from core.gui.graph.shapeutils import ShapeType, is_draw_shape, is_marker from core.gui.images import Images from core.gui.nodeutils import NodeUtils +if TYPE_CHECKING: + from core.gui.coreclient import CoreClient + ZOOM_IN = 1.1 ZOOM_OUT = 0.9 class CanvasGraph(tk.Canvas): - def __init__(self, master, core, width, height): + def __init__(self, master, core: "CoreClient", width: int, height: int): super().__init__(master, highlightthickness=0, background="#cccccc") self.app = master self.core = core @@ -68,7 +71,7 @@ class CanvasGraph(tk.Canvas): self.draw_canvas() self.draw_grid() - def draw_canvas(self, dimensions=None): + def draw_canvas(self, dimensions: Optional[Tuple[int, int]] = None): if self.grid is not None: self.delete(self.grid) if not dimensions: @@ -185,9 +188,6 @@ class CanvasGraph(tk.Canvas): def add_wireless_edge(self, src: CanvasNode, dst: CanvasNode): """ add a wireless edge between 2 canvas nodes - - :param CanvasNode src: source node - :param CanvasNode dst: destination node """ token = tuple(sorted((src.id, dst.id))) x1, y1 = self.coords(src.id) @@ -319,9 +319,6 @@ class CanvasGraph(tk.Canvas): def click_release(self, event: tk.Event): """ Draw a node or finish drawing an edge according to the current graph mode - - :param event: mouse event - :return: nothing """ logging.debug("click release") x, y = self.canvas_xy(event) @@ -760,7 +757,7 @@ class CanvasGraph(tk.Canvas): self.redraw_canvas((image.width(), image.height())) self.draw_wallpaper(image) - def redraw_canvas(self, dimensions: Optional[List[int]] = None): + def redraw_canvas(self, dimensions: Tuple[int, int] = None): logging.info("redrawing canvas to dimensions: %s", dimensions) # reset scale and move back to original position diff --git a/daemon/core/gui/graph/node.py b/daemon/core/gui/graph/node.py index 3602920a..c1d8e075 100644 --- a/daemon/core/gui/graph/node.py +++ b/daemon/core/gui/graph/node.py @@ -253,7 +253,7 @@ class CanvasNode: dialog = NodeServiceDialog(self.app.master, self.app, self) dialog.show() - def has_emane_link(self, interface_id: int) -> bool: + def has_emane_link(self, interface_id: int) -> core_pb2.Node: result = None for edge in self.edges: if self.id == edge.src: diff --git a/daemon/core/gui/graph/shape.py b/daemon/core/gui/graph/shape.py index 7e275ea3..011f7560 100644 --- a/daemon/core/gui/graph/shape.py +++ b/daemon/core/gui/graph/shape.py @@ -1,24 +1,28 @@ import logging -from typing import List, Optional, Union +from typing import TYPE_CHECKING, Dict, List, Union from core.gui.dialogs.shapemod import ShapeDialog from core.gui.graph import tags from core.gui.graph.shapeutils import ShapeType +if TYPE_CHECKING: + from core.gui.app import Application + from core.gui.graph.graph import CanvasGraph + class AnnotationData: def __init__( self, - text: Optional[str] = "", - font: Optional[str] = "Arial", - font_size: Optional[int] = 12, - text_color: Optional[str] = "#000000", - fill_color: Optional[str] = "", - border_color: Optional[str] = "#000000", - border_width: Optional[int] = 1, - bold: Optional[bool] = False, - italic: Optional[bool] = False, - underline: Optional[bool] = False, + text: str = "", + font: str = "Arial", + font_size: int = 12, + text_color: str = "#000000", + fill_color: str = "", + border_color: str = "#000000", + border_width: int = 1, + bold: bool = False, + italic: bool = False, + underline: bool = False, ): self.text = text self.font = font @@ -33,7 +37,17 @@ class AnnotationData: class Shape: - def __init__(self, app, canvas, shape_type, x1, y1, x2=None, y2=None, data=None): + def __init__( + self, + app: "Application", + canvas: "CanvasGraph", + shape_type: ShapeType, + x1: float, + y1: float, + x2: float = None, + y2: float = None, + data: AnnotationData = None, + ): self.app = app self.canvas = canvas self.shape_type = shape_type @@ -152,7 +166,7 @@ class Shape: self.canvas.delete(self.id) self.canvas.delete(self.text_id) - def metadata(self): + def metadata(self) -> Dict[str, Union[str, int, bool]]: coords = self.canvas.coords(self.id) # update coords to actual positions if len(coords) == 4: diff --git a/daemon/core/gui/graph/tooltip.py b/daemon/core/gui/graph/tooltip.py index 1e9ee317..a2193901 100644 --- a/daemon/core/gui/graph/tooltip.py +++ b/daemon/core/gui/graph/tooltip.py @@ -1,9 +1,12 @@ import tkinter as tk from tkinter import ttk -from typing import Optional +from typing import TYPE_CHECKING from core.gui.themes import Styles +if TYPE_CHECKING: + from core.gui.graph.graph import CanvasGraph + class CanvasTooltip: """ @@ -20,7 +23,14 @@ class CanvasTooltip: Alberto Vassena on 2016.12.10. """ - def __init__(self, canvas, *, pad=(5, 3, 5, 3), waittime=400, wraplength=600): + def __init__( + self, + canvas: "CanvasGraph", + *, + pad=(5, 3, 5, 3), + waittime: int = 400, + wraplength: int = 600 + ): # in miliseconds, originally 500 self.waittime = waittime # in pixels, originally 180 @@ -31,10 +41,10 @@ class CanvasTooltip: self.id = None self.tw = None - def on_enter(self, event: Optional[tk.Event] = None): + def on_enter(self, event: tk.Event = None): self.schedule() - def on_leave(self, event: Optional[tk.Event] = None): + def on_leave(self, event: tk.Event = None): self.unschedule() self.hide() @@ -48,7 +58,7 @@ class CanvasTooltip: if id_: self.canvas.after_cancel(id_) - def show(self, event: Optional[tk.Event] = None): + def show(self, event: tk.Event = None): def tip_pos_calculator(canvas, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)): c = canvas s_width, s_height = c.winfo_screenwidth(), c.winfo_screenheight() diff --git a/daemon/core/gui/interface.py b/daemon/core/gui/interface.py index a9b43220..fcd08712 100644 --- a/daemon/core/gui/interface.py +++ b/daemon/core/gui/interface.py @@ -1,21 +1,23 @@ import logging import random -from typing import Optional, Set +from typing import TYPE_CHECKING, Set, Union from netaddr import IPNetwork -from core.gui.graph.node import CanvasNode from core.gui.nodeutils import NodeUtils +if TYPE_CHECKING: + from core.gui.app import Application + from core.api.grpc import core_pb2 + from core.gui.graph.node import CanvasNode + def random_mac(): return ("{:02x}" * 6).format(*[random.randrange(256) for _ in range(6)]) class InterfaceManager: - def __init__( - self, app, address: Optional[str] = "10.0.0.0", mask: Optional[int] = 24 - ): + def __init__(self, app: "Application", address: str = "10.0.0.0", mask: int = 24): self.app = app self.mask = mask self.base_prefix = max(self.mask - 8, 0) @@ -49,11 +51,11 @@ class InterfaceManager: return str(ip4), str(ip6), prefix @classmethod - def get_subnet(cls, interface): + def get_subnet(cls, interface: "core_pb2.Interface") -> IPNetwork: return IPNetwork(f"{interface.ip4}/{interface.ip4mask}").cidr def determine_subnet( - self, canvas_src_node: CanvasNode, canvas_dst_node: CanvasNode + self, canvas_src_node: "CanvasNode", canvas_dst_node: "CanvasNode" ): src_node = canvas_src_node.core_node dst_node = canvas_dst_node.core_node @@ -76,7 +78,9 @@ class InterfaceManager: else: logging.info("ignoring subnet change for link between network nodes") - def find_subnet(self, canvas_node: CanvasNode, visited: Optional[Set[int]] = None): + def find_subnet( + self, canvas_node: "CanvasNode", visited: Set[int] = None + ) -> Union[IPNetwork, None]: logging.info("finding subnet for node: %s", canvas_node.core_node.name) canvas = self.app.canvas cidr = None diff --git a/daemon/core/gui/menuaction.py b/daemon/core/gui/menuaction.py index ac6cfb32..c03a75fd 100644 --- a/daemon/core/gui/menuaction.py +++ b/daemon/core/gui/menuaction.py @@ -6,7 +6,7 @@ import logging import tkinter as tk import webbrowser from tkinter import filedialog, messagebox -from typing import Optional +from typing import TYPE_CHECKING, Optional from core.gui.appconfig import XMLS_PATH from core.gui.dialogs.about import AboutDialog @@ -21,13 +21,16 @@ from core.gui.dialogs.sessions import SessionsDialog from core.gui.dialogs.throughput import ThroughputDialog from core.gui.task import BackgroundTask +if TYPE_CHECKING: + from core.gui.app import Application + class MenuAction: """ Actions performed when choosing menu items """ - def __init__(self, app, master): + def __init__(self, app: "Application", master: tk.Tk): self.master = master self.app = app self.canvas = app.canvas @@ -39,11 +42,9 @@ class MenuAction: # if quitapp: # self.app.quit() - def prompt_save_running_session(self, quitapp: Optional[bool] = False): + def prompt_save_running_session(self, quitapp: bool = False): """ Prompt use to stop running session before application is closed - - :return: nothing """ result = True if self.app.core.is_runtime(): @@ -58,15 +59,13 @@ class MenuAction: elif quitapp: self.app.quit() - def on_quit(self, event: Optional[tk.Event] = None): + def on_quit(self, event: tk.Event = None): """ Prompt user whether so save running session, and then close the application - - :return: nothing """ self.prompt_save_running_session(quitapp=True) - def file_save_as_xml(self, event: Optional[tk.Event] = None): + def file_save_as_xml(self, event: tk.Event = None): logging.info("menuaction.py file_save_as_xml()") file_path = filedialog.asksaveasfilename( initialdir=str(XMLS_PATH), diff --git a/daemon/core/gui/menubar.py b/daemon/core/gui/menubar.py index abacddbd..c8908333 100644 --- a/daemon/core/gui/menubar.py +++ b/daemon/core/gui/menubar.py @@ -1,16 +1,20 @@ import tkinter as tk from functools import partial +from typing import TYPE_CHECKING import core.gui.menuaction as action from core.gui.coreclient import OBSERVERS +if TYPE_CHECKING: + from core.gui.app import Application + class Menubar(tk.Menu): """ Core menubar """ - def __init__(self, master, app, cnf={}, **kwargs): + def __init__(self, master: tk.Tk, app: "Application", cnf={}, **kwargs): """ Create a CoreMenubar instance """ diff --git a/daemon/core/gui/statusbar.py b/daemon/core/gui/statusbar.py index 36fde4dc..e9d77494 100644 --- a/daemon/core/gui/statusbar.py +++ b/daemon/core/gui/statusbar.py @@ -3,13 +3,17 @@ status bar """ import tkinter as tk from tkinter import ttk +from typing import TYPE_CHECKING from core.gui.dialogs.alerts import AlertsDialog from core.gui.themes import Styles +if TYPE_CHECKING: + from core.gui.app import Application + class StatusBar(ttk.Frame): - def __init__(self, master: tk.Widget, app, **kwargs): + def __init__(self, master: tk.Widget, app: "Application", **kwargs): super().__init__(master, **kwargs) self.app = app self.status = None diff --git a/daemon/core/gui/themes.py b/daemon/core/gui/themes.py index b8266a0e..26778af8 100644 --- a/daemon/core/gui/themes.py +++ b/daemon/core/gui/themes.py @@ -159,7 +159,7 @@ def style_menu(widget: tk.Widget): ) -def style_listbox(widget: ttk.Widget): +def style_listbox(widget: tk.Widget): style = ttk.Style() bg = style.lookup(".", "background") fg = style.lookup(".", "foreground") diff --git a/daemon/core/gui/toolbar.py b/daemon/core/gui/toolbar.py index 827c2393..021c2bc1 100644 --- a/daemon/core/gui/toolbar.py +++ b/daemon/core/gui/toolbar.py @@ -4,9 +4,7 @@ import tkinter as tk from functools import partial from tkinter import messagebox, ttk from tkinter.font import Font -from typing import Callable - -from PIL import ImageTk +from typing import TYPE_CHECKING, Callable from core.api.grpc import core_pb2 from core.gui.dialogs.customnodes import CustomNodesDialog @@ -14,11 +12,15 @@ from core.gui.dialogs.marker import MarkerDialog from core.gui.graph.enums import GraphMode from core.gui.graph.shapeutils import ShapeType, is_marker from core.gui.images import ImageEnum, Images -from core.gui.nodeutils import NodeUtils +from core.gui.nodeutils import NodeDraw, NodeUtils from core.gui.task import BackgroundTask from core.gui.themes import Styles from core.gui.tooltip import Tooltip +if TYPE_CHECKING: + from core.gui.app import Application + from PIL import ImageTk + TOOLBAR_SIZE = 32 PICKER_SIZE = 24 @@ -32,11 +34,9 @@ class Toolbar(ttk.Frame): Core toolbar class """ - def __init__(self, master, app, **kwargs): + def __init__(self, master: "Application", app: "Application", **kwargs): """ Create a CoreToolbar instance - - :param tkinter.Frame edit_frame: edit frame """ super().__init__(master, **kwargs) self.app = app @@ -200,7 +200,7 @@ class Toolbar(ttk.Frame): self.app.unbind_all("") def create_picker_button( - self, image: ImageTk.PhotoImage, func: Callable, frame: ttk.Frame, label: str + self, image: "ImageTk.PhotoImage", func: Callable, frame: ttk.Frame, label: str ): """ Create button and put it on the frame @@ -218,7 +218,11 @@ class Toolbar(ttk.Frame): button.grid(pady=1) def create_button( - self, frame: ttk.Frame, image: ImageTk.PhotoImage, func: Callable, tooltip: str + self, + frame: ttk.Frame, + image: "ImageTk.PhotoImage", + func: Callable, + tooltip: str, ): button = ttk.Button(frame, image=image, command=func) button.image = image @@ -280,7 +284,7 @@ class Toolbar(ttk.Frame): dialog = CustomNodesDialog(self.app, self.app) dialog.show() - def update_button(self, button: ttk.Button, image, node_draw): + def update_button(self, button: ttk.Button, image: "ImageTk", node_draw: NodeDraw): logging.info("update button(%s): %s", button, node_draw) self.hide_pickers() button.configure(image=image) @@ -429,7 +433,7 @@ class Toolbar(ttk.Frame): if not response.result: messagebox.showerror("Stop Error", "Errors stopping session") - def update_annotation(self, image: ImageTk.PhotoImage, shape_type: str): + def update_annotation(self, image: "ImageTk.PhotoImage", shape_type: ShapeType): logging.info("clicked annotation: ") self.hide_pickers() self.annotation_button.configure(image=image) @@ -439,7 +443,7 @@ class Toolbar(ttk.Frame): if is_marker(shape_type): if self.marker_tool: self.marker_tool.destroy() - self.marker_tool = MarkerDialog(self.master, self.app) + self.marker_tool = MarkerDialog(self.app, self.app) self.marker_tool.show() def click_run_button(self): @@ -455,7 +459,7 @@ class Toolbar(ttk.Frame): self.app.canvas.annotation_type = ShapeType.MARKER if self.marker_tool: self.marker_tool.destroy() - self.marker_tool = MarkerDialog(self.master, self.app) + self.marker_tool = MarkerDialog(self.app, self.app) self.marker_tool.show() def click_two_node_button(self): diff --git a/daemon/core/gui/tooltip.py b/daemon/core/gui/tooltip.py index e0aecbb8..bc1ed9b5 100644 --- a/daemon/core/gui/tooltip.py +++ b/daemon/core/gui/tooltip.py @@ -1,6 +1,5 @@ import tkinter as tk from tkinter import ttk -from typing import Optional from core.gui.themes import Styles @@ -19,10 +18,10 @@ class Tooltip(object): self.id = None self.tw = None - def on_enter(self, event: Optional[tk.Event] = None): + def on_enter(self, event: tk.Event = None): self.schedule() - def on_leave(self, event: Optional[tk.Event] = None): + def on_leave(self, event: tk.Event = None): self.unschedule() self.close(event) @@ -36,7 +35,7 @@ class Tooltip(object): if id_: self.widget.after_cancel(id_) - def enter(self, event: Optional[tk.Event] = None): + def enter(self, event: tk.Event = None): x, y, cx, cy = self.widget.bbox("insert") x += self.widget.winfo_rootx() y += self.widget.winfo_rooty() + 32 @@ -51,6 +50,6 @@ class Tooltip(object): label = ttk.Label(frame, text=self.text, style=Styles.tooltip) label.grid() - def close(self, event: Optional[tk.Event] = None): + def close(self, event: tk.Event = None): if self.tw: self.tw.destroy() diff --git a/daemon/core/gui/validation.py b/daemon/core/gui/validation.py index aef8b09e..acb3d553 100644 --- a/daemon/core/gui/validation.py +++ b/daemon/core/gui/validation.py @@ -3,13 +3,17 @@ input validation """ import re import tkinter as tk +from typing import TYPE_CHECKING import netaddr from netaddr import IPNetwork +if TYPE_CHECKING: + from core.gui.app import Application + class InputValidation: - def __init__(self, app): + def __init__(self, app: "Application"): self.master = app.master self.positive_int = None self.positive_float = None diff --git a/daemon/core/gui/widgets.py b/daemon/core/gui/widgets.py index 513ef0dc..81c97568 100644 --- a/daemon/core/gui/widgets.py +++ b/daemon/core/gui/widgets.py @@ -3,11 +3,16 @@ import tkinter as tk from functools import partial from pathlib import PosixPath from tkinter import filedialog, font, ttk +from typing import TYPE_CHECKING, Dict, Optional from core.api.grpc import core_pb2 from core.gui import themes from core.gui.themes import FRAME_PAD, PADX, PADY +if TYPE_CHECKING: + from core.gui.app import Application + from core.gui.dialogs.dialog import Dialog + INT_TYPES = { core_pb2.ConfigOptionType.UINT8, core_pb2.ConfigOptionType.UINT16, @@ -27,7 +32,7 @@ def file_button_click(value: tk.StringVar, parent: tk.Widget): class FrameScroll(ttk.Frame): - def __init__(self, master, app, _cls=ttk.Frame, **kw): + def __init__(self, master: ttk.Widget, app: "Application", _cls=ttk.Frame, **kw): super().__init__(master, **kw) self.app = app self.rowconfigure(0, weight=1) @@ -65,7 +70,13 @@ class FrameScroll(ttk.Frame): class ConfigFrame(ttk.Notebook): - def __init__(self, master, app, config, **kw): + def __init__( + self, + master: ttk.Widget, + app: "Application", + config: Dict[str, core_pb2.ConfigOption], + **kw + ): super().__init__(master, **kw) self.app = app self.config = config @@ -175,7 +186,7 @@ class ConfigFrame(ttk.Notebook): class ListboxScroll(ttk.Frame): - def __init__(self, master=None, **kw): + def __init__(self, master: Optional[ttk.Widget] = None, **kw): super().__init__(master, **kw) self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) @@ -190,7 +201,7 @@ class ListboxScroll(ttk.Frame): class CheckboxList(FrameScroll): - def __init__(self, master, app, clicked=None, **kw): + def __init__(self, master: ttk.Widget, app: "Application", clicked=None, **kw): super().__init__(master, app, **kw) self.clicked = clicked self.frame.columnconfigure(0, weight=1) @@ -208,7 +219,7 @@ class CodeFont(font.Font): class CodeText(ttk.Frame): - def __init__(self, master, **kwargs): + def __init__(self, master: ttk.Widget, **kwargs): super().__init__(master, **kwargs) self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) @@ -232,14 +243,14 @@ class CodeText(ttk.Frame): class Spinbox(ttk.Entry): - def __init__(self, master=None, **kwargs): + def __init__(self, master: Optional[ttk.Widget] = None, **kwargs): super().__init__(master, "ttk::spinbox", **kwargs) def set(self, value): self.tk.call(self._w, "set", value) -def image_chooser(parent: tk.Widget, path: PosixPath): +def image_chooser(parent: "Dialog", path: PosixPath): return filedialog.askopenfilename( parent=parent, initialdir=str(path),