diff --git a/Build-exe-and-msi.py b/Build-exe-and-msi.py index adc04432..71e1eace 100644 --- a/Build-exe-and-msi.py +++ b/Build-exe-and-msi.py @@ -28,6 +28,9 @@ if sys.platform == 'win32': else: raise AssertionError(f'Unsupported platform {sys.platform}') + +# This added to make mypy happy +assert sys.platform == 'win32' ########################################################################### ########################################################################### diff --git a/EDMarketConnector.py b/EDMarketConnector.py index b6bbcf11..b9c7bdf2 100755 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -1617,10 +1617,11 @@ class AppWindow(object): monitor.system and tk.NORMAL or tk.DISABLED) - def ontop_changed(self, event=None) -> None: - """Set main window 'on top' state as appropriate.""" - config.set('always_ontop', self.always_ontop.get()) - self.w.wm_attributes('-topmost', self.always_ontop.get()) + if sys.platform == 'win32': + def ontop_changed(self, event=None) -> None: + """Set main window 'on top' state as appropriate.""" + config.set('always_ontop', self.always_ontop.get()) + self.w.wm_attributes('-topmost', self.always_ontop.get()) def copy(self, event=None) -> None: """Copy system, and possible station, name to clipboard.""" @@ -1760,13 +1761,14 @@ class AppWindow(object): with open(f, 'wb') as h: h.write(str(companion.session.capi_raw_data).encode(encoding='utf-8')) - def exit_tray(self, systray: 'SysTrayIcon') -> None: - """Tray icon is shutting down.""" - exit_thread = threading.Thread( - target=self.onexit, - daemon=True, - ) - exit_thread.start() + if sys.platform == 'win32': + def exit_tray(self, systray: 'SysTrayIcon') -> None: + """Tray icon is shutting down.""" + exit_thread = threading.Thread( + target=self.onexit, + daemon=True, + ) + exit_thread.start() def onexit(self, event=None) -> None: """Application shutdown procedure.""" diff --git a/config/linux.py b/config/linux.py index 04087b32..5d543d3f 100644 --- a/config/linux.py +++ b/config/linux.py @@ -3,7 +3,6 @@ import os import pathlib import sys from configparser import ConfigParser -from typing import List, Optional, Union from config import AbstractConfig, appname, logger @@ -18,7 +17,7 @@ class LinuxConfig(AbstractConfig): __unescape_lut = {'\\': '\\', 'n': '\n', ';': ';', 'r': '\r', '#': '#'} __escape_lut = {'\\': '\\', '\n': 'n', ';': ';', '\r': 'r'} - def __init__(self, filename: Optional[str] = None) -> None: + def __init__(self, filename: str | None = None) -> None: super().__init__() # http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html xdg_data_home = pathlib.Path(os.getenv('XDG_DATA_HOME', default='~/.local/share')).expanduser() @@ -42,7 +41,7 @@ class LinuxConfig(AbstractConfig): self.filename.parent.mkdir(exist_ok=True, parents=True) - self.config: Optional[ConfigParser] = ConfigParser(comment_prefixes=('#',), interpolation=None) + self.config: ConfigParser | None = ConfigParser(comment_prefixes=('#',), interpolation=None) self.config.read(self.filename) # read() ignores files that dont exist # Ensure that our section exists. This is here because configparser will happily create files for us, but it @@ -85,7 +84,7 @@ class LinuxConfig(AbstractConfig): :param s: str - The string to unescape. :return: str - The unescaped string. """ - out: List[str] = [] + out: list[str] = [] i = 0 while i < len(s): c = s[i] @@ -107,7 +106,7 @@ class LinuxConfig(AbstractConfig): return "".join(out) - def __raw_get(self, key: str) -> Optional[str]: + def __raw_get(self, key: str) -> str | None: """ Get a raw data value from the config file. @@ -119,7 +118,7 @@ class LinuxConfig(AbstractConfig): return self.config[self.SECTION].get(key) - def get_str(self, key: str, *, default: str = None) -> str: + def get_str(self, key: str, *, default: str | None = None) -> str: """ Return the string referred to by the given key if it exists, or the default. @@ -134,7 +133,7 @@ class LinuxConfig(AbstractConfig): return self.__unescape(data) - def get_list(self, key: str, *, default: list = None) -> list: + def get_list(self, key: str, *, default: list | None = None) -> list: """ Return the list referred to by the given key if it exists, or the default. @@ -168,7 +167,7 @@ class LinuxConfig(AbstractConfig): except ValueError as e: raise ValueError(f'requested {key=} as int cannot be converted to int') from e - def get_bool(self, key: str, *, default: bool = None) -> bool: + def get_bool(self, key: str, *, default: bool | None = None) -> bool: """ Return the bool referred to by the given key if it exists, or the default. @@ -183,7 +182,7 @@ class LinuxConfig(AbstractConfig): return bool(int(data)) - def set(self, key: str, val: Union[int, str, List[str]]) -> None: + def set(self, key: str, val: int | str | list[str]) -> None: """ Set the given key's data to the given value. @@ -192,7 +191,7 @@ class LinuxConfig(AbstractConfig): if self.config is None: raise ValueError('attempt to use a closed config') - to_set: Optional[str] = None + to_set: str | None = None if isinstance(val, bool): to_set = str(int(val)) diff --git a/hotkey/darwin.py b/hotkey/darwin.py index a053a55f..cbf9d260 100644 --- a/hotkey/darwin.py +++ b/hotkey/darwin.py @@ -3,6 +3,7 @@ import pathlib import sys import tkinter as tk from typing import Callable, Optional, Tuple, Union +assert sys.platform == 'darwin' import objc from AppKit import ( @@ -36,7 +37,7 @@ class MacHotkeyMgr(AbstractHotkeyMgr): def __init__(self): self.MODIFIERMASK = NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask \ - | NSNumericPadKeyMask + | NSNumericPadKeyMask self.root: tk.Tk self.keycode = 0 diff --git a/hotkey/linux.py b/hotkey/linux.py index 9a60515f..927c4d26 100644 --- a/hotkey/linux.py +++ b/hotkey/linux.py @@ -1,7 +1,11 @@ """Linux implementation of hotkey.AbstractHotkeyMgr.""" +import sys + from EDMCLogging import get_main_logger from hotkey import AbstractHotkeyMgr +assert sys.platform == 'linux' + logger = get_main_logger() @@ -20,6 +24,37 @@ class LinuxHotKeyMgr(AbstractHotkeyMgr): """Unregister the hotkey handling.""" pass + def acquire_start(self) -> None: + """Start acquiring hotkey state via polling.""" + pass + + def acquire_stop(self) -> None: + """Stop acquiring hotkey state.""" + pass + + def fromevent(self, event) -> bool | tuple | None: + """ + Return configuration (keycode, modifiers) or None=clear or False=retain previous. + + event.state is a pain - it shows the state of the modifiers *before* a modifier key was pressed. + event.state *does* differentiate between left and right Ctrl and Alt and between Return and Enter + by putting KF_EXTENDED in bit 18, but RegisterHotKey doesn't differentiate. + + :param event: tk event ? + :return: False to retain previous, None to not use, else (keycode, modifiers) + """ + pass + + def display(self, keycode: int, modifiers: int) -> str: + """ + Return displayable form of given hotkey + modifiers. + + :param keycode: + :param modifiers: + :return: string form + """ + return "Unsupported on linux" + def play_good(self) -> None: """Play the 'good' sound.""" pass diff --git a/hotkey/windows.py b/hotkey/windows.py index 0bc54d1a..8a1c7acd 100644 --- a/hotkey/windows.py +++ b/hotkey/windows.py @@ -2,6 +2,7 @@ import atexit import ctypes import pathlib +import sys import threading import tkinter as tk import winsound @@ -12,6 +13,8 @@ from config import config from EDMCLogging import get_main_logger from hotkey import AbstractHotkeyMgr +assert sys.platform == 'win32' + logger = get_main_logger() RegisterHotKey = ctypes.windll.user32.RegisterHotKey diff --git a/myNotebook.py b/myNotebook.py index 1989141f..30f95274 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -76,7 +76,8 @@ class Label(tk.Label): """Custom tk.Label class to fix some display issues.""" def __init__(self, master: Optional[ttk.Frame] = None, **kw): - if sys.platform in ['darwin', 'win32']: + # This format chosen over `sys.platform in (...)` as mypy and friends dont understand that + if sys.platform == 'darwin' or sys.platform == 'win32': kw['foreground'] = kw.pop('foreground', PAGEFG) kw['background'] = kw.pop('background', PAGEBG) else: diff --git a/protocol.py b/protocol.py index 290a7031..f0e1b4a8 100644 --- a/protocol.py +++ b/protocol.py @@ -121,9 +121,13 @@ elif (config.auth_force_edmc_protocol and not is_wine and not config.auth_force_localserver )): + # This could be false if you use auth_force_edmc_protocol, but then you get to keep the pieces + assert sys.platform == 'win32' # spell-checker: words HBRUSH HICON WPARAM wstring WNDCLASS HMENU HGLOBAL from ctypes import windll # type: ignore - from ctypes import POINTER, WINFUNCTYPE, Structure, byref, c_long, c_void_p, create_unicode_buffer, wstring_at + from ctypes import ( # type: ignore + POINTER, WINFUNCTYPE, Structure, byref, c_long, c_void_p, create_unicode_buffer, wstring_at + ) from ctypes.wintypes import ( ATOM, BOOL, DWORD, HBRUSH, HGLOBAL, HICON, HINSTANCE, HMENU, HWND, INT, LPARAM, LPCWSTR, LPVOID, LPWSTR, MSG, UINT, WPARAM diff --git a/tests/config/_old_config.py b/tests/config/_old_config.py index 0226bc36..211c1e72 100644 --- a/tests/config/_old_config.py +++ b/tests/config/_old_config.py @@ -1,3 +1,4 @@ +# type: ignore import numbers import sys import warnings