From 5ac3e7037eafe0b0171efb543ef4a5944a02ce98 Mon Sep 17 00:00:00 2001 From: RFCreate <107062289+RFCreate@users.noreply.github.com> Date: Tue, 16 Sep 2025 20:39:21 -0600 Subject: [PATCH 1/8] fix: avoid deleting files in setup.py --- pyproject.toml | 6 ++++++ setup.py | 20 -------------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index cb15687b..6eec0c51 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,6 +74,12 @@ line-length = 88 [tool.black] line-length = 88 +[tool.check-manifest] +ignore = [ + "wlroots/_build.py", + "wlroots/include/*.h", +] + [tool.mypy] check_untyped_defs = true # disallow_any_decorated = true diff --git a/setup.py b/setup.py index b5d2c1f1..46128f43 100644 --- a/setup.py +++ b/setup.py @@ -1,33 +1,13 @@ # Copyright (c) Sean Vig 2018 -import glob -import os import subprocess import sys from setuptools import setup -from setuptools.command.sdist import sdist - - -class SdistClean(sdist): - def run(self): - # These files are not tracked by git and as a result check-manifest complains - # when present, '_build.py' needs to be removed manually since it keeps being - # created by other setup commands and '.h' files are needen only during build - files = glob.glob("wlroots/include/*.h") - files.append("wlroots/_build.py") - for file in files: - try: - os.remove(file) - except Exception: - pass - sdist.run(self) - sys.path.insert(0, "wlroots") subprocess.run(["python", "wlroots/include/check_headers.py", "--generate"]) setup( - cmdclass={"sdist": SdistClean}, cffi_modules=["wlroots/ffi_build.py:ffi_builder"], ) From 75fa1a0e12f265c2d3702238c26f2e5464942b70 Mon Sep 17 00:00:00 2001 From: RFCreate <107062289+RFCreate@users.noreply.github.com> Date: Sun, 9 Nov 2025 14:57:06 -0600 Subject: [PATCH 2/8] feat(ruff): use as default formatter, remove black --- .github/workflows/ci.yml | 17 ----------------- .pre-commit-config.yaml | 12 ++++-------- pyproject.toml | 3 --- wlroots/ffi_build.py | 4 +++- 4 files changed, 7 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5aae72ef..d9c11692 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -227,23 +227,6 @@ jobs: run: | mypy -p wlroots mypy -p tiny - black-test: - name: black tests - runs-on: ubuntu-24.04 - env: - python-version: "3.13" - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: ${{ env.python-version }} - - name: Install Python dependencies - run: | - pip install black - - name: Run black test - run: black --check wlroots tiny packaging-test: name: packaging tests runs-on: ubuntu-24.04 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 11046f16..fb432251 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,7 @@ repos: - - repo: https://github.com/psf/black - rev: 25.1.0 - hooks: - - id: black - # Use the latest supported version here - language_version: python3.13 - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.0 + rev: v0.14.4 hooks: - - id: ruff + - id: ruff-check + args: [--fix] + - id: ruff-format diff --git a/pyproject.toml b/pyproject.toml index 6eec0c51..9a31e76a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,9 +71,6 @@ lint.select = ['E', 'F', 'I', 'N', 'W', 'UP', 'RUF'] lint.ignore = ["E501"] line-length = 88 -[tool.black] -line-length = 88 - [tool.check-manifest] ignore = [ "wlroots/_build.py", diff --git a/wlroots/ffi_build.py b/wlroots/ffi_build.py index f184fe24..b244e511 100644 --- a/wlroots/ffi_build.py +++ b/wlroots/ffi_build.py @@ -39,7 +39,9 @@ def load_wlroots_version(): lib = ffi.verify("#include ") except (PermissionError, OSError, VerificationError): lib = importlib.import_module("wlroots").lib - return f"{lib.WLR_VERSION_MAJOR}.{lib.WLR_VERSION_MINOR}.{lib.WLR_VERSION_MICRO}" # type: ignore[attr-defined] + return ( + f"{lib.WLR_VERSION_MAJOR}.{lib.WLR_VERSION_MINOR}.{lib.WLR_VERSION_MICRO}" # type: ignore[attr-defined] + ) else: return os.getenv("PYTHON_CROSSENV_WLROOTS_VERSION") From c8db0052a788e811fd9f1b6915b43deedcaa3b86 Mon Sep 17 00:00:00 2001 From: RFCreate <107062289+RFCreate@users.noreply.github.com> Date: Sun, 9 Nov 2025 15:08:19 -0600 Subject: [PATCH 3/8] feat: remove python 3.9 EOL --- .github/workflows/ci.yml | 1 - .github/workflows/release.yml | 3 +-- pyproject.toml | 3 +-- wlroots/__init__.py | 7 ++++--- wlroots/renderer.py | 3 +-- wlroots/wlr_types/input_device.py | 4 ++-- wlroots/wlr_types/scene.py | 3 ++- wlroots/wlr_types/xdg_shell.py | 7 ++++--- 8 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9c11692..6f4dd068 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,7 +110,6 @@ jobs: fail-fast: false matrix: python-version: - - "3.9" - "3.10" - "3.11" - "3.12" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f7e00ece..372831cc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -168,7 +168,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - name: Download wayland libraries uses: actions/download-artifact@v4 @@ -278,7 +278,6 @@ jobs: fail-fast: false matrix: python-version: - - "3.9" - "3.10" - "3.11" - "3.12" diff --git a/pyproject.toml b/pyproject.toml index 9a31e76a..de6b721d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta" name = "pywlroots" description = "Python binding to the wlroots library using cffi" authors = [{name = "Sean Vig", email = "sean.v.775@gmail.com"}] -requires-python = ">=3.9" +requires-python = ">=3.10" license = "NCSA" readme = "README.rst" classifiers = [ @@ -20,7 +20,6 @@ classifiers = [ "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", diff --git a/wlroots/__init__.py b/wlroots/__init__.py index 45dc696c..fbddd38d 100644 --- a/wlroots/__init__.py +++ b/wlroots/__init__.py @@ -2,8 +2,9 @@ from __future__ import annotations -import weakref -from typing import Any, Callable, TypeVar +from collections.abc import Callable +from typing import Any, TypeVar +from weakref import WeakKeyDictionary from ._ffi import ffi, lib from .version import version as _version @@ -14,7 +15,7 @@ __version__ = _version -_weakkeydict: weakref.WeakKeyDictionary = weakref.WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() T = TypeVar("T") diff --git a/wlroots/renderer.py b/wlroots/renderer.py index 18c8d104..52cb156a 100644 --- a/wlroots/renderer.py +++ b/wlroots/renderer.py @@ -4,7 +4,6 @@ import contextlib from collections.abc import Iterator -from typing import Union from pywayland.server import Display @@ -13,7 +12,7 @@ from wlroots.util.box import Box from wlroots.wlr_types import Matrix, Texture -ColorType = Union[list, tuple, ffi.CData] +ColorType = type[list[float] | tuple[float] | ffi.CData] class Renderer(Ptr): diff --git a/wlroots/wlr_types/input_device.py b/wlroots/wlr_types/input_device.py index e11aa55f..7b0547a0 100644 --- a/wlroots/wlr_types/input_device.py +++ b/wlroots/wlr_types/input_device.py @@ -2,13 +2,13 @@ from __future__ import annotations import enum -import weakref +from weakref import WeakKeyDictionary from pywayland.server import Signal from wlroots import PtrHasData, ffi, lib -_weakkeydict: weakref.WeakKeyDictionary = weakref.WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() @enum.unique diff --git a/wlroots/wlr_types/scene.py b/wlroots/wlr_types/scene.py index d2057f39..45440d22 100644 --- a/wlroots/wlr_types/scene.py +++ b/wlroots/wlr_types/scene.py @@ -3,7 +3,8 @@ from __future__ import annotations import enum -from typing import TYPE_CHECKING, Callable, TypeVar +from collections.abc import Callable +from typing import TYPE_CHECKING, TypeVar from pywayland.utils import wl_list_for_each diff --git a/wlroots/wlr_types/xdg_shell.py b/wlroots/wlr_types/xdg_shell.py index 5cba883a..d645fb61 100644 --- a/wlroots/wlr_types/xdg_shell.py +++ b/wlroots/wlr_types/xdg_shell.py @@ -3,8 +3,9 @@ from __future__ import annotations import enum -import weakref -from typing import Callable, TypeVar +from collections.abc import Callable +from typing import TypeVar +from weakref import WeakKeyDictionary from pywayland.server import Display, Signal @@ -15,7 +16,7 @@ from .compositor import Surface from .output import Output -_weakkeydict: weakref.WeakKeyDictionary = weakref.WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() T = TypeVar("T") SurfaceCallback = Callable[[Surface, int, int, T], None] From 9b298886f38952b1e8de4254a1e02f2c8ee3644f Mon Sep 17 00:00:00 2001 From: RFCreate <107062289+RFCreate@users.noreply.github.com> Date: Sun, 9 Nov 2025 13:09:30 -0600 Subject: [PATCH 4/8] feat(mypy): enable stronger type checking --- pyproject.toml | 26 ++++---- tiny/__main__.py | 3 +- tiny/keyboard_handler.py | 4 +- tiny/server.py | 63 ++++++++++++------- tiny/view.py | 16 +++-- wlroots/__init__.py | 4 +- wlroots/allocator.py | 2 +- wlroots/backend.py | 14 ++++- wlroots/ffi_build.py | 13 ++-- wlroots/helper.py | 2 +- wlroots/include/check_headers.py | 3 +- wlroots/renderer.py | 8 +-- wlroots/util/box.py | 13 ++-- wlroots/util/clock.py | 2 +- wlroots/util/log.py | 4 +- wlroots/util/region.py | 11 +++- wlroots/wlr_types/buffer.py | 2 +- wlroots/wlr_types/compositor.py | 10 +-- wlroots/wlr_types/cursor.py | 9 ++- wlroots/wlr_types/data_device_manager.py | 20 +++--- .../foreign_toplevel_management_v1.py | 16 ++--- wlroots/wlr_types/fractional_scale_v1.py | 2 +- wlroots/wlr_types/idle_inhibit_v1.py | 3 +- wlroots/wlr_types/idle_notify_v1.py | 1 + wlroots/wlr_types/input_device.py | 5 +- wlroots/wlr_types/keyboard.py | 14 ++--- wlroots/wlr_types/layer_shell_v1.py | 9 +-- wlroots/wlr_types/matrix.py | 4 +- wlroots/wlr_types/output.py | 14 +++-- wlroots/wlr_types/output_layout.py | 11 +++- wlroots/wlr_types/output_management_v1.py | 9 +-- .../wlr_types/output_power_management_v1.py | 4 +- wlroots/wlr_types/pointer.py | 28 ++++----- wlroots/wlr_types/pointer_constraints_v1.py | 6 +- wlroots/wlr_types/presentation_time.py | 2 +- .../wlr_types/relative_pointer_manager_v1.py | 2 +- wlroots/wlr_types/scene.py | 24 +++---- wlroots/wlr_types/seat.py | 43 ++++++++----- wlroots/wlr_types/server_decoration.py | 4 +- wlroots/wlr_types/session_lock_v1.py | 10 +-- wlroots/wlr_types/switch.py | 6 +- wlroots/wlr_types/texture.py | 2 +- wlroots/wlr_types/touch.py | 13 ++-- wlroots/wlr_types/virtual_keyboard_v1.py | 4 +- wlroots/wlr_types/virtual_pointer_v1.py | 8 +-- wlroots/wlr_types/xcursor_manager.py | 18 ++++-- wlroots/wlr_types/xdg_activation_v1.py | 6 +- wlroots/wlr_types/xdg_decoration_v1.py | 8 +-- wlroots/wlr_types/xdg_shell.py | 43 ++++++------- wlroots/xwayland.py | 14 ++--- 50 files changed, 324 insertions(+), 238 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index de6b721d..c9f73b2f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,27 +77,23 @@ ignore = [ ] [tool.mypy] -check_untyped_defs = true -# disallow_any_decorated = true -# disallow_any_explicit = true -# disallow_any_expr = true -# disallow_any_generics = true -# disallow_any_unimported = true -# disallow_incomplete_defs = true +packages = ["wlroots", "tiny"] +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true +strict_equality = true disallow_subclassing_any = true -# disallow_untyped_calls = true -# disallow_untyped_decorators = true -# disallow_untyped_defs = true +disallow_untyped_decorators = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +# warn_return_any = true no_implicit_optional = true show_error_codes = true -strict_equality = true warn_incomplete_stub = true warn_no_return = true -warn_redundant_casts = true -# warn_return_any = true warn_unreachable = true -warn_unused_configs = true -warn_unused_ignores = true [[tool.mypy.overrides]] module = [ diff --git a/tiny/__main__.py b/tiny/__main__.py index 056613b6..26dcf046 100644 --- a/tiny/__main__.py +++ b/tiny/__main__.py @@ -8,6 +8,7 @@ import logging import sys +from collections.abc import Sequence from pywayland.server import Display @@ -26,7 +27,7 @@ from .server import TinywlServer -def main(argv) -> None: +def main(argv: Sequence[str] | None) -> None: with Display() as display: _, allocator, renderer, backend, _ = build_compositor(display) device_manager = DataDeviceManager(display) # noqa: F841 diff --git a/tiny/keyboard_handler.py b/tiny/keyboard_handler.py index 3d122fa8..ad90e74b 100644 --- a/tiny/keyboard_handler.py +++ b/tiny/keyboard_handler.py @@ -5,6 +5,8 @@ from pywayland.server import Listener if TYPE_CHECKING: + from typing import Any + from wlroots.wlr_types import InputDevice, Keyboard from wlroots.wlr_types.keyboard import KeyboardKeyEvent @@ -25,7 +27,7 @@ def __init__( keyboard.modifiers_event.add(Listener(self.keyboard_handle_modifiers)) keyboard.key_event.add(Listener(self.keyboard_handle_key)) - def keyboard_handle_modifiers(self, listener: Listener, data) -> None: + def keyboard_handle_modifiers(self, listener: Listener, data: Any) -> None: """Activates the keyboard and sends the modifiers event to the active surface""" self.tinywl_server.send_modifiers(self.keyboard.modifiers, self.input_device) diff --git a/tiny/server.py b/tiny/server.py index 092a7d5d..6c35cf1f 100644 --- a/tiny/server.py +++ b/tiny/server.py @@ -25,6 +25,7 @@ OutputState, Scene, SceneBuffer, + SceneNode, SceneNodeType, SceneOutput, SceneOutputLayout, @@ -39,12 +40,6 @@ from wlroots.wlr_types.cursor import WarpMode from wlroots.wlr_types.input_device import ButtonState, InputDeviceType from wlroots.wlr_types.keyboard import KeyboardModifier -from wlroots.wlr_types.pointer import ( - PointerButtonEvent, - PointerMotionAbsoluteEvent, - PointerMotionEvent, -) -from wlroots.wlr_types.seat import RequestSetSelectionEvent from wlroots.wlr_types.xdg_shell import XdgSurface, XdgSurfaceRole from .cursor_mode import CursorMode @@ -52,14 +47,26 @@ from .view import View if TYPE_CHECKING: + from typing import Any + from wlroots.wlr_types import InputDevice from wlroots.wlr_types.keyboard import KeyboardKeyEvent, KeyboardModifiers from wlroots.wlr_types.output import OutputEventRequestState + from wlroots.wlr_types.pointer import ( + PointerAxisEvent, + PointerButtonEvent, + PointerMotionAbsoluteEvent, + PointerMotionEvent, + ) + from wlroots.wlr_types.seat import ( + PointerRequestSetCursorEvent, + RequestSetSelectionEvent, + ) -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[View, SceneNode] = WeakKeyDictionary() -def get_keysyms(xkb_state, keycode): +def get_keysyms(xkb_state: ffi.CData, keycode: int) -> list[int]: syms_out = ffi.new("const xkb_keysym_t **") nsyms = lib.xkb_state_key_get_syms(xkb_state, keycode, syms_out) if nsyms > 0: @@ -138,12 +145,12 @@ def __init__( backend.new_input_event.add(Listener(self.server_new_input)) - def _terminate_signal_callback(self, sig_num: int, display: Display): + def _terminate_signal_callback(self, sig_num: int, display: Display) -> None: logging.info("Terminating event loop.") display.terminate() def view_at( - self, layout_x, layout_y + self, layout_x: float, layout_y: float ) -> tuple[View | None, Surface | None, float, float]: maybe_node = self._scene.tree.node.node_at( layout_x, @@ -205,7 +212,7 @@ def _process_cursor_resize(self) -> None: self.grabbed_view.xdg_surface.set_size(new_width, new_height) - def process_cursor_motion(self, time) -> None: + def process_cursor_motion(self, time: int) -> None: self.idle_notify.notify_activity(self._seat) if self.cursor_mode == CursorMode.MOVE: self._process_cursor_move() @@ -319,7 +326,9 @@ def focus_view(self, view: View, surface: Surface | None = None) -> None: # ############################################################# # surface handling callbacks - def server_new_xdg_surface(self, listener, xdg_surface: XdgSurface) -> None: + def server_new_xdg_surface( + self, listener: Listener, xdg_surface: XdgSurface + ) -> None: logger.info("new surface") if xdg_surface.role == XdgSurfaceRole.POPUP: @@ -352,7 +361,7 @@ def server_new_xdg_surface(self, listener, xdg_surface: XdgSurface) -> None: # ############################################################# # output and frame handling callbacks - def server_new_output(self, listener, output: Output) -> None: + def server_new_output(self, listener: Listener, output: Output) -> None: output.init_render(self._allocator, self._renderer) state = OutputState() @@ -376,7 +385,7 @@ def server_new_output(self, listener, output: Output) -> None: if self._scene_layout: self._scene_layout.add_output(l_output, scene_output) - def output_frame(self, listener, data) -> None: + def output_frame(self, listener: Listener, data: Any) -> None: output = self.outputs[0] scene_output = self._scene.get_scene_output(output) scene_output.commit() @@ -384,14 +393,16 @@ def output_frame(self, listener, data) -> None: now = Timespec.get_monotonic_time() scene_output.send_frame_done(now) - def output_request_state(self, listener, request: OutputEventRequestState) -> None: + def output_request_state( + self, listener: Listener, request: OutputEventRequestState + ) -> None: output = self.outputs[0] output.commit(request.state) # ############################################################# # input handling callbacks - def server_new_input(self, listener, input_device: InputDevice) -> None: + def server_new_input(self, listener: Listener, input_device: InputDevice) -> None: if input_device.type == InputDeviceType.POINTER: self._server_new_pointer(input_device) elif input_device.type == InputDeviceType.KEYBOARD: @@ -426,7 +437,9 @@ def _server_new_keyboard(self, input_device: InputDevice) -> None: # ############################################################# # cursor motion callbacks - def server_cursor_motion(self, listener, event_motion: PointerMotionEvent) -> None: + def server_cursor_motion( + self, listener: Listener, event_motion: PointerMotionEvent + ) -> None: logging.debug("cursor motion") self._cursor.move( event_motion.delta_x, @@ -436,7 +449,7 @@ def server_cursor_motion(self, listener, event_motion: PointerMotionEvent) -> No self.process_cursor_motion(event_motion.time_msec) def server_cursor_motion_absolute( - self, listener, event_motion_absolute: PointerMotionAbsoluteEvent + self, listener: Listener, event_motion_absolute: PointerMotionAbsoluteEvent ) -> None: logging.debug("cursor abs motion") self._cursor.warp( @@ -447,7 +460,9 @@ def server_cursor_motion_absolute( ) self.process_cursor_motion(event_motion_absolute.time_msec) - def server_cursor_button(self, listener, event: PointerButtonEvent) -> None: + def server_cursor_button( + self, listener: Listener, event: PointerButtonEvent + ) -> None: logging.info("Got button click event %s", event.button_state) self._seat.pointer_notify_button( event.time_msec, event.button, event.button_state @@ -460,7 +475,7 @@ def server_cursor_button(self, listener, event: PointerButtonEvent) -> None: elif view is not None: self.focus_view(view, surface) - def server_cursor_axis(self, listener, event) -> None: + def server_cursor_axis(self, listener: Listener, event: PointerAxisEvent) -> None: self._seat.pointer_notify_axis( event.time_msec, event.orientation, @@ -469,19 +484,21 @@ def server_cursor_axis(self, listener, event) -> None: event.source, ) - def server_cursor_frame(self, listener, data) -> None: + def server_cursor_frame(self, listener: Listener, data: Any) -> None: self._seat.pointer_notify_frame() # ############################################################# # seat callbacks - def seat_request_cursor(self, listener, event): + def seat_request_cursor( + self, listener: Listener, event: PointerRequestSetCursorEvent + ) -> None: # This event is rasied by the seat when a client provides a cursor image # TODO: check that seat client is correct self._cursor.set_surface(event.surface, event.hotspot) def seat_request_set_selection( - self, listener, event: RequestSetSelectionEvent + self, listener: Listener, event: RequestSetSelectionEvent ) -> None: print("request set selection") self._seat.set_selection(event._ptr.source, event.serial) diff --git a/tiny/view.py b/tiny/view.py index 7089e523..866c93a5 100644 --- a/tiny/view.py +++ b/tiny/view.py @@ -11,8 +11,10 @@ from .cursor_mode import CursorMode if TYPE_CHECKING: + from typing import Any + from wlroots.wlr_types import SceneNode, Surface - from wlroots.wlr_types.xdg_shell import XdgSurface + from wlroots.wlr_types.xdg_shell import XdgSurface, XdgToplevelResizeEvent from .server import TinywlServer @@ -39,20 +41,20 @@ def __init__( toplevel.request_move_event.add(Listener(self.xdg_toplevel_request_move)) toplevel.request_resize_event.add(Listener(self.xdg_toplevel_request_resize)) - def xdg_toplevel_map(self, listener, data) -> None: + def xdg_toplevel_map(self, listener: Listener, data: Any) -> None: logging.info("mapped new view") self.mapped = True self.tinywl_server.focus_view(self) - def xdg_toplevel_unmap(self, listener, data) -> None: + def xdg_toplevel_unmap(self, listener: Listener, data: Any) -> None: logging.info("unmapped view") self.mapped = False - def xdg_toplevel_destroy(self, listener, data) -> None: + def xdg_toplevel_destroy(self, listener: Listener, data: Any) -> None: logging.info("destroyed view") self.tinywl_server.views.remove(self) - def xdg_toplevel_request_move(self, listener, data) -> None: + def xdg_toplevel_request_move(self, listener: Listener, data: Any) -> None: # This event is raised when a client would like to begin an interactive # move, typically because the user clicked on their client-side # decorations. Note that a more sophisticated compositor should check @@ -62,7 +64,9 @@ def xdg_toplevel_request_move(self, listener, data) -> None: logging.info("request move start") self._begin_interactive(CursorMode.MOVE, Edges.NONE) - def xdg_toplevel_request_resize(self, listener, event) -> None: + def xdg_toplevel_request_resize( + self, listener: Listener, event: XdgToplevelResizeEvent + ) -> None: # This event is raised when a client would like to begin an interactive # resize, typically because the user clicked on their client-side # decorations. Note that a more sophisticated compositor should check diff --git a/wlroots/__init__.py b/wlroots/__init__.py index fbddd38d..0e8f2c4c 100644 --- a/wlroots/__init__.py +++ b/wlroots/__init__.py @@ -15,7 +15,7 @@ __version__ = _version -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() T = TypeVar("T") @@ -30,7 +30,7 @@ class Ptr: _ptr: ffi.CData - def __eq__(self, other) -> bool: + def __eq__(self, other: object) -> bool: """Return true if the other object holds the same cdata""" return hasattr(other, "_ptr") and self._ptr == other._ptr diff --git a/wlroots/allocator.py b/wlroots/allocator.py index f1a948d9..6ec2564c 100644 --- a/wlroots/allocator.py +++ b/wlroots/allocator.py @@ -9,7 +9,7 @@ class Allocator(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """Create an allocator. The allocator is the bridge between the renderer and the backend. It diff --git a/wlroots/backend.py b/wlroots/backend.py index 34f79944..98233d75 100644 --- a/wlroots/backend.py +++ b/wlroots/backend.py @@ -4,6 +4,7 @@ import enum import weakref +from types import TracebackType from pywayland.server import Display, Signal @@ -20,7 +21,9 @@ class BackendType(enum.Enum): class Backend(Ptr): - def __init__(self, display: Display, *, backend_type=BackendType.AUTO) -> None: + def __init__( + self, display: Display, *, backend_type: BackendType = BackendType.AUTO + ) -> None: """Create a backend to interact with a Wayland display :param display: @@ -91,7 +94,12 @@ def __enter__(self) -> Backend: raise RuntimeError("Unable to start backend") return self - def __exit__(self, exc_type, exc_value, exc_tb) -> None: + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: """Destroy the backend on context exit""" self.destroy() @@ -116,7 +124,7 @@ def is_multi(self) -> bool: class Session: - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """The running session""" self._ptr = ptr diff --git a/wlroots/ffi_build.py b/wlroots/ffi_build.py index b244e511..c9743679 100644 --- a/wlroots/ffi_build.py +++ b/wlroots/ffi_build.py @@ -6,6 +6,7 @@ import subprocess import sys from pathlib import Path +from typing import Any from cffi import FFI, VerificationError from pywayland.ffi_build import ffi_builder as pywayland_ffi @@ -15,7 +16,7 @@ assert INCLUDE_PATH.is_dir(), f"missing {INCLUDE_PATH}" -def load_version(): +def load_version() -> str: """Load the current pywlroots version""" file_location = Path(__file__).parent / "version.py" spec = importlib.util.spec_from_file_location("wlroots.version", str(file_location)) @@ -26,7 +27,7 @@ def load_version(): return version_module.version -def load_wlroots_version(): +def load_wlroots_version() -> str | None: """Load the current wlroots version Load the version from the in-line cffi module. @@ -36,17 +37,17 @@ def load_wlroots_version(): if not os.getenv("PYTHON_CROSSENV"): try: - lib = ffi.verify("#include ") + lib: Any = ffi.verify("#include ") except (PermissionError, OSError, VerificationError): lib = importlib.import_module("wlroots").lib return ( - f"{lib.WLR_VERSION_MAJOR}.{lib.WLR_VERSION_MINOR}.{lib.WLR_VERSION_MICRO}" # type: ignore[attr-defined] + f"{lib.WLR_VERSION_MAJOR}.{lib.WLR_VERSION_MINOR}.{lib.WLR_VERSION_MICRO}" ) else: return os.getenv("PYTHON_CROSSENV_WLROOTS_VERSION") -def check_version(): +def check_version() -> None: """Check for wlroots version compatibility""" # When importing a system-level installed package, we may not be able to # create neighboring files, which is done by the `.verify` step. If this @@ -54,6 +55,8 @@ def check_version(): version = load_version() wlroots_version = load_wlroots_version() + if wlroots_version is None: + return if version.split(".")[:2] != wlroots_version.split(".")[:2]: major, minor = list(map(int, version.split(".")[:2])) print( diff --git a/wlroots/helper.py b/wlroots/helper.py index daf347e5..2acc5666 100644 --- a/wlroots/helper.py +++ b/wlroots/helper.py @@ -13,7 +13,7 @@ def build_compositor( display: Display, *, - backend_type=BackendType.AUTO, + backend_type: BackendType = BackendType.AUTO, compositor_version: int = 5, ) -> tuple[Compositor, Allocator, Renderer, Backend, SubCompositor]: """Build and run a compositor diff --git a/wlroots/include/check_headers.py b/wlroots/include/check_headers.py index d6eff8b3..91a0aa4f 100644 --- a/wlroots/include/check_headers.py +++ b/wlroots/include/check_headers.py @@ -5,6 +5,7 @@ import subprocess import sys import tempfile +from collections.abc import Sequence INCLUDE_PATH = pathlib.Path(__file__).parent WAYLAND_PROCOTOLS = [ @@ -99,7 +100,7 @@ def generate(protocols: list[pathlib.Path]) -> None: generate_protocol_header(protocol_xml, INCLUDE_PATH) -def parse_args(argv) -> tuple[list[pathlib.Path], bool]: +def parse_args(argv: Sequence[str] | None) -> tuple[list[pathlib.Path], bool]: parser = argparse.ArgumentParser() parser.add_argument( "--wayland-dir", default=get_wayland_protocols_dir(), type=pathlib.Path diff --git a/wlroots/renderer.py b/wlroots/renderer.py index 52cb156a..4c460943 100644 --- a/wlroots/renderer.py +++ b/wlroots/renderer.py @@ -16,7 +16,7 @@ class Renderer(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """Obtains the renderer this backend is using The renderer is automatically destroyed as the backend is destroyed. @@ -54,7 +54,7 @@ def begin(self, width: int, height: int) -> bool: """Begin rendering with the given height and width""" return lib.wlr_renderer_begin(self._ptr, width, height) - def end(self): + def end(self) -> None: """Finish rendering""" lib.wlr_renderer_end(self._ptr) @@ -98,7 +98,7 @@ def scissor(self, box: Box | None) -> None: class DRMFormatSet(Ptr): """struct wlr_drm_format_set""" - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr def get(self, format: int) -> DRMFormat | None: @@ -111,5 +111,5 @@ def get(self, format: int) -> DRMFormat | None: class DRMFormat(Ptr): """struct wlr_drm_format""" - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr diff --git a/wlroots/util/box.py b/wlroots/util/box.py index 250d67c1..a9be6b41 100644 --- a/wlroots/util/box.py +++ b/wlroots/util/box.py @@ -3,18 +3,21 @@ from __future__ import annotations +from collections.abc import Callable +from typing import Any + from wlroots import ffi, lib -def _int_getter(attr): - def getter(self): +def _int_getter(attr: str) -> Callable[..., int]: + def getter(self: Any) -> int: return getattr(self._ptr, attr) return getter -def _int_setter(attr): - def setter(self, value): +def _int_setter(attr: str) -> Callable[..., None]: + def setter(self: Any, value: int) -> None: setattr(self._ptr, attr, value) return setter @@ -27,7 +30,7 @@ def __init__( y: int | None = None, width: int | None = None, height: int | None = None, - ptr=None, + ptr: ffi.CData | None = None, ) -> None: """A simple box structure, represented by a coordinate and dimensions""" if ptr is None: diff --git a/wlroots/util/clock.py b/wlroots/util/clock.py index 25947e6d..7b76fc8e 100644 --- a/wlroots/util/clock.py +++ b/wlroots/util/clock.py @@ -6,7 +6,7 @@ class Timespec(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A wrapper aronud a timespec struct""" self._ptr = ptr diff --git a/wlroots/util/log.py b/wlroots/util/log.py index deabd5c9..b3729db3 100644 --- a/wlroots/util/log.py +++ b/wlroots/util/log.py @@ -7,8 +7,8 @@ logger = logging.getLogger("wlroots") -@ffi.def_extern() -def log_func_callback(importance: int, formatted_str) -> None: +@ffi.def_extern() # type: ignore[misc] +def log_func_callback(importance: int, formatted_str: ffi.CData) -> None: """Callback that logs the string at the given level""" log_str = ffi.string(formatted_str).decode() if importance == lib.WLR_ERROR: diff --git a/wlroots/util/region.py b/wlroots/util/region.py index c2a1f299..7c5c853a 100644 --- a/wlroots/util/region.py +++ b/wlroots/util/region.py @@ -2,6 +2,8 @@ from __future__ import annotations +from types import TracebackType + from pywayland.protocol.wayland import WlOutput from wlroots import Ptr, ffi, lib @@ -9,7 +11,7 @@ class PixmanRegion32(Ptr): - def __init__(self, ptr=None) -> None: + def __init__(self, ptr: ffi.CData | None = None) -> None: """This is a convenience wrapper around pixman_region32_t :param ptr: @@ -34,7 +36,12 @@ def __enter__(self) -> PixmanRegion32: self.init() return self - def __exit__(self, exc_type, exc_value, exc_tb) -> None: + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: """Finish up when exiting the context""" self.fini() diff --git a/wlroots/wlr_types/buffer.py b/wlroots/wlr_types/buffer.py index cc0065ba..c80b6748 100644 --- a/wlroots/wlr_types/buffer.py +++ b/wlroots/wlr_types/buffer.py @@ -13,7 +13,7 @@ class BufferDataPtrAccessFlag(enum.IntFlag): class Buffer(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr def drop(self) -> None: diff --git a/wlroots/wlr_types/compositor.py b/wlroots/wlr_types/compositor.py index acfdd524..34e092b3 100644 --- a/wlroots/wlr_types/compositor.py +++ b/wlroots/wlr_types/compositor.py @@ -13,7 +13,7 @@ from .texture import Texture -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() if TYPE_CHECKING: from wlroots.renderer import Renderer @@ -51,7 +51,7 @@ def __init__(self, display: Display) -> None: class Surface(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """Create a wlroots Surface :param ptr: @@ -86,7 +86,7 @@ def previous(self) -> SurfaceState: _weakkeydict[previous_ptr] = self._ptr return SurfaceState(previous_ptr) - def get_texture(self): + def get_texture(self) -> Texture | None: """Get the texture of the buffer currently attached to this surface Returns None if no buffer is currently attached or if something went @@ -104,7 +104,7 @@ def send_frame_done(self, when: Timespec) -> None: class SurfaceState(Ptr): - def __init__(self, ptr): + def __init__(self, ptr: ffi.CData) -> None: """The state of a given surface :param ptr: @@ -129,7 +129,7 @@ def height(self) -> int: class SubSurface(PtrHasData): - def __init__(self, ptr): + def __init__(self, ptr: ffi.CData) -> None: """A wlroots subsurface :param ptr: diff --git a/wlroots/wlr_types/cursor.py b/wlroots/wlr_types/cursor.py index 6662bc0e..7cf2af12 100644 --- a/wlroots/wlr_types/cursor.py +++ b/wlroots/wlr_types/cursor.py @@ -1,7 +1,9 @@ # Copyright (c) Sean Vig 2019 + from __future__ import annotations import enum +from types import TracebackType from typing import TYPE_CHECKING from pywayland.server import Signal @@ -273,7 +275,12 @@ def __enter__(self) -> Cursor: """Context manager to clean up the cursor""" return self - def __exit__(self, exc_type, exc_value, exc_tb) -> None: + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: """Clean up the cursor when exiting the context""" self.destroy() diff --git a/wlroots/wlr_types/data_device_manager.py b/wlroots/wlr_types/data_device_manager.py index ab43e6f2..32998833 100644 --- a/wlroots/wlr_types/data_device_manager.py +++ b/wlroots/wlr_types/data_device_manager.py @@ -1,6 +1,8 @@ # Copyright (c) Sean Vig 2019 # Copyright (c) Matt Colligan 2021 +from __future__ import annotations + from weakref import WeakKeyDictionary from pywayland.server import Display, Signal @@ -9,7 +11,7 @@ from .compositor import Surface -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() class DataDeviceManager(Ptr): @@ -23,7 +25,7 @@ def __init__(self, display: Display) -> None: class Drag(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_drag *", ptr) self.focus_event = Signal(ptr=ffi.addressof(self._ptr.events.focus)) @@ -38,7 +40,7 @@ def __init__(self, ptr) -> None: self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) @property - def icon(self) -> "DragIcon | None": + def icon(self) -> DragIcon | None: icon_ptr = self._ptr.icon if icon_ptr == ffi.NULL: return None @@ -46,14 +48,14 @@ def icon(self) -> "DragIcon | None": return DragIcon(icon_ptr) @property - def source(self) -> "DataSource": + def source(self) -> DataSource: source_ptr = self._ptr.source _weakkeydict[source_ptr] = self._ptr return DataSource(source_ptr) class DragMotionEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_drag_motion_event *", ptr) @property @@ -72,7 +74,7 @@ def sy(self) -> float: class DragDropEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_drag_motion_event *", ptr) @property @@ -83,7 +85,7 @@ def drag(self) -> Drag: class DragIcon(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_drag_icon *", ptr) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) @@ -95,7 +97,7 @@ def drag(self) -> Drag: return Drag(drag_ptr) @property - def surface(self) -> "Surface": + def surface(self) -> Surface: surface_ptr = self._ptr.surface _weakkeydict[surface_ptr] = self._ptr return Surface(surface_ptr) @@ -106,7 +108,7 @@ def mapped(self) -> bool: class DataSource(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_data_source *", ptr) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) diff --git a/wlroots/wlr_types/foreign_toplevel_management_v1.py b/wlroots/wlr_types/foreign_toplevel_management_v1.py index 9e132451..88525a03 100644 --- a/wlroots/wlr_types/foreign_toplevel_management_v1.py +++ b/wlroots/wlr_types/foreign_toplevel_management_v1.py @@ -16,7 +16,7 @@ if TYPE_CHECKING: from pywayland.server import Display -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() class ForeignToplevelHandleV1State(enum.IntFlag): @@ -27,7 +27,7 @@ class ForeignToplevelHandleV1State(enum.IntFlag): class ForeignToplevelManagerV1(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """An foreign toplevel manager: wlr_foreign_toplevel_manager_v1.""" self._ptr = ffi.cast("struct wlr_foreign_toplevel_manager_v1 *", ptr) @@ -46,7 +46,7 @@ def create_handle(self) -> ForeignToplevelHandleV1: class ForeignToplevelHandleV1(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """struct wlr_foreign_toplevel_handle_v1""" self._ptr = ffi.cast("struct wlr_foreign_toplevel_handle_v1 *", ptr) @@ -138,7 +138,7 @@ def toplevel(self) -> ForeignToplevelHandleV1: class ForeignToplevelHandleV1MaximizedEvent(_EventBase): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """Event emitted when a maximize state change is requested.""" self._ptr = ffi.cast( "struct wlr_foreign_toplevel_handle_v1_maximized_event *", ptr @@ -151,7 +151,7 @@ def maximized(self) -> bool: class ForeignToplevelHandleV1MinimizedEvent(_EventBase): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """Event emitted when a minimize state change is requested.""" self._ptr = ffi.cast( "struct wlr_foreign_toplevel_handle_v1_minimized_event *", ptr @@ -164,7 +164,7 @@ def minimized(self) -> bool: class ForeignToplevelHandleV1ActivatedEvent(_EventBase): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """Event emitted when activation of a toplevel is requested.""" self._ptr = ffi.cast( "struct wlr_foreign_toplevel_handle_v1_activated_event *", ptr @@ -172,7 +172,7 @@ def __init__(self, ptr) -> None: class ForeignToplevelHandleV1FullscreenEvent(_EventBase): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """Event emitted when a fullscreen state change is requested.""" self._ptr = ffi.cast( "struct wlr_foreign_toplevel_handle_v1_fullscreen_event *", ptr @@ -190,7 +190,7 @@ def output(self) -> Output: class ForeignToplevelHandleV1SetRectangleEvent(_EventBase): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """Event emitted when new geometry for a toplevel is requested.""" self._ptr = ffi.cast( "struct wlr_foreign_toplevel_handle_v1_set_rectangle_event *", ptr diff --git a/wlroots/wlr_types/fractional_scale_v1.py b/wlroots/wlr_types/fractional_scale_v1.py index 17802064..df04f34f 100644 --- a/wlroots/wlr_types/fractional_scale_v1.py +++ b/wlroots/wlr_types/fractional_scale_v1.py @@ -13,5 +13,5 @@ def __init__(self, display: Display, version: int = 1) -> None: self._ptr = lib.wlr_fractional_scale_manager_v1_create(display._ptr, version) -def notify_scale(surface: Surface, scale: float): +def notify_scale(surface: Surface, scale: float) -> None: lib.wlr_fractional_scale_v1_notify_scale(surface._ptr, scale) diff --git a/wlroots/wlr_types/idle_inhibit_v1.py b/wlroots/wlr_types/idle_inhibit_v1.py index 93d7bf3b..d915365e 100644 --- a/wlroots/wlr_types/idle_inhibit_v1.py +++ b/wlroots/wlr_types/idle_inhibit_v1.py @@ -1,4 +1,5 @@ # Copyright (c) Antonin Riha 2022 + from pywayland.server import Display, Signal from wlroots import Ptr, PtrHasData, ffi, lib @@ -18,7 +19,7 @@ def __init__(self, display: Display) -> None: class IdleInhibitorV1(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_idle_inhibitor_v1 *", ptr) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) diff --git a/wlroots/wlr_types/idle_notify_v1.py b/wlroots/wlr_types/idle_notify_v1.py index d619629e..3d7e9583 100644 --- a/wlroots/wlr_types/idle_notify_v1.py +++ b/wlroots/wlr_types/idle_notify_v1.py @@ -1,4 +1,5 @@ # Copyright (c) Charbel Assaad 2023 + from pywayland.server import Display from wlroots import Ptr, lib diff --git a/wlroots/wlr_types/input_device.py b/wlroots/wlr_types/input_device.py index 7b0547a0..a67fc391 100644 --- a/wlroots/wlr_types/input_device.py +++ b/wlroots/wlr_types/input_device.py @@ -1,4 +1,5 @@ # Copyright (c) Sean Vig 2019 + from __future__ import annotations import enum @@ -8,7 +9,7 @@ from wlroots import PtrHasData, ffi, lib -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() @enum.unique @@ -28,7 +29,7 @@ class InputDeviceType(enum.IntEnum): class InputDevice(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """Create the input device from the given cdata :param ptr: diff --git a/wlroots/wlr_types/keyboard.py b/wlroots/wlr_types/keyboard.py index 418a5c3e..089db8fd 100644 --- a/wlroots/wlr_types/keyboard.py +++ b/wlroots/wlr_types/keyboard.py @@ -11,7 +11,7 @@ from wlroots import Ptr, PtrHasData, ffi, lib from wlroots.wlr_types.input_device import InputDevice -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() @enum.unique @@ -53,7 +53,7 @@ def add(self, modifier: str) -> None: class KeyboardKeyEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """Event that a key has been pressed or release This event is emitted before the xkb state of the keyboard has been @@ -83,7 +83,7 @@ def state(self) -> WlKeyboard.key_state: class Keyboard(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """The Keyboard wlroots object :param ptr: @@ -113,11 +113,11 @@ def from_input_device(cls, input_device: InputDevice) -> Keyboard: ptr = lib.wlr_keyboard_from_input_device(input_device._ptr) return cls(ptr) - def set_keymap(self, keymap) -> None: + def set_keymap(self, keymap: ffi.CData) -> None: """Set the keymap associated with the keyboard""" lib.wlr_keyboard_set_keymap(self._ptr, keymap._keymap) - def set_repeat_info(self, rate, delay) -> None: + def set_repeat_info(self, rate: int, delay: int) -> None: """Sets the keyboard repeat info :param rate: @@ -135,7 +135,7 @@ def notify_modifiers(self, mask: ModifiersMask) -> None: ) @property - def keycodes(self): + def keycodes(self) -> int: """Keycodes associated with the keyboard""" return self._ptr.keycodes @@ -161,7 +161,7 @@ def modifier(self) -> KeyboardModifier: class KeyboardModifiers(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """Modifiers of a given keyboard :param ptr: diff --git a/wlroots/wlr_types/layer_shell_v1.py b/wlroots/wlr_types/layer_shell_v1.py index ec8c75af..cd9092a4 100644 --- a/wlroots/wlr_types/layer_shell_v1.py +++ b/wlroots/wlr_types/layer_shell_v1.py @@ -1,4 +1,5 @@ # Copyright (c) 2021 Matt Colligan + from __future__ import annotations import enum @@ -17,7 +18,7 @@ if TYPE_CHECKING: from pywayland.server import Display -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() class LayerSurfaceV1KeyboardInteractivity(enum.IntEnum): @@ -51,7 +52,7 @@ class Margin: class LayerSurfaceV1State(Ptr): - def __init__(self, ptr): + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr @property @@ -93,7 +94,7 @@ def layer(self) -> LayerShellV1Layer: class LayerSurfaceV1(PtrHasData): - def __init__(self, ptr): + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_layer_surface_v1 *", ptr) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) @@ -114,7 +115,7 @@ def output(self) -> Output | None: return Output(output_ptr) @output.setter - def output(self, output: Output): + def output(self, output: Output) -> None: self._ptr.output = output._ptr @property diff --git a/wlroots/wlr_types/matrix.py b/wlroots/wlr_types/matrix.py index 1b05a733..bb22bee2 100644 --- a/wlroots/wlr_types/matrix.py +++ b/wlroots/wlr_types/matrix.py @@ -9,7 +9,7 @@ class Matrix(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A matrix which encodes transformations used for rendering""" self._ptr = ptr @@ -80,5 +80,5 @@ def __str__(self) -> str: ) @staticmethod - def _build_matrix_ptr(): + def _build_matrix_ptr() -> ffi.CData: return ffi.new("float [9]") diff --git a/wlroots/wlr_types/output.py b/wlroots/wlr_types/output.py index cfec5047..ffa8288e 100644 --- a/wlroots/wlr_types/output.py +++ b/wlroots/wlr_types/output.py @@ -3,6 +3,7 @@ from __future__ import annotations +from types import TracebackType from typing import TYPE_CHECKING, NamedTuple from pywayland.protocol.wayland import WlOutput @@ -22,7 +23,7 @@ class Output(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A compositor output region This typically corresponds to a monitor that displays part of the @@ -158,7 +159,12 @@ def __enter__(self) -> Output: """Start rendering frame""" return self - def __exit__(self, exc_type, exc_value, exc_tb) -> None: + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: """Stop rendering frame, commit when exiting normally, otherwise rollback""" if exc_type is None: if not self.commit(): @@ -308,7 +314,7 @@ def is_headless(self) -> bool: class OutputMode(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr @property @@ -413,7 +419,7 @@ def finish(self) -> None: class OutputEventRequestState(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_output_event_request_state *", ptr) @property diff --git a/wlroots/wlr_types/output_layout.py b/wlroots/wlr_types/output_layout.py index ae40dadf..f2ffa211 100644 --- a/wlroots/wlr_types/output_layout.py +++ b/wlroots/wlr_types/output_layout.py @@ -2,6 +2,8 @@ from __future__ import annotations +from types import TracebackType + from pywayland.server import Signal from wlroots import Ptr, ffi, lib @@ -61,7 +63,12 @@ def __enter__(self) -> OutputLayout: """Use the output layout in a context manager""" return self - def __exit__(self, exc_type, exc_value, exc_tb) -> None: + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: """Clean up the output layout when exiting the context""" self.destroy() @@ -130,6 +137,6 @@ def closest_point( class OutputLayoutOutput(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A `struct wlr_output_layout_output`""" self._ptr = ptr diff --git a/wlroots/wlr_types/output_management_v1.py b/wlroots/wlr_types/output_management_v1.py index d8fdda88..140edd9d 100644 --- a/wlroots/wlr_types/output_management_v1.py +++ b/wlroots/wlr_types/output_management_v1.py @@ -1,4 +1,5 @@ # Copyright (c) Matt Colligan 2021 + from __future__ import annotations from collections.abc import Iterator @@ -13,7 +14,7 @@ class OutputHeadV1State(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """wlr_output_head_v1_state""" self._ptr = ptr @@ -69,7 +70,7 @@ def custom_mode(self) -> CustomMode: return CustomMode(width=mode.width, height=mode.height, refresh=mode.refresh) @custom_mode.setter - def custom_mode(self, mode: CustomMode): + def custom_mode(self, mode: CustomMode) -> None: self._ptr.custom_mode.width = mode.width self._ptr.custom_mode.height = mode.height self._ptr.custom_mode.refresh = mode.refresh @@ -103,7 +104,7 @@ def apply(self, output_state: OutputState) -> None: class OutputConfigurationV1(Ptr): - def __init__(self, ptr=None) -> None: + def __init__(self, ptr: ffi.CData) -> None: """wlr_output_configuration_v1 If a pointer is not given, a new instance is created. Pointers are given when @@ -144,7 +145,7 @@ def destroy(self) -> None: class OutputConfigurationHeadV1(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """An instance of wlr_output_configuration_head_v1""" self._ptr = ptr diff --git a/wlroots/wlr_types/output_power_management_v1.py b/wlroots/wlr_types/output_power_management_v1.py index 5cdd0bec..a2328e28 100644 --- a/wlroots/wlr_types/output_power_management_v1.py +++ b/wlroots/wlr_types/output_power_management_v1.py @@ -17,7 +17,7 @@ class OutputPowerManagementV1Mode(enum.IntEnum): class OutputPowerV1(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_output_power_v1 *", ptr) @property @@ -42,7 +42,7 @@ def __init__(self, display: Display) -> None: class OutputPowerV1SetModeEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_output_power_v1_set_mode_event *", ptr) @property diff --git a/wlroots/wlr_types/pointer.py b/wlroots/wlr_types/pointer.py index 68280576..45651b13 100644 --- a/wlroots/wlr_types/pointer.py +++ b/wlroots/wlr_types/pointer.py @@ -10,7 +10,7 @@ from .input_device import ButtonState, InputDevice -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() @enum.unique @@ -28,7 +28,7 @@ class AxisOrientation(enum.IntEnum): class Pointer(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr @staticmethod @@ -59,7 +59,7 @@ def time_msec(self) -> int: class PointerMotionEvent(_PointerEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A relative motion pointer event""" self._ptr = ffi.cast("struct wlr_pointer_motion_event *", ptr) @@ -81,7 +81,7 @@ def unaccel_delta_y(self) -> float: class PointerMotionAbsoluteEvent(_PointerEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A absolute motion pointer event""" self._ptr = ffi.cast("struct wlr_pointer_motion_absolute_event *", ptr) @@ -95,7 +95,7 @@ def y(self) -> float: class PointerButtonEvent(_PointerEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A pointer button event""" self._ptr = ffi.cast("struct wlr_pointer_button_event *", ptr) @@ -109,7 +109,7 @@ def button_state(self) -> ButtonState: class PointerAxisEvent(_PointerEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A pointer axis event""" self._ptr = ffi.cast("struct wlr_pointer_axis_event *", ptr) @@ -131,7 +131,7 @@ def delta_discrete(self) -> int: class PointerSwipeBeginEvent(_PointerEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_pointer_swipe_begin_event *", ptr) @property @@ -140,7 +140,7 @@ def fingers(self) -> int: class PointerSwipeUpdateEvent(_PointerEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_pointer_swipe_update_event *", ptr) @property @@ -157,7 +157,7 @@ def dy(self) -> float: class PointerSwipeEndEvent(_PointerEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: ptr = ffi.cast("struct wlr_pointer_swipe_end_event *", ptr) self._ptr = ptr @@ -167,7 +167,7 @@ def cancelled(self) -> bool: class PointerPinchBeginEvent(_PointerEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_pointer_pinch_begin_event *", ptr) @property @@ -188,7 +188,7 @@ def dy(self) -> float: class PointerPinchUpdateEvent(_PointerEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_pointer_pinch_update_event *", ptr) @property @@ -221,7 +221,7 @@ def cancelled(self) -> bool: class PointerPinchEndEvent(_PointerEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: ptr = ffi.cast("struct wlr_pointer_pinch_end_event *", ptr) self._ptr = ptr @@ -231,7 +231,7 @@ def cancelled(self) -> bool: class PointerHoldBeginEvent(_PointerEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_pointer_hold_begin_event *", ptr) @property @@ -240,7 +240,7 @@ def fingers(self) -> int: class PointerHoldEndEvent(_PointerEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_pointer_hold_end_event *", ptr) @property diff --git a/wlroots/wlr_types/pointer_constraints_v1.py b/wlroots/wlr_types/pointer_constraints_v1.py index 98db3bb8..ef05f01a 100644 --- a/wlroots/wlr_types/pointer_constraints_v1.py +++ b/wlroots/wlr_types/pointer_constraints_v1.py @@ -16,7 +16,7 @@ if TYPE_CHECKING: from pywayland.server import Display -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() class PointerConstraintV1Type(enum.IntEnum): @@ -45,7 +45,7 @@ def __init__(self, display: Display) -> None: class PointerConstraintV1(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A `struct wlr_pointer_constraint_v1` instance.""" self._ptr = ffi.cast("struct wlr_pointer_constraint_v1 *", ptr) @@ -88,7 +88,7 @@ def pending(self) -> PointerConstraintV1State: class PointerConstraintV1State(Ptr): - def __init__(self, ptr): + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr @property diff --git a/wlroots/wlr_types/presentation_time.py b/wlroots/wlr_types/presentation_time.py index 1bcb7ff5..0f8376d0 100644 --- a/wlroots/wlr_types/presentation_time.py +++ b/wlroots/wlr_types/presentation_time.py @@ -13,7 +13,7 @@ class Presentation(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A presentation time manager: struct wlr_presentation.""" self._ptr = ffi.cast("struct wlr_presentation *", ptr) diff --git a/wlroots/wlr_types/relative_pointer_manager_v1.py b/wlroots/wlr_types/relative_pointer_manager_v1.py index 80c6fc96..df9a68c9 100644 --- a/wlroots/wlr_types/relative_pointer_manager_v1.py +++ b/wlroots/wlr_types/relative_pointer_manager_v1.py @@ -47,7 +47,7 @@ def send_relative_motion( class RelativePointerV1(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A `struct wlr_relative_pointer_v1` instance.""" self._ptr = ffi.cast("struct wlr_relative_pointer_v1 *", ptr) diff --git a/wlroots/wlr_types/scene.py b/wlroots/wlr_types/scene.py index 45440d22..5a513125 100644 --- a/wlroots/wlr_types/scene.py +++ b/wlroots/wlr_types/scene.py @@ -88,7 +88,7 @@ def layer_surface_v1_create( class SceneOutput(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A viewport for an output in the scene-graph""" self._ptr = ptr @@ -126,7 +126,7 @@ def set_position(self, lx: int, ly: int) -> None: class SceneTree(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """struct wlr_scene_tree""" self._ptr = ptr @@ -162,7 +162,7 @@ def children(self) -> Iterator[SceneNode]: class SceneBuffer(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """struct wlr_scene_buffer""" self._ptr = ptr @@ -205,8 +205,10 @@ def set_opacity(self, opacity: float) -> None: BufferCallback = Callable[[SceneBuffer, int, int, T], None] -@ffi.def_extern() -def buffer_iterator_callback(buffer_ptr, sx, sy, data_ptr): +@ffi.def_extern() # type: ignore[misc] +def buffer_iterator_callback( + buffer_ptr: ffi.CData, sx: int, sy: int, data_ptr: ffi.CData +) -> None: """Callback used to invoke the for_each_buffer method""" func, py_data = ffi.from_handle(data_ptr) buffer = SceneBuffer(buffer_ptr) @@ -214,7 +216,7 @@ def buffer_iterator_callback(buffer_ptr, sx, sy, data_ptr): class SceneNode(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A node is an object in the scene.""" self._ptr = ptr @@ -303,7 +305,7 @@ def for_each_buffer( self._ptr, lib.buffer_iterator_callback, handle ) - def subsurface_tree_set_clip(self, clip: Box | None): + def subsurface_tree_set_clip(self, clip: Box | None) -> None: """ Sets a cropping region for any subsurface trees that are children of this scene node. @@ -316,7 +318,7 @@ def subsurface_tree_set_clip(self, clip: Box | None): class SceneSurface(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """struct wlr_scene_surface""" self._ptr = ptr @@ -355,7 +357,7 @@ def set_color(self, color: ffi.CData) -> None: class SceneLayerSurfaceV1(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr @property @@ -380,7 +382,7 @@ def configure(self, full_area: Box, usable_area: Box) -> None: class SceneOutputLayout(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A `struct wlr_scene_output_layout_scene`""" self._ptr = ptr @@ -394,6 +396,6 @@ def add_output( class SceneOutputStateOptions(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A `struct wlr_scene_output_state_options`.""" self._ptr = ptr diff --git a/wlroots/wlr_types/seat.py b/wlroots/wlr_types/seat.py index e30a245d..29b05300 100644 --- a/wlroots/wlr_types/seat.py +++ b/wlroots/wlr_types/seat.py @@ -3,6 +3,7 @@ from __future__ import annotations from collections.abc import Iterator +from types import TracebackType from weakref import WeakKeyDictionary from pywayland.protocol.wayland import WlSeat @@ -17,7 +18,7 @@ from .keyboard import Keyboard, KeyboardKeyEvent, KeyboardModifiers from .pointer import AxisOrientation, AxisSource -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() class KeyboardGrab(Ptr): @@ -31,7 +32,12 @@ def __enter__(self) -> KeyboardGrab: lib.wlr_seat_keyboard_start_grab(self._seat._ptr, self._ptr) return self - def __exit__(self, exc_type, exc_value, exc_tb) -> None: + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: """End the grab of the keyboard of this seat""" lib.wlr_seat_keyboard_end_grab(self._seat._ptr) @@ -388,7 +394,7 @@ def touch_point_clear_focus( """Clear the focused surface for the touch point given by `touch_id`.""" lib.wlr_seat_touch_point_clear_focus(self._ptr, time_msec, touch_id) - def touch_notify_cancel(self, surface: Surface): + def touch_notify_cancel(self, surface: Surface) -> None: """Notify the seat that this is a global gesture and the client should cancel processing it. Defers to any grab of the touch device.""" lib.wlr_seat_touch_notify_cancel(self._ptr, surface._ptr) @@ -417,7 +423,7 @@ def touch_get_point(self, touch_id: int) -> TouchPoint | None: ptr = lib.wlr_seat_touch_get_point(self._ptr, touch_id) return instance_or_none(TouchPoint, ptr) - def set_selection(self, source, serial: int) -> None: + def set_selection(self, source: ffi.CData | None, serial: int) -> None: """Sets the current selection for the seat None can be provided to clear it. This removes the previous one if @@ -430,7 +436,7 @@ def set_selection(self, source, serial: int) -> None: # TODO: wrap source in a data source lib.wlr_seat_set_selection(self._ptr, source, serial) - def set_primary_selection(self, source, serial: int) -> None: + def set_primary_selection(self, source: ffi.CData | None, serial: int) -> None: """Sets the current primary selection for the seat. None can be provided to clear it. This removes the previous one if @@ -461,13 +467,18 @@ def __enter__(self) -> Seat: """Context manager to clean up the seat""" return self - def __exit__(self, exc_type, exc_value, exc_tb) -> None: + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: """Clean up the seat when exiting the context""" self.destroy() class PointerRequestSetCursorEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_seat_pointer_request_set_cursor_event *", ptr) # TODO: seat client @@ -487,7 +498,7 @@ def hotspot(self) -> tuple[int, int]: class RequestSetSelectionEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_seat_request_set_selection_event *", ptr) # TODO: source @@ -498,7 +509,7 @@ def serial(self) -> int: class RequestSetPrimarySelectionEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast( "struct wlr_seat_request_set_primary_selection_event *", ptr ) @@ -511,7 +522,7 @@ def serial(self) -> int: class RequestStartDragEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_seat_request_start_drag_event *", ptr) @property @@ -545,7 +556,7 @@ def new_surface(self) -> Surface: class PointerFocusChangeEvent(_FocusChangeEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_seat_pointer_focus_change_event *", ptr) @property @@ -558,12 +569,12 @@ def surface_y(self) -> float: class KeyboardFocusChangeEvent(_FocusChangeEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_seat_keyboard_focus_change_event *", ptr) class SeatPointerState(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """The current state of the pointer on the seat""" self._ptr = ptr @@ -587,7 +598,7 @@ def focused_surface(self) -> Surface | None: class SeatKeyboardState(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """The current state of the keyboard on the seat""" self._ptr = ptr @@ -603,7 +614,7 @@ def focused_surface(self) -> Surface | None: class SeatTouchState(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """The current state of touch on the seat""" self._ptr = ptr @@ -626,7 +637,7 @@ def touch_points(self) -> Iterator[TouchPoint]: class TouchPoint(Ptr): - def __init__(self, ptr): + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr @property diff --git a/wlroots/wlr_types/server_decoration.py b/wlroots/wlr_types/server_decoration.py index ae7ba5bd..40cfa3e6 100644 --- a/wlroots/wlr_types/server_decoration.py +++ b/wlroots/wlr_types/server_decoration.py @@ -8,7 +8,7 @@ import enum from typing import TYPE_CHECKING -from wlroots import PtrHasData, lib +from wlroots import PtrHasData, ffi, lib if TYPE_CHECKING: from pywayland.server import Display @@ -21,7 +21,7 @@ class ServerDecorationManagerMode(enum.IntEnum): class ServerDecorationManager(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """ A decoration negotiation interface which implements the KDE protocol: wlr_server_decoration_manager. diff --git a/wlroots/wlr_types/session_lock_v1.py b/wlroots/wlr_types/session_lock_v1.py index 692945a1..fdd59a81 100644 --- a/wlroots/wlr_types/session_lock_v1.py +++ b/wlroots/wlr_types/session_lock_v1.py @@ -27,7 +27,7 @@ from .compositor import Surface -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() class SessionLockManagerV1(PtrHasData): @@ -40,7 +40,7 @@ def __init__(self, display: Display) -> None: class SessionLockV1(PtrHasData): - def __init__(self, ptr): + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_session_lock_v1 *", ptr) self.new_surface_event = Signal( ptr=ffi.addressof(self._ptr.events.new_surface), @@ -49,10 +49,10 @@ def __init__(self, ptr): self.unlock_event = Signal(ptr=ffi.addressof(self._ptr.events.unlock)) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) - def send_locked(self): + def send_locked(self) -> None: lib.wlr_session_lock_v1_send_locked(self._ptr) - def destroy(self): + def destroy(self) -> None: lib.wlr_session_lock_v1_destroy(self._ptr) @@ -61,7 +61,7 @@ class SessionLockSurfaceV1(PtrHasData): A surface displayed while the session is locked """ - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_session_lock_surface_v1 *", ptr) self.map_event = Signal(ptr=ffi.addressof(self._ptr.events.map)) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) diff --git a/wlroots/wlr_types/switch.py b/wlroots/wlr_types/switch.py index 46de1dd9..452c901b 100644 --- a/wlroots/wlr_types/switch.py +++ b/wlroots/wlr_types/switch.py @@ -9,7 +9,7 @@ from .input_device import InputDevice -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() @enum.unique @@ -34,7 +34,7 @@ class Switch(PtrHasData): See https://wayland.freedesktop.org/libinput/doc/latest/switches.html """ - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr self.toggle_event = Signal( ptr=ffi.addressof(self._ptr.events.toggle), data_wrapper=SwitchToggleEvent @@ -57,7 +57,7 @@ def base(self) -> InputDevice: class SwitchToggleEvent(Ptr): - def __init__(self, ptr): + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr @property diff --git a/wlroots/wlr_types/texture.py b/wlroots/wlr_types/texture.py index dba2ccb7..bf6fa5e9 100644 --- a/wlroots/wlr_types/texture.py +++ b/wlroots/wlr_types/texture.py @@ -14,7 +14,7 @@ class Texture(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr @staticmethod diff --git a/wlroots/wlr_types/touch.py b/wlroots/wlr_types/touch.py index 766c2f2c..d6ec41a0 100644 --- a/wlroots/wlr_types/touch.py +++ b/wlroots/wlr_types/touch.py @@ -1,4 +1,5 @@ # Copyright (c) Matt Colligan 2021 + from __future__ import annotations from weakref import WeakKeyDictionary @@ -7,11 +8,11 @@ from .input_device import InputDevice -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() class Touch(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr @staticmethod @@ -54,7 +55,7 @@ def touch_id(self) -> int: class TouchDownEvent(_TouchEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_touch_down_event *", ptr) @property @@ -67,12 +68,12 @@ def y(self) -> float: class TouchUpEvent(_TouchEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_touch_up_event *", ptr) class TouchMotionEvent(_TouchEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_touch_motion_event *", ptr) @property @@ -85,5 +86,5 @@ def y(self) -> float: class TouchCancelEvent(_TouchEvent): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_touch_cancel_event *", ptr) diff --git a/wlroots/wlr_types/virtual_keyboard_v1.py b/wlroots/wlr_types/virtual_keyboard_v1.py index 76c5d013..8505d724 100644 --- a/wlroots/wlr_types/virtual_keyboard_v1.py +++ b/wlroots/wlr_types/virtual_keyboard_v1.py @@ -7,7 +7,7 @@ from wlroots import Ptr, ffi, lib from wlroots.wlr_types.keyboard import Keyboard -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() class VirtualKeyboardManagerV1(Ptr): @@ -23,7 +23,7 @@ def __init__(self, display: Display) -> None: class VirtualKeyboardV1(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A wlr_virtual_keyboard_v1 instance.""" self._ptr = ffi.cast("struct wlr_virtual_keyboard_v1 *", ptr) diff --git a/wlroots/wlr_types/virtual_pointer_v1.py b/wlroots/wlr_types/virtual_pointer_v1.py index 8255216d..8e3cfa9c 100644 --- a/wlroots/wlr_types/virtual_pointer_v1.py +++ b/wlroots/wlr_types/virtual_pointer_v1.py @@ -5,13 +5,13 @@ from collections.abc import Iterable from weakref import WeakKeyDictionary -from pywayland.protocol.wayland.wl_pointer import WlPointer +from pywayland.protocol.wayland import WlPointer from pywayland.server import Display, Signal from wlroots import Ptr, ffi, lib from wlroots.wlr_types.pointer import Pointer, PointerAxisEvent -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() class VirtualPointerManagerV1(Ptr): @@ -27,7 +27,7 @@ def __init__(self, display: Display) -> None: class VirtualPointerV1NewPointerEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A wlr_virtual_pointer_v1_new_pointer_event struct.""" self._ptr = ffi.cast("struct wlr_virtual_pointer_v1_new_pointer_event *", ptr) @@ -37,7 +37,7 @@ def new_pointer(self) -> VirtualPointerV1: class VirtualPointerV1(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A wlr_virtual_pointer_v1 struct.""" self._ptr = ffi.cast("struct wlr_virtual_pointer_v1 *", ptr) diff --git a/wlroots/wlr_types/xcursor_manager.py b/wlroots/wlr_types/xcursor_manager.py index b7e2ffd0..57bb60e5 100644 --- a/wlroots/wlr_types/xcursor_manager.py +++ b/wlroots/wlr_types/xcursor_manager.py @@ -2,6 +2,7 @@ from __future__ import annotations +from types import TracebackType from typing import TYPE_CHECKING from wlroots import Ptr, ffi, lib @@ -11,7 +12,7 @@ class XCursorManager(Ptr): - def __init__(self, theme: str | None, size: int = 24, scale: float = 1.0): + def __init__(self, theme: str | None, size: int = 24, scale: float = 1.0) -> None: """Creates a new XCursor manager using the theme and size and ensures an xcursor with scale is loaded @@ -24,7 +25,7 @@ def __init__(self, theme: str | None, size: int = 24, scale: float = 1.0): lib.wlr_xcursor_manager_load(self._ptr, scale) - def destroy(self): + def destroy(self) -> None: """Destroy the x cursor manager""" if self._ptr is not None: ffi.release(self._ptr) @@ -41,11 +42,16 @@ def get_xcursor(self, name: str, scale: float = 1) -> XCursor | None: return None return XCursor(ptr) - def __enter__(self): + def __enter__(self) -> XCursorManager: """Setup X cursor manager in a context manager""" return self - def __exit__(self, exc_type, exc_value, exc_tb): + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: """Clean-up the X cursor manager on contex manager exit""" self.destroy() @@ -59,7 +65,7 @@ def load(self, scale: float) -> bool: class XCursor(Ptr): """struct wlr_xcursor""" - def __init__(self, ptr): + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr @property @@ -71,5 +77,5 @@ def images(self) -> Iterator[XCursorImage]: class XCursorImage(Ptr): """struct wlr_xcursor_image""" - def __init__(self, ptr): + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr diff --git a/wlroots/wlr_types/xdg_activation_v1.py b/wlroots/wlr_types/xdg_activation_v1.py index 02a7a437..aafe8788 100644 --- a/wlroots/wlr_types/xdg_activation_v1.py +++ b/wlroots/wlr_types/xdg_activation_v1.py @@ -14,11 +14,11 @@ if TYPE_CHECKING: from pywayland.server import Display -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() class XdgActivationV1(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """An XDG activation manager: struct wlr_xdg_activation_v1.""" self._ptr = ffi.cast("struct wlr_xdg_activation_v1 *", ptr) @@ -36,7 +36,7 @@ def create(cls, display: Display) -> XdgActivationV1: class XdgActivationV1RequestActivateEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """struct wlr_xdg_activation_v1_request_activate_event""" self._ptr = ffi.cast( "struct wlr_xdg_activation_v1_request_activate_event *", ptr diff --git a/wlroots/wlr_types/xdg_decoration_v1.py b/wlroots/wlr_types/xdg_decoration_v1.py index 53b04b99..ba290ab1 100644 --- a/wlroots/wlr_types/xdg_decoration_v1.py +++ b/wlroots/wlr_types/xdg_decoration_v1.py @@ -15,7 +15,7 @@ if TYPE_CHECKING: from pywayland.server import Display -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() class XdgToplevelDecorationV1Mode(enum.IntEnum): @@ -25,7 +25,7 @@ class XdgToplevelDecorationV1Mode(enum.IntEnum): class XdgDecorationManagerV1(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """An XDG decoration manager: wlr_xdg_decoration_manager_v1.""" self._ptr = ffi.cast("struct wlr_xdg_decoration_manager_v1 *", ptr) @@ -36,14 +36,14 @@ def __init__(self, ptr) -> None: self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) @classmethod - def create(cls, display: Display): + def create(cls, display: Display) -> XdgDecorationManagerV1: """Create a wlr_xdg_decoration_manager_v1 for the given display.""" ptr = lib.wlr_xdg_decoration_manager_v1_create(display._ptr) return cls(ptr) class XdgToplevelDecorationV1(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """struct wlr_xdg_toplevel_decoration_v1""" self._ptr = ffi.cast("struct wlr_xdg_toplevel_decoration_v1 *", ptr) diff --git a/wlroots/wlr_types/xdg_shell.py b/wlroots/wlr_types/xdg_shell.py index d645fb61..32bd88d7 100644 --- a/wlroots/wlr_types/xdg_shell.py +++ b/wlroots/wlr_types/xdg_shell.py @@ -16,14 +16,16 @@ from .compositor import Surface from .output import Output -_weakkeydict: WeakKeyDictionary = WeakKeyDictionary() +_weakkeydict: WeakKeyDictionary[ffi.CData, ffi.CData] = WeakKeyDictionary() T = TypeVar("T") SurfaceCallback = Callable[[Surface, int, int, T], None] -@ffi.def_extern() -def surface_iterator_callback(surface_ptr, sx, sy, data_ptr): +@ffi.def_extern() # type: ignore[misc] +def surface_iterator_callback( + surface_ptr: ffi.CData, sx: int, sy: int, data_ptr: ffi.CData +) -> None: """Callback used to invoke the for_each_surface method""" func, py_data = ffi.from_handle(data_ptr) surface = Surface(surface_ptr) @@ -59,7 +61,7 @@ def __init__(self, display: Display, version: int = 5) -> None: class XdgSurface(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A user interface element requiring management by the compositor An xdg-surface is a user interface element requiring management by the @@ -113,13 +115,9 @@ def toplevel(self) -> XdgToplevel: if self.role != XdgSurfaceRole.TOPLEVEL: raise ValueError(f"xdg surface must be top-level, got: {self.role.name}") - toplevel = XdgToplevel(self._ptr.toplevel) - - # the toplevel does not own the ptr data, ensure the underlying cdata - # is kept alive - _weakkeydict[toplevel] = self - - return toplevel + toplevel_ptr = self._ptr.toplevel + _weakkeydict[toplevel_ptr] = self + return XdgToplevel(self._ptr.toplevel) @property def popup(self) -> XdgPopup: @@ -130,10 +128,9 @@ def popup(self) -> XdgPopup: if self.role != XdgSurfaceRole.POPUP: raise ValueError(f"xdg surface must be popup, got: {self.role}") - popup = XdgPopup(self._ptr.popup) - _weakkeydict[popup] = self - - return popup + popup_ptr = self._ptr.popup + _weakkeydict[popup_ptr] = self + return XdgPopup(popup_ptr) def get_geometry(self) -> Box: """Get the surface geometry @@ -224,7 +221,7 @@ def schedule_configure(self) -> int: class XdgSurfaceConfigure(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_xdg_surface_configure *", ptr) @property @@ -238,7 +235,7 @@ def serial(self) -> int: class XdgToplevel(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A top level surface object :param ptr: @@ -301,7 +298,7 @@ def requested(self) -> XdgToplevelRequested: class XdgToplevelMoveEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_xdg_toplevel_move_event *", ptr) @property @@ -317,7 +314,7 @@ def serial(self) -> int: class XdgToplevelResizeEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_xdg_toplevel_resize_event *", ptr) @property @@ -337,7 +334,7 @@ def edges(self) -> Edges: class XdgToplevelShowWindowMenuEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_xdg_toplevel_show_window_menu_event *", ptr) @property @@ -361,7 +358,7 @@ def y(self) -> int: class XdgPopup(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A wlr_xdg_popup :param ptr: @@ -405,7 +402,7 @@ def destroy(self) -> None: class XdgPopupState(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: """A struct wlr_xdg_popup_state :param ptr: @@ -427,7 +424,7 @@ def reactive(self) -> bool: class XdgToplevelRequested(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr @property diff --git a/wlroots/xwayland.py b/wlroots/xwayland.py index 17a94829..3bfb7a97 100644 --- a/wlroots/xwayland.py +++ b/wlroots/xwayland.py @@ -22,7 +22,7 @@ class ServerOptions(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ptr @classmethod @@ -154,7 +154,7 @@ class ICCCMInputModel(enum.IntEnum): class Surface(PtrHasData): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_xwayland_surface *", ptr) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) @@ -380,7 +380,7 @@ def for_each_surface( class SurfaceConfigureEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_xwayland_surface_configure_event *", ptr) @property @@ -409,7 +409,7 @@ def mask(self) -> int: class ResizeEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_xwayland_resize_event *", ptr) @property @@ -422,7 +422,7 @@ def edges(self) -> int: class MinimizeEvent(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("struct wlr_xwayland_minimize_event *", ptr) @property @@ -435,7 +435,7 @@ def minimize(self) -> bool: class Hints(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("xcb_icccm_wm_hints_t *", ptr) @property @@ -476,7 +476,7 @@ def window_group(self) -> int: class SizeHints(Ptr): - def __init__(self, ptr) -> None: + def __init__(self, ptr: ffi.CData) -> None: self._ptr = ffi.cast("xcb_size_hints_t *", ptr) @property From c9b43da9730e6f4e7afd20394774acfedae092d7 Mon Sep 17 00:00:00 2001 From: RFCreate <107062289+RFCreate@users.noreply.github.com> Date: Sun, 9 Nov 2025 17:12:58 -0600 Subject: [PATCH 5/8] feat: add mypy to pre-commit --- .pre-commit-config.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fb432251..c296354e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,3 +5,8 @@ repos: - id: ruff-check args: [--fix] - id: ruff-format + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.18.2 + hooks: + - id: mypy + files: "^(wlroots|tiny)\/.*" From 86a5b1635cd2a98f5be4119e4a2ea942c3420e34 Mon Sep 17 00:00:00 2001 From: RFCreate <107062289+RFCreate@users.noreply.github.com> Date: Sun, 9 Nov 2025 17:28:43 -0600 Subject: [PATCH 6/8] feat: handle dependencies in pyproject.toml --- .github/workflows/ci.yml | 12 ++++++------ pyproject.toml | 5 +++++ requirements.txt | 2 -- 3 files changed, 11 insertions(+), 8 deletions(-) delete mode 100644 requirements.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f4dd068..d8512ace 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -204,6 +204,8 @@ jobs: run: | sudo apt update sudo apt-get install -y --no-install-recommends \ + libinput-dev \ + libpixman-1-dev \ libxkbcommon-dev \ - name: Download wayland libraries uses: actions/download-artifact@v4 @@ -219,9 +221,7 @@ jobs: python-version: ${{ env.python-version }} - name: Install Python dependencies run: | - pip install wheel - pip install -r requirements.txt - pip install mypy types-cffi types-dataclasses + pip install .[typecheck] - name: Run mypy test run: | mypy -p wlroots @@ -244,6 +244,8 @@ jobs: run: | sudo apt update sudo apt-get install -y --no-install-recommends \ + libinput-dev \ + libpixman-1-dev \ libxkbcommon-dev \ - name: Checkout repo uses: actions/checkout@v4 @@ -253,9 +255,7 @@ jobs: python-version: ${{ env.python-version }} - name: Install Python dependencies run: | - pip install wheel - pip install -r requirements.txt - pip install check-manifest twine + pip install .[packaging] - name: Run packaging test run: | check-manifest diff --git a/pyproject.toml b/pyproject.toml index c9f73b2f..246f0ad5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,6 +43,11 @@ typecheck = [ "types-cffi", "types-dataclasses", ] +packaging = [ + "build", + "check-manifest", + "twine", +] [project.urls] homepage = "https://github.com/flacjacket/pywlroots" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index f6b2d986..00000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pywayland>=0.4.14 -xkbcommon>=0.2 From 499e4e11271fdc0be1ad311a81eb049509436e3d Mon Sep 17 00:00:00 2001 From: RFCreate <107062289+RFCreate@users.noreply.github.com> Date: Sun, 9 Nov 2025 17:31:19 -0600 Subject: [PATCH 7/8] feat(ci): use pre-commit for better maintainability --- .github/workflows/ci.yml | 26 +++++--------------------- pyproject.toml | 5 ----- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8512ace..5cf32a71 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -178,22 +178,8 @@ jobs: WLR_LIBINPUT_NO_DEVICES: '1' WLR_RENDERER: pixman WLR_RENDERER_ALLOW_SOFTWARE: '1' - ruff-test: - name: ruff tests - runs-on: ubuntu-24.04 - env: - python-version: "3.13" - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: ${{ env.python-version }} - - name: Run ruff check - uses: astral-sh/ruff-action@v3 - mypy-test: - name: mypy tests + pre-commit-test: + name: pre-commit tests runs-on: ubuntu-24.04 needs: build-wayland env: @@ -221,11 +207,9 @@ jobs: python-version: ${{ env.python-version }} - name: Install Python dependencies run: | - pip install .[typecheck] - - name: Run mypy test - run: | - mypy -p wlroots - mypy -p tiny + pip install . + - name: Run pre-commit test + uses: pre-commit/action@v3.0.1 packaging-test: name: packaging tests runs-on: ubuntu-24.04 diff --git a/pyproject.toml b/pyproject.toml index 246f0ad5..fc3fbb69 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,11 +38,6 @@ dynamic = ["version"] [project.optional-dependencies] test = ["pytest"] -typecheck = [ - "mypy", - "types-cffi", - "types-dataclasses", -] packaging = [ "build", "check-manifest", From e9d04a6798026361b8fe2f2e4f89cb8f36d95edf Mon Sep 17 00:00:00 2001 From: RFCreate <107062289+RFCreate@users.noreply.github.com> Date: Sun, 9 Nov 2025 17:32:33 -0600 Subject: [PATCH 8/8] feat: add python 3.14 support --- .github/workflows/ci.yml | 7 ++++--- .github/workflows/release.yml | 5 +++-- pyproject.toml | 1 + 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5cf32a71..0db4c4c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,6 +114,7 @@ jobs: - "3.11" - "3.12" - "3.13" + - "3.14" - "pypy-3.11" wlroots-version: ["0.17.4"] steps: @@ -183,7 +184,7 @@ jobs: runs-on: ubuntu-24.04 needs: build-wayland env: - python-version: "3.13" + python-version: "3.14" wlroots-version: "0.17.4" steps: - name: Install dependencies @@ -215,7 +216,7 @@ jobs: runs-on: ubuntu-24.04 needs: build-wayland env: - python-version: "3.13" + python-version: "3.14" wlroots-version: "0.17.4" steps: - name: Download wayland libraries @@ -251,7 +252,7 @@ jobs: runs-on: ubuntu-24.04 needs: build-wayland env: - python-version: "3.13" + python-version: "3.14" wlroots-version: "0.17.4" steps: - name: Download wayland libraries diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 372831cc..1328adbf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -168,7 +168,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - name: Download wayland libraries uses: actions/download-artifact@v4 @@ -282,6 +282,7 @@ jobs: - "3.11" - "3.12" - "3.13" + - "3.14" - "pypy-3.11" steps: - name: Install dependencies @@ -322,7 +323,7 @@ jobs: container: quay.io/pypa/manylinux_2_34_x86_64 needs: build-wayland env: - python-version: "3.13" + python-version: "3.14" steps: - name: Download wayland libraries uses: actions/download-artifact@v4 diff --git a/pyproject.toml b/pyproject.toml index fc3fbb69..a45d17da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Desktop Environment :: Window Managers",