From 118260bc1dec7701386235be3ec8e307bd3771a5 Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Tue, 2 Jun 2026 12:43:47 +0100 Subject: [PATCH 1/6] Fix annotations for pynput event callbacks They are designed to accept any number of arguments up to the maximum amount, so `on_click()` and `on_click(x, y)` are both perfectly valid callbacks. Here are the full signatures for each callback: - `on_move(x: int, y: int, injected: bool)` - `on_click(x: int, y: int, button: Button, pressed: bool, injected: bool)` - `on_scroll(x: int, y: int, dx: int, dy: int, injected: bool)` - `on_press(key: Key | KeyCode | None, injected: bool)` - `on_release(key: Key | KeyCode | None, injected: bool)` Test passes with `python tests/regr_test.py pynput` --- .../@tests/test_cases/check_listener.py | 32 +++++++++++++++++++ stubs/pynput/pynput/keyboard/_base.pyi | 14 ++++++-- stubs/pynput/pynput/mouse/_base.pyi | 28 ++++++++++++++-- 3 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 stubs/pynput/@tests/test_cases/check_listener.py diff --git a/stubs/pynput/@tests/test_cases/check_listener.py b/stubs/pynput/@tests/test_cases/check_listener.py new file mode 100644 index 000000000000..1227ee02c02e --- /dev/null +++ b/stubs/pynput/@tests/test_cases/check_listener.py @@ -0,0 +1,32 @@ +from pynput.keyboard import Key, KeyCode, Listener as KeyboardListener +from pynput.mouse import Button, Listener as MouseListener + +# on_move: 0–3 args +MouseListener(on_move=lambda: None) +MouseListener(on_move=lambda x: None) +MouseListener(on_move=lambda x, y: None) +MouseListener(on_move=lambda x, y, injected: None) + +# on_click: 0–5 args +MouseListener(on_click=lambda: None) +MouseListener(on_click=lambda x: None) +MouseListener(on_click=lambda x, y: None) +MouseListener(on_click=lambda x, y, button: None) +MouseListener(on_click=lambda x, y, button, pressed: None) +MouseListener(on_click=lambda x, y, button, pressed, injected: None) + +# on_scroll: 0–5 args +MouseListener(on_scroll=lambda: None) +MouseListener(on_scroll=lambda x: None) +MouseListener(on_scroll=lambda x, y: None) +MouseListener(on_scroll=lambda x, y, dx: None) +MouseListener(on_scroll=lambda x, y, dx, dy: None) +MouseListener(on_scroll=lambda x, y, dx, dy, injected: None) + +# on_press / on_release: 0–2 args +KeyboardListener(on_press=lambda: None) +KeyboardListener(on_press=lambda key: None) +KeyboardListener(on_press=lambda key, injected: None) +KeyboardListener(on_release=lambda: None) +KeyboardListener(on_release=lambda key: None) +KeyboardListener(on_release=lambda key, injected: None) diff --git a/stubs/pynput/pynput/keyboard/_base.pyi b/stubs/pynput/pynput/keyboard/_base.pyi index 59922d1900e6..287343ac7cce 100644 --- a/stubs/pynput/pynput/keyboard/_base.pyi +++ b/stubs/pynput/pynput/keyboard/_base.pyi @@ -127,8 +127,18 @@ class Controller: class Listener(AbstractListener): def __init__( self, - on_press: Callable[[Key | KeyCode | None], None] | None = None, - on_release: Callable[[Key | KeyCode | None], None] | None = None, + on_press: ( + Callable[[], None] + | Callable[[Key | KeyCode | None], None] + | Callable[[Key | KeyCode | None, bool], None] + | None + ) = None, + on_release: ( + Callable[[], None] + | Callable[[Key | KeyCode | None], None] + | Callable[[Key | KeyCode | None, bool], None] + | None + ) = None, suppress: bool = False, **kwargs: Any, ) -> None: ... diff --git a/stubs/pynput/pynput/mouse/_base.pyi b/stubs/pynput/pynput/mouse/_base.pyi index 9ae82dd422df..69cfd78ac520 100644 --- a/stubs/pynput/pynput/mouse/_base.pyi +++ b/stubs/pynput/pynput/mouse/_base.pyi @@ -88,9 +88,31 @@ class Listener(AbstractListener): def __init__( self, - on_move: Callable[[int, int], bool | None] | None = None, - on_click: Callable[[int, int, Button, bool], bool | None] | None = None, - on_scroll: Callable[[int, int, int, int], bool | None] | None = None, + on_move: ( + Callable[[], bool | None] + | Callable[[int], bool | None] + | Callable[[int, int], bool | None] + | Callable[[int, int, bool], bool | None] + | None + ) = None, + on_click: ( + Callable[[], bool | None] + | Callable[[int], bool | None] + | Callable[[int, int], bool | None] + | Callable[[int, int, Button], bool | None] + | Callable[[int, int, Button, bool], bool | None] + | Callable[[int, int, Button, bool, bool], bool | None] + | None + ) = None, + on_scroll: ( + Callable[[], bool | None] + | Callable[[int], bool | None] + | Callable[[int, int], bool | None] + | Callable[[int, int, int], bool | None] + | Callable[[int, int, int, int], bool | None] + | Callable[[int, int, int, int, bool], bool | None] + | None + ) = None, suppress: bool = False, **kwargs: Any, ) -> None: ... From 38c313d1ed5694bafe161941e6cfc65508e78c33 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 11:54:08 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stubs/pynput/pynput/keyboard/_base.pyi | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/stubs/pynput/pynput/keyboard/_base.pyi b/stubs/pynput/pynput/keyboard/_base.pyi index 287343ac7cce..e721f80650aa 100644 --- a/stubs/pynput/pynput/keyboard/_base.pyi +++ b/stubs/pynput/pynput/keyboard/_base.pyi @@ -128,16 +128,10 @@ class Listener(AbstractListener): def __init__( self, on_press: ( - Callable[[], None] - | Callable[[Key | KeyCode | None], None] - | Callable[[Key | KeyCode | None, bool], None] - | None + Callable[[], None] | Callable[[Key | KeyCode | None], None] | Callable[[Key | KeyCode | None, bool], None] | None ) = None, on_release: ( - Callable[[], None] - | Callable[[Key | KeyCode | None], None] - | Callable[[Key | KeyCode | None, bool], None] - | None + Callable[[], None] | Callable[[Key | KeyCode | None], None] | Callable[[Key | KeyCode | None, bool], None] | None ) = None, suppress: bool = False, **kwargs: Any, From 672b120f1cba31c49d78b7a517f085e2430a9c05 Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Tue, 2 Jun 2026 13:09:20 +0100 Subject: [PATCH 3/6] Remove unused imports --- stubs/pynput/@tests/test_cases/check_listener.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stubs/pynput/@tests/test_cases/check_listener.py b/stubs/pynput/@tests/test_cases/check_listener.py index 1227ee02c02e..84fca698c616 100644 --- a/stubs/pynput/@tests/test_cases/check_listener.py +++ b/stubs/pynput/@tests/test_cases/check_listener.py @@ -1,5 +1,5 @@ -from pynput.keyboard import Key, KeyCode, Listener as KeyboardListener -from pynput.mouse import Button, Listener as MouseListener +from pynput.keyboard import Listener as KeyboardListener +from pynput.mouse import Listener as MouseListener # on_move: 0–3 args MouseListener(on_move=lambda: None) From a0af897262fb32e9e9db82b33f6a86bca3af20ba Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Tue, 2 Jun 2026 13:37:11 +0100 Subject: [PATCH 4/6] Remove unnecessary test Only needed for complex cases, which this is not. --- .../@tests/test_cases/check_listener.py | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 stubs/pynput/@tests/test_cases/check_listener.py diff --git a/stubs/pynput/@tests/test_cases/check_listener.py b/stubs/pynput/@tests/test_cases/check_listener.py deleted file mode 100644 index 84fca698c616..000000000000 --- a/stubs/pynput/@tests/test_cases/check_listener.py +++ /dev/null @@ -1,32 +0,0 @@ -from pynput.keyboard import Listener as KeyboardListener -from pynput.mouse import Listener as MouseListener - -# on_move: 0–3 args -MouseListener(on_move=lambda: None) -MouseListener(on_move=lambda x: None) -MouseListener(on_move=lambda x, y: None) -MouseListener(on_move=lambda x, y, injected: None) - -# on_click: 0–5 args -MouseListener(on_click=lambda: None) -MouseListener(on_click=lambda x: None) -MouseListener(on_click=lambda x, y: None) -MouseListener(on_click=lambda x, y, button: None) -MouseListener(on_click=lambda x, y, button, pressed: None) -MouseListener(on_click=lambda x, y, button, pressed, injected: None) - -# on_scroll: 0–5 args -MouseListener(on_scroll=lambda: None) -MouseListener(on_scroll=lambda x: None) -MouseListener(on_scroll=lambda x, y: None) -MouseListener(on_scroll=lambda x, y, dx: None) -MouseListener(on_scroll=lambda x, y, dx, dy: None) -MouseListener(on_scroll=lambda x, y, dx, dy, injected: None) - -# on_press / on_release: 0–2 args -KeyboardListener(on_press=lambda: None) -KeyboardListener(on_press=lambda key: None) -KeyboardListener(on_press=lambda key, injected: None) -KeyboardListener(on_release=lambda: None) -KeyboardListener(on_release=lambda key: None) -KeyboardListener(on_release=lambda key, injected: None) From b02d440e51f2ec4f27fc9fcbe44e640d11253714 Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Tue, 2 Jun 2026 14:22:39 +0100 Subject: [PATCH 5/6] Fix pynput return type Technically they accept any return type, but as the only effect is returning False stops the iteration, then it makes sense to limit it to bool or None. --- stubs/pynput/pynput/keyboard/_base.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stubs/pynput/pynput/keyboard/_base.pyi b/stubs/pynput/pynput/keyboard/_base.pyi index e721f80650aa..5c2c0c1a6541 100644 --- a/stubs/pynput/pynput/keyboard/_base.pyi +++ b/stubs/pynput/pynput/keyboard/_base.pyi @@ -128,10 +128,10 @@ class Listener(AbstractListener): def __init__( self, on_press: ( - Callable[[], None] | Callable[[Key | KeyCode | None], None] | Callable[[Key | KeyCode | None, bool], None] | None + Callable[[], bool | None] | Callable[[Key | KeyCode | None], bool | None] | Callable[[Key | KeyCode | None, bool], bool | None] | None ) = None, on_release: ( - Callable[[], None] | Callable[[Key | KeyCode | None], None] | Callable[[Key | KeyCode | None, bool], None] | None + Callable[[], bool | None] | Callable[[Key | KeyCode | None], bool | None] | Callable[[Key | KeyCode | None, bool], bool | None] | None ) = None, suppress: bool = False, **kwargs: Any, From cd9af42d754f8652c89f671585e08106ba60a0a3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:24:41 +0000 Subject: [PATCH 6/6] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stubs/pynput/pynput/keyboard/_base.pyi | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/stubs/pynput/pynput/keyboard/_base.pyi b/stubs/pynput/pynput/keyboard/_base.pyi index 5c2c0c1a6541..a30a70814ed5 100644 --- a/stubs/pynput/pynput/keyboard/_base.pyi +++ b/stubs/pynput/pynput/keyboard/_base.pyi @@ -128,10 +128,16 @@ class Listener(AbstractListener): def __init__( self, on_press: ( - Callable[[], bool | None] | Callable[[Key | KeyCode | None], bool | None] | Callable[[Key | KeyCode | None, bool], bool | None] | None + Callable[[], bool | None] + | Callable[[Key | KeyCode | None], bool | None] + | Callable[[Key | KeyCode | None, bool], bool | None] + | None ) = None, on_release: ( - Callable[[], bool | None] | Callable[[Key | KeyCode | None], bool | None] | Callable[[Key | KeyCode | None, bool], bool | None] | None + Callable[[], bool | None] + | Callable[[Key | KeyCode | None], bool | None] + | Callable[[Key | KeyCode | None, bool], bool | None] + | None ) = None, suppress: bool = False, **kwargs: Any,