File kvmd-python3.9-compat.patch of Package kvmd

From 2f4f23e13e9e77b34b6e9eb1ef7afbb35352fdee Mon Sep 17 00:00:00 2001
From: Oleg Girko <ol@infoserver.lv>
Date: Wed, 12 Mar 2025 14:10:58 +0000
Subject: [PATCH] Fix Python 3.9 compatibility.

The following changes are mafe to preserve Python 3.9 compatibility.
* Do not use match statement.
* Import annotations from __future__ to allow type unions with "|" syntax.
* Pass loop argument to asyncio.Queue() constructor in kvmd/aiogp.py
  file, but only if Python version < 3.10 (partially reverts 1d4b39ef1).

This is needed for RHEL 9 that has Python 3.9 by default as well as many
packages built for Python 3.9 that are necessary for KVMD.

Signed-off-by: Oleg Girko <ol@infoserver.lv>
---
 genmap.py                              |  2 ++
 kvmd/aiogp.py                          |  6 +++++-
 kvmd/aiomulti.py                       |  2 ++
 kvmd/aioproc.py                        |  2 ++
 kvmd/aiotools.py                       |  2 ++
 kvmd/apps/__init__.py                  |  2 ++
 kvmd/apps/cleanup/__init__.py          |  2 ++
 kvmd/apps/edidconf/__init__.py         |  2 ++
 kvmd/apps/htpasswd/__init__.py         |  2 ++
 kvmd/apps/ipmi/__init__.py             |  2 ++
 kvmd/apps/ipmi/server.py               |  2 ++
 kvmd/apps/janus/__init__.py            |  2 ++
 kvmd/apps/janus/runner.py              |  2 ++
 kvmd/apps/janus/stun.py                |  2 ++
 kvmd/apps/kvmd/__init__.py             |  2 ++
 kvmd/apps/kvmd/api/log.py              |  2 ++
 kvmd/apps/kvmd/api/msd.py              |  2 ++
 kvmd/apps/kvmd/auth.py                 |  2 ++
 kvmd/apps/kvmd/info/base.py            |  2 ++
 kvmd/apps/kvmd/info/extras.py          |  2 ++
 kvmd/apps/kvmd/info/fan.py             |  2 ++
 kvmd/apps/kvmd/info/hw.py              |  2 ++
 kvmd/apps/kvmd/info/meta.py            |  2 ++
 kvmd/apps/kvmd/ocr.py                  |  2 ++
 kvmd/apps/kvmd/server.py               |  2 ++
 kvmd/apps/kvmd/streamer.py             |  2 ++
 kvmd/apps/kvmd/sysunit.py              |  2 ++
 kvmd/apps/kvmd/ugpio.py                |  2 ++
 kvmd/apps/otg/__init__.py              |  2 ++
 kvmd/apps/otg/hid/keyboard.py          |  2 ++
 kvmd/apps/otg/hid/mouse.py             |  2 ++
 kvmd/apps/otgconf/__init__.py          |  2 ++
 kvmd/apps/otgmsd/__init__.py           |  2 ++
 kvmd/apps/otgnet/__init__.py           |  2 ++
 kvmd/apps/pst/__init__.py              |  2 ++
 kvmd/apps/pstrun/__init__.py           |  2 ++
 kvmd/apps/totp/__init__.py             |  2 ++
 kvmd/apps/vnc/__init__.py              |  2 ++
 kvmd/apps/vnc/rfb/encodings.py         |  2 ++
 kvmd/apps/vnc/rfb/stream.py            |  2 ++
 kvmd/apps/vnc/server.py                |  2 ++
 kvmd/apps/watchdog/__init__.py         |  2 ++
 kvmd/clients/kvmd.py                   |  2 ++
 kvmd/htclient.py                       |  2 ++
 kvmd/htserver.py                       |  2 ++
 kvmd/inotify.py                        |  2 ++
 kvmd/logging.py                        |  2 ++
 kvmd/plugins/atx/gpio.py               |  2 ++
 kvmd/plugins/auth/http.py              |  2 ++
 kvmd/plugins/hid/__init__.py           |  2 ++
 kvmd/plugins/hid/_mcu/__init__.py      |  2 ++
 kvmd/plugins/hid/_mcu/gpio.py          |  2 ++
 kvmd/plugins/hid/bt/__init__.py        |  2 ++
 kvmd/plugins/hid/bt/bluez.py           |  2 ++
 kvmd/plugins/hid/bt/server.py          |  2 ++
 kvmd/plugins/hid/ch9329/__init__.py    |  2 ++
 kvmd/plugins/hid/ch9329/mouse.py       | 21 +++++++++------------
 kvmd/plugins/hid/otg/__init__.py       |  2 ++
 kvmd/plugins/hid/otg/device.py         |  2 ++
 kvmd/plugins/hid/otg/events.py         |  2 ++
 kvmd/plugins/hid/otg/keyboard.py       |  2 ++
 kvmd/plugins/hid/otg/mouse.py          |  2 ++
 kvmd/plugins/hid/spi.py                |  2 ++
 kvmd/plugins/msd/__init__.py           |  2 ++
 kvmd/plugins/msd/disabled.py           |  2 ++
 kvmd/plugins/msd/otg/__init__.py       |  2 ++
 kvmd/plugins/ugpio/__init__.py         |  2 ++
 kvmd/plugins/ugpio/ezcoo.py            |  2 ++
 kvmd/plugins/ugpio/gpio.py             |  2 ++
 kvmd/plugins/ugpio/hidrelay.py         |  2 ++
 kvmd/plugins/ugpio/hue.py              |  2 ++
 kvmd/plugins/ugpio/ipmi.py             |  2 ++
 kvmd/plugins/ugpio/locator.py          |  2 ++
 kvmd/plugins/ugpio/pway.py             |  2 ++
 kvmd/plugins/ugpio/pwm.py              |  2 ++
 kvmd/plugins/ugpio/tesmart.py          |  2 ++
 kvmd/plugins/ugpio/wol.py              |  2 ++
 kvmd/plugins/ugpio/xh_hk4401.py        |  2 ++
 kvmd/validators/__init__.py            |  2 ++
 kvmd/validators/basic.py               |  2 ++
 kvmd/validators/ugpio.py               |  2 ++
 kvmd/yamlconf/__init__.py              |  2 ++
 testenv/linters/mypy.ini               |  2 +-
 testenv/tests/apps/kvmd/test_auth.py   |  2 ++
 testenv/tests/plugins/auth/test_pam.py |  2 ++
 85 files changed, 179 insertions(+), 14 deletions(-)

diff --git a/genmap.py b/genmap.py
index 6a6b63bf..e082964f 100755
--- a/genmap.py
+++ b/genmap.py
@@ -21,6 +21,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import sys
 import csv
 import textwrap
diff --git a/kvmd/aiogp.py b/kvmd/aiogp.py
index 7559a9d9..6545aefe 100644
--- a/kvmd/aiogp.py
+++ b/kvmd/aiogp.py
@@ -20,6 +20,9 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
+import sys
 import asyncio
 import threading
 import dataclasses
@@ -135,7 +138,8 @@ class _DebouncedValue:
         self.__notifier = notifier
         self.__loop = loop
 
-        self.__queue: "asyncio.Queue[bool]" = asyncio.Queue()  # type: ignore
+        queue_kwargs = ({"loop": loop} if sys.version_info < (3, 10) else {})
+        self.__queue: "asyncio.Queue[bool]" = asyncio.Queue(**queue_kwargs)  # type: ignore
         self.__task = loop.create_task(self.__consumer_task_loop())
 
     def set(self, value: bool) -> None:
diff --git a/kvmd/aiomulti.py b/kvmd/aiomulti.py
index 5e7032d3..35314f3d 100644
--- a/kvmd/aiomulti.py
+++ b/kvmd/aiomulti.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import multiprocessing
 import queue
 
diff --git a/kvmd/aioproc.py b/kvmd/aioproc.py
index 81864b7f..96ecef46 100644
--- a/kvmd/aioproc.py
+++ b/kvmd/aioproc.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import signal
 import asyncio
diff --git a/kvmd/aiotools.py b/kvmd/aiotools.py
index 2b148573..53705098 100644
--- a/kvmd/aiotools.py
+++ b/kvmd/aiotools.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import signal
 import asyncio
diff --git a/kvmd/apps/__init__.py b/kvmd/apps/__init__.py
index 6b04778f..cba0abfc 100644
--- a/kvmd/apps/__init__.py
+++ b/kvmd/apps/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import sys
 import os
 import functools
diff --git a/kvmd/apps/cleanup/__init__.py b/kvmd/apps/cleanup/__init__.py
index c4855efb..89afbd03 100644
--- a/kvmd/apps/cleanup/__init__.py
+++ b/kvmd/apps/cleanup/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import signal
 import time
 
diff --git a/kvmd/apps/edidconf/__init__.py b/kvmd/apps/edidconf/__init__.py
index c42f4c91..88aef08f 100644
--- a/kvmd/apps/edidconf/__init__.py
+++ b/kvmd/apps/edidconf/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import sys
 import os
 import re
diff --git a/kvmd/apps/htpasswd/__init__.py b/kvmd/apps/htpasswd/__init__.py
index 3d655484..6d350a3d 100644
--- a/kvmd/apps/htpasswd/__init__.py
+++ b/kvmd/apps/htpasswd/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import sys
 import os
 import getpass
diff --git a/kvmd/apps/ipmi/__init__.py b/kvmd/apps/ipmi/__init__.py
index 60982275..ee8a1c12 100644
--- a/kvmd/apps/ipmi/__init__.py
+++ b/kvmd/apps/ipmi/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from ...clients.kvmd import KvmdClient
 
 from ... import htclient
diff --git a/kvmd/apps/ipmi/server.py b/kvmd/apps/ipmi/server.py
index 3679ce10..892274fd 100644
--- a/kvmd/apps/ipmi/server.py
+++ b/kvmd/apps/ipmi/server.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import select
 import asyncio
diff --git a/kvmd/apps/janus/__init__.py b/kvmd/apps/janus/__init__.py
index 92f6e26d..a2fd4be3 100644
--- a/kvmd/apps/janus/__init__.py
+++ b/kvmd/apps/janus/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from .. import init
 
 from .runner import JanusRunner
diff --git a/kvmd/apps/janus/runner.py b/kvmd/apps/janus/runner.py
index e08fade0..13b06bfa 100644
--- a/kvmd/apps/janus/runner.py
+++ b/kvmd/apps/janus/runner.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import asyncio
 import asyncio.subprocess
 import socket
diff --git a/kvmd/apps/janus/stun.py b/kvmd/apps/janus/stun.py
index 5fea9da6..b737463f 100644
--- a/kvmd/apps/janus/stun.py
+++ b/kvmd/apps/janus/stun.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import asyncio
 import socket
 import ipaddress
diff --git a/kvmd/apps/kvmd/__init__.py b/kvmd/apps/kvmd/__init__.py
index 2d0219db..f4874711 100644
--- a/kvmd/apps/kvmd/__init__.py
+++ b/kvmd/apps/kvmd/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from ...logging import get_logger
 
 from ...plugins.hid import get_hid_class
diff --git a/kvmd/apps/kvmd/api/log.py b/kvmd/apps/kvmd/api/log.py
index 7a73693b..1db97144 100644
--- a/kvmd/apps/kvmd/api/log.py
+++ b/kvmd/apps/kvmd/api/log.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from aiohttp.web import Request
 from aiohttp.web import StreamResponse
 
diff --git a/kvmd/apps/kvmd/api/msd.py b/kvmd/apps/kvmd/api/msd.py
index 94b08299..397a6c9b 100644
--- a/kvmd/apps/kvmd/api/msd.py
+++ b/kvmd/apps/kvmd/api/msd.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import lzma
 import time
 
diff --git a/kvmd/apps/kvmd/auth.py b/kvmd/apps/kvmd/auth.py
index 53b1d532..84b2c557 100644
--- a/kvmd/apps/kvmd/auth.py
+++ b/kvmd/apps/kvmd/auth.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import secrets
 import pyotp
 
diff --git a/kvmd/apps/kvmd/info/base.py b/kvmd/apps/kvmd/info/base.py
index a73565d2..98151456 100644
--- a/kvmd/apps/kvmd/info/base.py
+++ b/kvmd/apps/kvmd/info/base.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 # =====
 class BaseInfoSubmanager:
     async def get_state(self) -> (dict | None):
diff --git a/kvmd/apps/kvmd/info/extras.py b/kvmd/apps/kvmd/info/extras.py
index 922526fe..059b11e9 100644
--- a/kvmd/apps/kvmd/info/extras.py
+++ b/kvmd/apps/kvmd/info/extras.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import re
 import asyncio
diff --git a/kvmd/apps/kvmd/info/fan.py b/kvmd/apps/kvmd/info/fan.py
index 39572059..5e60ceda 100644
--- a/kvmd/apps/kvmd/info/fan.py
+++ b/kvmd/apps/kvmd/info/fan.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import copy
 import asyncio
 
diff --git a/kvmd/apps/kvmd/info/hw.py b/kvmd/apps/kvmd/info/hw.py
index ed6d8a2c..0da118be 100644
--- a/kvmd/apps/kvmd/info/hw.py
+++ b/kvmd/apps/kvmd/info/hw.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import asyncio
 
diff --git a/kvmd/apps/kvmd/info/meta.py b/kvmd/apps/kvmd/info/meta.py
index 0da96a35..3ca89d2f 100644
--- a/kvmd/apps/kvmd/info/meta.py
+++ b/kvmd/apps/kvmd/info/meta.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from ....logging import get_logger
 
 from ....yamlconf.loader import load_yaml_file
diff --git a/kvmd/apps/kvmd/ocr.py b/kvmd/apps/kvmd/ocr.py
index ba96093c..d2ba1555 100644
--- a/kvmd/apps/kvmd/ocr.py
+++ b/kvmd/apps/kvmd/ocr.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import stat
 import io
diff --git a/kvmd/apps/kvmd/server.py b/kvmd/apps/kvmd/server.py
index 8f696fb7..3858edc0 100644
--- a/kvmd/apps/kvmd/server.py
+++ b/kvmd/apps/kvmd/server.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 import operator
 import dataclasses
diff --git a/kvmd/apps/kvmd/streamer.py b/kvmd/apps/kvmd/streamer.py
index 26b5082a..c072caaa 100644
--- a/kvmd/apps/kvmd/streamer.py
+++ b/kvmd/apps/kvmd/streamer.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import io
 import signal
 import asyncio
diff --git a/kvmd/apps/kvmd/sysunit.py b/kvmd/apps/kvmd/sysunit.py
index 5a555553..ef77c911 100644
--- a/kvmd/apps/kvmd/sysunit.py
+++ b/kvmd/apps/kvmd/sysunit.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import types
 
 import dbus_next
diff --git a/kvmd/apps/kvmd/ugpio.py b/kvmd/apps/kvmd/ugpio.py
index bda9cef6..336127ce 100644
--- a/kvmd/apps/kvmd/ugpio.py
+++ b/kvmd/apps/kvmd/ugpio.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 
 from typing import AsyncGenerator
diff --git a/kvmd/apps/otg/__init__.py b/kvmd/apps/otg/__init__.py
index 43dd3e5a..d87fb575 100644
--- a/kvmd/apps/otg/__init__.py
+++ b/kvmd/apps/otg/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import re
 import shutil
diff --git a/kvmd/apps/otg/hid/keyboard.py b/kvmd/apps/otg/hid/keyboard.py
index a49a22a0..886c2131 100644
--- a/kvmd/apps/otg/hid/keyboard.py
+++ b/kvmd/apps/otg/hid/keyboard.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from . import Hid
 
 
diff --git a/kvmd/apps/otg/hid/mouse.py b/kvmd/apps/otg/hid/mouse.py
index 99f53833..7c210b06 100644
--- a/kvmd/apps/otg/hid/mouse.py
+++ b/kvmd/apps/otg/hid/mouse.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from . import Hid
 
 
diff --git a/kvmd/apps/otgconf/__init__.py b/kvmd/apps/otgconf/__init__.py
index 8035aade..166f15a2 100644
--- a/kvmd/apps/otgconf/__init__.py
+++ b/kvmd/apps/otgconf/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import json
 import contextlib
diff --git a/kvmd/apps/otgmsd/__init__.py b/kvmd/apps/otgmsd/__init__.py
index 33e58699..21aea7f5 100644
--- a/kvmd/apps/otgmsd/__init__.py
+++ b/kvmd/apps/otgmsd/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import errno
 import argparse
diff --git a/kvmd/apps/otgnet/__init__.py b/kvmd/apps/otgnet/__init__.py
index 8ea1c509..4430dd3e 100644
--- a/kvmd/apps/otgnet/__init__.py
+++ b/kvmd/apps/otgnet/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 import ipaddress
 import dataclasses
diff --git a/kvmd/apps/pst/__init__.py b/kvmd/apps/pst/__init__.py
index 35930ae7..df8a3f61 100644
--- a/kvmd/apps/pst/__init__.py
+++ b/kvmd/apps/pst/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from ...logging import get_logger
 
 from .. import init
diff --git a/kvmd/apps/pstrun/__init__.py b/kvmd/apps/pstrun/__init__.py
index be6a900f..c28106cc 100644
--- a/kvmd/apps/pstrun/__init__.py
+++ b/kvmd/apps/pstrun/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import sys
 import os
 import signal
diff --git a/kvmd/apps/totp/__init__.py b/kvmd/apps/totp/__init__.py
index 329a8b52..53fd8a71 100644
--- a/kvmd/apps/totp/__init__.py
+++ b/kvmd/apps/totp/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import socket
 import argparse
 
diff --git a/kvmd/apps/vnc/__init__.py b/kvmd/apps/vnc/__init__.py
index a5d3c781..0091ab8d 100644
--- a/kvmd/apps/vnc/__init__.py
+++ b/kvmd/apps/vnc/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from ...clients.kvmd import KvmdClient
 from ...clients.streamer import StreamFormats
 from ...clients.streamer import BaseStreamerClient
diff --git a/kvmd/apps/vnc/rfb/encodings.py b/kvmd/apps/vnc/rfb/encodings.py
index 597e3a92..b3d01968 100644
--- a/kvmd/apps/vnc/rfb/encodings.py
+++ b/kvmd/apps/vnc/rfb/encodings.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import dataclasses
 
 from typing import Any
diff --git a/kvmd/apps/vnc/rfb/stream.py b/kvmd/apps/vnc/rfb/stream.py
index 44998617..bcea964b 100644
--- a/kvmd/apps/vnc/rfb/stream.py
+++ b/kvmd/apps/vnc/rfb/stream.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 import ssl
 import struct
diff --git a/kvmd/apps/vnc/server.py b/kvmd/apps/vnc/server.py
index c7d943d2..744c1ad1 100644
--- a/kvmd/apps/vnc/server.py
+++ b/kvmd/apps/vnc/server.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import asyncio
 import socket
diff --git a/kvmd/apps/watchdog/__init__.py b/kvmd/apps/watchdog/__init__.py
index 2a3ba41b..e7de79e5 100644
--- a/kvmd/apps/watchdog/__init__.py
+++ b/kvmd/apps/watchdog/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import argparse
 import errno
 import time
diff --git a/kvmd/clients/kvmd.py b/kvmd/clients/kvmd.py
index 569fb9d0..d5bb3ab5 100644
--- a/kvmd/clients/kvmd.py
+++ b/kvmd/clients/kvmd.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 import contextlib
 import struct
diff --git a/kvmd/htclient.py b/kvmd/htclient.py
index 53eebe4e..c100dd15 100644
--- a/kvmd/htclient.py
+++ b/kvmd/htclient.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import contextlib
 
diff --git a/kvmd/htserver.py b/kvmd/htserver.py
index 2974feed..ad097fb2 100644
--- a/kvmd/htserver.py
+++ b/kvmd/htserver.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import socket
 import asyncio
diff --git a/kvmd/inotify.py b/kvmd/inotify.py
index d5677b13..ba4694d8 100644
--- a/kvmd/inotify.py
+++ b/kvmd/inotify.py
@@ -22,6 +22,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import sys
 import os
 import asyncio
diff --git a/kvmd/logging.py b/kvmd/logging.py
index df3efc11..25c78ad3 100644
--- a/kvmd/logging.py
+++ b/kvmd/logging.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import sys
 import types
 import logging
diff --git a/kvmd/plugins/atx/gpio.py b/kvmd/plugins/atx/gpio.py
index 476dacb0..4ec1e072 100644
--- a/kvmd/plugins/atx/gpio.py
+++ b/kvmd/plugins/atx/gpio.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 
 from typing import AsyncGenerator
diff --git a/kvmd/plugins/auth/http.py b/kvmd/plugins/auth/http.py
index 7b802c55..e6ff5827 100644
--- a/kvmd/plugins/auth/http.py
+++ b/kvmd/plugins/auth/http.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import aiohttp
 import aiohttp.web
 
diff --git a/kvmd/plugins/hid/__init__.py b/kvmd/plugins/hid/__init__.py
index 40661d74..5f39cb00 100644
--- a/kvmd/plugins/hid/__init__.py
+++ b/kvmd/plugins/hid/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 import time
 
diff --git a/kvmd/plugins/hid/_mcu/__init__.py b/kvmd/plugins/hid/_mcu/__init__.py
index 7f5f7a74..d53640c6 100644
--- a/kvmd/plugins/hid/_mcu/__init__.py
+++ b/kvmd/plugins/hid/_mcu/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import multiprocessing
 import contextlib
 import queue
diff --git a/kvmd/plugins/hid/_mcu/gpio.py b/kvmd/plugins/hid/_mcu/gpio.py
index 648ab447..3ee2a8c9 100644
--- a/kvmd/plugins/hid/_mcu/gpio.py
+++ b/kvmd/plugins/hid/_mcu/gpio.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import types
 import time
 
diff --git a/kvmd/plugins/hid/bt/__init__.py b/kvmd/plugins/hid/bt/__init__.py
index 1b50f26a..c9614164 100644
--- a/kvmd/plugins/hid/bt/__init__.py
+++ b/kvmd/plugins/hid/bt/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import multiprocessing
 import time
 
diff --git a/kvmd/plugins/hid/bt/bluez.py b/kvmd/plugins/hid/bt/bluez.py
index 8d1da819..0d7ab7e2 100644
--- a/kvmd/plugins/hid/bt/bluez.py
+++ b/kvmd/plugins/hid/bt/bluez.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import types
 
 from typing import Any
diff --git a/kvmd/plugins/hid/bt/server.py b/kvmd/plugins/hid/bt/server.py
index c00480c9..a046e96a 100644
--- a/kvmd/plugins/hid/bt/server.py
+++ b/kvmd/plugins/hid/bt/server.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import socket
 import select
 import multiprocessing
diff --git a/kvmd/plugins/hid/ch9329/__init__.py b/kvmd/plugins/hid/ch9329/__init__.py
index 4e2be8c9..975fe2d7 100644
--- a/kvmd/plugins/hid/ch9329/__init__.py
+++ b/kvmd/plugins/hid/ch9329/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import multiprocessing
 import queue
 import time
diff --git a/kvmd/plugins/hid/ch9329/mouse.py b/kvmd/plugins/hid/ch9329/mouse.py
index 0a0cfbcc..e1ba0c77 100644
--- a/kvmd/plugins/hid/ch9329/mouse.py
+++ b/kvmd/plugins/hid/ch9329/mouse.py
@@ -42,19 +42,16 @@ class Mouse:  # pylint: disable=too-many-instance-attributes
     def is_absolute(self) -> bool:
         return self.__absolute
 
+    button_code = {
+        "left":   0x01,
+        "right":  0x02,
+        "middle": 0x04,
+        "up":     0x08,
+        "down":   0x10,
+    }
+
     def process_button(self, button: str, state: bool) -> bytes:
-        code = 0x00
-        match button:
-            case "left":
-                code = 0x01
-            case "right":
-                code = 0x02
-            case "middle":
-                code = 0x04
-            case "up":
-                code = 0x08
-            case "down":
-                code = 0x10
+        code = button_code.get(button, 0x00)
         if code:
             if state:
                 self.__buttons |= code
diff --git a/kvmd/plugins/hid/otg/__init__.py b/kvmd/plugins/hid/otg/__init__.py
index 61b8a194..4de9b4a7 100644
--- a/kvmd/plugins/hid/otg/__init__.py
+++ b/kvmd/plugins/hid/otg/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from typing import Iterable
 from typing import AsyncGenerator
 from typing import Any
diff --git a/kvmd/plugins/hid/otg/device.py b/kvmd/plugins/hid/otg/device.py
index af30188b..d804a446 100644
--- a/kvmd/plugins/hid/otg/device.py
+++ b/kvmd/plugins/hid/otg/device.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import select
 import multiprocessing
diff --git a/kvmd/plugins/hid/otg/events.py b/kvmd/plugins/hid/otg/events.py
index 39986772..f9813f1a 100644
--- a/kvmd/plugins/hid/otg/events.py
+++ b/kvmd/plugins/hid/otg/events.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import struct
 import dataclasses
 
diff --git a/kvmd/plugins/hid/otg/keyboard.py b/kvmd/plugins/hid/otg/keyboard.py
index 75d31735..c63bcb74 100644
--- a/kvmd/plugins/hid/otg/keyboard.py
+++ b/kvmd/plugins/hid/otg/keyboard.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from typing import Iterable
 from typing import Generator
 from typing import Any
diff --git a/kvmd/plugins/hid/otg/mouse.py b/kvmd/plugins/hid/otg/mouse.py
index b25d8380..ec18a5f4 100644
--- a/kvmd/plugins/hid/otg/mouse.py
+++ b/kvmd/plugins/hid/otg/mouse.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from typing import Generator
 from typing import Any
 
diff --git a/kvmd/plugins/hid/spi.py b/kvmd/plugins/hid/spi.py
index 74c3d3b8..07750935 100644
--- a/kvmd/plugins/hid/spi.py
+++ b/kvmd/plugins/hid/spi.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import contextlib
 import time
diff --git a/kvmd/plugins/msd/__init__.py b/kvmd/plugins/msd/__init__.py
index cb8d8130..6cfa0c12 100644
--- a/kvmd/plugins/msd/__init__.py
+++ b/kvmd/plugins/msd/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import contextlib
 import time
diff --git a/kvmd/plugins/msd/disabled.py b/kvmd/plugins/msd/disabled.py
index cb0ace41..fc560191 100644
--- a/kvmd/plugins/msd/disabled.py
+++ b/kvmd/plugins/msd/disabled.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import contextlib
 
 from typing import AsyncGenerator
diff --git a/kvmd/plugins/msd/otg/__init__.py b/kvmd/plugins/msd/otg/__init__.py
index c769bda2..ac079dee 100644
--- a/kvmd/plugins/msd/otg/__init__.py
+++ b/kvmd/plugins/msd/otg/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 import contextlib
 import dataclasses
diff --git a/kvmd/plugins/ugpio/__init__.py b/kvmd/plugins/ugpio/__init__.py
index 48d203be..b2306043 100644
--- a/kvmd/plugins/ugpio/__init__.py
+++ b/kvmd/plugins/ugpio/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from typing import Callable
 from typing import Any
 
diff --git a/kvmd/plugins/ugpio/ezcoo.py b/kvmd/plugins/ugpio/ezcoo.py
index 9f312743..016f8149 100644
--- a/kvmd/plugins/ugpio/ezcoo.py
+++ b/kvmd/plugins/ugpio/ezcoo.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import re
 import multiprocessing
 import functools
diff --git a/kvmd/plugins/ugpio/gpio.py b/kvmd/plugins/ugpio/gpio.py
index b86799a1..25abe085 100644
--- a/kvmd/plugins/ugpio/gpio.py
+++ b/kvmd/plugins/ugpio/gpio.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from typing import Callable
 from typing import Any
 
diff --git a/kvmd/plugins/ugpio/hidrelay.py b/kvmd/plugins/ugpio/hidrelay.py
index 7b8c083e..1840e419 100644
--- a/kvmd/plugins/ugpio/hidrelay.py
+++ b/kvmd/plugins/ugpio/hidrelay.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 import contextlib
 import functools
diff --git a/kvmd/plugins/ugpio/hue.py b/kvmd/plugins/ugpio/hue.py
index 91f4ac52..07d652df 100644
--- a/kvmd/plugins/ugpio/hue.py
+++ b/kvmd/plugins/ugpio/hue.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 
 from typing import Callable
diff --git a/kvmd/plugins/ugpio/ipmi.py b/kvmd/plugins/ugpio/ipmi.py
index 32d97cfa..763aca62 100644
--- a/kvmd/plugins/ugpio/ipmi.py
+++ b/kvmd/plugins/ugpio/ipmi.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 import functools
 
diff --git a/kvmd/plugins/ugpio/locator.py b/kvmd/plugins/ugpio/locator.py
index 79c10df7..2ef99b6f 100644
--- a/kvmd/plugins/ugpio/locator.py
+++ b/kvmd/plugins/ugpio/locator.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 
 from typing import Callable
diff --git a/kvmd/plugins/ugpio/pway.py b/kvmd/plugins/ugpio/pway.py
index 26e30921..0ffffa3a 100644
--- a/kvmd/plugins/ugpio/pway.py
+++ b/kvmd/plugins/ugpio/pway.py
@@ -22,6 +22,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import re
 import multiprocessing
 import functools
diff --git a/kvmd/plugins/ugpio/pwm.py b/kvmd/plugins/ugpio/pwm.py
index f8df4338..3ab41a3c 100644
--- a/kvmd/plugins/ugpio/pwm.py
+++ b/kvmd/plugins/ugpio/pwm.py
@@ -21,6 +21,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from typing import Callable
 from typing import Any
 
diff --git a/kvmd/plugins/ugpio/tesmart.py b/kvmd/plugins/ugpio/tesmart.py
index 6c081cdb..840b8f4e 100644
--- a/kvmd/plugins/ugpio/tesmart.py
+++ b/kvmd/plugins/ugpio/tesmart.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import asyncio
 import functools
 
diff --git a/kvmd/plugins/ugpio/wol.py b/kvmd/plugins/ugpio/wol.py
index 78670e8a..e31192d7 100644
--- a/kvmd/plugins/ugpio/wol.py
+++ b/kvmd/plugins/ugpio/wol.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import socket
 import functools
 
diff --git a/kvmd/plugins/ugpio/xh_hk4401.py b/kvmd/plugins/ugpio/xh_hk4401.py
index 995708df..976becf8 100644
--- a/kvmd/plugins/ugpio/xh_hk4401.py
+++ b/kvmd/plugins/ugpio/xh_hk4401.py
@@ -21,6 +21,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import re
 import multiprocessing
 import functools
diff --git a/kvmd/validators/__init__.py b/kvmd/validators/__init__.py
index 57c96d8a..f7fd0970 100644
--- a/kvmd/validators/__init__.py
+++ b/kvmd/validators/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import re
 
 from typing import Mapping
diff --git a/kvmd/validators/basic.py b/kvmd/validators/basic.py
index c7b45971..8489f50b 100644
--- a/kvmd/validators/basic.py
+++ b/kvmd/validators/basic.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import re
 
 from typing import Type
diff --git a/kvmd/validators/ugpio.py b/kvmd/validators/ugpio.py
index 12461d0d..fb28b10f 100644
--- a/kvmd/validators/ugpio.py
+++ b/kvmd/validators/ugpio.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 from typing import Any
 
 from . import raise_error
diff --git a/kvmd/yamlconf/__init__.py b/kvmd/yamlconf/__init__.py
index 8e688a56..2ace0860 100644
--- a/kvmd/yamlconf/__init__.py
+++ b/kvmd/yamlconf/__init__.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import contextlib
 import json
 
diff --git a/testenv/linters/mypy.ini b/testenv/linters/mypy.ini
index d436fd2c..00dd6881 100644
--- a/testenv/linters/mypy.ini
+++ b/testenv/linters/mypy.ini
@@ -1,5 +1,5 @@
 [mypy]
-python_version = 3.11
+python_version = 3.9
 ignore_missing_imports = true
 disallow_untyped_defs = true
 strict_optional = true
diff --git a/testenv/tests/apps/kvmd/test_auth.py b/testenv/tests/apps/kvmd/test_auth.py
index 402c9273..654a0d39 100644
--- a/testenv/tests/apps/kvmd/test_auth.py
+++ b/testenv/tests/apps/kvmd/test_auth.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import contextlib
 
diff --git a/testenv/tests/plugins/auth/test_pam.py b/testenv/tests/plugins/auth/test_pam.py
index 9c327c56..cc265c49 100644
--- a/testenv/tests/plugins/auth/test_pam.py
+++ b/testenv/tests/plugins/auth/test_pam.py
@@ -20,6 +20,8 @@
 # ========================================================================== #
 
 
+from __future__ import annotations
+
 import os
 import asyncio
 import pwd
-- 
2.48.1