From 4f5362e4c91f3b77e51e2e9e324433da35af41e9 Mon Sep 17 00:00:00 2001 From: Avasam Date: Wed, 16 Nov 2022 18:14:21 -0500 Subject: [PATCH 01/17] py.typed and type comments --- Xlib/XK.py | 3 + Xlib/display.py | 108 +++++++++++++++++++-- Xlib/error.py | 20 +++- Xlib/ext/composite.py | 23 +++++ Xlib/ext/damage.py | 11 ++- Xlib/ext/dpms.py | 11 +++ Xlib/ext/ge.py | 16 ++++ Xlib/ext/nvcontrol.py | 54 +++++++++++ Xlib/ext/randr.py | 44 +++++++++ Xlib/ext/record.py | 23 +++++ Xlib/ext/res.py | 17 ++++ Xlib/ext/screensaver.py | 20 ++++ Xlib/ext/security.py | 15 +++ Xlib/ext/shape.py | 20 ++++ Xlib/ext/xfixes.py | 11 ++- Xlib/ext/xinerama.py | 10 ++ Xlib/ext/xinput.py | 43 ++++++++- Xlib/ext/xtest.py | 7 ++ Xlib/protocol/display.py | 99 +++++++++++++++++--- Xlib/protocol/request.py | 2 + Xlib/protocol/rq.py | 177 +++++++++++++++++++++++++++++++---- Xlib/protocol/structs.py | 5 + Xlib/py.typed | 1 + Xlib/rdb.py | 56 ++++++++++- Xlib/support/connect.py | 20 +++- Xlib/support/lock.py | 1 + Xlib/support/unix_connect.py | 42 +++++---- Xlib/support/vms_connect.py | 12 ++- Xlib/xauth.py | 7 +- Xlib/xobject/colormap.py | 24 +++++ Xlib/xobject/cursor.py | 14 +++ Xlib/xobject/drawable.py | 97 +++++++++++++++++++ Xlib/xobject/fontable.py | 21 +++++ Xlib/xobject/resource.py | 17 ++++ setup.py | 1 + 35 files changed, 982 insertions(+), 70 deletions(-) create mode 100644 Xlib/py.typed diff --git a/Xlib/XK.py b/Xlib/XK.py index 7603ccd0..a7f0fd72 100644 --- a/Xlib/XK.py +++ b/Xlib/XK.py @@ -26,6 +26,7 @@ from Xlib.X import NoSymbol def string_to_keysym(keysym): + # type: (str) -> int '''Return the (16 bit) numeric code of keysym. Given the name of a keysym as a string, return its numeric code. @@ -34,6 +35,7 @@ def string_to_keysym(keysym): return globals().get('XK_' + keysym, NoSymbol) def load_keysym_group(group): + # type: (str) -> None '''Load all the keysyms in group. Given a group name such as 'latin1' or 'katakana' load the keysyms @@ -68,6 +70,7 @@ def _load_keysyms_into_XK(mod): def keysym_to_string(keysym): + # type: (int) -> str | None '''Translate a keysym (16 bit number) into a python string. This will pass 0 to 0xff as well as XK_BackSpace, XK_Tab, XK_Clear, diff --git a/Xlib/display.py b/Xlib/display.py index e0f7b5c8..7a79601c 100644 --- a/Xlib/display.py +++ b/Xlib/display.py @@ -41,6 +41,28 @@ from .xobject import colormap from .xobject import cursor +try: + from typing import TYPE_CHECKING, overload, TypeVar, Optional, Union, Any +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from collections.abc import Sequence, Callable + from typing_extensions import Literal, TypeAlias + from re import Pattern + _T = TypeVar("_T") + _ErrorHandler: TypeAlias = Callable[[error.XError, Optional[rq.Request]], _T] + _ResourceBaseClass: TypeAlias = Union[ + resource.Resource, + drawable.Drawable, + drawable.Window, + drawable.Pixmap, + fontable.Fontable, + fontable.Font, + fontable.GC, + colormap.Colormap, + cursor.Cursor, + ] + _resource_baseclasses = { 'resource': resource.Resource, 'drawable': drawable.Drawable, @@ -67,11 +89,13 @@ class _BaseDisplay(protocol_display.Display): # dealing with some ICCCM properties not defined in Xlib.Xatom def __init__(self, *args, **keys): + # type: (str | None, object, object) -> None self.resource_classes = _resource_baseclasses.copy() protocol_display.Display.__init__(self, *args, **keys) self._atom_cache = {} def get_atom(self, atomname, only_if_exists=0): + # type: (str, bool) -> int if atomname in self._atom_cache: return self._atom_cache[atomname] @@ -86,22 +110,23 @@ def get_atom(self, atomname, only_if_exists=0): class Display(object): def __init__(self, display = None): + # type: (str | None) -> None self.display = _BaseDisplay(display) # Create the keymap cache - self._keymap_codes = [()] * 256 - self._keymap_syms = {} + self._keymap_codes = [()] * 256 # type: list[tuple[int, ...]] + self._keymap_syms = {} # type: dict[int, list[tuple[int, ...]]] self._update_keymap(self.display.info.min_keycode, (self.display.info.max_keycode - self.display.info.min_keycode + 1)) # Translations for keysyms to strings. - self.keysym_translations = {} + self.keysym_translations = {} # type: dict[int, str] # Find all supported extensions - self.extensions = [] - self.class_extension_dicts = {} - self.display_extension_methods = {} + self.extensions = [] # type: list[str] + self.class_extension_dicts = {} # type: dict[str, dict[str, types.FunctionType]] + self.display_extension_methods = {} # type: dict[str, Callable[..., Any]] # a dict that maps the event name to the code # or, when it's an event with a subcode, to a tuple of (event,subcode) @@ -161,6 +186,7 @@ def close(self): self.display.close() def set_error_handler(self, handler): + # type: (_ErrorHandler[object] | None) -> None """Set the default error handler which will be called for all unhandled errors. handler should take two arguments as a normal request error handler, but the second argument (the request) will @@ -192,11 +218,32 @@ def pending_events(self): return self.display.pending_events() def has_extension(self, extension): + # type: (str) -> bool """Check if both the server and the client library support the X extension named extension.""" return extension in self.extensions + if TYPE_CHECKING: + @overload + def create_resource_object(self, type: Literal['resource'], id: int) -> resource.Resource: ... + @overload + def create_resource_object(self, type: Literal['drawable'], id: int) -> drawable.Drawable: ... + @overload + def create_resource_object(self, type: Literal['window'], id: int) -> drawable.Window: ... + @overload + def create_resource_object(self, type: Literal['pixmap'], id: int) -> drawable.Pixmap: ... + @overload + def create_resource_object(self, type: Literal['fontable'], id: int) -> fontable.Fontable: ... + @overload + def create_resource_object(self, type: Literal['font'], id: int) -> fontable.Font: ... + @overload + def create_resource_object(self, type: Literal['gc'], id: int) -> fontable.GC: ... + @overload + def create_resource_object(self, type: Literal['colormap'], id: int) -> colormap.Colormap: ... + @overload + def create_resource_object(self, type: Literal['cursor'], id: int) -> cursor.Cursor: ... def create_resource_object(self, type, id): + # type: (str, int) -> resource.Resource """Create a resource object of type for the integer id. type should be one of the following strings: @@ -220,6 +267,7 @@ class directly, since any X extensions dynamically added by the # We need this to handle display extension methods def __getattr__(self, attr): + # type: (str) -> types.MethodType try: function = self.display_extension_methods[attr] return types.MethodType(function, self) @@ -231,6 +279,7 @@ def __getattr__(self, attr): ### def screen(self, sno = None): + # type: (int | None) -> rq.Struct if sno is None: return self.display.info.roots[self.display.default_screen] else: @@ -250,6 +299,7 @@ def get_default_screen(self): ### def extension_add_method(self, object, name, function): + # type: (str, str, Callable[..., Any]) -> None """extension_add_method(object, name, function) Add an X extension module method. OBJECT is the type of @@ -292,6 +342,7 @@ def extension_add_method(self, object, name, function): self.class_extension_dicts[class_name] = { name: method } def extension_add_event(self, code, evt, name = None): + # type: (int, type, str | None) -> None """extension_add_event(code, evt, [name]) Add an extension event. CODE is the numeric code, and EVT is @@ -315,6 +366,7 @@ def extension_add_event(self, code, evt, name = None): setattr(self.extension_event, name, code) def extension_add_subevent(self, code, subcode, evt, name = None): + # type: (int, int | None, type[rq.Event], str | None) -> None """extension_add_subevent(code, evt, [name]) Add an extension subevent. CODE is the numeric code, subcode @@ -341,6 +393,7 @@ def extension_add_subevent(self, code, subcode, evt, name = None): setattr(self.extension_event, name, (code,subcode)) def extension_add_error(self, code, err): + # type: (int, type[error.XError]) -> None """extension_add_error(code, err) Add an extension error. CODE is the numeric code, and ERR is @@ -364,6 +417,7 @@ def extension_add_error(self, code, err): # index is the keysyms index in the map for that keycode. def keycode_to_keysym(self, keycode, index): + # type: (int, int) -> int """Convert a keycode to a keysym, looking in entry index. Normally index 0 is unshifted, 1 is shifted, 2 is alt grid, and 3 is shift+alt grid. If that key entry is not bound, X.NoSymbol is @@ -374,6 +428,7 @@ def keycode_to_keysym(self, keycode, index): return X.NoSymbol def keysym_to_keycode(self, keysym): + # type: (int) -> int """Look up the primary keycode that is bound to keysym. If several keycodes are found, the one with the lowest index and lowest code is returned. If keysym is not bound to any key, 0 is @@ -384,6 +439,7 @@ def keysym_to_keycode(self, keysym): return 0 def keysym_to_keycodes(self, keysym): + # type: (int) -> map[tuple[int, int]] | list[tuple[int, int]] """Look up all the keycodes that is bound to keysym. A list of tuples (keycode, index) is returned, sorted primarily on the lowest index and secondarily on the lowest keycode.""" @@ -394,6 +450,7 @@ def keysym_to_keycodes(self, keysym): return [] def refresh_keyboard_mapping(self, evt): + # type: (rq.Event) -> None """This method should be called once when a MappingNotify event is received, to update the keymap cache. evt should be the event object.""" @@ -446,6 +503,7 @@ def _update_keymap(self, first_keycode, count): ### def lookup_string(self, keysym): + # type: (int) -> str | None """Return a string corresponding to KEYSYM, or None if no reasonable translation is found. """ @@ -457,6 +515,7 @@ def lookup_string(self, keysym): return Xlib.XK.keysym_to_string(keysym) def rebind_string(self, keysym, newstring): + # type: (int, str | None) -> None """Change the translation of KEYSYM to NEWSTRING. If NEWSTRING is None, remove old translation if any. """ @@ -474,6 +533,7 @@ def rebind_string(self, keysym, newstring): ### def intern_atom(self, name, only_if_exists = 0): + # type: (str, int) -> int """Intern the string name, returning its atom number. If only_if_exists is true and the atom does not already exist, it will not be created and X.NONE is returned.""" @@ -483,11 +543,13 @@ def intern_atom(self, name, only_if_exists = 0): return r.atom def get_atom(self, atom, only_if_exists = 0): + # type: (str, int) -> int """Alias for intern_atom, using internal cache""" return self.display.get_atom(atom, only_if_exists) def get_atom_name(self, atom): + # type: (int) -> str """Look up the name of atom, returning it as a string. Will raise BadAtom if atom does not exist.""" r = request.GetAtomName(display = self.display, @@ -495,6 +557,7 @@ def get_atom_name(self, atom): return r.name def get_selection_owner(self, selection): + # type: (int) -> int """Return the window that owns selection (an atom), or X.NONE if there is no owner for the selection. Can raise BadAtom.""" r = request.GetSelectionOwner(display = self.display, @@ -503,6 +566,7 @@ def get_selection_owner(self, selection): def send_event(self, destination, event, event_mask = 0, propagate = 0, onerror = None): + # type: (int, rq.Event, int, bool, _ErrorHandler[object] | None) -> None """Send a synthetic event to the window destination which can be a window object, or X.PointerWindow or X.InputFocus. event is the event object to send, instantiated from one of the classes in @@ -517,6 +581,7 @@ def send_event(self, destination, event, event_mask = 0, propagate = 0, event = event) def ungrab_pointer(self, time, onerror = None): + # type: (int, _ErrorHandler[object] | None) -> None """Release a grabbed pointer and any queued events. See XUngrabPointer(3X11).""" request.UngrabPointer(display = self.display, @@ -524,6 +589,7 @@ def ungrab_pointer(self, time, onerror = None): time = time) def change_active_pointer_grab(self, event_mask, cursor, time, onerror = None): + # type: (int, cursor.Cursor, int, _ErrorHandler[object] | None) -> None """Change the dynamic parameters of a pointer grab. See XChangeActivePointerGrab(3X11).""" request.ChangeActivePointerGrab(display = self.display, @@ -533,6 +599,7 @@ def change_active_pointer_grab(self, event_mask, cursor, time, onerror = None): event_mask = event_mask) def ungrab_keyboard(self, time, onerror = None): + # type: (int, _ErrorHandler[object] | None) -> None """Ungrab a grabbed keyboard and any queued events. See XUngrabKeyboard(3X11).""" request.UngrabKeyboard(display = self.display, @@ -540,6 +607,7 @@ def ungrab_keyboard(self, time, onerror = None): time = time) def allow_events(self, mode, time, onerror = None): + # type: (int, int, _ErrorHandler[object] | None) -> None """Release some queued events. mode should be one of X.AsyncPointer, X.SyncPointer, X.AsyncKeyboard, X.SyncKeyboard, X.ReplayPointer, X.ReplayKeyboard, X.AsyncBoth, or X.SyncBoth. @@ -550,6 +618,7 @@ def allow_events(self, mode, time, onerror = None): time = time) def grab_server(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None """Disable processing of requests on all other client connections until the server is ungrabbed. Server grabbing should be avoided as much as possible.""" @@ -557,12 +626,14 @@ def grab_server(self, onerror = None): onerror = onerror) def ungrab_server(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None """Release the server if it was previously grabbed by this client.""" request.UngrabServer(display = self.display, onerror = onerror) def warp_pointer(self, x, y, src_window = X.NONE, src_x = 0, src_y = 0, src_width = 0, src_height = 0, onerror = None): + # type: (int, int, int, int, int, int, int, _ErrorHandler[object] | None) -> None """Move the pointer relative its current position by the offsets (x, y). However, if src_window is a window the pointer is only moved if the specified rectangle in src_window contains it. If @@ -582,6 +653,7 @@ def warp_pointer(self, x, y, src_window = X.NONE, src_x = 0, src_y = 0, dst_y = y) def set_input_focus(self, focus, revert_to, time, onerror = None): + # type: (int, int, int, _ErrorHandler[object] | None) -> None """Set input focus to focus, which should be a window, X.PointerRoot or X.NONE. revert_to specifies where the focus reverts to if the focused window becomes not visible, and should @@ -596,6 +668,7 @@ def set_input_focus(self, focus, revert_to, time, onerror = None): time = time) def get_input_focus(self): + # type: () -> request.GetInputFocus """Return an object with the following attributes: focus @@ -607,6 +680,7 @@ def get_input_focus(self): return request.GetInputFocus(display = self.display) def query_keymap(self): + # type: () -> bytes # TODO: Validate if this is correct """Return a bit vector for the logical state of the keyboard, where each bit set to 1 indicates that the corresponding key is currently pressed down. The vector is represented as a list of 32 @@ -616,6 +690,7 @@ def query_keymap(self): return r.map def open_font(self, name): + # type: (str) -> _ResourceBaseClass | None """Open the font identifed by the pattern name and return its font object. If name does not match any font, None is returned.""" fid = self.display.allocate_resource_id() @@ -635,6 +710,7 @@ def open_font(self, name): return cls(self.display, fid, owner = 1) def list_fonts(self, pattern, max_names): + # type: (Pattern[str] | str, int) -> list[str] """Return a list of font names matching pattern. No more than max_names will be returned.""" r = request.ListFonts(display = self.display, @@ -643,6 +719,7 @@ def list_fonts(self, pattern, max_names): return r.fonts def list_fonts_with_info(self, pattern, max_names): + # type: (Pattern[str] | str, int) -> request.ListFontsWithInfo """Return a list of fonts matching pattern. No more than max_names will be returned. Each list item represents one font and has the following properties: @@ -676,6 +753,7 @@ def list_fonts_with_info(self, pattern, max_names): pattern = pattern) def set_font_path(self, path, onerror = None): + # type: (Sequence[str], _ErrorHandler[object] | None) -> None """Set the font path to path, which should be a list of strings. If path is empty, the default font path of the server will be restored.""" @@ -684,11 +762,13 @@ def set_font_path(self, path, onerror = None): path = path) def get_font_path(self): + # type: () -> list[str] """Return the current font path as a list of strings.""" r = request.GetFontPath(display = self.display) return r.paths def query_extension(self, name): + # type: (str) -> request.QueryExtension | None """Ask the server if it supports the extension name. If it is supported an object with the following attributes is returned: @@ -708,11 +788,13 @@ def query_extension(self, name): return None def list_extensions(self): + # type: () -> list[str] """Return a list of all the extensions provided by the server.""" r = request.ListExtensions(display = self.display) return r.names def change_keyboard_mapping(self, first_keycode, keysyms, onerror = None): + # type: (int, Sequence[Sequence[int]], _ErrorHandler[object] | None) -> None """Modify the keyboard mapping, starting with first_keycode. keysyms is a list of tuples of keysyms. keysyms[n][i] will be assigned to keycode first_keycode+n at index i.""" @@ -722,6 +804,7 @@ def change_keyboard_mapping(self, first_keycode, keysyms, onerror = None): keysyms = keysyms) def get_keyboard_mapping(self, first_keycode, count): + # type: (int, int) -> list[tuple[int, ...]] """Return the current keyboard mapping as a list of tuples, starting at first_keycount and no more than count.""" r = request.GetKeyboardMapping(display = self.display, @@ -730,6 +813,7 @@ def get_keyboard_mapping(self, first_keycode, count): return r.keysyms def change_keyboard_control(self, onerror = None, **keys): + # type: (_ErrorHandler[object] | None, object) -> None """Change the parameters provided as keyword arguments: key_click_percent @@ -786,6 +870,7 @@ def get_keyboard_control(self): return request.GetKeyboardControl(display = self.display) def bell(self, percent = 0, onerror = None): + # type: (int, _ErrorHandler[object] | None) -> None """Ring the bell at the volume percent which is relative the base volume. See XBell(3X11).""" request.Bell(display = self.display, @@ -793,6 +878,7 @@ def bell(self, percent = 0, onerror = None): percent = percent) def change_pointer_control(self, accel = None, threshold = None, onerror = None): + # type: (tuple[int, int] | None, int | None, _ErrorHandler[object] | None) -> None """To change the pointer acceleration, set accel to a tuple (num, denum). The pointer will then move num/denum times the normal speed if it moves beyond the threshold number of pixels at once. @@ -833,6 +919,7 @@ def get_pointer_control(self): return request.GetPointerControl(display = self.display) def set_screen_saver(self, timeout, interval, prefer_blank, allow_exposures, onerror = None): + # type: (int, int, int, int, _ErrorHandler[object] | None) -> None """See XSetScreenSaver(3X11).""" request.SetScreenSaver(display = self.display, onerror = onerror, @@ -848,6 +935,7 @@ def get_screen_saver(self): return request.GetScreenSaver(display = self.display) def change_hosts(self, mode, host_family, host, onerror = None): + # type: (int, int, Sequence[int] | Sequence[bytes], _ErrorHandler[object] | None) -> None # TODO: validate the list of bytes """mode is either X.HostInsert or X.HostDelete. host_family is one of X.FamilyInternet, X.FamilyDECnet, X.FamilyChaos, X.FamilyServerInterpreted or X.FamilyInternetV6. @@ -877,6 +965,7 @@ def list_hosts(self): return request.ListHosts(display = self.display) def set_access_control(self, mode, onerror = None): + # type: (int, _ErrorHandler[object] | None) -> None """Enable use of access control lists at connection setup if mode is X.EnableAccess, disable if it is X.DisableAccess.""" request.SetAccessControl(display = self.display, @@ -884,6 +973,7 @@ def set_access_control(self, mode, onerror = None): mode = mode) def set_close_down_mode(self, mode, onerror = None): + # type: (int, _ErrorHandler[object] | None) -> None """Control what will happen with the client's resources at connection close. The default is X.DestroyAll, the other values are X.RetainPermanent and X.RetainTemporary.""" @@ -892,6 +982,7 @@ def set_close_down_mode(self, mode, onerror = None): mode = mode) def force_screen_saver(self, mode, onerror = None): + # type: (int, _ErrorHandler[object] | None) -> None """If mode is X.ScreenSaverActive the screen saver is activated. If it is X.ScreenSaverReset, the screen saver is deactivated as if device input had been received.""" @@ -900,6 +991,7 @@ def force_screen_saver(self, mode, onerror = None): mode = mode) def set_pointer_mapping(self, map): + # type: (Sequence[int]) -> int """Set the mapping of the pointer buttons. map is a list of logical button numbers. map must be of the same length as the list returned by Display.get_pointer_mapping(). @@ -918,12 +1010,14 @@ def set_pointer_mapping(self, map): return r.status def get_pointer_mapping(self): + # type: () -> list[int] """Return a list of the pointer button mappings. Entry N in the list sets the logical button number for the physical button N+1.""" r = request.GetPointerMapping(display = self.display) return r.map def set_modifier_mapping(self, keycodes): + # type: (Sequence[Sequence[int]] | tuple[Sequence[int], Sequence[int], Sequence[int], Sequence[int], Sequence[int], Sequence[int], Sequence[int], Sequence[int]]) -> int """Set the keycodes for the eight modifiers X.Shift, X.Lock, X.Control, X.Mod1, X.Mod2, X.Mod3, X.Mod4 and X.Mod5. keycodes should be a eight-element list where each entry is a list of the @@ -939,6 +1033,7 @@ def set_modifier_mapping(self, keycodes): return r.status def get_modifier_mapping(self): + # type: () -> list[list[int]] """Return a list of eight lists, one for each modifier. The list can be indexed using X.ShiftMapIndex, X.Mod1MapIndex, and so on. The sublists list the keycodes bound to that modifier.""" @@ -946,6 +1041,7 @@ def get_modifier_mapping(self): return r.keycodes def no_operation(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None """Do nothing but send a request to the server.""" request.NoOperation(display = self.display, onerror = onerror) diff --git a/Xlib/error.py b/Xlib/error.py index cb6d0d07..060024db 100644 --- a/Xlib/error.py +++ b/Xlib/error.py @@ -25,9 +25,20 @@ # Xlib.protocol modules from .protocol import rq +try: + from typing import TYPE_CHECKING, Any, Union +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from mmap import mmap + from array import array + from typing_extensions import TypeAlias, Literal + from Xlib.protocol import display + _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array[Any], mmap] class DisplayError(Exception): def __init__(self, display): + # type: (object) -> None self.display = display def __str__(self): @@ -39,6 +50,7 @@ def __str__(self): class DisplayConnectionError(DisplayError): def __init__(self, display, msg): + # type: (object, object) -> None self.display = display self.msg = msg @@ -47,6 +59,7 @@ def __str__(self): class ConnectionClosedError(Exception): def __init__(self, whom): + # type: (object) -> None self.whom = whom def __str__(self): @@ -70,6 +83,7 @@ class XError(rq.GetAttrData, Exception): ) def __init__(self, display, data): + # type: (display.Display, _SliceableBuffer) -> None self._data, data = self._fields.parse_binary(data, display, rawdict = 1) def __str__(self): @@ -131,11 +145,13 @@ class BadImplementation(XError): pass class CatchError(object): def __init__(self, *errors): + # type: (type[XError]) -> None self.error_types = errors - self.error = None - self.request = None + self.error = None # type: XError | None + self.request = None # type: rq.Request | None def __call__(self, error, request): + # type: (XError, rq.Request | None) -> Literal[0, 1] if self.error_types: for etype in self.error_types: if isinstance(error, etype): diff --git a/Xlib/ext/composite.py b/Xlib/ext/composite.py index 0e10b635..3c825e56 100644 --- a/Xlib/ext/composite.py +++ b/Xlib/ext/composite.py @@ -37,6 +37,20 @@ from Xlib.protocol import rq from Xlib.xobject import drawable +try: + from typing import TYPE_CHECKING, TypeVar, Optional, Union +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from collections.abc import Callable + from typing_extensions import TypeAlias + from Xlib.error import XError + from Xlib.display import Display + from Xlib.xobject import resource + _T = TypeVar("_T") + _ErrorHandler: TypeAlias = Callable[[XError, Optional[rq.Request]], _T] + _Update: TypeAlias = Callable[[Union[rq.DictWrapper, dict[str, object]]], object] + extname = 'Composite' RedirectAutomatic = 0 @@ -62,6 +76,7 @@ class QueryVersion(rq.ReplyRequest): ) def query_version(self): + # type: (Display | resource.Resource) -> QueryVersion return QueryVersion( display = self.display, opcode = self.display.get_extension_major(extname), @@ -81,6 +96,7 @@ class RedirectWindow(rq.Request): ) def redirect_window(self, update, onerror = None): + # type: (drawable.Window, _Update, _ErrorHandler[object] | None) -> None """Redirect the hierarchy starting at this window to off-screen storage. """ @@ -103,6 +119,7 @@ class RedirectSubwindows(rq.Request): ) def redirect_subwindows(self, update, onerror = None): + # type: (drawable.Window, _Update, _ErrorHandler[object] | None) -> None """Redirect the hierarchies starting at all current and future children to this window to off-screen storage. """ @@ -125,6 +142,7 @@ class UnredirectWindow(rq.Request): ) def unredirect_window(self, update, onerror = None): + # type: (drawable.Window, _Update, _ErrorHandler[object] | None) -> None """Stop redirecting this window hierarchy. """ UnredirectWindow(display = self.display, @@ -146,6 +164,7 @@ class UnredirectSubindows(rq.Request): ) def unredirect_subwindows(self, update, onerror = None): + # type: (drawable.Window, _Update, _ErrorHandler[object] | None) -> None """Stop redirecting the hierarchies of children to this window. """ RedirectWindow(display = self.display, @@ -166,6 +185,7 @@ class CreateRegionFromBorderClip(rq.Request): ) def create_region_from_border_clip(self, onerror = None): + # type: (drawable.Window, _ErrorHandler[object] | None) -> int """Create a region of the border clip of the window, i.e. the area that is not clipped by the parent and any sibling windows. """ @@ -193,6 +213,7 @@ class NameWindowPixmap(rq.Request): ) def name_window_pixmap(self, onerror = None): + # type: (drawable.Window, _ErrorHandler[object] | None) -> drawable.Pixmap """Create a new pixmap that refers to the off-screen storage of the window, including its border. @@ -231,6 +252,7 @@ class GetOverlayWindow(rq.ReplyRequest): ) def get_overlay_window(self): + # type: (Display | resource.Resource) -> GetOverlayWindow """Return the overlay window of the root window. """ @@ -239,6 +261,7 @@ def get_overlay_window(self): window = self) def init(disp, info): + # type: (Display, object) -> None disp.extension_add_method('display', 'composite_query_version', query_version) diff --git a/Xlib/ext/damage.py b/Xlib/ext/damage.py index 60c56606..c68ba920 100644 --- a/Xlib/ext/damage.py +++ b/Xlib/ext/damage.py @@ -21,9 +21,10 @@ from Xlib import X -from Xlib.protocol import rq, structs -from Xlib.xobject import resource +from Xlib.protocol import rq, structs, request from Xlib.error import XError +from Xlib.display import Display +from Xlib.xobject import resource extname = 'DAMAGE' @@ -71,6 +72,7 @@ class QueryVersion(rq.ReplyRequest): ) def query_version(self): + # type: (Display | resource.Resource) -> QueryVersion return QueryVersion(display=self.display, opcode=self.display.get_extension_major(extname), major_version=1, @@ -87,6 +89,7 @@ class DamageCreate(rq.Request): ) def damage_create(self, level): + # type: (Display | resource.Resource, int) -> int did = self.display.allocate_resource_id() DamageCreate(display=self.display, opcode=self.display.get_extension_major(extname), @@ -104,6 +107,7 @@ class DamageDestroy(rq.Request): ) def damage_destroy(self, damage): + # type: (Display | resource.Resource, int) -> None DamageDestroy(display=self.display, opcode=self.display.get_extension_major(extname), damage=damage, @@ -121,6 +125,7 @@ class DamageSubtract(rq.Request): ) def damage_subtract(self, damage, repair=X.NONE, parts=X.NONE): + # type: (Display | resource.Resource, int, int, int) -> None DamageSubtract(display=self.display, opcode=self.display.get_extension_major(extname), damage=damage, @@ -136,6 +141,7 @@ class DamageAdd(rq.Request): ) def damage_add(self, repair, parts): + # type: (Display | resource.Resource, int, int) -> None DamageAdd(display=self.display, opcode=self.display.get_extension_major(extname), repair=repair, @@ -157,6 +163,7 @@ class DamageNotify(rq.Event): ) def init(disp, info): + # type: (Display, request.QueryExtension) -> None disp.extension_add_method('display', 'damage_query_version', query_version) diff --git a/Xlib/ext/dpms.py b/Xlib/ext/dpms.py index 3ff9a246..8f7ba131 100644 --- a/Xlib/ext/dpms.py +++ b/Xlib/ext/dpms.py @@ -29,6 +29,8 @@ from Xlib import X from Xlib.protocol import rq +from Xlib.display import Display +from Xlib.xobject import resource extname = 'DPMS' @@ -72,6 +74,7 @@ class DPMSGetVersion(rq.ReplyRequest): def get_version(self): + # type: (Display | resource.Resource) -> DPMSGetVersion return DPMSGetVersion(display=self.display, opcode=self.display.get_extension_major(extname), major_version=1, @@ -96,6 +99,7 @@ class DPMSCapable(rq.ReplyRequest): def capable(self): + # type: (Display | resource.Resource) -> DPMSCapable return DPMSCapable(display=self.display, opcode=self.display.get_extension_major(extname), major_version=1, @@ -122,6 +126,7 @@ class DPMSGetTimeouts(rq.ReplyRequest): def get_timeouts(self): + # type: (Display | resource.Resource) -> DPMSGetTimeouts return DPMSGetTimeouts(display=self.display, opcode=self.display.get_extension_major(extname), major_version=1, @@ -141,6 +146,7 @@ class DPMSSetTimeouts(rq.Request): def set_timeouts(self, standby_timeout, suspend_timeout, off_timeout): + # type: (Display | resource.Resource, int, int, int) -> DPMSSetTimeouts return DPMSSetTimeouts(display=self.display, opcode=self.display.get_extension_major(extname), major_version=1, @@ -159,6 +165,7 @@ class DPMSEnable(rq.Request): def enable(self): + # type: (Display | resource.Resource) -> DPMSEnable return DPMSEnable(display=self.display, opcode=self.display.get_extension_major(extname), major_version=1, @@ -174,6 +181,7 @@ class DPMSDisable(rq.Request): def disable(self): + # type: (Display | resource.Resource) -> DPMSDisable return DPMSDisable(display=self.display, opcode=self.display.get_extension_major(extname), major_version=1, @@ -190,6 +198,7 @@ class DPMSForceLevel(rq.Request): def force_level(self, power_level): + # type: (Display | resource.Resource, int) -> DPMSForceLevel return DPMSForceLevel(display=self.display, opcode=self.display.get_extension_major(extname), major_version=1, @@ -216,6 +225,7 @@ class DPMSInfo(rq.ReplyRequest): def info(self): + # type: (Display | resource.Resource) -> DPMSInfo return DPMSInfo(display=self.display, opcode=self.display.get_extension_major(extname), major_version=1, @@ -223,6 +233,7 @@ def info(self): def init(disp, _info): + # type: (Display, object) -> None disp.extension_add_method('display', 'dpms_get_version', get_version) disp.extension_add_method('display', 'dpms_capable', capable) disp.extension_add_method('display', 'dpms_get_timeouts', get_timeouts) diff --git a/Xlib/ext/ge.py b/Xlib/ext/ge.py index 291ffa9a..43c775bc 100644 --- a/Xlib/ext/ge.py +++ b/Xlib/ext/ge.py @@ -25,6 +25,18 @@ ''' from Xlib.protocol import rq +try: + from typing import TYPE_CHECKING, Union, Any +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from Xlib.display import Display + from Xlib.protocol import display + from Xlib.xobject import resource + from mmap import mmap + from array import array + from typing_extensions import TypeAlias + _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array[Any], mmap] extname = 'Generic Event Extension' @@ -52,6 +64,7 @@ class GEQueryVersion(rq.ReplyRequest): def query_version(self): + # type: (Display | resource.Resource) -> GEQueryVersion return GEQueryVersion( display=self.display, opcode=self.display.get_extension_major(extname), @@ -77,6 +90,7 @@ class GenericEvent(rq.Event): ) def __init__(self, binarydata = None, display = None, **keys): + # type: (_SliceableBuffer | None, display.Display | None, object) -> None if binarydata: data = binarydata[10:] binarydata = binarydata[:10] @@ -101,12 +115,14 @@ def __init__(self, binarydata = None, display = None, **keys): def add_event_data(self, extension, evtype, estruct): + # type: (Display | resource.Resource, int, int, int) -> None if not hasattr(self.display, 'ge_event_data'): self.display.ge_event_data = {} self.display.ge_event_data[(extension, evtype)] = estruct def init(disp, info): + # type: (Display, object) -> None disp.extension_add_method('display', 'ge_query_version', query_version) disp.extension_add_method('display', 'ge_add_event_data', add_event_data) disp.extension_add_event(GenericEventCode, GenericEvent) diff --git a/Xlib/ext/nvcontrol.py b/Xlib/ext/nvcontrol.py index 7a21826c..6d098210 100644 --- a/Xlib/ext/nvcontrol.py +++ b/Xlib/ext/nvcontrol.py @@ -23,11 +23,14 @@ """NV-CONTROL - provide access to the NV-CONTROL extension information.""" from Xlib.protocol import rq +from Xlib.display import Display +from Xlib.xobject import resource extname = 'NV-CONTROL' def query_target_count(self, target): + # type: (Display | resource.Resource, Target) -> int """Return the target count""" reply = NVCtrlQueryTargetCountReplyRequest(display=self.display, opcode=self.display.get_extension_major(extname), @@ -36,6 +39,7 @@ def query_target_count(self, target): def query_int_attribute(self, target, display_mask, attr): + # type: (Display | resource.Resource, Target, int, int) -> int | None """Return the value of an integer attribute""" reply = NVCtrlQueryAttributeReplyRequest(display=self.display, opcode=self.display.get_extension_major(extname), @@ -49,6 +53,7 @@ def query_int_attribute(self, target, display_mask, attr): def set_int_attribute(self, target, display_mask, attr, value): + # type: (Display | resource.Resource, Target, int, int, int) -> bool """Set the value of an integer attribute""" reply = NVCtrlSetAttributeAndGetStatusReplyRequest(display=self.display, opcode=self.display.get_extension_major(extname), @@ -61,6 +66,7 @@ def set_int_attribute(self, target, display_mask, attr, value): def query_string_attribute(self, target, display_mask, attr): + # type: (Display | resource.Resource, Target, int, int) -> str | None """Return the value of a string attribute""" reply = NVCtrlQueryStringAttributeReplyRequest(display=self.display, opcode=self.display.get_extension_major(extname), @@ -74,6 +80,7 @@ def query_string_attribute(self, target, display_mask, attr): def query_valid_attr_values(self, target, display_mask, attr): + # type: (Display | resource.Resource, Target, int, int) -> tuple[int, int] | None """Return the value of an integer attribute""" reply = NVCtrlQueryValidAttributeValuesReplyRequest(display=self.display, opcode=self.display.get_extension_major(extname), @@ -87,6 +94,7 @@ def query_valid_attr_values(self, target, display_mask, attr): def query_binary_data(self, target, display_mask, attr): + # type: (Display | resource.Resource, Target, int, int) -> bytes | None """Return binary data""" reply = NVCtrlQueryBinaryDataReplyRequest(display=self.display, opcode=self.display.get_extension_major(extname), @@ -100,6 +108,7 @@ def query_binary_data(self, target, display_mask, attr): def get_coolers_used_by_gpu(self, target): + # type: (Display | resource.Resource, Target) -> bytes | None reply = NVCtrlQueryListCard32ReplyRequest(display=self.display, opcode=self.display.get_extension_major(extname), target_id=target.id(), @@ -116,30 +125,36 @@ def get_coolers_used_by_gpu(self, target): def get_gpu_count(self): + # type: (Display | resource.Resource) -> int """Return the number of GPU's present in the system.""" return int(query_target_count(self, Gpu())) def get_name(self, target): + # type: (Display | resource.Resource, Target) -> str | None """Return the GPU product name on which the specified X screen is running""" return query_string_attribute(self, target, 0, NV_CTRL_STRING_PRODUCT_NAME) def get_driver_version(self, target): + # type: (Display | resource.Resource, Target) -> str | None """Return the NVIDIA (kernel level) driver version for the specified screen or GPU""" return query_string_attribute(self, target, 0, NV_CTRL_STRING_NVIDIA_DRIVER_VERSION) def get_vbios_version(self, target): + # type: (Display | resource.Resource, Target) -> str | None """Return the version of the VBIOS for the specified screen or GPU""" return query_string_attribute(self, target, 0, NV_CTRL_STRING_VBIOS_VERSION) def get_gpu_uuid(self, target): + # type: (Display | resource.Resource, Target) -> str | None return query_string_attribute(self, target, 0, NV_CTRL_STRING_GPU_UUID) def get_utilization_rates(self, target): + # type: (Display | resource.Resource, Target) -> dict[str, str | int] string = query_string_attribute(self, target, 0, NV_CTRL_STRING_GPU_UTILIZATION) result = {} if string is not None and string != '': @@ -150,6 +165,7 @@ def get_utilization_rates(self, target): def get_performance_modes(self, target): + # type: (Display | resource.Resource, Target) -> list[dict[str, str | int]] string = query_string_attribute(self, target, 0, NV_CTRL_STRING_PERFORMANCE_MODES) result = [] if string is not None and string != '': @@ -163,6 +179,7 @@ def get_performance_modes(self, target): def get_clock_info(self, target): + # type: (Display | resource.Resource, Target) -> dict[str, str | int] string = query_string_attribute(self, target, 0, NV_CTRL_STRING_GPU_CURRENT_CLOCK_FREQS) result = {} if string is not None and string != '': @@ -173,15 +190,18 @@ def get_clock_info(self, target): def get_vram(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_VIDEO_RAM) def get_irq(self, target): + # type: (Display | resource.Resource, Target) -> int | None """Return the interrupt request line used by the GPU driving the screen""" return query_int_attribute(self, target, 0, NV_CTRL_IRQ) def supports_framelock(self, target): + # type: (Display | resource.Resource, Target) -> int | None """Return whether the underlying GPU supports Frame Lock. All of the other frame lock attributes are only applicable if this returns True. @@ -190,6 +210,7 @@ def supports_framelock(self, target): def gvo_supported(self, screen): + # type: (Display | resource.Resource, Target) -> int | None """Return whether this X screen supports GVO If this screen does not support GVO output, then all other GVO attributes are unavailable. @@ -198,11 +219,13 @@ def gvo_supported(self, screen): def get_core_temp(self, target): + # type: (Display | resource.Resource, Target) -> int | None """Return the current core temperature of the GPU driving the X screen.""" return query_int_attribute(self, target, 0, NV_CTRL_GPU_CORE_TEMPERATURE) def get_core_threshold(self, target): + # type: (Display | resource.Resource, Target) -> int | None """Return the current GPU core slowdown threshold temperature. It reflects the temperature at which the GPU is throttled to prevent overheating. @@ -211,113 +234,140 @@ def get_core_threshold(self, target): def get_default_core_threshold(self, target): + # type: (Display | resource.Resource, Target) -> int | None """Return the default core threshold temperature.""" return query_int_attribute(self, target, 0, NV_CTRL_GPU_DEFAULT_CORE_THRESHOLD) def get_max_core_threshold(self, target): + # type: (Display | resource.Resource, Target) -> int | None """Return the maximum core threshold temperature.""" return query_int_attribute(self, target, 0, NV_CTRL_GPU_MAX_CORE_THRESHOLD) def get_ambient_temp(self, target): + # type: (Display | resource.Resource, Target) -> int | None """Return the current temperature in the immediate neighbourhood of the GPU driving the X screen.""" return query_int_attribute(self, target, 0, NV_CTRL_AMBIENT_TEMPERATURE) def get_cuda_cores(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_GPU_CORES) def get_memory_bus_width(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_GPU_MEMORY_BUS_WIDTH) def get_total_dedicated_gpu_memory(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY) def get_used_dedicated_gpu_memory(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_USED_DEDICATED_GPU_MEMORY) def get_curr_pcie_link_width(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_GPU_PCIE_CURRENT_LINK_WIDTH) def get_max_pcie_link_width(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_GPU_PCIE_MAX_LINK_WIDTH) def get_curr_pcie_link_generation(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_GPU_PCIE_GENERATION) def get_encoder_utilization(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_VIDEO_ENCODER_UTILIZATION) def get_decoder_utilization(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_VIDEO_DECODER_UTILIZATION) def get_current_performance_level(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_GPU_CURRENT_PERFORMANCE_LEVEL) def get_gpu_nvclock_offset(self, target, perf_level): + # type: (Display | resource.Resource, Target, int) -> int | None return query_int_attribute(self, target, perf_level, NV_CTRL_GPU_NVCLOCK_OFFSET) def set_gpu_nvclock_offset(self, target, perf_level, offset): + # type: (Display | resource.Resource, Target, int, int) -> bool return set_int_attribute(self, target, perf_level, NV_CTRL_GPU_NVCLOCK_OFFSET, offset) def set_gpu_nvclock_offset_all_levels(self, target, offset): + # type: (Display | resource.Resource, Target, int) -> bool return set_int_attribute(self, target, 0, NV_CTRL_GPU_NVCLOCK_OFFSET_ALL_PERFORMANCE_LEVELS, offset) def get_gpu_nvclock_offset_range(self, target, perf_level): + # type: (Display | resource.Resource, Target, int) -> tuple[int, int] | None return query_valid_attr_values(self, target, perf_level, NV_CTRL_GPU_NVCLOCK_OFFSET) def get_mem_transfer_rate_offset(self, target, perf_level): + # type: (Display | resource.Resource, Target, int) -> int | None return query_int_attribute(self, target, perf_level, NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET) def set_mem_transfer_rate_offset(self, target, perf_level, offset): + # type: (Display | resource.Resource, Target, int, int) -> bool return set_int_attribute(self, target, perf_level, NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET, offset) def set_mem_transfer_rate_offset_all_levels(self, target, offset): + # type: (Display | resource.Resource, Target, int) -> bool return set_int_attribute(self, target, 0, NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET_ALL_PERFORMANCE_LEVELS, offset) def get_mem_transfer_rate_offset_range(self, target, perf_level): + # type: (Display | resource.Resource, Target, int) -> tuple[int, int] | None return query_valid_attr_values(self, target, perf_level, NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET) def get_cooler_manual_control_enabled(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_GPU_COOLER_MANUAL_CONTROL) def set_cooler_manual_control_enabled(self, target, enabled): + # type: (Display | resource.Resource, Target, bool) -> bool return set_int_attribute(self, target, 0, NV_CTRL_GPU_COOLER_MANUAL_CONTROL, 1 if enabled else 0) == 1 def get_fan_duty(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_THERMAL_COOLER_CURRENT_LEVEL) def set_fan_duty(self, cooler, speed): + # type: (Display | resource.Resource, Target, int) -> bool return set_int_attribute(self, cooler, 0, NV_CTRL_THERMAL_COOLER_LEVEL, speed) def get_fan_rpm(self, target): + # type: (Display | resource.Resource, Target) -> int | None return query_int_attribute(self, target, 0, NV_CTRL_THERMAL_COOLER_SPEED) def get_max_displays(self, target): + # type: (Display | resource.Resource, Target) -> int | None """Return the maximum number of display devices that can be driven simultaneously on a GPU. Note that this does not indicate the maximum number of bits that can be set in @@ -354,6 +404,7 @@ def _displays2mask(displays): def init(disp, info): + # type: (Display, object) -> None disp.extension_add_method('display', 'nvcontrol_query_target_count', query_target_count) disp.extension_add_method('display', 'nvcontrol_query_int_attribute', query_int_attribute) disp.extension_add_method('display', 'nvcontrol_query_string_attribute', query_string_attribute) @@ -5199,6 +5250,7 @@ def __str__(self): class Gpu(Target): def __init__(self, ngpu=0): + # type: (int) -> None """Target a GPU""" super(self.__class__, self).__init__() self._id = ngpu @@ -5208,6 +5260,7 @@ def __init__(self, ngpu=0): class Screen(Target): def __init__(self, nscr=0): + # type: (int) -> None """Target an X screen""" super(self.__class__, self).__init__() self._id = nscr @@ -5217,6 +5270,7 @@ def __init__(self, nscr=0): class Cooler(Target): def __init__(self, nfan=0): + # type: (int) -> None """Target a fann""" super(self.__class__, self).__init__() self._id = nfan diff --git a/Xlib/ext/randr.py b/Xlib/ext/randr.py index 256e3dee..023e9566 100644 --- a/Xlib/ext/randr.py +++ b/Xlib/ext/randr.py @@ -37,6 +37,16 @@ from tkinter import W from Xlib import X from Xlib.protocol import rq, structs +try: + from typing import TYPE_CHECKING +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from Xlib import error + from Xlib.display import Display + from Xlib.protocol import request + from Xlib.xobject import resource, drawable + from collections.abc import Sequence extname = 'RANDR' @@ -210,6 +220,7 @@ class QueryVersion(rq.ReplyRequest): ) def query_version(self): + # type: (Display | resource.Resource) -> QueryVersion """Get the current version of the RandR extension. """ @@ -285,6 +296,7 @@ class SetScreenConfig(rq.ReplyRequest): ) def set_screen_config(self, size_id, rotation, config_timestamp, rate=0, timestamp=X.CurrentTime): + # type: (drawable.Drawable, int, int, int, int, int) -> SetScreenConfig """Sets the screen to the specified size, rate, rotation and reflection. rate can be 0 to have the server select an appropriate rate. @@ -313,6 +325,7 @@ class SelectInput(rq.Request): ) def select_input(self, mask): + # type: (drawable.Window, int) -> SelectInput return SelectInput( display=self.display, opcode=self.display.get_extension_major(extname), @@ -347,6 +360,7 @@ class GetScreenInfo(rq.ReplyRequest): ) def get_screen_info(self): + # type: (drawable.Window) -> GetScreenInfo """Retrieve information about the current and available configurations for the screen associated with this window. @@ -380,6 +394,7 @@ class GetScreenSizeRange(rq.ReplyRequest): ) def get_screen_size_range(self): + # type: (drawable.Window) -> GetScreenSizeRange """Retrieve the range of possible screen sizes. The screen may be set to any size within this range. @@ -404,6 +419,7 @@ class SetScreenSize(rq.Request): ) def set_screen_size(self, width, height, width_in_millimeters=None, height_in_millimeters=None): + # type: (drawable.Window, int, int, int | None, int | None) -> SetScreenSize return SetScreenSize( display=self.display, opcode=self.display.get_extension_major(extname), @@ -441,6 +457,7 @@ class GetScreenResources(rq.ReplyRequest): ) def get_screen_resources(self): + # type: (drawable.Window) -> GetScreenResources return GetScreenResources( display=self.display, opcode=self.display.get_extension_major(extname), @@ -479,6 +496,7 @@ class GetOutputInfo(rq.ReplyRequest): ) def get_output_info(self, output, config_timestamp): + # type: (Display | resource.Resource, int, int) -> GetOutputInfo return GetOutputInfo( display=self.display, opcode=self.display.get_extension_major(extname), @@ -505,6 +523,7 @@ class ListOutputProperties(rq.ReplyRequest): ) def list_output_properties(self, output): + # type: (Display | resource.Resource, int) -> ListOutputProperties return ListOutputProperties ( display=self.display, opcode=self.display.get_extension_major(extname), @@ -533,6 +552,7 @@ class QueryOutputProperty(rq.ReplyRequest): ) def query_output_property(self, output, property): + # type: (Display | resource.Resource, int, int) -> QueryOutputProperty return QueryOutputProperty ( display=self.display, opcode=self.display.get_extension_major(extname), @@ -555,6 +575,7 @@ class ConfigureOutputProperty (rq.Request): ) def configure_output_property (self, output, property): + # type: (Display | resource.Resource, int, int) -> ConfigureOutputProperty return ConfigureOutputProperty ( display=self.display, opcode=self.display.get_extension_major(extname), @@ -579,6 +600,7 @@ class ChangeOutputProperty(rq.Request): ) def change_output_property(self, output, property, type, mode, value): + # type: (Display | resource.Resource, int, int, int, int, Sequence[float] | Sequence[str]) -> ChangeOutputProperty return ChangeOutputProperty( display=self.display, opcode=self.display.get_extension_major(extname), @@ -600,6 +622,7 @@ class DeleteOutputProperty(rq.Request): ) def delete_output_property(self, output, property): + # type: (Display | resource.Resource, int, int) -> DeleteOutputProperty return DeleteOutputProperty( display=self.display, opcode=self.display.get_extension_major(extname), @@ -635,6 +658,7 @@ class GetOutputProperty(rq.ReplyRequest): ) def get_output_property(self, output, property, type, long_offset, long_length, delete=False, pending=False): + # type: (Display | resource.Resource, int, int, int, int, int, bool, bool) -> GetOutputProperty return GetOutputProperty( display=self.display, opcode=self.display.get_extension_major(extname), @@ -667,6 +691,7 @@ class CreateMode(rq.ReplyRequest): ) def create_mode(self, mode, name): + # type: (drawable.Window, tuple[int, int, int, int, int, int, int, int, int, int, int, int, int], str) -> CreateMode return CreateMode ( display=self.display, opcode=self.display.get_extension_major(extname), @@ -685,6 +710,7 @@ class DestroyMode(rq.Request): ) def destroy_mode(self, mode): + # type: (Display | resource.Resource, int) -> DestroyMode return DestroyMode( display=self.display, opcode=self.display.get_extension_major(extname), @@ -702,6 +728,7 @@ class AddOutputMode(rq.Request): ) def add_output_mode(self, output, mode): + # type: (Display | resource.Resource, int, int) -> AddOutputMode return AddOutputMode( display=self.display, opcode=self.display.get_extension_major(extname), @@ -720,6 +747,7 @@ class DeleteOutputMode(rq.Request): ) def delete_output_mode(self, output, mode): + # type: (Display | resource.Resource, int, int) -> DeleteOutputMode return DeleteOutputMode( display=self.display, opcode=self.display.get_extension_major(extname), @@ -756,6 +784,7 @@ class GetCrtcInfo(rq.ReplyRequest): ) def get_crtc_info(self, crtc, config_timestamp): + # type: (Display | resource.Resource, int, int) -> GetCrtcInfo return GetCrtcInfo ( display=self.display, opcode=self.display.get_extension_major(extname), @@ -789,6 +818,7 @@ class SetCrtcConfig(rq.ReplyRequest): ) def set_crtc_config(self, crtc, config_timestamp, x, y, mode, rotation, outputs, timestamp=X.CurrentTime): + # type: (Display | resource.Resource, int, int, int, int, int, int, Sequence[int], int) -> SetCrtcConfig return SetCrtcConfig ( display=self.display, opcode=self.display.get_extension_major(extname), @@ -820,6 +850,7 @@ class GetCrtcGammaSize(rq.ReplyRequest): ) def get_crtc_gamma_size(self, crtc): + # type: (Display | resource.Resource, int) -> GetCrtcGammaSize return GetCrtcGammaSize ( display=self.display, opcode=self.display.get_extension_major(extname), @@ -847,6 +878,7 @@ class GetCrtcGamma(rq.ReplyRequest): ) def get_crtc_gamma(self, crtc): + # type: (Display | resource.Resource, int) -> GetCrtcGamma return GetCrtcGamma ( display=self.display, opcode=self.display.get_extension_major(extname), @@ -868,6 +900,7 @@ class SetCrtcGamma(rq.Request): ) def set_crtc_gamma(self, crtc, size, red, green, blue): + # type: (Display | resource.Resource, int, int, Sequence[int], Sequence[int], Sequence[int]) -> SetCrtcGamma return SetCrtcGamma( display=self.display, opcode=self.display.get_extension_major(extname), @@ -907,6 +940,7 @@ class GetScreenResourcesCurrent(rq.ReplyRequest): ) def get_screen_resources_current(self): + # type: (drawable.Window) -> GetScreenResourcesCurrent return GetScreenResourcesCurrent( display=self.display, opcode=self.display.get_extension_major(extname), @@ -928,6 +962,7 @@ class SetCrtcTransform(rq.Request): ) def set_crtc_transform(self, crtc, n_bytes_filter): + # type: (Display | resource.Resource, int, Sequence[int]) -> SetCrtcTransform return SetCrtcTransform( display=self.display, opcode=self.display.get_extension_major(extname), @@ -964,6 +999,7 @@ class GetCrtcTransform(rq.ReplyRequest): ) def get_crtc_transform(self, crtc): + # type: (Display | resource.Resource, int) -> GetCrtcTransform return GetCrtcTransform( display=self.display, opcode=self.display.get_extension_major(extname), @@ -999,6 +1035,7 @@ class GetPanning(rq.ReplyRequest): ) def get_panning(self, crtc): + # type: (Display | resource.Resource, int) -> GetPanning return GetPanning ( display=self.display, opcode=self.display.get_extension_major(extname), @@ -1036,6 +1073,7 @@ class SetPanning(rq.ReplyRequest): ) def set_panning(self, crtc, left, top, width, height, track_left, track_top, track_width, track_height, border_left, border_top, border_width, border_height, timestamp=X.CurrentTime): + # type: (Display | resource.Resource, int, int, int, int, int, int, int, int, int, int, int, int, int, int) -> SetPanning return SetPanning ( display=self.display, opcode=self.display.get_extension_major(extname), @@ -1066,6 +1104,7 @@ class SetOutputPrimary(rq.Request): ) def set_output_primary(self, output): + # type: (drawable.Window, int) -> SetOutputPrimary return SetOutputPrimary( display=self.display, opcode=self.display.get_extension_major(extname), @@ -1091,6 +1130,7 @@ class GetOutputPrimary(rq.ReplyRequest): ) def get_output_primary(self): + # type: (drawable.Window) -> GetOutputPrimary return GetOutputPrimary( display=self.display, opcode=self.display.get_extension_major(extname), @@ -1124,6 +1164,7 @@ class GetMonitors(rq.ReplyRequest): def get_monitors(self, is_active=True): + # type: (drawable.Window, bool) -> GetMonitors return GetMonitors( display=self.display, opcode=self.display.get_extension_major(extname), @@ -1142,6 +1183,7 @@ class SetMonitor(rq.Request): def set_monitor(self, monitor_info): + # type: (drawable.Window, tuple[int, bool, bool, Sequence[int], int, int, int, int, int]) -> SetMonitor return SetMonitor( display=self.display, opcode=self.display.get_extension_major(extname), @@ -1161,6 +1203,7 @@ class DeleteMonitor(rq.Request): def delete_monitor(self, name): + # type: (Display | resource.Resource, str) -> DeleteMonitor return DeleteMonitor( display=self.display, opcode=self.display.get_extension_major(extname), @@ -1242,6 +1285,7 @@ class OutputPropertyNotify(rq.Event): # Initialization # def init(disp, info): + # type: (Display, request.QueryExtension) -> None disp.extension_add_method('display', 'xrandr_query_version', query_version) disp.extension_add_method('window', 'xrandr_select_input', select_input) disp.extension_add_method('window', 'xrandr_get_screen_info', get_screen_info) diff --git a/Xlib/ext/record.py b/Xlib/ext/record.py index bb53ec19..9793e0e1 100644 --- a/Xlib/ext/record.py +++ b/Xlib/ext/record.py @@ -21,6 +21,17 @@ from Xlib import X from Xlib.protocol import rq +try: + from typing import TYPE_CHECKING, Any, TypeVar +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from Xlib.display import Display + from Xlib.protocol import display + from collections.abc import Sequence, Sized, Callable + from Xlib.xobject import resource + _T = TypeVar("_T") + _S = TypeVar("_S", bound=Sized) extname = 'RECORD' @@ -73,9 +84,11 @@ class RawField(rq.ValueField): structcode = None def pack_value(self, val): + # type: (_S) -> tuple[_S, int, None] return val, len(val), None def parse_binary_value(self, data, display, length, format): + # type: (_T, object, object, object) -> tuple[_T, bytes] return data, '' @@ -95,6 +108,7 @@ class GetVersion(rq.ReplyRequest): rq.Pad(20)) def get_version(self, major, minor): + # type: (Display | resource.Resource, int, int) -> GetVersion return GetVersion( display = self.display, opcode = self.display.get_extension_major(extname), @@ -116,6 +130,7 @@ class CreateContext(rq.Request): rq.List('ranges', Record_Range)) def create_context(self, datum_flags, clients, ranges): + # type: (Display | resource.Resource, int, Sequence[int], Sequence[tuple[tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int], bool, bool]]) -> int context = self.display.allocate_resource_id() CreateContext( display = self.display, @@ -141,6 +156,7 @@ class RegisterClients(rq.Request): rq.List('ranges', Record_Range)) def register_clients(self, context, element_header, clients, ranges): + # type: (Display | resource.Resource, int, int, Sequence[int], Sequence[tuple[tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int], bool, bool]]) -> None RegisterClients( display = self.display, opcode = self.display.get_extension_major(extname), @@ -160,6 +176,7 @@ class UnregisterClients(rq.Request): rq.List('clients', rq.Card32Obj)) def unregister_clients(self, context, clients): + # type: (Display | resource.Resource, int, Sequence[int]) -> None UnregisterClients( display = self.display, opcode = self.display.get_extension_major(extname), @@ -184,6 +201,7 @@ class GetContext(rq.ReplyRequest): rq.List('client_info', Record_ClientInfo)) def get_context(self, context): + # type: (Display | resource.Resource, int) -> GetContext return GetContext( display = self.display, opcode = self.display.get_extension_major(extname), @@ -216,6 +234,7 @@ class EnableContext(rq.ReplyRequest): # See the discussion on ListFonstsWithInfo in request.py def __init__(self, callback, *args, **keys): + # type: (Callable[[rq.DictWrapper | dict[str, object]], Any], display.Display, object, bool, object) -> None self._callback = callback rq.ReplyRequest.__init__(self, *args, **keys) @@ -236,6 +255,7 @@ def _parse_response(self, data): self._display.sent_requests.insert(0, self) def enable_context(self, context, callback): + # type: (Display | resource.Resource, int, Callable[[rq.DictWrapper | dict[str, object]], Any]) -> None EnableContext( callback = callback, display = self.display, @@ -251,6 +271,7 @@ class DisableContext(rq.Request): rq.Card32('context')) # Record_RC def disable_context(self, context): + # type: (Display | resource.Resource, int) -> None DisableContext( display = self.display, opcode = self.display.get_extension_major(extname), @@ -265,6 +286,7 @@ class FreeContext(rq.Request): rq.Card32('context')) # Record_RC def free_context(self, context): + # type: (Display | resource.Resource, int) -> None FreeContext( display = self.display, opcode = self.display.get_extension_major(extname), @@ -273,6 +295,7 @@ def free_context(self, context): def init(disp, info): + # type: (Display, object) -> None disp.extension_add_method('display', 'record_get_version', get_version) disp.extension_add_method('display', 'record_create_context', create_context) disp.extension_add_method('display', 'record_register_clients', register_clients) diff --git a/Xlib/ext/res.py b/Xlib/ext/res.py index f2c4e9fe..2eb088dd 100644 --- a/Xlib/ext/res.py +++ b/Xlib/ext/res.py @@ -29,6 +29,14 @@ https://cgit.freedesktop.org/xcb/proto/tree/src/res.xml """ from Xlib.protocol import rq +try: + from typing import TYPE_CHECKING +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from Xlib.display import Display + from Xlib.xobject import resource + from collections.abc import Sequence RES_MAJOR_VERSION = 1 RES_MINOR_VERSION = 2 @@ -65,6 +73,7 @@ class QueryVersion(rq.ReplyRequest): def query_version(self, client_major=RES_MAJOR_VERSION, client_minor=RES_MINOR_VERSION): + # type: (Display | resource.Resource, int, int) -> QueryVersion """ Query the protocol version supported by the X server. The client sends the highest supported version to the server and the @@ -98,6 +107,7 @@ class QueryClients(rq.ReplyRequest): def query_clients(self): + # type: (Display | resource.Resource) -> QueryClients """Request the list of all currently connected clients.""" return QueryClients( display=self.display, @@ -126,6 +136,7 @@ class QueryClientResources(rq.ReplyRequest): def query_client_resources(self, client): + # type: (Display | resource.Resource, int) -> QueryClientResources """Request the number of resources owned by a client. The server will return the counts of each type of resource. @@ -153,6 +164,7 @@ class QueryClientPixmapBytes(rq.ReplyRequest): def query_client_pixmap_bytes(self, client): + # type: (Display | resource.Resource, int) -> QueryClientPixmapBytes """Query the pixmap usage of some client. The returned number is a sum of memory usage of each pixmap that can be @@ -169,10 +181,12 @@ class SizeOf(rq.LengthOf): may vary, e.g. List """ def __init__(self, name, size, item_size): + # type: (str | list[str] | tuple[str, ...], int, int) -> None rq.LengthOf.__init__(self, name, size) self.item_size = item_size def parse_value(self, length, display): + # type: (int, object) -> int return length // self.item_size @@ -209,6 +223,7 @@ class QueryClientIds(rq.ReplyRequest): def query_client_ids(self, specs): + # type: (Display | resource.Resource, Sequence[tuple[int, int]]) -> QueryClientIds """Request to identify a given set of clients with some identification method. The request sends a list of specifiers that select clients and @@ -262,6 +277,7 @@ class QueryResourceBytes(rq.ReplyRequest): def query_resource_bytes(self, client, specs): + # type: (Display | resource.Resource, int, Sequence[tuple[int, int]]) -> QueryResourceBytes """Query the sizes of resources from X server. The request sends a list of specifiers that selects resources for size @@ -276,6 +292,7 @@ def query_resource_bytes(self, client, specs): def init(disp, info): + # type: (Display, object) -> None disp.extension_add_method("display", "res_query_version", query_version) disp.extension_add_method("display", "res_query_clients", query_clients) disp.extension_add_method("display", "res_query_client_resources", diff --git a/Xlib/ext/screensaver.py b/Xlib/ext/screensaver.py index 12f4325c..8f7095ee 100644 --- a/Xlib/ext/screensaver.py +++ b/Xlib/ext/screensaver.py @@ -33,6 +33,20 @@ from Xlib import X from Xlib.protocol import rq, structs +try: + from typing import TYPE_CHECKING, TypeVar, Optional +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from collections.abc import Callable + from typing_extensions import TypeAlias + from Xlib.error import XError + from Xlib.protocol import request + from Xlib.display import Display + from Xlib.xobject import drawable, resource + _T = TypeVar("_T") + _ErrorHandler: TypeAlias = Callable[[XError, Optional[rq.Request]], _T] + extname = 'MIT-SCREEN-SAVER' # Event members @@ -70,6 +84,7 @@ class QueryVersion(rq.ReplyRequest): ) def query_version(self): + # type: (Display | resource.Resource) -> QueryVersion return QueryVersion(display=self.display, opcode=self.display.get_extension_major(extname), major_version=1, @@ -98,6 +113,7 @@ class QueryInfo(rq.ReplyRequest): ) def query_info(self): + # type: (drawable.Drawable) -> QueryInfo return QueryInfo(display=self.display, opcode=self.display.get_extension_major(extname), drawable=self, @@ -114,6 +130,7 @@ class SelectInput(rq.Request): ) def select_input(self, mask): + # type: (drawable.Drawable, int) -> SelectInput return SelectInput(display=self.display, opcode=self.display.get_extension_major(extname), drawable=self, @@ -144,6 +161,7 @@ def set_attributes(self, x, y, width, height, border_width, visual = X.CopyFromParent, onerror = None, **keys): + # type: (drawable.Drawable, int, int, int, int, int, int, int, int, _ErrorHandler[object] | None, object) -> SetAttributes return SetAttributes(display=self.display, onerror = onerror, opcode=self.display.get_extension_major(extname), @@ -168,6 +186,7 @@ class UnsetAttributes(rq.Request): ) def unset_attributes(self, onerror = None): + # type: (drawable.Drawable, _ErrorHandler[object] | None) -> UnsetAttributes return UnsetAttributes(display=self.display, onerror = onerror, opcode=self.display.get_extension_major(extname), @@ -189,6 +208,7 @@ class Notify(rq.Event): ) def init(disp, info): + # type: (Display, request.QueryExtension) -> None disp.extension_add_method('display', 'screensaver_query_version', query_version) disp.extension_add_method('drawable', 'screensaver_query_info', query_info) disp.extension_add_method('drawable', 'screensaver_select_input', select_input) diff --git a/Xlib/ext/security.py b/Xlib/ext/security.py index a8210171..bbe145eb 100644 --- a/Xlib/ext/security.py +++ b/Xlib/ext/security.py @@ -26,6 +26,17 @@ ''' from Xlib.protocol import rq +try: + from typing import TYPE_CHECKING, Any, Union +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from mmap import mmap + from typing_extensions import TypeAlias + from Xlib.display import Display + from Xlib.xobject import resource + from array import array + _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array[Any], mmap] extname = 'SECURITY' @@ -58,6 +69,7 @@ class QueryVersion(rq.ReplyRequest): def query_version(self): + # type: (Display | resource.Resource) -> QueryVersion return QueryVersion(display=self.display, opcode=self.display.get_extension_major(extname), major_version=1, @@ -91,6 +103,7 @@ class SecurityGenerateAuthorization(rq.ReplyRequest): def generate_authorization(self, auth_proto, auth_data=b'', timeout=None, trust_level=None, group=None, event_mask=None): + # type: (Display | resource.Resource, str, _SliceableBuffer, int | None, int | None, int | None, int | None) -> SecurityGenerateAuthorization value_mask = 0 values = [] if timeout is not None: @@ -122,12 +135,14 @@ class SecurityRevokeAuthorization(rq.Request): def revoke_authorization(self, authid): + # type: (Display | resource.Resource, int) -> SecurityRevokeAuthorization return SecurityRevokeAuthorization(display=self.display, opcode=self.display.get_extension_major(extname), authid=authid) def init(disp, info): + # type: (Display, object) -> None disp.extension_add_method('display', 'security_query_version', query_version) diff --git a/Xlib/ext/shape.py b/Xlib/ext/shape.py index 05a517ac..8b931308 100644 --- a/Xlib/ext/shape.py +++ b/Xlib/ext/shape.py @@ -2,6 +2,15 @@ # Generated from: /usr/share/xcb/shape.xml from Xlib.protocol import rq, structs +try: + from typing import TYPE_CHECKING +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from Xlib.display import Display + from Xlib.protocol import request + from Xlib.xobject import resource, drawable + from collections.abc import Sequence extname = 'SHAPE' @@ -23,6 +32,7 @@ class SK: class KIND(rq.Set): def __init__(self, name): + # type: (str) -> None super(KIND, self).__init__(name, 1, values=(SK.Bounding, SK.Clip, @@ -201,6 +211,7 @@ class Event: Notify = 0 def combine(self, operation, destination_kind, source_kind, x_offset, y_offset): + # type: (drawable.Window, int, int, int, int, int) -> None Combine( display=self.display, opcode=self.display.get_extension_major(extname), @@ -213,6 +224,7 @@ def combine(self, operation, destination_kind, source_kind, x_offset, y_offset): ) def get_rectangles(self, source_kind): + # type: (drawable.Window, int) -> GetRectangles return GetRectangles( display=self.display, opcode=self.display.get_extension_major(extname), @@ -221,6 +233,7 @@ def get_rectangles(self, source_kind): ) def input_selected(self, ): + # type: (drawable.Window) -> InputSelected return InputSelected( display=self.display, opcode=self.display.get_extension_major(extname), @@ -228,6 +241,7 @@ def input_selected(self, ): ) def mask(self, operation, destination_kind, x_offset, y_offset, source_bitmap): + # type: (drawable.Window, int, int, int, int, int) -> None Mask( display=self.display, opcode=self.display.get_extension_major(extname), @@ -240,6 +254,7 @@ def mask(self, operation, destination_kind, x_offset, y_offset, source_bitmap): ) def offset(self, destination_kind, x_offset, y_offset): + # type: (drawable.Window, int, int, int) -> None Offset( display=self.display, opcode=self.display.get_extension_major(extname), @@ -250,6 +265,7 @@ def offset(self, destination_kind, x_offset, y_offset): ) def query_extents(self, ): + # type: (drawable.Window) -> QueryExtents return QueryExtents( display=self.display, opcode=self.display.get_extension_major(extname), @@ -257,12 +273,14 @@ def query_extents(self, ): ) def query_version(self, ): + # type: (Display | resource.Resource) -> QueryVersion return QueryVersion( display=self.display, opcode=self.display.get_extension_major(extname), ) def rectangles(self, operation, destination_kind, ordering, x_offset, y_offset, rectangles): + # type: (drawable.Window, int, int, int, int, int, Sequence[tuple[int, int, int, int]]) -> None Rectangles( display=self.display, opcode=self.display.get_extension_major(extname), @@ -276,6 +294,7 @@ def rectangles(self, operation, destination_kind, ordering, x_offset, y_offset, ) def select_input(self, enable): + # type: (drawable.Window, int) -> None SelectInput( display=self.display, opcode=self.display.get_extension_major(extname), @@ -284,6 +303,7 @@ def select_input(self, enable): ) def init(disp, info): + # type: (Display, request.QueryExtension) -> None disp.extension_add_method('window', 'shape_combine', combine) disp.extension_add_method('window', 'shape_get_rectangles', get_rectangles) disp.extension_add_method('window', 'shape_input_selected', input_selected) diff --git a/Xlib/ext/xfixes.py b/Xlib/ext/xfixes.py index 59f9277b..c887aa26 100644 --- a/Xlib/ext/xfixes.py +++ b/Xlib/ext/xfixes.py @@ -26,7 +26,9 @@ ''' from Xlib import X -from Xlib.protocol import rq, structs +from Xlib.protocol import rq, request +from Xlib.display import Display +from Xlib.xobject import resource, drawable extname = 'XFIXES' @@ -61,6 +63,7 @@ class QueryVersion(rq.ReplyRequest): def query_version(self): + # type: (Display | resource.Resource) -> QueryVersion return QueryVersion(display=self.display, opcode=self.display.get_extension_major(extname), major_version=4, @@ -75,6 +78,7 @@ class HideCursor(rq.Request): ) def hide_cursor(self): + # type: (drawable.Window) -> None HideCursor(display=self.display, opcode=self.display.get_extension_major(extname), window=self) @@ -89,6 +93,7 @@ class ShowCursor(rq.Request): def show_cursor(self): + # type: (drawable.Window) -> None ShowCursor(display=self.display, opcode=self.display.get_extension_major(extname), window=self) @@ -103,6 +108,7 @@ class SelectSelectionInput(rq.Request): ) def select_selection_input(self, window, selection, mask): + # type: (Display | resource.Resource, int, int, int) -> SelectSelectionInput return SelectSelectionInput(opcode=self.display.get_extension_major(extname), display=self.display, window=window, @@ -144,6 +150,7 @@ class SelectCursorInput(rq.Request): ) def select_cursor_input(self, window, mask): + # type: (Display | resource.Resource, int, int) -> SelectCursorInput return SelectCursorInput(opcode=self.display.get_extension_major(extname), display=self.display, window=window, @@ -172,6 +179,7 @@ class GetCursorImage(rq.ReplyRequest): ) def get_cursor_image(self, window): + # type: (Display | resource.Resource, object) -> GetCursorImage return GetCursorImage(opcode=self.display.get_extension_major(extname), display=self.display, ) @@ -188,6 +196,7 @@ class DisplayCursorNotify(rq.Event): def init(disp, info): + # type: (Display, request.QueryExtension) -> None disp.extension_add_method('display', 'xfixes_select_selection_input', select_selection_input) disp.extension_add_method('display', 'xfixes_query_version', query_version) disp.extension_add_method('window', 'xfixes_hide_cursor', hide_cursor) diff --git a/Xlib/ext/xinerama.py b/Xlib/ext/xinerama.py index f0546707..7be784fb 100644 --- a/Xlib/ext/xinerama.py +++ b/Xlib/ext/xinerama.py @@ -37,6 +37,8 @@ from Xlib import X from Xlib.protocol import rq, structs +from Xlib.display import Display +from Xlib.xobject import resource, drawable extname = 'XINERAMA' @@ -62,6 +64,7 @@ class QueryVersion(rq.ReplyRequest): ) def query_version(self): + # type: (Display | resource.Resource) -> QueryVersion return QueryVersion(display=self.display, opcode=self.display.get_extension_major(extname), major_version=1, @@ -85,6 +88,7 @@ class GetState(rq.ReplyRequest): ) def get_state(self): + # type: (drawable.Window) -> GetState return GetState(display=self.display, opcode=self.display.get_extension_major(extname), window=self.id, @@ -108,6 +112,7 @@ class GetScreenCount(rq.ReplyRequest): ) def get_screen_count(self): + # type: (drawable.Window) -> GetScreenCount return GetScreenCount(display=self.display, opcode=self.display.get_extension_major(extname), window=self.id, @@ -135,6 +140,7 @@ class GetScreenSize(rq.ReplyRequest): ) def get_screen_size(self, screen_no): + # type: (drawable.Window, int) -> GetScreenSize """Returns the size of the given screen number""" return GetScreenSize(display=self.display, opcode=self.display.get_extension_major(extname), @@ -161,6 +167,7 @@ class IsActive(rq.ReplyRequest): ) def is_active(self): + # type: (Display | resource.Resource) -> int r = IsActive(display=self.display, opcode=self.display.get_extension_major(extname), ) @@ -185,6 +192,7 @@ class QueryScreens(rq.ReplyRequest): ) def query_screens(self): + # type: (Display | resource.Resource) -> QueryScreens # Hmm. This one needs to read the screen data from the socket. Ooops... return QueryScreens(display=self.display, opcode=self.display.get_extension_major(extname), @@ -209,11 +217,13 @@ class GetInfo(rq.ReplyRequest): ) def get_info(self, visual): + # type: (Display | resource.Resource, int) -> None r = GetInfo(display=self.display, opcode=self.display.get_extension_major(extname), visual=visual) def init(disp, info): + # type: (Display, object) -> None disp.extension_add_method('display', 'xinerama_query_version', query_version) disp.extension_add_method('window', 'xinerama_get_state', get_state) disp.extension_add_method('window', 'xinerama_get_screen_count', get_screen_count) diff --git a/Xlib/ext/xinput.py b/Xlib/ext/xinput.py index f9218064..c3edb199 100644 --- a/Xlib/ext/xinput.py +++ b/Xlib/ext/xinput.py @@ -34,6 +34,22 @@ from Xlib.protocol import rq from Xlib import X +try: + from typing import TYPE_CHECKING, Union, Any, SupportsFloat, TypeVar +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from Xlib.display import Display + from Xlib.protocol import display + from Xlib.protocol import request + from collections.abc import Sequence, Iterable + from Xlib.xobject import drawable, resource + from mmap import mmap + from typing_extensions import TypeAlias, SupportsIndex + from _typeshed import ReadableBuffer + _T = TypeVar("_T") + _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array.array[Any], mmap] + _Floatable: TypeAlias = Union[SupportsFloat, SupportsIndex, str, ReadableBuffer] extname = 'XInputExtension' @@ -163,9 +179,11 @@ class FP1616(rq.Int32): def check_value(self, value): + # type: (float) -> int return int(value * 65536.0) def parse_value(self, value, display): + # type: (_Floatable, object) -> float return float(value) / float(1 << 16) class FP3232(rq.ValueField): @@ -173,9 +191,11 @@ class FP3232(rq.ValueField): structvalues = 2 def check_value(self, value): + # type: (_T) -> _T return value def parse_value(self, value, display): + # type: (tuple[_Floatable, _Floatable], object) -> float integral, frac = value ret = float(integral) # optimised math.ldexp(float(frac), -32) @@ -202,6 +222,7 @@ class XIQueryVersion(rq.ReplyRequest): def query_version(self): + # type: (Display | resource.Resource) -> XIQueryVersion return XIQueryVersion( display=self.display, opcode=self.display.get_extension_major(extname), @@ -212,11 +233,13 @@ def query_version(self): class Mask(rq.List): def __init__(self, name): + # type: (str) -> None rq.List.__init__(self, name, rq.Card32, pad=0) def pack_value(self, val): + # type: (int | Iterable[int]) -> tuple[bytes, int, None] - mask_seq = array.array(rq.struct_to_array_codes['L']) + mask_seq = array.array(rq.struct_to_array_codes['L']) # type: array.array[int] if isinstance(val, integer_types): # We need to build a "binary mask" that (as far as I can tell) is @@ -259,6 +282,7 @@ class XISelectEvents(rq.Request): ) def select_events(self, event_masks): + # type: (drawable.Window, Sequence[tuple[int, Sequence[int]]]) -> XISelectEvents ''' select_events(event_masks) @@ -284,6 +308,7 @@ def select_events(self, event_masks): class ButtonMask(object): def __init__(self, value, length): + # type: (int, int) -> None self._value = value self._length = length @@ -291,6 +316,7 @@ def __len__(self): return self._length def __getitem__(self, key): + # type: (int) -> int return self._value & (1 << key) def __str__(self): @@ -305,9 +331,11 @@ class ButtonState(rq.ValueField): structcode = None def __init__(self, name): + # type: (str) -> None rq.ValueField.__init__(self, name) def parse_binary_value(self, data, display, length, fmt): + # type: (_SliceableBuffer, object, int, object) -> tuple[ButtonMask, _SliceableBuffer] # Mask: bitfield of button states. mask_len = 4 * ((((length + 7) >> 3) + 3) >> 2) mask_data = data[:mask_len] @@ -382,6 +410,7 @@ class ClassInfoClass(object): structcode = None def parse_binary(self, data, display): + # type: (_SliceableBuffer, display.Display | None) -> tuple[rq.DictWrapper, _SliceableBuffer] class_type, length = struct.unpack('=HH', data[:4]) class_struct = INFO_CLASSES.get(class_type, AnyInfo) class_data, _ = class_struct.parse_binary(data, display) @@ -422,6 +451,7 @@ class XIQueryDevice(rq.ReplyRequest): ) def query_device(self, deviceid): + # type: (Display | resource.Resource, int) -> XIQueryDevice return XIQueryDevice( display=self.display, opcode=self.display.get_extension_major(extname), @@ -448,6 +478,7 @@ class XIListProperties(rq.ReplyRequest): ) def list_device_properties(self, deviceid): + # type: (Display | resource.Resource, int) -> XIListProperties return XIListProperties( display=self.display, opcode=self.display.get_extension_major(extname), @@ -482,6 +513,7 @@ class XIGetProperty(rq.ReplyRequest): ) def get_device_property(self, deviceid, property, type, offset, length, delete=False): + # type: (Display | resource.Resource, int, int, int, int, int, int) -> XIGetProperty return XIGetProperty( display=self.display, opcode=self.display.get_extension_major(extname), @@ -508,6 +540,7 @@ class XIChangeProperty(rq.Request): ) def change_device_property(self, deviceid, property, type, mode, value): + # type: (Display | resource.Resource, int, int, int, int, Sequence[float] | Sequence[str]) -> XIChangeProperty return XIChangeProperty( display=self.display, opcode=self.display.get_extension_major(extname), @@ -529,6 +562,7 @@ class XIDeleteProperty(rq.Request): ) def delete_device_property(self, deviceid, property): + # type: (Display | resource.Resource, int, int) -> XIDeleteProperty return XIDeleteProperty( display=self.display, opcode=self.display.get_extension_major(extname), @@ -563,6 +597,7 @@ class XIGrabDevice(rq.ReplyRequest): ) def grab_device(self, deviceid, time, grab_mode, paired_device_mode, owner_events, event_mask): + # type: (drawable.Window, int, int, int, int, bool, Sequence[int]) -> XIGrabDevice return XIGrabDevice( display=self.display, opcode=self.display.get_extension_major(extname), @@ -587,6 +622,7 @@ class XIUngrabDevice(rq.Request): ) def ungrab_device(self, deviceid, time): + # type: (Display | resource.Resource, int, int) -> XIUngrabDevice return XIUngrabDevice( display=self.display, opcode=self.display.get_extension_major(extname), @@ -629,6 +665,7 @@ class XIPassiveGrabDevice(rq.ReplyRequest): def passive_grab_device(self, deviceid, time, detail, grab_type, grab_mode, paired_device_mode, owner_events, event_mask, modifiers): + # type: (drawable.Window, int, int, int, int, int, int, bool, Sequence[int], Sequence[int]) -> XIPassiveGrabDevice return XIPassiveGrabDevice( display=self.display, opcode=self.display.get_extension_major(extname), @@ -648,6 +685,7 @@ def passive_grab_device(self, deviceid, time, detail, def grab_keycode(self, deviceid, time, keycode, grab_mode, paired_device_mode, owner_events, event_mask, modifiers): + # type: (drawable.Window, int, int, int, int, int, bool, Sequence[int], Sequence[int]) -> XIPassiveGrabDevice return passive_grab_device(self, deviceid, time, keycode, GrabtypeKeycode, grab_mode, paired_device_mode, @@ -671,6 +709,7 @@ class XIPassiveUngrabDevice(rq.Request): ) def passive_ungrab_device(self, deviceid, detail, grab_type, modifiers): + # type: (drawable.Window, int, int, int, Sequence[int]) -> XIPassiveUngrabDevice return XIPassiveUngrabDevice( display=self.display, opcode=self.display.get_extension_major(extname), @@ -682,6 +721,7 @@ def passive_ungrab_device(self, deviceid, detail, grab_type, modifiers): ) def ungrab_keycode(self, deviceid, keycode, modifiers): + # type: (drawable.Window, int, int, Sequence[int]) -> XIPassiveUngrabDevice return passive_ungrab_device(self, deviceid, keycode, GrabtypeKeycode, modifiers) @@ -758,6 +798,7 @@ def ungrab_keycode(self, deviceid, keycode, modifiers): ) def init(disp, info): + # type: (Display, request.QueryExtension) -> None disp.extension_add_method('display', 'xinput_query_version', query_version) disp.extension_add_method('window', 'xinput_select_events', select_events) disp.extension_add_method('display', 'xinput_query_device', query_device) diff --git a/Xlib/ext/xtest.py b/Xlib/ext/xtest.py index 602df2ae..0a8901f2 100644 --- a/Xlib/ext/xtest.py +++ b/Xlib/ext/xtest.py @@ -21,6 +21,8 @@ from Xlib import X from Xlib.protocol import rq +from Xlib.display import Display +from Xlib.xobject import resource extname = 'XTEST' @@ -44,6 +46,7 @@ class GetVersion(rq.ReplyRequest): ) def get_version(self, major, minor): + # type: (Display | resource.Resource, int, int) -> GetVersion return GetVersion(display = self.display, opcode = self.display.get_extension_major(extname), major_version = major, @@ -65,6 +68,7 @@ class CompareCursor(rq.ReplyRequest): ) def compare_cursor(self, cursor): + # type: (Display | resource.Resource, int) -> int r = CompareCursor(display = self.display, opcode = self.display.get_extension_major(extname), window = self.id, @@ -92,6 +96,7 @@ class FakeInput(rq.Request): def fake_input(self, event_type, detail = 0, time = X.CurrentTime, root = X.NONE, x = 0, y = 0): + # type: (Display | resource.Resource, int, int, int, int, int, int) -> None FakeInput(display = self.display, opcode = self.display.get_extension_major(extname), @@ -111,11 +116,13 @@ class GrabControl(rq.Request): ) def grab_control(self, impervious): + # type: (Display | resource.Resource, bool) -> None GrabControl(display = self.display, opcode = self.display.get_extension_major(extname), impervious = impervious) def init(disp, info): + # type: (Display, object) -> None disp.extension_add_method('display', 'xtest_get_version', get_version) disp.extension_add_method('window', 'xtest_compare_cursor', compare_cursor) disp.extension_add_method('display', 'xtest_fake_input', fake_input) diff --git a/Xlib/protocol/display.py b/Xlib/protocol/display.py index 56623c35..412a8f55 100644 --- a/Xlib/protocol/display.py +++ b/Xlib/protocol/display.py @@ -21,6 +21,8 @@ # Suite 330, # Boston, MA 02111-1307 USA +from __future__ import annotations + # Standard modules import errno import math @@ -30,7 +32,7 @@ import sys # Python 2/3 compatibility. -from six import PY3, byte2int, indexbytes +from six import byte2int, indexbytes # Xlib modules from .. import error @@ -42,11 +44,28 @@ from . import rq from . import event -if PY3: +try: + from typing import TYPE_CHECKING, overload, Union, Any, Optional, TypeVar +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from typing_extensions import TypeAlias, Literal + from array import array + from mmap import mmap + from collections.abc import Callable + from Xlib.display import _resource_baseclasses, _ResourceBaseClass + from Xlib.xobject import cursor, colormap, fontable, drawable, resource + _T = TypeVar("_T") + _BaseClasses = type(_resource_baseclasses) + _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array[Any], mmap] + _ErrorHandler: TypeAlias = Callable[[error.XError, Optional[rq.Request]], _T] + +if sys.version_info[0] == 3: class bytesview(object): def __init__(self, data, offset=0, size=None): + # type: (_SliceableBuffer | bytesview, int, int | None) -> None if size is None: size = len(data)-offset if isinstance(data, bytes): @@ -55,12 +74,21 @@ def __init__(self, data, offset=0, size=None): view = data.view else: raise TypeError('unsupported type: {}'.format(type(data))) - self.view = view[offset:offset+size] + self.view = view[offset:offset+size] # type: memoryview def __len__(self): return len(self.view) + if TYPE_CHECKING: + def __contains__(self, other: object) -> bool: ... + + @overload + def __getitem__(self, key: int) -> int: ... + @overload + def __getitem__(self, key: slice) -> bytes: ... + def __getitem__(self, key): + # type: (slice | int) -> bytes | int if isinstance(key, slice): return bytes(self.view[key]) return self.view[key] @@ -76,11 +104,13 @@ def bytesview(data, offset=0, size=None): class Display(object): - extension_major_opcodes = {} - error_classes = error.xerror_class.copy() - event_classes = event.event_class.copy() + extension_major_opcodes = {} # type: dict[str, int] + error_classes = error.xerror_class.copy() # type: dict[int, type[error.XError]] + event_classes = event.event_class.copy() # type: dict[int, type[rq.Event] | dict[int, type[rq.Event]]] + resource_classes = {} # type: _BaseClasses def __init__(self, display = None): + # type: (str | None) -> None name, protocol, host, displayno, screenno = connect.get_display(display) self.display_name = name @@ -97,17 +127,17 @@ def __init__(self, display = None): # Socket error indicator, set when the socket is closed # in one way or another self.socket_error_lock = lock.allocate_lock() - self.socket_error = None + self.socket_error = None # type: Exception | None # Event queue self.event_queue_read_lock = lock.allocate_lock() self.event_queue_write_lock = lock.allocate_lock() - self.event_queue = [] + self.event_queue = [] # type: list[rq.Event] # Unsent request queue and sequence number counter self.request_queue_lock = lock.allocate_lock() self.request_serial = 1 - self.request_queue = [] + self.request_queue = [] # type: list[tuple[rq.Request | rq.ReplyRequest | ConnectionSetupRequest, bool]] # Send-and-receive loop, see function send_and_receive # for a detailed explanation @@ -127,26 +157,26 @@ def __init__(self, display = None): self.recv_buffer_size = int(buffer_size) # Data used by the send-and-receive loop - self.sent_requests = [] + self.sent_requests = [] # type: list[rq.Request | rq.ReplyRequest | ConnectionSetupRequest] self.recv_packet_len = 0 self.data_send = b'' - self.data_recv = b'' + self.data_recv = b'' # type: bytes | bytesview self.data_sent_bytes = 0 # Resource ID structures self.resource_id_lock = lock.allocate_lock() - self.resource_ids = {} + self.resource_ids = {} # type: dict[int, None] self.last_resource_id = 0 # Use an default error handler, one which just prints the error - self.error_handler = None + self.error_handler = None # type: _ErrorHandler[object] | None # Right, now we're all set up for the connection setup # request with the server. # Figure out which endianness the hardware uses - self.big_endian = struct.unpack('BB', struct.pack('H', 0x0100))[0] + self.big_endian = struct.unpack('BB', struct.pack('H', 0x0100))[0] # type: bool if self.big_endian: order = 0x42 @@ -259,10 +289,12 @@ def close(self): self.close_internal('client') def set_error_handler(self, handler): + # type: (_ErrorHandler[object] | None) -> None self.error_handler = handler def allocate_resource_id(self): + # type: () -> int """id = d.allocate_resource_id() Allocate a new X resource id number ID. @@ -287,6 +319,7 @@ def allocate_resource_id(self): self.resource_id_lock.release() def free_resource_id(self, rid): + # type: (int) -> None """d.free_resource_id(rid) Free resource id RID. Attempts to free a resource id which @@ -309,8 +342,32 @@ def free_resource_id(self, rid): self.resource_id_lock.release() + if TYPE_CHECKING: + @overload + def get_resource_class(self, class_name: Literal['resource'], default: object = ...) -> type[resource.Resource]: ... + @overload + def get_resource_class(self, class_name: Literal['drawable'], default: object = ...) -> type[drawable.Drawable]: ... + @overload + def get_resource_class(self, class_name: Literal['window'], default: object = ...) -> type[drawable.Window]: ... + @overload + def get_resource_class(self, class_name: Literal['pixmap'], default: object = ...) -> type[drawable.Pixmap]: ... + @overload + def get_resource_class(self, class_name: Literal['fontable'], default: object = ...) -> type[fontable.Fontable]: ... + @overload + def get_resource_class(self, class_name: Literal['font'], default: object = ...) -> type[fontable.Font]: ... + @overload + def get_resource_class(self, class_name: Literal['gc'], default: object = ...) -> type[fontable.GC]: ... + @overload + def get_resource_class(self, class_name: Literal['colormap'], default: object = ...) -> type[colormap.Colormap]: ... + @overload + def get_resource_class(self, class_name: Literal['cursor'], default: object) -> type[cursor.Cursor]: ... + @overload + def get_resource_class(self, class_name: str, default: _T) -> type[_ResourceBaseClass] | _T: ... + @overload + def get_resource_class(self, class_name: str, default: None = ...) -> type[_ResourceBaseClass] | None: ... def get_resource_class(self, class_name, default = None): + # type: (str, _T | None) -> _T | None """class = d.get_resource_class(class_name, default = None) Return the class to be used for X resource objects of type @@ -320,12 +377,15 @@ def get_resource_class(self, class_name, default = None): return self.resource_classes.get(class_name, default) def set_extension_major(self, extname, major): + # type: (str, int) -> None self.extension_major_opcodes[extname] = major def get_extension_major(self, extname): + # type: (str) -> int return self.extension_major_opcodes[extname] def add_extension_event(self, code, evt, subcode=None): + # type: (int, type[rq.Event], int | None) -> None if subcode == None: self.event_classes[code] = evt else: @@ -335,6 +395,7 @@ def add_extension_event(self, code, evt, subcode=None): self.event_classes[code][subcode] = evt def add_extension_error(self, code, err): + # type: (int, type[error.XError]) -> None self.error_classes[code] = err @@ -351,6 +412,7 @@ def check_for_error(self): raise err def send_request(self, request, wait_for_response): + # type: (rq.Request | rq.ReplyRequest | ConnectionSetupRequest, bool) -> None if self.socket_error: raise self.socket_error @@ -368,6 +430,7 @@ def send_request(self, request, wait_for_response): # self.flush() def close_internal(self, whom): + # type: (object) -> None # Clear out data structures self.request_queue = None self.sent_requests = None @@ -385,6 +448,7 @@ def close_internal(self, whom): def send_and_recv(self, flush = None, event = None, request = None, recv = None): + # type: (bool, bool, int | None, bool) -> None """send_and_recv(flush = None, event = None, request = None, recv = None) Perform I/O, or wait for some other thread to do it for us. @@ -675,6 +739,7 @@ def send_and_recv(self, flush = None, event = None, request = None, recv = None) def parse_response(self, request): + # type: (int) -> bool """Internal method. Parse data received from server. If REQUEST is not None @@ -731,6 +796,7 @@ def parse_response(self, request): def parse_error_response(self, request): + # type: (int) -> bool # Code is second byte code = indexbytes(self.data_recv, 1) @@ -776,10 +842,12 @@ def parse_error_response(self, request): def default_error_handler(self, err): + # type: (object) -> None sys.stderr.write('X protocol error:\n%s\n' % err) def parse_request_response(self, request): + # type: (int) -> bool req = self.get_waiting_replyrequest() # Sequence number is always data[2:4] @@ -811,6 +879,7 @@ def parse_request_response(self, request): def parse_event_response(self, etype): + # type: (int) -> None # Skip bit 8, that is set if this event came from an SendEvent etype = etype & 0x7f @@ -866,6 +935,7 @@ def parse_event_response(self, etype): def get_waiting_request(self, sno): + # type: (int) -> rq.ReplyRequest | ConnectionSetupRequest | None if not self.sent_requests: return None @@ -1060,6 +1130,7 @@ class ConnectionSetupRequest(rq.GetAttrData): def __init__(self, display, *args, **keys): + # type: (Display, object, object) -> None self._binary = self._request.to_binary(*args, **keys) self._data = None diff --git a/Xlib/protocol/request.py b/Xlib/protocol/request.py index b431e137..b6c0dbab 100644 --- a/Xlib/protocol/request.py +++ b/Xlib/protocol/request.py @@ -26,6 +26,7 @@ # Xlib.protocol modules from . import rq from . import structs +from . import display class CreateWindow(rq.Request): @@ -786,6 +787,7 @@ class ListFontsWithInfo(rq.ReplyRequest): # Bastards. def __init__(self, *args, **keys): + # type: (display.Display, bool, object, object) -> None self._fonts = [] rq.ReplyRequest.__init__(self, *args, **keys) diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index 86cb2def..634c4c84 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -20,6 +20,7 @@ # Boston, MA 02111-1307 USA # Standard modules +from __future__ import annotations import sys import traceback import struct @@ -27,18 +28,39 @@ import types # Python 2/3 compatibility. -from six import PY3, binary_type, byte2int, indexbytes, iterbytes +from six import binary_type, byte2int, indexbytes, iterbytes # Xlib modules from .. import X from ..support import lock +try: + from typing import TYPE_CHECKING, Any, TypeVar, Union, Optional, SupportsInt, overload +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from ..display import _BaseDisplay + from mmap import mmap + from collections.abc import Iterable, Sequence, Callable + from typing_extensions import TypeAlias, Literal, SupportsIndex, LiteralString + from Xlib.error import XError + from Xlib.protocol import display + from pickle import PickleBuffer + from ctypes import _CData + from Xlib.ext.xinput import ClassInfoClass + from Xlib.display import _ResourceBaseClass + _T = TypeVar("_T") + _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array[Any], mmap] + _IntNew: TypeAlias = Union[str, _SliceableBuffer, _CData, PickleBuffer, SupportsInt, SupportsIndex] + _ErrorHandler: TypeAlias = Callable[[XError, Optional["Request"]], _T] def decode_string(bs): + # type: (bytes | bytearray) -> str return bs.decode('latin1') -if PY3: +if sys.version_info[0] == 3: def encode_array(a): + # type: (array[Any] | memoryview) -> bytes return a.tobytes() else: def encode_array(a): @@ -60,8 +82,8 @@ class BadDataError(Exception): pass # # Bleah. -array_unsigned_codes = { } -struct_to_array_codes = { } +array_unsigned_codes = { } # type: dict[int, LiteralString] +struct_to_array_codes = { } # type: dict[str, LiteralString] for c in 'bhil': size = array(c).itemsize @@ -110,14 +132,15 @@ class Field(object): f.parse_binary_value() instead. See its documentation string for details. """ - name = None - default = None + name = None # type: str + default = None # type: int | None + pack_value = None # type: Callable[[Any], tuple[Any, int | None, int | None]] | None - structcode = None + structcode = None # type: str | None structvalues = 0 - check_value = None - parse_value = None + check_value = None # type: Callable[[Any], Any] | None + parse_value = None # type: Callable[[Any, Any], Any] | None keyword_args = 0 @@ -125,6 +148,7 @@ def __init__(self): pass def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, display.Display | None, int, int) -> tuple[Any, _SliceableBuffer] """value, remaindata = f.parse_binary_value(data, display, length, format) Decode a value for this field from the binary string DATA. @@ -144,6 +168,7 @@ def parse_binary_value(self, data, display, length, format): class Pad(Field): def __init__(self, size): + # type: (int) -> None self.size = size self.value = b'\0' * size self.structcode = '{0}x'.format(size) @@ -152,6 +177,7 @@ def __init__(self, size): class ConstantField(Field): def __init__(self, value): + # type: (int) -> None self.value = value @@ -183,9 +209,10 @@ class LengthField(Field): """ structcode = 'L' structvalues = 1 - other_fields = None + other_fields = None # type: Sequence[str] | None def calc_length(self, length): + # type: (int) -> int """newlen = lf.calc_length(length) Return a new length NEWLEN based on the provided LENGTH. @@ -202,6 +229,7 @@ class RequestLength(TotalLengthField): structvalues = 1 def calc_length(self, length): + # type: (int) -> int return length // 4 class ReplyLength(TotalLengthField): @@ -209,11 +237,13 @@ class ReplyLength(TotalLengthField): structvalues = 1 def calc_length(self, length): + # type: (int) -> int return (length - 32) // 4 class LengthOf(LengthField): def __init__(self, name, size): + # type: (str | list[str] | tuple[str, ...], int) -> None if isinstance(name, (list, tuple)): self.name = name[0] self.other_fields = name[1:] @@ -227,12 +257,15 @@ class OddLength(LengthField): structvalues = 1 def __init__(self, name): + # type: (str) -> None self.name = name def calc_length(self, length): + # type: (int) -> int return length % 2 def parse_value(self, value, display): + # type: (int, object) -> Literal['even', 'odd'] if value == 0: return 'even' else: @@ -250,6 +283,7 @@ class FormatField(Field): structvalues = 1 def __init__(self, name, size): + # type: (str, int) -> None self.name = name self.structcode = unsigned_codes[size] @@ -258,6 +292,7 @@ def __init__(self, name, size): class ValueField(Field): def __init__(self, name, default = None): + # type: (str, int | None) -> None self.name = name self.default = default @@ -292,16 +327,19 @@ class Resource(Card32): class_name = 'resource' def __init__(self, name, codes = (), default = None): + # type: (str, tuple[int, ...], int | None) -> None Card32.__init__(self, name, default) self.codes = codes def check_value(self, value): + # type: (Callable[[], _T]) -> _T | int if hasattr(value, self.cast_function): return getattr(value, self.cast_function)() else: return value def parse_value(self, value, display): + # type: (int, _BaseDisplay) -> int | _ResourceBaseClass # if not display: # return value if value in self.codes: @@ -351,17 +389,20 @@ class Bool(ValueField): structcode = 'B' def check_value(self, value): + # type: (object) -> bool return not not value class Set(ValueField): structvalues = 1 def __init__(self, name, size, values, default = None): + # type: (str, int, Sequence[object], int | None) -> None ValueField.__init__(self, name, default) self.structcode = unsigned_codes[size] self.values = values def check_value(self, val): + # type: (_T) -> _T if val not in self.values: raise ValueError('field %s: argument %s not in %s' % (self.name, val, self.values)) @@ -370,6 +411,7 @@ def check_value(self, val): class Gravity(Set): def __init__(self, name): + # type: (str) -> None Set.__init__(self, name, 1, (X.ForgetGravity, X.StaticGravity, X.NorthWestGravity, X.NorthGravity, X.NorthEastGravity, X.WestGravity, @@ -382,6 +424,7 @@ class FixedBinary(ValueField): structvalues = 1 def __init__(self, name, size): + # type: (str, int) -> None ValueField.__init__(self, name) self.structcode = '{0}s'.format(size) @@ -390,10 +433,12 @@ class Binary(ValueField): structcode = None def __init__(self, name, pad = 1): + # type: (str, int) -> None ValueField.__init__(self, name) self.pad = pad def pack_value(self, val): + # type: (bytes | bytearray) -> tuple[bytes | bytearray, int, None] val_bytes = val slen = len(val_bytes) @@ -401,8 +446,14 @@ def pack_value(self, val): return val_bytes + b'\0' * ((4 - slen % 4) % 4), slen, None else: return val_bytes, slen, None + if TYPE_CHECKING: + @overload + def parse_binary_value(self, data: _T, display: object, length: None, format: object) -> tuple[_T, Literal[b'']]: ... + @overload + def parse_binary_value(self, data: _SliceableBuffer, display: object, length: int, format: object) -> tuple[_SliceableBuffer, _SliceableBuffer]: ... def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, object, int, object) -> tuple[_SliceableBuffer, _SliceableBuffer] if length is None: return data, b'' @@ -418,10 +469,12 @@ class String8(ValueField): structcode = None def __init__(self, name, pad = 1): + # type: (str, int) -> None ValueField.__init__(self, name) self.pad = pad def pack_value(self, val): + # type: (bytes | str) -> tuple[bytes, int, None] if isinstance(val, bytes): val_bytes = val else: @@ -433,7 +486,14 @@ def pack_value(self, val): else: return val_bytes, slen, None + if TYPE_CHECKING: + @overload + def parse_binary_value(self, data: bytes | bytearray, display: object, length: None, format: object) -> tuple[str, Literal[b'']]: ... + @overload + def parse_binary_value(self, data: _SliceableBuffer, display: object, length: int, format: object) -> tuple[str, _SliceableBuffer]: ... + def parse_binary_value(self, data, display, length, format): + # type: (bytes | bytearray, object, int, object) -> tuple[str, bytes | bytearray] if length is None: return decode_string(data), b'' @@ -451,10 +511,12 @@ class String16(ValueField): structcode = None def __init__(self, name, pad = 1): + # type: (str, int) -> None ValueField.__init__(self, name) self.pad = pad def pack_value(self, val): + # type: (Sequence[object]) -> tuple[bytes, int, None] """Convert 8-byte string into 16-byte list""" if isinstance(val, bytes): val = list(iterbytes(val)) @@ -469,6 +531,7 @@ def pack_value(self, val): return struct.pack('>' + 'H' * slen, *val) + pad, slen, None def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, object, int | Literal['odd', 'even'], object) -> tuple[tuple[Any, ...], _SliceableBuffer] if length == 'odd': length = len(data) // 2 - 1 elif length == 'even': @@ -495,11 +558,13 @@ class List(ValueField): structcode = None def __init__(self, name, type, pad = 1): + # type: (str, Struct | ScalarObj | ResourceObj | ClassInfoClass | type[ValueField], int) -> None ValueField.__init__(self, name) self.type = type self.pad = pad def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, display.Display | None, SupportsIndex | None, object) -> tuple[list[DictWrapper | None], _SliceableBuffer] if length is None: ret = [] if self.type.structcode is None: @@ -556,6 +621,7 @@ def parse_binary_value(self, data, display, length, format): return ret, data def pack_value(self, val): + # type: (Sequence[object] | dict[str, object]) -> tuple[bytes, int, None] # Single-char values, we'll assume that means integer lists. if self.type.structcode and len(self.type.structcode) == 1: if self.type.check_value is not None: @@ -578,13 +644,16 @@ def pack_value(self, val): class FixedList(List): def __init__(self, name, size, type, pad = 1): + # type: (str, int, Struct | ScalarObj, int) -> None List.__init__(self, name, type, pad) self.size = size def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, display.Display | None, object, object) -> tuple[list[DictWrapper | None], _SliceableBuffer] return List.parse_binary_value(self, data, display, self.size, format) def pack_value(self, val): + # type: (Sequence[object] | dict[str, object]) -> tuple[bytes, int, None] if len(val) != self.size: raise BadDataError('length mismatch for FixedList %s' % self.name) return List.pack_value(self, val) @@ -592,21 +661,26 @@ def pack_value(self, val): class Object(ValueField): def __init__(self, name, type, default = None): + # type: (str, Struct, int | None) -> None ValueField.__init__(self, name, default) self.type = type self.structcode = self.type.structcode self.structvalues = self.type.structvalues def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, display.Display | None, object, object) -> tuple[DictWrapper, _SliceableBuffer] return self.type.parse_binary(data, display) def parse_value(self, val, display): + # type: (_SliceableBuffer, display.Display | None) -> DictWrapper return self.type.parse_value(val, display) def pack_value(self, val): + # type: (tuple[object, ...] | dict[str, object] | DictWrapper) -> bytes return self.type.pack_value(val) def check_value(self, val): + # type: (tuple[_T, ...] | dict[str, _T] | DictWrapper) -> list[_T] if isinstance(val, tuple): vals = [] i = 0 @@ -649,6 +723,7 @@ class PropertyData(ValueField): structcode = None def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, object, _IntNew | None, int) -> tuple[tuple[int, _SliceableBuffer] | None, _SliceableBuffer] if length is None: length = len(data) // (format // 8) else: @@ -672,6 +747,7 @@ def parse_binary_value(self, data, display, length, format): return ret, data def pack_value(self, value): + # type: (tuple[int, Sequence[float] | Sequence[str]]) -> tuple[bytes, int, Literal[8, 16, 32]] fmt, val = value if fmt not in (8, 16, 32): @@ -705,14 +781,17 @@ def pack_value(self, value): class FixedPropertyData(PropertyData): def __init__(self, name, size): + # type: (str, int) -> None PropertyData.__init__(self, name) self.size = size def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, object, _IntNew | None, int) -> tuple[tuple[int, _SliceableBuffer] | None, _SliceableBuffer] return PropertyData.parse_binary_value(self, data, display, self.size // (format // 8), format) def pack_value(self, value): + # type: (tuple[int, Sequence[float] | Sequence[str]]) -> tuple[bytes, int, Literal[8, 16, 32]] data, dlen, fmt = PropertyData.pack_value(self, value) if len(data) != self.size: @@ -728,10 +807,11 @@ class ValueList(Field): default = 'usekeywords' def __init__(self, name, mask, pad, *fields): + # type: (str, int, int, _HasStructCodeAndName) -> None self.name = name self.maskcode = '={0}{1}x'.format(unsigned_codes[mask], pad).encode() self.maskcodelen = struct.calcsize(self.maskcode) - self.fields = [] + self.fields = [] # type: list[tuple[_HasStructCodeAndName, int]] flag = 1 for f in fields: @@ -740,6 +820,7 @@ def __init__(self, name, mask, pad, *fields): flag = flag << 1 def pack_value(self, arg, keys): + # type: (str | dict[str, object], dict[str, object]) -> tuple[bytes, None, None] mask = 0 data = b'' @@ -760,6 +841,7 @@ def pack_value(self, arg, keys): return struct.pack(self.maskcode, mask) + data, None, None def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, display.Display | None, object, object) -> tuple[DictWrapper, _SliceableBuffer] r = {} mask = int(struct.unpack(self.maskcode, data[:self.maskcodelen])[0]) @@ -789,6 +871,7 @@ class KeyboardMapping(ValueField): structcode = None def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, object, int | None, int) -> tuple[list[int], _SliceableBuffer] if length is None: dlen = len(data) else: @@ -803,6 +886,7 @@ def parse_binary_value(self, data, display, length, format): return ret, data[dlen:] def pack_value(self, value): + # type: (Sequence[Sequence[object]]) -> tuple[bytes, int, int] keycodes = 0 for v in value: keycodes = max(keycodes, len(v)) @@ -822,6 +906,7 @@ class ModifierMapping(ValueField): structcode = None def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, object, object, int) -> tuple[list[array[int]], _SliceableBuffer] a = array(array_unsigned_codes[1], data[:8 * format]) ret = [] @@ -831,6 +916,7 @@ def parse_binary_value(self, data, display, length, format): return ret, data[8 * format:] def pack_value(self, value): + # type: (Sequence[Sequence[object]] | tuple[Sequence[object], Sequence[object], Sequence[object], Sequence[object], Sequence[object], Sequence[object], Sequence[object], Sequence[object]]) -> tuple[bytes, int, int] if len(value) != 8: raise BadDataError('ModifierMapping list should have eight elements') @@ -852,16 +938,17 @@ class EventField(ValueField): structcode = None def pack_value(self, value): + # type: (Event) -> tuple[_SliceableBuffer, None, None] if not isinstance(value, Event): raise BadDataError('%s is not an Event for field %s' % (value, self.name)) return value._binary, None, None def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, display.Display, object, object) -> tuple[Event, _SliceableBuffer] from . import event - estruct = display.event_classes.get(byte2int(data) & 0x7f, event.AnyEvent) - if type(estruct) == dict: + estruct = display.event_classes.get(byte2int(data) & 0x7f, event.AnyEvent) # type: dict[int, type[Event]] | type[Event] # this etype refers to a set of sub-events with individual subcodes estruct = estruct[indexbytes(data, 1)] @@ -889,10 +976,12 @@ class ResourceObj(object): structvalues = 1 def __init__(self, class_name): + # type: (str) -> None self.class_name = class_name self.check_value = None def parse_value(self, value, display): + # type: (int, _BaseDisplay) -> int | _ResourceBaseClass # if not display: # return value c = display.get_resource_class(self.class_name) @@ -908,9 +997,11 @@ class StrClass(object): structcode = None def pack_value(self, val): + # type: (str) -> bytes return (chr(len(val)) + val).encode() def parse_binary(self, data, display): + # type: (bytes | bytearray, object) -> tuple[str, _SliceableBuffer] slen = byte2int(data) + 1 return decode_string(data[1:slen]), data[slen:] @@ -940,14 +1031,15 @@ class Field. The fields of a structure are given as arguments """ def __init__(self, *fields): + # type: (Field) -> None self.fields = fields # Structures for to_binary, parse_value and parse_binary self.static_codes = '=' self.static_values = 0 - self.static_fields = [] + self.static_fields = [] # type: list[Field] self.static_size = None - self.var_fields = [] + self.var_fields = [] # type: list[Field] for f in self.fields: # Append structcode if there is one and we haven't @@ -981,6 +1073,7 @@ def __init__(self, *fields): # object def to_binary(self, *varargs, **keys): + # type: (object, object) -> bytes """data = s.to_binary(...) Convert Python values into the binary representation. The @@ -1072,6 +1165,7 @@ def to_binary(self, *varargs, **keys): def pack_value(self, value): + # type: (tuple[object, ...] | dict[str, object] | DictWrapper) -> bytes """ This function allows Struct objects to be used in List and Object fields. Each item represents the arguments to pass to @@ -1088,8 +1182,19 @@ def pack_value(self, value): else: raise BadDataError('%s is not a tuple or a list' % (value)) + if TYPE_CHECKING: + # Structs generate their attributes + # TODO: Complete all classes inheriting from Struct + # and create a type-only class for all direct instances + def __getattr__(self, __name: str) -> Any: ... + + @overload + def parse_value(self, val: _SliceableBuffer, display: display.Display | None, rawdict: Literal[True]) -> dict[str, Any]: ... + @overload + def parse_value(self, val: _SliceableBuffer, display: display.Display | None, rawdict: Literal[False] = ...) -> DictWrapper:... def parse_value(self, val, display, rawdict = 0): + # type: (_SliceableBuffer, display.Display | None, bool) -> dict[str, Any] | DictWrapper """This function is used by List and Object fields to convert Struct objects with no var_fields into Python values. @@ -1132,7 +1237,13 @@ def parse_value(self, val, display, rawdict = 0): return DictWrapper(ret) return ret + if TYPE_CHECKING: + @overload + def parse_binary(self, data: _SliceableBuffer, display: display.Display | None, rawdict: Literal[True]) -> tuple[dict[str, Any], _SliceableBuffer]: ... + @overload + def parse_binary(self, data: _SliceableBuffer, display: display.Display | None, rawdict: Literal[False] = ...) -> tuple[DictWrapper , _SliceableBuffer]:... def parse_binary(self, data, display, rawdict = 0): + # type: (_SliceableBuffer, display.Display | None, bool) -> tuple[DictWrapper | dict[str, Any], _SliceableBuffer] """values, remdata = s.parse_binary(data, display, rawdict = 0) @@ -1153,8 +1264,8 @@ def parse_binary(self, data, display, rawdict = 0): """ ret = {} val = struct.unpack(self.static_codes, data[:self.static_size]) - lengths = {} - formats = {} + lengths = {} # type: dict[str, int] + formats = {} # type: dict[str, int] vno = 0 for f in self.static_fields: @@ -1216,6 +1327,7 @@ class TextElements8(ValueField): String8('string', pad = 0) ) def pack_value(self, value): + # type: (Iterable[Field | str | bytes | tuple[Sequence[object], ...] | dict[str, Sequence[object]] | DictWrapper]) -> tuple[bytes, None, None] data = b'' args = {} @@ -1257,7 +1369,8 @@ def pack_value(self, value): return data + b'\0' * ((4 - dlen % 4) % 4), None, None def parse_binary_value(self, data, display, length, format): - values = [] + # type: (_SliceableBuffer, display.Display | None, object, object) -> tuple[list[DictWrapper], Literal[b'']] + values = [] # type: list[DictWrapper] while 1: if len(data) < 2: break @@ -1288,7 +1401,10 @@ class TextElements16(TextElements8): class GetAttrData(object): + # GetAttrData classes get their attributes dynamically + # TODO: Complete all classes inheriting from GetAttrData def __getattr__(self, attr): + # type: (str) -> Any try: if self._data: return self._data[attr] @@ -1296,24 +1412,32 @@ def __getattr__(self, attr): raise AttributeError(attr) except KeyError: raise AttributeError(attr) + if TYPE_CHECKING: + def __setattr__(self, __name: str, __value: Any) -> None: ... class DictWrapper(GetAttrData): def __init__(self, dict): + # type: (dict[str, object]) -> None self.__dict__['_data'] = dict def __getitem__(self, key): + # type: (str) -> object return self._data[key] def __setitem__(self, key, value): + # type: (str, object) -> None self._data[key] = value def __delitem__(self, key): + # type: (str) -> None del self._data[key] def __setattr__(self, key, value): + # type: (str, object) -> None self._data[key] = value def __delattr__(self, key): + # type: (str) -> None del self._data[key] def __str__(self): @@ -1323,18 +1447,21 @@ def __repr__(self): return '%s(%s)' % (self.__class__.__name__, repr(self._data)) def __lt__(self, other): + # type: (object) -> bool if isinstance(other, DictWrapper): return self._data < other._data else: return self._data < other def __gt__(self, other): + # type: (object) -> bool if isinstance(other, DictWrapper): return self._data > other._data else: return self._data > other def __eq__(self, other): + # type: (object) -> bool if isinstance(other, DictWrapper): return self._data == other._data else: @@ -1343,6 +1470,7 @@ def __eq__(self, other): class Request(object): def __init__(self, display, onerror = None, *args, **keys): + # type: (_BaseDisplay, _ErrorHandler[object] | None, object, object) -> None self._errorhandler = onerror self._binary = self._request.to_binary(*args, **keys) self._serial = None @@ -1356,10 +1484,10 @@ def _set_error(self, error): class ReplyRequest(GetAttrData): def __init__(self, display, defer = 0, *args, **keys): + # type: (display.Display, bool, object, object) -> None self._display = display self._binary = self._request.to_binary(*args, **keys) - self._serial = None - self._data = None + self._serial = None # type: int | None self._error = None self._response_lock = lock.allocate_lock() @@ -1406,6 +1534,7 @@ def __repr__(self): class Event(GetAttrData): def __init__(self, binarydata = None, display = None, **keys): + # type: (_SliceableBuffer | None, display.Display | None, object) -> None if binarydata: self._binary = binarydata self._data, data = self._fields.parse_binary(binarydata, display, @@ -1437,18 +1566,21 @@ def __repr__(self): return '%s(%s)' % (self.__class__.__name__, kws) def __lt__(self, other): + # type: (object) -> bool if isinstance(other, Event): return self._data < other._data else: return self._data < other def __gt__(self, other): + # type: (object) -> bool if isinstance(other, Event): return self._data > other._data else: return self._data > other def __eq__(self, other): + # type: (object) -> bool if isinstance(other, Event): return self._data == other._data else: @@ -1456,9 +1588,14 @@ def __eq__(self, other): def call_error_handler(handler, error, request): + # type: (_ErrorHandler[_T], XError, Request | None) -> _T | Literal[0] try: return handler(error, request) except: sys.stderr.write('Exception raised by error handler.\n') traceback.print_exc() return 0 + +if TYPE_CHECKING: + # What about StrClass, Mask, RawField, SizeOf, FP1616 and FP3232 ? + _HasStructCodeAndName: TypeAlias = Union[Pad, Opcode, ReplyCode, LengthField, FormatField, Int8, Int16, Int32, Card8, Card16, Card32, Bool, Set, FixedBinary] diff --git a/Xlib/protocol/structs.py b/Xlib/protocol/structs.py index 1661440d..430cbacd 100644 --- a/Xlib/protocol/structs.py +++ b/Xlib/protocol/structs.py @@ -25,7 +25,11 @@ # Xlib.protocol modules from . import rq +# TODO: Complete all classes using WindowValues and GCValues +# Currently *object is used to represent the ValueList instead of the possible attribute types + def WindowValues(arg): + # type: (str) -> rq.ValueList return rq.ValueList( arg, 4, 0, rq.Pixmap('background_pixmap'), rq.Card32('background_pixel'), @@ -46,6 +50,7 @@ def WindowValues(arg): ) def GCValues(arg): + # type: (str) -> rq.ValueList return rq.ValueList( arg, 4, 0, rq.Set('function', 1, (X.GXclear, X.GXand, X.GXandReverse, diff --git a/Xlib/py.typed b/Xlib/py.typed new file mode 100644 index 00000000..4521c3fb --- /dev/null +++ b/Xlib/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561. The Xlib package uses inline types. diff --git a/Xlib/rdb.py b/Xlib/rdb.py index 03b06e2a..ed71ef62 100644 --- a/Xlib/rdb.py +++ b/Xlib/rdb.py @@ -22,7 +22,7 @@ # See end of file for an explanation of the algorithm and # data structures used. - +from __future__ import annotations # Standard modules import re @@ -31,6 +31,24 @@ # Xlib modules from .support import lock +try: + from typing import TYPE_CHECKING, Any, TypeVar, Protocol, overload +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from collections.abc import Iterable, Sequence + from _typeshed import SupportsRead, SupportsDunderLT, SupportsDunderGT + class SupportsDunderEQ(Protocol): + def __eq__(self, __other: object) -> bool: ... + class SupportsComparisons( + SupportsDunderLT[object], SupportsDunderGT[object], SupportsDunderEQ, Protocol + ): ... + from typing_extensions import TypeAlias + from Xlib import display + _T = TypeVar("_T") + _C = TypeVar("_C", bound=SupportsComparisons) + _DB: TypeAlias = dict[str, tuple["_DB", ...]] + # Set up a few regexpes for parsing string representation of resources comment_re = re.compile(r'^\s*!') @@ -52,7 +70,8 @@ class OptionError(Exception): class ResourceDB(object): def __init__(self, file = None, string = None, resources = None): - self.db = {} + # type: (bytes | SupportsRead[str] | None, str | None, Iterable[tuple[str, object]] | None) -> None + self.db = {} # type: _DB self.lock = lock.allocate_lock() if file is not None: @@ -63,6 +82,7 @@ def __init__(self, file = None, string = None, resources = None): self.insert_resources(resources) def insert_file(self, file): + # type: (bytes | SupportsRead[str]) -> None """insert_file(file) Load resources entries from FILE, and insert them into the @@ -77,6 +97,7 @@ def insert_file(self, file): def insert_string(self, data): + # type: (str) -> None """insert_string(data) Insert the resources entries in the string DATA into the @@ -137,6 +158,7 @@ def insert_string(self, data): def insert_resources(self, resources): + # type: (Iterable[tuple[str, object]]) -> None """insert_resources(resources) Insert all resources entries in the list RESOURCES into the @@ -152,6 +174,7 @@ def insert_resources(self, resources): self.insert(res, value) def insert(self, resource, value): + # type: (str, object) -> None """insert(resource, value) Insert a resource entry into the database. RESOURCE is a @@ -191,6 +214,7 @@ def insert(self, resource, value): self.lock.release() def __getitem__(self, keys_tuple): + # type: (tuple[str, str]) -> Any """db[name, class] Return the value matching the resource identified by NAME and @@ -303,7 +327,14 @@ def __getitem__(self, keys_tuple): finally: self.lock.release() + if TYPE_CHECKING: + @overload + def get(self, res: str, cls: str, default: None = ...) -> Any: ... + @overload + def get(self, res: str, cls: str, default: _T) -> _T: ... + def get(self, res, cls, default = None): + # type: (str, str, object) -> Any """get(name, class [, default]) Return the value matching the resource identified by NAME and @@ -318,6 +349,7 @@ def get(self, res, cls, default = None): return default def update(self, db): + # type: (ResourceDB) -> None """update(db) Update this database with all resources entries in the resource @@ -341,6 +373,7 @@ def output(self): return text def getopt(self, name, argv, opts): + # type: (str, Sequence[str], dict[str, Option]) -> Sequence[str] """getopt(name, argv, opts) Parse X command line options, inserting the recognised options @@ -452,6 +485,7 @@ def value(self): # def bin_insert(list, element): + # type: (list[_C], _C) -> None """bin_insert(list, element) Insert ELEMENT into LIST. LIST must be sorted, and ELEMENT will @@ -487,6 +521,7 @@ def bin_insert(list, element): # def update_db(dest, src): + # type: (_DB, _DB) -> None for comp, group in src.items(): # DEST already contains this component, update it @@ -507,9 +542,11 @@ def update_db(dest, src): dest[comp] = copy_group(group) def copy_group(group): + # type: (tuple[_DB, ...]) -> tuple[_DB, ...] return (copy_db(group[0]), copy_db(group[1])) + group[2:] def copy_db(db): + # type: (_DB) -> _DB newdb = {} for comp, group in db.items(): newdb[comp] = copy_group(group) @@ -522,6 +559,7 @@ def copy_db(db): # def output_db(prefix, db): + # type: (str, _DB) -> str res = '' for comp, group in db.items(): @@ -536,6 +574,7 @@ def output_db(prefix, db): return res def output_escape(value): + # type: (object) -> str value = str(value) if not value: return value @@ -564,39 +603,47 @@ def __init__(self): pass def parse(self, name, db, args): + # type: (str, ResourceDB, Sequence[_T]) -> Sequence[_T] pass class NoArg(Option): """Value is provided to constructor.""" def __init__(self, specifier, value): + # type: (str, object) -> None self.specifier = specifier self.value = value def parse(self, name, db, args): + # type: (str, ResourceDB, Sequence[_T]) -> Sequence[_T] db.insert(name + self.specifier, self.value) return args[1:] class IsArg(Option): """Value is the option string itself.""" def __init__(self, specifier): + # type: (str) -> None self.specifier = specifier def parse(self, name, db, args): + # type: (str, ResourceDB, Sequence[_T]) -> Sequence[_T] db.insert(name + self.specifier, args[0]) return args[1:] class SepArg(Option): """Value is the next argument.""" def __init__(self, specifier): + # type: (str) -> None self.specifier = specifier def parse(self, name, db, args): + # type: (str, ResourceDB, Sequence[_T]) -> Sequence[_T] db.insert(name + self.specifier, args[1]) return args[2:] class ResArgClass(Option): """Resource and value in the next argument.""" def parse(self, name, db, args): + # type: (str, ResourceDB, Sequence[str]) -> Sequence[str] db.insert_string(args[1]) return args[2:] @@ -605,6 +652,7 @@ def parse(self, name, db, args): class SkipArgClass(Option): """Ignore this option and next argument.""" def parse(self, name, db, args): + # type: (str, ResourceDB, Sequence[_T]) -> Sequence[_T] return args[2:] SkipArg = SkipArgClass() @@ -612,6 +660,7 @@ def parse(self, name, db, args): class SkipLineClass(Option): """Ignore rest of the arguments.""" def parse(self, name, db, args): + # type: (str, ResourceDB, Sequence[_T]) -> Sequence[_T] return [] SkipLine = SkipLineClass() @@ -619,14 +668,17 @@ def parse(self, name, db, args): class SkipNArgs(Option): """Ignore this option and the next COUNT arguments.""" def __init__(self, count): + # type: (int) -> None self.count = count def parse(self, name, db, args): + # type: (str, ResourceDB, Sequence[_T]) -> Sequence[_T] return args[1 + self.count:] def get_display_opts(options, argv = sys.argv): + # type: (dict[str, Option], Sequence[str]) -> tuple[display.Display, str, ResourceDB, Sequence[str]] """display, name, db, args = get_display_opts(options, [argv]) Parse X OPTIONS from ARGV (or sys.argv if not provided). diff --git a/Xlib/support/connect.py b/Xlib/support/connect.py index 4db4c2f4..31e6cd3e 100644 --- a/Xlib/support/connect.py +++ b/Xlib/support/connect.py @@ -18,10 +18,21 @@ # 59 Temple Place, # Suite 330, # Boston, MA 02111-1307 USA +from __future__ import annotations import sys import importlib +try: + from typing import TYPE_CHECKING, Any, Union +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + import socket + from typing_extensions import TypeAlias + from Xlib.support.unix_connect import _Protocol + _Address: TypeAlias = Union[tuple[Any, ...], str] + # List the modules which contain the corresponding functions _display_mods = { @@ -54,8 +65,14 @@ def _relative_import(modname): return importlib.import_module('..' + modname, __name__) +if TYPE_CHECKING: + if sys.platform == 'OpenVMS': + from Xlib.support.vms_connect import get_display as get_display, get_socket as get_socket + else: + from Xlib.support.unix_connect import get_display as get_display, get_socket as get_socket def get_display(display): + # type: (str | None) -> tuple[str, str | None, str | None, int, int] """dname, protocol, host, dno, screen = get_display(display) Parse DISPLAY into its components. If DISPLAY is None, use @@ -72,8 +89,8 @@ def get_display(display): mod = _relative_import(modname) return mod.get_display(display) - def get_socket(dname, protocol, host, dno): + # type: (_Address, _Protocol, _Address | None, int) -> socket.socket """socket = get_socket(dname, protocol, host, dno) Connect to the display specified by DNAME, PROTOCOL, HOST and DNO, which @@ -88,6 +105,7 @@ def get_socket(dname, protocol, host, dno): def get_auth(sock, dname, protocol, host, dno): + # type: (socket.socket, object, _Protocol, object, int) -> tuple[bytes, bytes] """auth_name, auth_data = get_auth(sock, dname, protocol, host, dno) Return authentication data for the display on the other side of diff --git a/Xlib/support/lock.py b/Xlib/support/lock.py index 6eee31f4..fd1af54c 100644 --- a/Xlib/support/lock.py +++ b/Xlib/support/lock.py @@ -34,6 +34,7 @@ def __init__(self): self.acquire = self.release = self.locked = self.__noop def __noop(self, *args): + # type: (object) -> None return diff --git a/Xlib/support/unix_connect.py b/Xlib/support/unix_connect.py index c2261dae..6401e987 100644 --- a/Xlib/support/unix_connect.py +++ b/Xlib/support/unix_connect.py @@ -19,35 +19,37 @@ # Suite 330, # Boston, MA 02111-1307 USA +import sys import re import os import platform import socket -# FCNTL is deprecated from Python 2.2, so only import it if we doesn't -# get the names we need. Furthermore, FD_CLOEXEC seems to be missing -# in Python 2.2. - -import fcntl - -if hasattr(fcntl, 'F_SETFD'): - F_SETFD = fcntl.F_SETFD - if hasattr(fcntl, 'FD_CLOEXEC'): - FD_CLOEXEC = fcntl.FD_CLOEXEC - else: - FD_CLOEXEC = 1 -else: - from FCNTL import F_SETFD, FD_CLOEXEC +try: + import fcntl + FD_CLOEXEC = getattr(fcntl, 'FD_CLOEXEC', 1) + F_SETFD = getattr(fcntl, 'F_SETFD', 2) +except ImportError: + FD_CLOEXEC = 1 + F_SETFD = 2 from Xlib import error, xauth SUPPORTED_PROTOCOLS = (None, 'tcp', 'unix') +try: + from typing import TYPE_CHECKING, Any, Union +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from typing_extensions import TypeAlias + _Protocol = type(SUPPORTED_PROTOCOLS) + _Address: TypeAlias = Union[tuple[Any, ...], str] + # Darwin funky socket. -uname = platform.uname() -if (uname[0] == 'Darwin') and ([int(x) for x in uname[2].split('.')] >= [9, 0]): +if sys.platform == 'darwin' and ([int(x) for x in platform.release().split('.')] >= [9, 0]): SUPPORTED_PROTOCOLS += ('darwin',) DARWIN_DISPLAY_RE = re.compile(r'^/private/tmp/[-:a-zA-Z0-9._]*:(?P[0-9]+)(\.(?P[0-9]+))?$') @@ -55,13 +57,14 @@ def get_display(display): + # type: (str | None) -> tuple[str, str | None, str | None, int, int] # Use $DISPLAY if display isn't provided if display is None: display = os.environ.get('DISPLAY', '') - re_list = [(DISPLAY_RE, {})] + re_list = [(DISPLAY_RE, {})] # type: list[tuple[re.Pattern[str], dict[str, str]]] - if 'darwin' in SUPPORTED_PROTOCOLS: + if sys.platform == 'darwin' and 'darwin' in SUPPORTED_PROTOCOLS: re_list.insert(0, (DARWIN_DISPLAY_RE, {'protocol': 'darwin'})) for re, defaults in re_list: @@ -99,6 +102,7 @@ def _get_unix_socket(address): return s def get_socket(dname, protocol, host, dno): + # type: (_Address, _Protocol, _Address | None, int) -> socket.socket assert protocol in SUPPORTED_PROTOCOLS try: # Darwin funky socket. @@ -133,6 +137,7 @@ def get_socket(dname, protocol, host, dno): def new_get_auth(sock, dname, protocol, host, dno): + # type: (socket.socket, object, _Protocol, object, int) -> tuple[bytes, bytes] assert protocol in SUPPORTED_PROTOCOLS # Translate socket address into the xauth domain if protocol == 'darwin': @@ -173,6 +178,7 @@ def new_get_auth(sock, dname, protocol, host, dno): def old_get_auth(sock, dname, host, dno): + # type: (object, _Address, object, object) -> tuple[str, bytes] # Find authorization cookie auth_name = auth_data = b'' diff --git a/Xlib/support/vms_connect.py b/Xlib/support/vms_connect.py index 3c53695f..e6e9c4ce 100644 --- a/Xlib/support/vms_connect.py +++ b/Xlib/support/vms_connect.py @@ -24,10 +24,18 @@ from Xlib import error +try: + from typing import TYPE_CHECKING, Any, Union +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from typing_extensions import TypeAlias + _Address: TypeAlias = Union[tuple[Any, ...], str] + display_re = re.compile(r'^([-a-zA-Z0-9._]*):([0-9]+)(\.([0-9]+))?$') def get_display(display): - + # type: (str | None) -> tuple[str, None, str, int, int] # Use dummy display if none is set. We really should # check DECW$DISPLAY instead, but that has to wait @@ -56,6 +64,7 @@ def get_display(display): def get_socket(dname, protocol, host, dno): + # type: (_Address, object, _Address, int) -> socket.socket try: # Always use TCP/IP sockets. Later it would be nice to # be able to use DECNET och LOCAL connections. @@ -70,5 +79,6 @@ def get_socket(dname, protocol, host, dno): def get_auth(sock, dname, host, dno): + # type: (object, object, object, object) -> tuple[str, str] # VMS doesn't have xauth return '', '' diff --git a/Xlib/xauth.py b/Xlib/xauth.py index 303bd491..3fd78b96 100644 --- a/Xlib/xauth.py +++ b/Xlib/xauth.py @@ -18,6 +18,7 @@ # 59 Temple Place, # Suite 330, # Boston, MA 02111-1307 USA +from __future__ import annotations import os import struct @@ -33,6 +34,7 @@ class Xauthority(object): def __init__(self, filename = None): + # type: (str | bytes | os.PathLike[str] | os.PathLike[bytes] | int | None) -> None if filename is None: filename = os.environ.get('XAUTHORITY') @@ -49,7 +51,7 @@ def __init__(self, filename = None): except IOError as err: raise error.XauthError('could not read from {0}: {1}'.format(filename, err)) - self.entries = [] + self.entries = [] # type: list[tuple[bytes, bytes, bytes, bytes, bytes]] # entry format (all shorts in big-endian) # short family; @@ -99,11 +101,12 @@ def __len__(self): return len(self.entries) def __getitem__(self, i): + # type: (int) -> tuple[bytes, bytes, bytes, bytes, bytes] return self.entries[i] def get_best_auth(self, family, address, dispno, types = ( b"MIT-MAGIC-COOKIE-1", )): - + # type: (bytes, bytes, bytes, tuple[bytes]) -> tuple[bytes, bytes] """Find an authentication entry matching FAMILY, ADDRESS and DISPNO. diff --git a/Xlib/xobject/colormap.py b/Xlib/xobject/colormap.py index 033fb493..63ed8ffe 100644 --- a/Xlib/xobject/colormap.py +++ b/Xlib/xobject/colormap.py @@ -26,6 +26,18 @@ import re +try: + from typing import TYPE_CHECKING, TypeVar, Optional +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from collections.abc import Callable, Sequence + from typing_extensions import TypeAlias + from Xlib.protocol import rq + + _T = TypeVar("_T") + _ErrorHandler: TypeAlias = Callable[[error.XError, Optional[rq.Request]], _T] + rgb_res = [ re.compile(r'\Argb:([0-9a-fA-F]{1,4})/([0-9a-fA-F]{1,4})/([0-9a-fA-F]{1,4})\Z'), re.compile(r'\A#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])\Z'), @@ -38,6 +50,7 @@ class Colormap(resource.Resource): __colormap__ = resource.Resource.__resource__ def free(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.FreeColormap(display = self.display, onerror = onerror, cmap = self.id) @@ -45,6 +58,7 @@ def free(self, onerror = None): self.display.free_resource_id(self.id) def copy_colormap_and_free(self, scr_cmap): + # type: (int) -> Colormap mid = self.display.allocate_resource_id() request.CopyColormapAndFree(display = self.display, mid = mid, @@ -54,11 +68,13 @@ def copy_colormap_and_free(self, scr_cmap): return cls(self.display, mid, owner = 1) def install_colormap(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.InstallColormap(display = self.display, onerror = onerror, cmap = self.id) def uninstall_colormap(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.UninstallColormap(display = self.display, onerror = onerror, cmap = self.id) @@ -71,6 +87,7 @@ def alloc_color(self, red, green, blue): blue = blue) def alloc_named_color(self, name): + # type: (str) -> request.AllocColor | request.AllocNamedColor | None for r in rgb_res: m = r.match(name) if m: @@ -93,6 +110,7 @@ def alloc_named_color(self, name): return None def alloc_color_cells(self, contiguous, colors, planes): + # type: (bool, int, int) -> request.AllocColorCells return request.AllocColorCells(display = self.display, contiguous = contiguous, cmap = self.id, @@ -100,6 +118,7 @@ def alloc_color_cells(self, contiguous, colors, planes): planes = planes) def alloc_color_planes(self, contiguous, colors, red, green, blue): + # type: (bool, int, int, int, int) -> request.AllocColorPlanes return request.AllocColorPlanes(display = self.display, contiguous = contiguous, cmap = self.id, @@ -109,6 +128,7 @@ def alloc_color_planes(self, contiguous, colors, red, green, blue): blue = blue) def free_colors(self, pixels, plane_mask, onerror = None): + # type: (Sequence[int], int, _ErrorHandler[object] | None) -> None request.FreeColors(display = self.display, onerror = onerror, cmap = self.id, @@ -116,12 +136,14 @@ def free_colors(self, pixels, plane_mask, onerror = None): pixels = pixels) def store_colors(self, items, onerror = None): + # type: (dict[str, int], _ErrorHandler[object] | None) -> None request.StoreColors(display = self.display, onerror = onerror, cmap = self.id, items = items) def store_named_color(self, name, pixel, flags, onerror = None): + # type: (str, int, int, _ErrorHandler[object] | None) -> None request.StoreNamedColor(display = self.display, onerror = onerror, flags = flags, @@ -130,12 +152,14 @@ def store_named_color(self, name, pixel, flags, onerror = None): name = name) def query_colors(self, pixels): + # type: (Sequence[int]) -> rq.Struct r = request.QueryColors(display = self.display, cmap = self.id, pixels = pixels) return r.colors def lookup_color(self, name): + # type: (str) -> request.LookupColor return request.LookupColor(display = self.display, cmap = self.id, name = name) diff --git a/Xlib/xobject/cursor.py b/Xlib/xobject/cursor.py index 432e4fd9..9fe79b9a 100644 --- a/Xlib/xobject/cursor.py +++ b/Xlib/xobject/cursor.py @@ -23,16 +23,30 @@ from . import resource +try: + from typing import TYPE_CHECKING, TypeVar, Optional +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from collections.abc import Callable + from typing_extensions import TypeAlias + from Xlib.error import XError + from Xlib.protocol.rq import Request + _T = TypeVar("_T") + _ErrorHandler: TypeAlias = Callable[[XError, Optional[Request]], _T] + class Cursor(resource.Resource): __cursor__ = resource.Resource.__resource__ def free(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.FreeCursor(display = self.display, onerror = onerror, cursor = self.id) self.display.free_resource_id(self.id) def recolor(self, foreground, background, onerror=None): + # type: (tuple[int, int, int], tuple[int, int, int], _ErrorHandler[object] | None) -> None fore_red, fore_green, fore_blue = foreground back_red, back_green, back_blue = background diff --git a/Xlib/xobject/drawable.py b/Xlib/xobject/drawable.py index c36a9738..1e3eb23a 100644 --- a/Xlib/xobject/drawable.py +++ b/Xlib/xobject/drawable.py @@ -31,6 +31,21 @@ # Inter-client communication conventions from . import icccm +try: + from typing import TYPE_CHECKING, TypeVar, Optional, Union, Any +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from collections.abc import Callable, Sequence, Iterable + from typing_extensions import TypeAlias + from Xlib.error import XError + from PIL import Image + from array import array + from mmap import mmap + _T = TypeVar("_T") + _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array[Any], mmap] + _ErrorHandler: TypeAlias = Callable[[XError, Optional[rq.Request]], _T] + class Drawable(resource.Resource): __drawable__ = resource.Resource.__resource__ @@ -39,6 +54,7 @@ def get_geometry(self): drawable = self) def create_pixmap(self, width, height, depth): + # type: (int, int, int) -> Pixmap pid = self.display.allocate_resource_id() request.CreatePixmap(display = self.display, depth = depth, @@ -51,6 +67,7 @@ def create_pixmap(self, width, height, depth): return cls(self.display, pid, owner = 1) def create_gc(self, **keys): + # type: (object) -> fontable.GC cid = self.display.allocate_resource_id() request.CreateGC(display = self.display, cid = cid, @@ -61,6 +78,7 @@ def create_gc(self, **keys): return cls(self.display, cid, owner = 1) def copy_area(self, gc, src_drawable, src_x, src_y, width, height, dst_x, dst_y, onerror = None): + # type: (int, int, int, int, int, int, int, int, _ErrorHandler[object] | None) -> None request.CopyArea(display = self.display, onerror = onerror, src_drawable = src_drawable, @@ -75,6 +93,7 @@ def copy_area(self, gc, src_drawable, src_x, src_y, width, height, dst_x, dst_y, def copy_plane(self, gc, src_drawable, src_x, src_y, width, height, dst_x, dst_y, bit_plane, onerror = None): + # type: (int, int, int, int, int, int, int, int, int, _ErrorHandler[object] | None) -> None request.CopyPlane(display = self.display, onerror = onerror, src_drawable = src_drawable, @@ -89,6 +108,7 @@ def copy_plane(self, gc, src_drawable, src_x, src_y, width, height, bit_plane = bit_plane) def poly_point(self, gc, coord_mode, points, onerror = None): + # type: (int, int, Sequence[tuple[int, int]], _ErrorHandler[object] | None) -> None request.PolyPoint(display = self.display, onerror = onerror, coord_mode = coord_mode, @@ -97,6 +117,7 @@ def poly_point(self, gc, coord_mode, points, onerror = None): points = points) def point(self, gc, x, y, onerror = None): + # type: (int, int, int, _ErrorHandler[object] | None) -> None request.PolyPoint(display = self.display, onerror = onerror, coord_mode = X.CoordModeOrigin, @@ -105,6 +126,7 @@ def point(self, gc, x, y, onerror = None): points = [(x, y)]) def poly_line(self, gc, coord_mode, points, onerror = None): + # type: (int, int, Sequence[tuple[int, int]], _ErrorHandler[object] | None) -> None request.PolyLine(display = self.display, onerror = onerror, coord_mode = coord_mode, @@ -113,6 +135,7 @@ def poly_line(self, gc, coord_mode, points, onerror = None): points = points) def line(self, gc, x1, y1, x2, y2, onerror = None): + # type: (int, int, int, int, int, _ErrorHandler[object] | None) -> None request.PolySegment(display = self.display, onerror = onerror, drawable = self.id, @@ -120,6 +143,7 @@ def line(self, gc, x1, y1, x2, y2, onerror = None): segments = [(x1, y1, x2, y2)]) def poly_segment(self, gc, segments, onerror = None): + # type: (int, Sequence[tuple[int, int, int, int]], _ErrorHandler[object] | None) -> None request.PolySegment(display = self.display, onerror = onerror, drawable = self.id, @@ -127,6 +151,7 @@ def poly_segment(self, gc, segments, onerror = None): segments = segments) def poly_rectangle(self, gc, rectangles, onerror = None): + # type: (int, Sequence[tuple[int, int, int, int]], _ErrorHandler[object] | None) -> None request.PolyRectangle(display = self.display, onerror = onerror, drawable = self.id, @@ -134,6 +159,7 @@ def poly_rectangle(self, gc, rectangles, onerror = None): rectangles = rectangles) def rectangle(self, gc, x, y, width, height, onerror = None): + # type: (int, int, int, int, int, _ErrorHandler[object] | None) -> None request.PolyRectangle(display = self.display, onerror = onerror, drawable = self.id, @@ -142,6 +168,7 @@ def rectangle(self, gc, x, y, width, height, onerror = None): def poly_arc(self, gc, arcs, onerror = None): + # type: (int, Sequence[tuple[int, int, int, int, int, int]], _ErrorHandler[object] | None) -> None request.PolyArc(display = self.display, onerror = onerror, drawable = self.id, @@ -149,6 +176,7 @@ def poly_arc(self, gc, arcs, onerror = None): arcs = arcs) def arc(self, gc, x, y, width, height, angle1, angle2, onerror = None): + # type: (int, int, int, int, int, int, int, _ErrorHandler[object] | None) -> None request.PolyArc(display = self.display, onerror = onerror, drawable = self.id, @@ -156,6 +184,7 @@ def arc(self, gc, x, y, width, height, angle1, angle2, onerror = None): arcs = [(x, y, width, height, angle1, angle2)]) def fill_poly(self, gc, shape, coord_mode, points, onerror = None): + # type: (int, int, int, Sequence[tuple[int, int]], _ErrorHandler[object] | None) -> None request.FillPoly(display = self.display, onerror = onerror, shape = shape, @@ -165,6 +194,7 @@ def fill_poly(self, gc, shape, coord_mode, points, onerror = None): points = points) def poly_fill_rectangle(self, gc, rectangles, onerror = None): + # type: (int, Sequence[tuple[int, int, int, int]], _ErrorHandler[object] | None) -> None request.PolyFillRectangle(display = self.display, onerror = onerror, drawable = self.id, @@ -172,6 +202,7 @@ def poly_fill_rectangle(self, gc, rectangles, onerror = None): rectangles = rectangles) def fill_rectangle(self, gc, x, y, width, height, onerror = None): + # type: (int, int, int, int, int, _ErrorHandler[object] | None) -> None request.PolyFillRectangle(display = self.display, onerror = onerror, drawable = self.id, @@ -179,6 +210,7 @@ def fill_rectangle(self, gc, x, y, width, height, onerror = None): rectangles = [(x, y, width, height)]) def poly_fill_arc(self, gc, arcs, onerror = None): + # type: (int, Sequence[tuple[int, int, int, int, int, int]], _ErrorHandler[object] | None) -> None request.PolyFillArc(display = self.display, onerror = onerror, drawable = self.id, @@ -186,6 +218,7 @@ def poly_fill_arc(self, gc, arcs, onerror = None): arcs = arcs) def fill_arc(self, gc, x, y, width, height, angle1, angle2, onerror = None): + # type: (int, int, int, int, int, int, int, _ErrorHandler[object] | None) -> None request.PolyFillArc(display = self.display, onerror = onerror, drawable = self.id, @@ -195,6 +228,7 @@ def fill_arc(self, gc, x, y, width, height, angle1, angle2, onerror = None): def put_image(self, gc, x, y, width, height, format, depth, left_pad, data, onerror = None): + # type: (int, int, int, int, int, int, int, int, _SliceableBuffer, _ErrorHandler[object] | None) -> None request.PutImage(display = self.display, onerror = onerror, format = format, @@ -211,6 +245,7 @@ def put_image(self, gc, x, y, width, height, format, # Trivial little method for putting PIL images. Will break on anything # but depth 1 or 24... def put_pil_image(self, gc, x, y, image, onerror = None): + # type: (int, int, int, Image.Image, _ErrorHandler[object] | None) -> None width, height = image.size if image.mode == '1': format = X.XYBitmap @@ -256,6 +291,7 @@ def put_pil_image(self, gc, x, y, image, onerror = None): def get_image(self, x, y, width, height, format, plane_mask): + # type: (int, int, int, int, int, int) -> request.GetImage return request.GetImage(display = self.display, format = format, drawable = self.id, @@ -266,6 +302,7 @@ def get_image(self, x, y, width, height, format, plane_mask): plane_mask = plane_mask) def draw_text(self, gc, x, y, text, onerror = None): + # type: (int, int, int, dict[str, str | int], _ErrorHandler[object] | None) -> None request.PolyText8(display = self.display, onerror = onerror, drawable = self.id, @@ -275,6 +312,7 @@ def draw_text(self, gc, x, y, text, onerror = None): items = [text]) def poly_text(self, gc, x, y, items, onerror = None): + # type: (int, int, int, Sequence[dict[str, str | int]], _ErrorHandler[object] | None) -> None request.PolyText8(display = self.display, onerror = onerror, drawable = self.id, @@ -284,6 +322,7 @@ def poly_text(self, gc, x, y, items, onerror = None): items = items) def poly_text_16(self, gc, x, y, items, onerror = None): + # type: (int, int, int, Sequence[dict[str, str | int]], _ErrorHandler[object] | None) -> None request.PolyText16(display = self.display, onerror = onerror, drawable = self.id, @@ -293,6 +332,7 @@ def poly_text_16(self, gc, x, y, items, onerror = None): items = items) def image_text(self, gc, x, y, string, onerror = None): + # type: (int, int, int, str, _ErrorHandler[object] | None) -> None request.ImageText8(display = self.display, onerror = onerror, drawable = self.id, @@ -302,6 +342,7 @@ def image_text(self, gc, x, y, string, onerror = None): string = string) def image_text_16(self, gc, x, y, string, onerror = None): + # type: (int, int, int, str, _ErrorHandler[object] | None) -> None request.ImageText16(display = self.display, onerror = onerror, drawable = self.id, @@ -311,6 +352,7 @@ def image_text_16(self, gc, x, y, string, onerror = None): string = string) def query_best_size(self, item_class, width, height): + # type: (int, int, int) -> request.QueryBestSize return request.QueryBestSize(display = self.display, item_class = item_class, drawable = self.id, @@ -328,6 +370,7 @@ def create_window(self, x, y, width, height, border_width, depth, visual = X.CopyFromParent, onerror = None, **keys): + # type: (int, int, int, int, int, int, int, int, _ErrorHandler[object] | None, object) -> Window wid = self.display.allocate_resource_id() request.CreateWindow(display = self.display, @@ -348,6 +391,7 @@ def create_window(self, x, y, width, height, border_width, depth, return cls(self.display, wid, owner = 1) def change_attributes(self, onerror = None, **keys): + # type: (_ErrorHandler[object] | None, object) -> None request.ChangeWindowAttributes(display = self.display, onerror = onerror, window = self.id, @@ -358,6 +402,7 @@ def get_attributes(self): window = self.id) def destroy(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.DestroyWindow(display = self.display, onerror = onerror, window = self.id) @@ -365,18 +410,21 @@ def destroy(self, onerror = None): self.display.free_resource_id(self.id) def destroy_sub_windows(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.DestroySubWindows(display = self.display, onerror = onerror, window = self.id) def change_save_set(self, mode, onerror = None): + # type: (int, _ErrorHandler[object] | None) -> None request.ChangeSaveSet(display = self.display, onerror = onerror, mode = mode, window = self.id) def reparent(self, parent, x, y, onerror = None): + # type: (int, int, int, _ErrorHandler[object] | None) -> None request.ReparentWindow(display = self.display, onerror = onerror, window = self.id, @@ -385,38 +433,45 @@ def reparent(self, parent, x, y, onerror = None): y = y) def map(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.MapWindow(display = self.display, onerror = onerror, window = self.id) def map_sub_windows(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.MapSubwindows(display = self.display, onerror = onerror, window = self.id) def unmap(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.UnmapWindow(display = self.display, onerror = onerror, window = self.id) def unmap_sub_windows(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.UnmapSubwindows(display = self.display, onerror = onerror, window = self.id) def configure(self, onerror = None, **keys): + # type: (_ErrorHandler[object] | None, object) -> None request.ConfigureWindow(display = self.display, onerror = onerror, window = self.id, attrs = keys) def circulate(self, direction, onerror = None): + # type: (int, _ErrorHandler[object] | None) -> None request.CirculateWindow(display = self.display, onerror = onerror, direction = direction, window = self.id) def raise_window(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None """alias for raising the window to the top - as in XRaiseWindow""" self.configure(onerror, stack_mode = X.Above) @@ -426,6 +481,7 @@ def query_tree(self): def change_property(self, property, property_type, format, data, mode = X.PropModeReplace, onerror = None): + # type: (int, int, int, Sequence[float] | Sequence[str], int, _ErrorHandler[object] | None) -> None request.ChangeProperty(display = self.display, onerror = onerror, @@ -437,6 +493,7 @@ def change_property(self, property, property_type, format, data, def change_text_property(self, property, property_type, data, mode = X.PropModeReplace, onerror = None): + # type: (int, int, bytes | str, int, _ErrorHandler[object] | None) -> None if not isinstance(data, bytes): if property_type == Xatom.STRING: data = data.encode(self._STRING_ENCODING) @@ -446,12 +503,14 @@ def change_text_property(self, property, property_type, data, mode=mode, onerror=onerror) def delete_property(self, property, onerror = None): + # type: (int, _ErrorHandler[object] | None) -> None request.DeleteProperty(display = self.display, onerror = onerror, window = self.id, property = property) def get_property(self, property, property_type, offset, length, delete = 0): + # type: (int, int, int, int, bool) -> request.GetProperty | None r = request.GetProperty(display = self.display, delete = delete, window = self.id, @@ -469,6 +528,7 @@ def get_property(self, property, property_type, offset, length, delete = 0): return None def get_full_property(self, property, property_type, sizehint = 10): + # type: (int, int, int) -> request.GetProperty | None prop = self.get_property(property, property_type, 0, sizehint) if prop: val = prop.value @@ -483,6 +543,7 @@ def get_full_property(self, property, property_type, sizehint = 10): return None def get_full_text_property(self, property, property_type=X.AnyPropertyType, sizehint = 10): + # type: (int, int, int) -> str | None prop = self.get_full_property(property, property_type, sizehint=sizehint) if prop is None or prop.format != 8: @@ -496,11 +557,13 @@ def get_full_text_property(self, property, property_type=X.AnyPropertyType, size return prop.value def list_properties(self): + # type: () -> list[int] r = request.ListProperties(display = self.display, window = self.id) return r.atoms def set_selection_owner(self, selection, time, onerror = None): + # type: (int, int, _ErrorHandler[object] | None) -> None request.SetSelectionOwner(display = self.display, onerror = onerror, window = self.id, @@ -508,6 +571,7 @@ def set_selection_owner(self, selection, time, onerror = None): time = time) def convert_selection(self, selection, target, property, time, onerror = None): + # type: (int, int, int, int, _ErrorHandler[object] | None) -> None request.ConvertSelection(display = self.display, onerror = onerror, requestor = self.id, @@ -517,6 +581,7 @@ def convert_selection(self, selection, target, property, time, onerror = None): time = time) def send_event(self, event, event_mask = 0, propagate = 0, onerror = None): + # type: (rq.Event, int, bool, _ErrorHandler[object] | None) -> None request.SendEvent(display = self.display, onerror = onerror, propagate = propagate, @@ -527,6 +592,7 @@ def send_event(self, event, event_mask = 0, propagate = 0, onerror = None): def grab_pointer(self, owner_events, event_mask, pointer_mode, keyboard_mode, confine_to, cursor, time): + # type: (bool, int, int, int, int, int, int) -> None r = request.GrabPointer(display = self.display, owner_events = owner_events, @@ -542,6 +608,7 @@ def grab_pointer(self, owner_events, event_mask, def grab_button(self, button, modifiers, owner_events, event_mask, pointer_mode, keyboard_mode, confine_to, cursor, onerror = None): + # type: (int, int, bool, int, int, int, int, int, _ErrorHandler[object] | None) -> None request.GrabButton(display = self.display, onerror = onerror, @@ -556,6 +623,7 @@ def grab_button(self, button, modifiers, owner_events, event_mask, modifiers = modifiers) def ungrab_button(self, button, modifiers, onerror = None): + # type: (int, int, _ErrorHandler[object] | None) -> None request.UngrabButton(display = self.display, onerror = onerror, button = button, @@ -564,6 +632,7 @@ def ungrab_button(self, button, modifiers, onerror = None): def grab_keyboard(self, owner_events, pointer_mode, keyboard_mode, time): + # type: (bool, int, int, int) -> int r = request.GrabKeyboard(display = self.display, owner_events = owner_events, grab_window = self.id, @@ -574,6 +643,7 @@ def grab_keyboard(self, owner_events, pointer_mode, keyboard_mode, time): return r.status def grab_key(self, key, modifiers, owner_events, pointer_mode, keyboard_mode, onerror = None): + # type: (int, int, bool, int, int, _ErrorHandler[object] | None) -> None request.GrabKey(display = self.display, onerror = onerror, owner_events = owner_events, @@ -584,6 +654,7 @@ def grab_key(self, key, modifiers, owner_events, pointer_mode, keyboard_mode, on keyboard_mode = keyboard_mode) def ungrab_key(self, key, modifiers, onerror = None): + # type: (int, int, _ErrorHandler[object] | None) -> None request.UngrabKey(display = self.display, onerror = onerror, key = key, @@ -595,6 +666,7 @@ def query_pointer(self): window = self.id) def get_motion_events(self, start, stop): + # type: (int, int) -> rq.Struct r = request.GetMotionEvents(display = self.display, window = self.id, start = start, @@ -602,6 +674,7 @@ def get_motion_events(self, start, stop): return r.events def translate_coords(self, src_window, src_x, src_y): + # type: (int, int, int) -> request.TranslateCoords return request.TranslateCoords(display = self.display, src_wid = src_window, dst_wid = self.id, @@ -610,6 +683,7 @@ def translate_coords(self, src_window, src_x, src_y): def warp_pointer(self, x, y, src_window = 0, src_x = 0, src_y = 0, src_width = 0, src_height = 0, onerror = None): + # type: (int, int, int, int, int, int, int, _ErrorHandler[object] | None) -> None request.WarpPointer(display = self.display, onerror = onerror, @@ -623,6 +697,7 @@ def warp_pointer(self, x, y, src_window = 0, src_x = 0, src_y = 0, dst_y = y) def set_input_focus(self, revert_to, time, onerror = None): + # type: (int, int, _ErrorHandler[object] | None) -> None request.SetInputFocus(display = self.display, onerror = onerror, revert_to = revert_to, @@ -630,6 +705,7 @@ def set_input_focus(self, revert_to, time, onerror = None): time = time) def clear_area(self, x = 0, y = 0, width = 0, height = 0, exposures = 0, onerror = None): + # type: (int, int, int, int, bool, _ErrorHandler[object] | None) -> None request.ClearArea(display = self.display, onerror = onerror, exposures = exposures, @@ -640,6 +716,7 @@ def clear_area(self, x = 0, y = 0, width = 0, height = 0, exposures = 0, onerror height = height) def create_colormap(self, visual, alloc): + # type: (int, int) -> colormap.Colormap mid = self.display.allocate_resource_id() request.CreateColormap(display = self.display, alloc = alloc, @@ -650,11 +727,13 @@ def create_colormap(self, visual, alloc): return cls(self.display, mid, owner = 1) def list_installed_colormaps(self): + # type: () -> list[colormap.Colormap] r = request.ListInstalledColormaps(display = self.display, window = self.id) return r.cmaps def rotate_properties(self, properties, delta, onerror = None): + # type: (Sequence[int], int, _ErrorHandler[object] | None) -> None request.RotateProperties(display = self.display, onerror = onerror, window = self.id, @@ -662,6 +741,7 @@ def rotate_properties(self, properties, delta, onerror = None): properties = properties) def set_wm_name(self, name, onerror = None): + # type: (bytes | str, _ErrorHandler[object] | None) -> None self.change_text_property(Xatom.WM_NAME, Xatom.STRING, name, onerror = onerror) @@ -669,6 +749,7 @@ def get_wm_name(self): return self.get_full_text_property(Xatom.WM_NAME, Xatom.STRING) def set_wm_icon_name(self, name, onerror = None): + # type: (bytes | str, _ErrorHandler[object] | None) -> None self.change_text_property(Xatom.WM_ICON_NAME, Xatom.STRING, name, onerror = onerror) @@ -676,6 +757,7 @@ def get_wm_icon_name(self): return self.get_full_text_property(Xatom.WM_ICON_NAME, Xatom.STRING) def set_wm_class(self, inst, cls, onerror = None): + # type: (str, str, _ErrorHandler[object] | None) -> None self.change_text_property(Xatom.WM_CLASS, Xatom.STRING, '%s\0%s\0' % (inst, cls), onerror = onerror) @@ -691,6 +773,7 @@ def get_wm_class(self): return parts[0], parts[1] def set_wm_transient_for(self, window, onerror = None): + # type: (Window, _ErrorHandler[object] | None) -> None self.change_property(Xatom.WM_TRANSIENT_FOR, Xatom.WINDOW, 32, [window.id], onerror = onerror) @@ -705,11 +788,13 @@ def get_wm_transient_for(self): def set_wm_protocols(self, protocols, onerror = None): + # type: (Iterable[int], _ErrorHandler[object] | None) -> None self.change_property(self.display.get_atom('WM_PROTOCOLS'), Xatom.ATOM, 32, protocols, onerror = onerror) def get_wm_protocols(self): + # type: () -> list[int] d = self.get_full_property(self.display.get_atom('WM_PROTOCOLS'), Xatom.ATOM) if d is None or d.format != 32: return [] @@ -717,12 +802,14 @@ def get_wm_protocols(self): return d.value def set_wm_colormap_windows(self, windows, onerror = None): + # type: (Iterable[Window], _ErrorHandler[object] | None) -> None self.change_property(self.display.get_atom('WM_COLORMAP_WINDOWS'), Xatom.WINDOW, 32, map(lambda w: w.id, windows), onerror = onerror) def get_wm_colormap_windows(self): + # type: () -> list[Window] | map[Window] d = self.get_full_property(self.display.get_atom('WM_COLORMAP_WINDOWS'), Xatom.WINDOW) if d is None or d.format != 32: @@ -734,6 +821,7 @@ def get_wm_colormap_windows(self): def set_wm_client_machine(self, name, onerror = None): + # type: (bytes | str, _ErrorHandler[object] | None) -> None self.change_text_property(Xatom.WM_CLIENT_MACHINE, Xatom.STRING, name, onerror = onerror) @@ -741,6 +829,7 @@ def get_wm_client_machine(self): return self.get_full_text_property(Xatom.WM_CLIENT_MACHINE, Xatom.STRING) def set_wm_normal_hints(self, hints = {}, onerror = None, **keys): + # type: (rq.DictWrapper | dict[str, object], _ErrorHandler[object] | None, object) -> None self._set_struct_prop(Xatom.WM_NORMAL_HINTS, Xatom.WM_SIZE_HINTS, icccm.WMNormalHints, hints, keys, onerror) @@ -749,6 +838,7 @@ def get_wm_normal_hints(self): icccm.WMNormalHints) def set_wm_hints(self, hints = {}, onerror = None, **keys): + # type: (rq.DictWrapper | dict[str, object], _ErrorHandler[object] | None, object) -> None self._set_struct_prop(Xatom.WM_HINTS, Xatom.WM_HINTS, icccm.WMHints, hints, keys, onerror) @@ -757,6 +847,7 @@ def get_wm_hints(self): icccm.WMHints) def set_wm_state(self, hints = {}, onerror = None, **keys): + # type: (rq.DictWrapper | dict[str, object], _ErrorHandler[object] | None, object) -> None atom = self.display.get_atom('WM_STATE') self._set_struct_prop(atom, atom, icccm.WMState, hints, keys, onerror) @@ -765,6 +856,7 @@ def get_wm_state(self): return self._get_struct_prop(atom, atom, icccm.WMState) def set_wm_icon_size(self, hints = {}, onerror = None, **keys): + # type: (rq.DictWrapper | dict[str, object], _ErrorHandler[object] | None, object) -> None self._set_struct_prop(Xatom.WM_ICON_SIZE, Xatom.WM_ICON_SIZE, icccm.WMIconSize, hints, keys, onerror) @@ -777,6 +869,7 @@ def get_wm_icon_size(self): # Returns a DictWrapper, or None def _get_struct_prop(self, pname, ptype, pstruct): + # type: (int, int, rq.Struct) -> rq.DictWrapper | None r = self.get_property(pname, ptype, 0, pstruct.static_size // 4) if r and r.format == 32: value = rq.encode_array(r.value) @@ -791,6 +884,7 @@ def _get_struct_prop(self, pname, ptype, pstruct): # will be modified. onerror is the error handler. def _set_struct_prop(self, pname, ptype, pstruct, hints, keys, onerror): + # type: (int, int, rq.Struct, rq.DictWrapper | dict[str, object], dict[str, object], _ErrorHandler[object] | None) -> None if isinstance(hints, rq.DictWrapper): keys.update(hints._data) else: @@ -805,6 +899,7 @@ class Pixmap(Drawable): __pixmap__ = resource.Resource.__resource__ def free(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.FreePixmap(display = self.display, onerror = onerror, pixmap = self.id) @@ -812,6 +907,7 @@ def free(self, onerror = None): self.display.free_resource_id(self.id) def create_cursor(self, mask, foreground, background, x, y): + # type: (int, tuple[int, int, int], tuple[int, int, int], int, int) -> cursor.Cursor fore_red, fore_green, fore_blue = foreground back_red, back_green, back_blue = background cid = self.display.allocate_resource_id() @@ -832,4 +928,5 @@ def create_cursor(self, mask, foreground, background, x, y): def roundup(value, unit): + # type: (int, int) -> int return (value + (unit - 1)) & ~(unit - 1) diff --git a/Xlib/xobject/fontable.py b/Xlib/xobject/fontable.py index 892f2665..a0e460c5 100644 --- a/Xlib/xobject/fontable.py +++ b/Xlib/xobject/fontable.py @@ -24,6 +24,19 @@ from . import resource from . import cursor +try: + from typing import TYPE_CHECKING, TypeVar, Optional +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from collections.abc import Callable + from typing_extensions import TypeAlias + from Xlib.error import XError + from Xlib.protocol.rq import Request + from collections.abc import Sequence + _T = TypeVar("_T") + _ErrorHandler: TypeAlias = Callable[[XError, Optional[Request]], _T] + class Fontable(resource.Resource): __fontable__ = resource.Resource.__resource__ @@ -32,6 +45,7 @@ def query(self): font = self.id) def query_text_extents(self, string): + # type: (str) -> request.QueryTextExtents return request.QueryTextExtents(display = self.display, font = self.id, string = string) @@ -41,6 +55,7 @@ class GC(Fontable): __gc__ = resource.Resource.__resource__ def change(self, onerror = None, **keys): + # type: (_ErrorHandler[object] | None, object) -> None request.ChangeGC(display = self.display, onerror = onerror, gc = self.id, @@ -48,6 +63,7 @@ def change(self, onerror = None, **keys): def copy(self, src_gc, mask, onerror = None): + # type: (int, int, _ErrorHandler[object] | None) -> None request.CopyGC(display = self.display, onerror = onerror, src_gc = src_gc, @@ -55,6 +71,7 @@ def copy(self, src_gc, mask, onerror = None): mask = mask) def set_dashes(self, offset, dashes, onerror = None): + # type: (int, Sequence[int], _ErrorHandler[object] | None) -> None request.SetDashes(display = self.display, onerror = onerror, gc = self.id, @@ -62,6 +79,7 @@ def set_dashes(self, offset, dashes, onerror = None): dashes = dashes) def set_clip_rectangles(self, x_origin, y_origin, rectangles, ordering, onerror = None): + # type: (int, int, Sequence[Sequence[int] | tuple[int, int, int, int]], Sequence[int] | tuple[int, int, int, int], _ErrorHandler[object] | None) -> None request.SetClipRectangles(display = self.display, onerror = onerror, ordering = ordering, @@ -70,6 +88,7 @@ def set_clip_rectangles(self, x_origin, y_origin, rectangles, ordering, onerror y_origin = y_origin, rectangles = rectangles) def free(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.FreeGC(display = self.display, onerror = onerror, gc = self.id) @@ -82,6 +101,7 @@ class Font(Fontable): __font__ = resource.Resource.__resource__ def close(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.CloseFont(display = self.display, onerror = onerror, font = self.id) @@ -89,6 +109,7 @@ def close(self, onerror = None): def create_glyph_cursor(self, mask, source_char, mask_char, foreground, background): + # type: (Font, int, int, tuple[int, int, int], tuple[int, int, int]) -> cursor.Cursor fore_red, fore_green, fore_blue = foreground back_red, back_green, back_blue = background diff --git a/Xlib/xobject/resource.py b/Xlib/xobject/resource.py index ea256ca1..274e2ff9 100644 --- a/Xlib/xobject/resource.py +++ b/Xlib/xobject/resource.py @@ -21,8 +21,22 @@ from Xlib.protocol import request +try: + from typing import TYPE_CHECKING, TypeVar, Optional +except ImportError: + TYPE_CHECKING = False +if TYPE_CHECKING: + from collections.abc import Callable + from typing_extensions import TypeAlias + from Xlib.error import XError + from Xlib.protocol.rq import Request + from Xlib.display import _BaseDisplay + _T = TypeVar("_T") + _ErrorHandler: TypeAlias = Callable[[XError, Optional[Request]], _T] + class Resource(object): def __init__(self, display, rid, owner = 0): + # type: (_BaseDisplay, int, int) -> None self.display = display self.id = rid self.owner = owner @@ -31,6 +45,7 @@ def __resource__(self): return self.id def __eq__(self, obj): + # type: (object) -> bool if isinstance(obj, Resource): if self.display == obj.display: return self.id == obj.id @@ -40,6 +55,7 @@ def __eq__(self, obj): return id(self) == id(obj) def __ne__(self, obj): + # type: (object) -> bool return not self == obj def __hash__(self): @@ -49,6 +65,7 @@ def __repr__(self): return '<%s 0x%08x>' % (self.__class__.__name__, self.id) def kill_client(self, onerror = None): + # type: (_ErrorHandler[object] | None) -> None request.KillClient(display = self.display, onerror = onerror, resource = self.id) diff --git a/setup.py b/setup.py index 71bdb085..e11ae542 100644 --- a/setup.py +++ b/setup.py @@ -20,4 +20,5 @@ 'Xlib.support', 'Xlib.xobject' ], + package_data={"Xlib": ["Xlib/py.typed"]}, ) From 834881fc418ca0ff5239c90571b41f42845148f0 Mon Sep 17 00:00:00 2001 From: Avasam Date: Wed, 16 Nov 2022 18:56:47 -0500 Subject: [PATCH 02/17] Update rq.py --- Xlib/protocol/rq.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index 634c4c84..cf4d49df 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -1109,7 +1109,7 @@ def to_binary(self, *varargs, **keys): for f in self.var_fields: if f.keyword_args: - v, l, fm = f.pack_value(field_args[f.name], keys) + v, l, fm = f.pack_value(field_args[f.name], keys) # ValueList else: v, l, fm = f.pack_value(field_args[f.name]) var_vals[f.name] = v @@ -1473,7 +1473,7 @@ def __init__(self, display, onerror = None, *args, **keys): # type: (_BaseDisplay, _ErrorHandler[object] | None, object, object) -> None self._errorhandler = onerror self._binary = self._request.to_binary(*args, **keys) - self._serial = None + self._serial = None # type: int | None display.send_request(self, onerror is not None) def _set_error(self, error): From 4d052606a5fc8a0caf272f995c852741c289c973 Mon Sep 17 00:00:00 2001 From: Avasam Date: Wed, 16 Nov 2022 18:59:35 -0500 Subject: [PATCH 03/17] Update display.py --- Xlib/display.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Xlib/display.py b/Xlib/display.py index 7a79601c..8a1b0bc2 100644 --- a/Xlib/display.py +++ b/Xlib/display.py @@ -533,7 +533,7 @@ def rebind_string(self, keysym, newstring): ### def intern_atom(self, name, only_if_exists = 0): - # type: (str, int) -> int + # type: (str, bool) -> int """Intern the string name, returning its atom number. If only_if_exists is true and the atom does not already exist, it will not be created and X.NONE is returned.""" @@ -543,7 +543,7 @@ def intern_atom(self, name, only_if_exists = 0): return r.atom def get_atom(self, atom, only_if_exists = 0): - # type: (str, int) -> int + # type: (str, bool) -> int """Alias for intern_atom, using internal cache""" return self.display.get_atom(atom, only_if_exists) From f53aa8ecefa231ac37c2905d190a82041589f4d3 Mon Sep 17 00:00:00 2001 From: Avasam Date: Fri, 18 Nov 2022 16:05:17 -0500 Subject: [PATCH 04/17] Update types --- Xlib/display.py | 2 +- Xlib/ext/record.py | 2 +- Xlib/protocol/display.py | 4 ++-- Xlib/protocol/rq.py | 17 ++++++++++------- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Xlib/display.py b/Xlib/display.py index 7a79601c..03e80db0 100644 --- a/Xlib/display.py +++ b/Xlib/display.py @@ -89,7 +89,7 @@ class _BaseDisplay(protocol_display.Display): # dealing with some ICCCM properties not defined in Xlib.Xatom def __init__(self, *args, **keys): - # type: (str | None, object, object) -> None + # type: (str | None) -> None self.resource_classes = _resource_baseclasses.copy() protocol_display.Display.__init__(self, *args, **keys) self._atom_cache = {} diff --git a/Xlib/ext/record.py b/Xlib/ext/record.py index 9793e0e1..e433058f 100644 --- a/Xlib/ext/record.py +++ b/Xlib/ext/record.py @@ -234,7 +234,7 @@ class EnableContext(rq.ReplyRequest): # See the discussion on ListFonstsWithInfo in request.py def __init__(self, callback, *args, **keys): - # type: (Callable[[rq.DictWrapper | dict[str, object]], Any], display.Display, object, bool, object) -> None + # type: (Callable[[rq.DictWrapper | dict[str, object]], Any], display.Display, bool, object, object) -> None self._callback = callback rq.ReplyRequest.__init__(self, *args, **keys) diff --git a/Xlib/protocol/display.py b/Xlib/protocol/display.py index 412a8f55..551ea27c 100644 --- a/Xlib/protocol/display.py +++ b/Xlib/protocol/display.py @@ -466,7 +466,7 @@ def send_and_recv(self, flush = None, event = None, request = None, recv = None) To wait for an event to be received, event should be true. To wait for a response to a certain request (either an error - or a response), request should be set the that request's + or a response), request should be set to that request's serial number. To just read any pending data from the server, recv should be true. @@ -1132,7 +1132,7 @@ class ConnectionSetupRequest(rq.GetAttrData): def __init__(self, display, *args, **keys): # type: (Display, object, object) -> None self._binary = self._request.to_binary(*args, **keys) - self._data = None + self._data = None # type: dict[str, object] # Don't bother about locking, since no other threads have # access to the display yet diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index 634c4c84..169a4347 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -331,17 +331,20 @@ def __init__(self, name, codes = (), default = None): Card32.__init__(self, name, default) self.codes = codes + if TYPE_CHECKING: + @overload + def check_value(self, value: Callable[[], _T]) -> _T: ... + @overload + def check_value(self, value: _T) -> _T: ... def check_value(self, value): - # type: (Callable[[], _T]) -> _T | int + # type: (Callable[[], _T] | _T) -> _T if hasattr(value, self.cast_function): return getattr(value, self.cast_function)() else: return value def parse_value(self, value, display): - # type: (int, _BaseDisplay) -> int | _ResourceBaseClass - # if not display: - # return value + # type: (int, _BaseDisplay | None) -> int | _ResourceBaseClass if value in self.codes: return value @@ -981,9 +984,9 @@ def __init__(self, class_name): self.check_value = None def parse_value(self, value, display): - # type: (int, _BaseDisplay) -> int | _ResourceBaseClass - # if not display: - # return value + # type: (int, _BaseDisplay | None) -> int | _ResourceBaseClass + if not display: + return value c = display.get_resource_class(self.class_name) if c: return c(display, value) From eba9e6fa4f0c83d77a1afe699cca65ed31aae465 Mon Sep 17 00:00:00 2001 From: Avasam Date: Fri, 18 Nov 2022 16:23:58 -0500 Subject: [PATCH 05/17] Fix syntax error --- Xlib/protocol/rq.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index 169a4347..94bdb2ea 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -952,6 +952,7 @@ def parse_binary_value(self, data, display, length, format): from . import event estruct = display.event_classes.get(byte2int(data) & 0x7f, event.AnyEvent) # type: dict[int, type[Event]] | type[Event] + if type(estruct) == dict: # this etype refers to a set of sub-events with individual subcodes estruct = estruct[indexbytes(data, 1)] From c7a798aa32f8266562647cbbe94b12a6ed9174bf Mon Sep 17 00:00:00 2001 From: Avasam Date: Fri, 18 Nov 2022 16:35:49 -0500 Subject: [PATCH 06/17] No TypeAlias explicit typing --- Xlib/display.py | 6 +++--- Xlib/error.py | 4 ++-- Xlib/ext/composite.py | 5 ++--- Xlib/ext/ge.py | 3 +-- Xlib/ext/screensaver.py | 3 +-- Xlib/ext/security.py | 3 +-- Xlib/ext/xinput.py | 6 +++--- Xlib/protocol/display.py | 6 +++--- Xlib/protocol/rq.py | 10 +++++----- Xlib/rdb.py | 3 +-- Xlib/support/connect.py | 3 +-- Xlib/support/unix_connect.py | 3 +-- Xlib/support/vms_connect.py | 3 +-- Xlib/xobject/colormap.py | 4 +--- Xlib/xobject/cursor.py | 3 +-- Xlib/xobject/drawable.py | 5 ++--- Xlib/xobject/fontable.py | 3 +-- Xlib/xobject/resource.py | 3 +-- 18 files changed, 31 insertions(+), 45 deletions(-) diff --git a/Xlib/display.py b/Xlib/display.py index 3508a5c7..29a8994d 100644 --- a/Xlib/display.py +++ b/Xlib/display.py @@ -47,11 +47,11 @@ TYPE_CHECKING = False if TYPE_CHECKING: from collections.abc import Sequence, Callable - from typing_extensions import Literal, TypeAlias + from typing_extensions import Literal from re import Pattern _T = TypeVar("_T") - _ErrorHandler: TypeAlias = Callable[[error.XError, Optional[rq.Request]], _T] - _ResourceBaseClass: TypeAlias = Union[ + _ErrorHandler = Callable[[error.XError, Optional[rq.Request]], _T] + _ResourceBaseClass = Union[ resource.Resource, drawable.Drawable, drawable.Window, diff --git a/Xlib/error.py b/Xlib/error.py index 060024db..8184c136 100644 --- a/Xlib/error.py +++ b/Xlib/error.py @@ -32,9 +32,9 @@ if TYPE_CHECKING: from mmap import mmap from array import array - from typing_extensions import TypeAlias, Literal + from typing_extensions import Literal from Xlib.protocol import display - _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array[Any], mmap] + _SliceableBuffer = Union[bytes, bytearray, memoryview, array[Any], mmap] class DisplayError(Exception): def __init__(self, display): diff --git a/Xlib/ext/composite.py b/Xlib/ext/composite.py index 3c825e56..e5ee4275 100644 --- a/Xlib/ext/composite.py +++ b/Xlib/ext/composite.py @@ -43,13 +43,12 @@ TYPE_CHECKING = False if TYPE_CHECKING: from collections.abc import Callable - from typing_extensions import TypeAlias from Xlib.error import XError from Xlib.display import Display from Xlib.xobject import resource _T = TypeVar("_T") - _ErrorHandler: TypeAlias = Callable[[XError, Optional[rq.Request]], _T] - _Update: TypeAlias = Callable[[Union[rq.DictWrapper, dict[str, object]]], object] + _ErrorHandler = Callable[[XError, Optional[rq.Request]], _T] + _Update = Callable[[Union[rq.DictWrapper, dict[str, object]]], object] extname = 'Composite' diff --git a/Xlib/ext/ge.py b/Xlib/ext/ge.py index 43c775bc..89badb6a 100644 --- a/Xlib/ext/ge.py +++ b/Xlib/ext/ge.py @@ -35,8 +35,7 @@ from Xlib.xobject import resource from mmap import mmap from array import array - from typing_extensions import TypeAlias - _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array[Any], mmap] + _SliceableBuffer = Union[bytes, bytearray, memoryview, array[Any], mmap] extname = 'Generic Event Extension' diff --git a/Xlib/ext/screensaver.py b/Xlib/ext/screensaver.py index 8f7095ee..9bde3d78 100644 --- a/Xlib/ext/screensaver.py +++ b/Xlib/ext/screensaver.py @@ -39,13 +39,12 @@ TYPE_CHECKING = False if TYPE_CHECKING: from collections.abc import Callable - from typing_extensions import TypeAlias from Xlib.error import XError from Xlib.protocol import request from Xlib.display import Display from Xlib.xobject import drawable, resource _T = TypeVar("_T") - _ErrorHandler: TypeAlias = Callable[[XError, Optional[rq.Request]], _T] + _ErrorHandler = Callable[[XError, Optional[rq.Request]], _T] extname = 'MIT-SCREEN-SAVER' diff --git a/Xlib/ext/security.py b/Xlib/ext/security.py index bbe145eb..01fd807c 100644 --- a/Xlib/ext/security.py +++ b/Xlib/ext/security.py @@ -32,11 +32,10 @@ TYPE_CHECKING = False if TYPE_CHECKING: from mmap import mmap - from typing_extensions import TypeAlias from Xlib.display import Display from Xlib.xobject import resource from array import array - _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array[Any], mmap] + _SliceableBuffer = Union[bytes, bytearray, memoryview, array[Any], mmap] extname = 'SECURITY' diff --git a/Xlib/ext/xinput.py b/Xlib/ext/xinput.py index c3edb199..297976c1 100644 --- a/Xlib/ext/xinput.py +++ b/Xlib/ext/xinput.py @@ -45,11 +45,11 @@ from collections.abc import Sequence, Iterable from Xlib.xobject import drawable, resource from mmap import mmap - from typing_extensions import TypeAlias, SupportsIndex + from typing_extensions import SupportsIndex from _typeshed import ReadableBuffer _T = TypeVar("_T") - _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array.array[Any], mmap] - _Floatable: TypeAlias = Union[SupportsFloat, SupportsIndex, str, ReadableBuffer] + _SliceableBuffer = Union[bytes, bytearray, memoryview, array.array[Any], mmap] + _Floatable = Union[SupportsFloat, SupportsIndex, str, ReadableBuffer] extname = 'XInputExtension' diff --git a/Xlib/protocol/display.py b/Xlib/protocol/display.py index 551ea27c..642c0f6b 100644 --- a/Xlib/protocol/display.py +++ b/Xlib/protocol/display.py @@ -49,7 +49,7 @@ except ImportError: TYPE_CHECKING = False if TYPE_CHECKING: - from typing_extensions import TypeAlias, Literal + from typing_extensions import Literal from array import array from mmap import mmap from collections.abc import Callable @@ -57,8 +57,8 @@ from Xlib.xobject import cursor, colormap, fontable, drawable, resource _T = TypeVar("_T") _BaseClasses = type(_resource_baseclasses) - _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array[Any], mmap] - _ErrorHandler: TypeAlias = Callable[[error.XError, Optional[rq.Request]], _T] + _SliceableBuffer = Union[bytes, bytearray, memoryview, array[Any], mmap] + _ErrorHandler = Callable[[error.XError, Optional[rq.Request]], _T] if sys.version_info[0] == 3: diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index 11a41226..4e8293c9 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -42,7 +42,7 @@ from ..display import _BaseDisplay from mmap import mmap from collections.abc import Iterable, Sequence, Callable - from typing_extensions import TypeAlias, Literal, SupportsIndex, LiteralString + from typing_extensions import Literal, SupportsIndex, LiteralString from Xlib.error import XError from Xlib.protocol import display from pickle import PickleBuffer @@ -50,9 +50,9 @@ from Xlib.ext.xinput import ClassInfoClass from Xlib.display import _ResourceBaseClass _T = TypeVar("_T") - _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array[Any], mmap] - _IntNew: TypeAlias = Union[str, _SliceableBuffer, _CData, PickleBuffer, SupportsInt, SupportsIndex] - _ErrorHandler: TypeAlias = Callable[[XError, Optional["Request"]], _T] + _SliceableBuffer = Union[bytes, bytearray, memoryview, array[Any], mmap] + _IntNew = Union[str, _SliceableBuffer, _CData, PickleBuffer, SupportsInt, SupportsIndex] + _ErrorHandler = Callable[[XError, Optional["Request"]], _T] def decode_string(bs): # type: (bytes | bytearray) -> str @@ -1602,4 +1602,4 @@ def call_error_handler(handler, error, request): if TYPE_CHECKING: # What about StrClass, Mask, RawField, SizeOf, FP1616 and FP3232 ? - _HasStructCodeAndName: TypeAlias = Union[Pad, Opcode, ReplyCode, LengthField, FormatField, Int8, Int16, Int32, Card8, Card16, Card32, Bool, Set, FixedBinary] + _HasStructCodeAndName = Union[Pad, Opcode, ReplyCode, LengthField, FormatField, Int8, Int16, Int32, Card8, Card16, Card32, Bool, Set, FixedBinary] diff --git a/Xlib/rdb.py b/Xlib/rdb.py index ed71ef62..b448783f 100644 --- a/Xlib/rdb.py +++ b/Xlib/rdb.py @@ -43,11 +43,10 @@ def __eq__(self, __other: object) -> bool: ... class SupportsComparisons( SupportsDunderLT[object], SupportsDunderGT[object], SupportsDunderEQ, Protocol ): ... - from typing_extensions import TypeAlias from Xlib import display _T = TypeVar("_T") _C = TypeVar("_C", bound=SupportsComparisons) - _DB: TypeAlias = dict[str, tuple["_DB", ...]] + _DB = dict[str, tuple["_DB", ...]] # Set up a few regexpes for parsing string representation of resources diff --git a/Xlib/support/connect.py b/Xlib/support/connect.py index 31e6cd3e..ae0363c4 100644 --- a/Xlib/support/connect.py +++ b/Xlib/support/connect.py @@ -29,9 +29,8 @@ TYPE_CHECKING = False if TYPE_CHECKING: import socket - from typing_extensions import TypeAlias from Xlib.support.unix_connect import _Protocol - _Address: TypeAlias = Union[tuple[Any, ...], str] + _Address = Union[tuple[Any, ...], str] # List the modules which contain the corresponding functions diff --git a/Xlib/support/unix_connect.py b/Xlib/support/unix_connect.py index 6401e987..dab4d7e9 100644 --- a/Xlib/support/unix_connect.py +++ b/Xlib/support/unix_connect.py @@ -44,9 +44,8 @@ except ImportError: TYPE_CHECKING = False if TYPE_CHECKING: - from typing_extensions import TypeAlias _Protocol = type(SUPPORTED_PROTOCOLS) - _Address: TypeAlias = Union[tuple[Any, ...], str] + _Address = Union[tuple[Any, ...], str] # Darwin funky socket. if sys.platform == 'darwin' and ([int(x) for x in platform.release().split('.')] >= [9, 0]): diff --git a/Xlib/support/vms_connect.py b/Xlib/support/vms_connect.py index e6e9c4ce..d445e9ee 100644 --- a/Xlib/support/vms_connect.py +++ b/Xlib/support/vms_connect.py @@ -29,8 +29,7 @@ except ImportError: TYPE_CHECKING = False if TYPE_CHECKING: - from typing_extensions import TypeAlias - _Address: TypeAlias = Union[tuple[Any, ...], str] + _Address = Union[tuple[Any, ...], str] display_re = re.compile(r'^([-a-zA-Z0-9._]*):([0-9]+)(\.([0-9]+))?$') diff --git a/Xlib/xobject/colormap.py b/Xlib/xobject/colormap.py index 63ed8ffe..57ed8d1b 100644 --- a/Xlib/xobject/colormap.py +++ b/Xlib/xobject/colormap.py @@ -32,11 +32,9 @@ TYPE_CHECKING = False if TYPE_CHECKING: from collections.abc import Callable, Sequence - from typing_extensions import TypeAlias from Xlib.protocol import rq - _T = TypeVar("_T") - _ErrorHandler: TypeAlias = Callable[[error.XError, Optional[rq.Request]], _T] + _ErrorHandler = Callable[[error.XError, Optional[rq.Request]], _T] rgb_res = [ re.compile(r'\Argb:([0-9a-fA-F]{1,4})/([0-9a-fA-F]{1,4})/([0-9a-fA-F]{1,4})\Z'), diff --git a/Xlib/xobject/cursor.py b/Xlib/xobject/cursor.py index 9fe79b9a..a9932aa1 100644 --- a/Xlib/xobject/cursor.py +++ b/Xlib/xobject/cursor.py @@ -29,11 +29,10 @@ TYPE_CHECKING = False if TYPE_CHECKING: from collections.abc import Callable - from typing_extensions import TypeAlias from Xlib.error import XError from Xlib.protocol.rq import Request _T = TypeVar("_T") - _ErrorHandler: TypeAlias = Callable[[XError, Optional[Request]], _T] + _ErrorHandler = Callable[[XError, Optional[Request]], _T] class Cursor(resource.Resource): __cursor__ = resource.Resource.__resource__ diff --git a/Xlib/xobject/drawable.py b/Xlib/xobject/drawable.py index 1e3eb23a..32c83ceb 100644 --- a/Xlib/xobject/drawable.py +++ b/Xlib/xobject/drawable.py @@ -37,14 +37,13 @@ TYPE_CHECKING = False if TYPE_CHECKING: from collections.abc import Callable, Sequence, Iterable - from typing_extensions import TypeAlias from Xlib.error import XError from PIL import Image from array import array from mmap import mmap _T = TypeVar("_T") - _SliceableBuffer: TypeAlias = Union[bytes, bytearray, memoryview, array[Any], mmap] - _ErrorHandler: TypeAlias = Callable[[XError, Optional[rq.Request]], _T] + _SliceableBuffer = Union[bytes, bytearray, memoryview, array[Any], mmap] + _ErrorHandler = Callable[[XError, Optional[rq.Request]], _T] class Drawable(resource.Resource): __drawable__ = resource.Resource.__resource__ diff --git a/Xlib/xobject/fontable.py b/Xlib/xobject/fontable.py index a0e460c5..994a5017 100644 --- a/Xlib/xobject/fontable.py +++ b/Xlib/xobject/fontable.py @@ -30,12 +30,11 @@ TYPE_CHECKING = False if TYPE_CHECKING: from collections.abc import Callable - from typing_extensions import TypeAlias from Xlib.error import XError from Xlib.protocol.rq import Request from collections.abc import Sequence _T = TypeVar("_T") - _ErrorHandler: TypeAlias = Callable[[XError, Optional[Request]], _T] + _ErrorHandler = Callable[[XError, Optional[Request]], _T] class Fontable(resource.Resource): __fontable__ = resource.Resource.__resource__ diff --git a/Xlib/xobject/resource.py b/Xlib/xobject/resource.py index 274e2ff9..60b39cda 100644 --- a/Xlib/xobject/resource.py +++ b/Xlib/xobject/resource.py @@ -27,12 +27,11 @@ TYPE_CHECKING = False if TYPE_CHECKING: from collections.abc import Callable - from typing_extensions import TypeAlias from Xlib.error import XError from Xlib.protocol.rq import Request from Xlib.display import _BaseDisplay _T = TypeVar("_T") - _ErrorHandler: TypeAlias = Callable[[XError, Optional[Request]], _T] + _ErrorHandler = Callable[[XError, Optional[Request]], _T] class Resource(object): def __init__(self, display, rid, owner = 0): From 53bd753b8e84cfa90967bc5efb76fe0ff6438e26 Mon Sep 17 00:00:00 2001 From: Avasam Date: Fri, 18 Nov 2022 17:00:54 -0500 Subject: [PATCH 07/17] XK --- Xlib/XK.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Xlib/XK.py b/Xlib/XK.py index a7f0fd72..be2c3e2f 100644 --- a/Xlib/XK.py +++ b/Xlib/XK.py @@ -24,6 +24,10 @@ # definition modules in the Xlib/keysymdef directory. from Xlib.X import NoSymbol +try: + from typing import TYPE_CHECKING +except ImportError: + TYPE_CHECKING = False def string_to_keysym(keysym): # type: (str) -> int @@ -66,7 +70,11 @@ def _load_keysyms_into_XK(mod): # Always import miscellany and latin1 keysyms load_keysym_group('miscellany') +if TYPE_CHECKING: + from Xlib.keysymdef.miscellany import * load_keysym_group('latin1') +if TYPE_CHECKING: + from Xlib.keysymdef.latin1 import * def keysym_to_string(keysym): From 7697da91fd4276b3969820e10cdfe7e9598935b3 Mon Sep 17 00:00:00 2001 From: Avasam Date: Fri, 18 Nov 2022 17:32:48 -0500 Subject: [PATCH 08/17] Fix overload and TYPE_CHECKING type comments --- Xlib/display.py | 40 +++++++++++++++++++++------ Xlib/ext/security.py | 1 - Xlib/ext/shape.py | 1 - Xlib/protocol/display.py | 59 ++++++++++++++++++++++++++++------------ Xlib/protocol/rq.py | 54 +++++++++++++++++++++++++----------- Xlib/rdb.py | 15 ++++++---- Xlib/support/connect.py | 10 +++---- 7 files changed, 125 insertions(+), 55 deletions(-) diff --git a/Xlib/display.py b/Xlib/display.py index 29a8994d..6fa14359 100644 --- a/Xlib/display.py +++ b/Xlib/display.py @@ -225,23 +225,45 @@ def has_extension(self, extension): if TYPE_CHECKING: @overload - def create_resource_object(self, type: Literal['resource'], id: int) -> resource.Resource: ... + def create_resource_object(self, type, id): + # type: (Literal['resource'], int) -> resource.Resource + pass @overload - def create_resource_object(self, type: Literal['drawable'], id: int) -> drawable.Drawable: ... + def create_resource_object(self, type, id): + # type: (Literal['drawable'], int) -> resource.Drawable + pass @overload - def create_resource_object(self, type: Literal['window'], id: int) -> drawable.Window: ... + def create_resource_object(self, type, id): + # type: (Literal['window'], int) -> resource.Window + pass @overload - def create_resource_object(self, type: Literal['pixmap'], id: int) -> drawable.Pixmap: ... + def create_resource_object(self, type, id): + # type: (Literal['pixmap'], int) -> resource.Pixmap + pass @overload - def create_resource_object(self, type: Literal['fontable'], id: int) -> fontable.Fontable: ... + def create_resource_object(self, type, id): + # type: (Literal['fontable'], int) -> resource.Fontable + pass @overload - def create_resource_object(self, type: Literal['font'], id: int) -> fontable.Font: ... + def create_resource_object(self, type, id): + # type: (Literal['font'], int) -> resource.Font + pass @overload - def create_resource_object(self, type: Literal['gc'], id: int) -> fontable.GC: ... + def create_resource_object(self, type, id): + # type: (Literal['gc'], int) -> resource.GC + pass @overload - def create_resource_object(self, type: Literal['colormap'], id: int) -> colormap.Colormap: ... + def create_resource_object(self, type, id): + # type: (Literal['colormap'], int) -> resource.Colormap + pass @overload - def create_resource_object(self, type: Literal['cursor'], id: int) -> cursor.Cursor: ... + def create_resource_object(self, type, id): + # type: (Literal['cursor'], int) -> resource.Cursor + pass + @overload + def create_resource_object(self, type, id): + # type: (str, int) -> resource.Resource + pass def create_resource_object(self, type, id): # type: (str, int) -> resource.Resource """Create a resource object of type for the integer id. type diff --git a/Xlib/ext/security.py b/Xlib/ext/security.py index 01fd807c..786e4f6f 100644 --- a/Xlib/ext/security.py +++ b/Xlib/ext/security.py @@ -37,7 +37,6 @@ from array import array _SliceableBuffer = Union[bytes, bytearray, memoryview, array[Any], mmap] - extname = 'SECURITY' diff --git a/Xlib/ext/shape.py b/Xlib/ext/shape.py index 8b931308..8102e0c1 100644 --- a/Xlib/ext/shape.py +++ b/Xlib/ext/shape.py @@ -12,7 +12,6 @@ from Xlib.xobject import resource, drawable from collections.abc import Sequence - extname = 'SHAPE' OP = rq.Card8 diff --git a/Xlib/protocol/display.py b/Xlib/protocol/display.py index 642c0f6b..9f4ccb6b 100644 --- a/Xlib/protocol/display.py +++ b/Xlib/protocol/display.py @@ -80,13 +80,18 @@ def __len__(self): return len(self.view) if TYPE_CHECKING: - def __contains__(self, other: object) -> bool: ... + def __contains__(self, other): + # type: (object) -> bool + pass @overload - def __getitem__(self, key: int) -> int: ... + def __getitem__(self, key): + # type: (int) -> int + pass @overload - def __getitem__(self, key: slice) -> bytes: ... - + def __getitem__(self, key): + # type: (slice) -> bytes + pass def __getitem__(self, key): # type: (slice | int) -> bytes | int if isinstance(key, slice): @@ -341,31 +346,51 @@ def free_resource_id(self, rid): finally: self.resource_id_lock.release() - if TYPE_CHECKING: @overload - def get_resource_class(self, class_name: Literal['resource'], default: object = ...) -> type[resource.Resource]: ... + def get_resource_class(self, class_name, default = None): + # type: (Literal['resource'], object) -> type[resource.Resource] + pass @overload - def get_resource_class(self, class_name: Literal['drawable'], default: object = ...) -> type[drawable.Drawable]: ... + def get_resource_class(self, class_name, default = None): + # type: (Literal['drawable'], object) -> type[drawable.Drawable] + pass @overload - def get_resource_class(self, class_name: Literal['window'], default: object = ...) -> type[drawable.Window]: ... + def get_resource_class(self, class_name, default = None): + # type: (Literal['window'], object) -> type[drawable.Window] + pass @overload - def get_resource_class(self, class_name: Literal['pixmap'], default: object = ...) -> type[drawable.Pixmap]: ... + def get_resource_class(self, class_name, default = None): + # type: (Literal['pixmap'], object) -> type[drawable.Pixmap] + pass @overload - def get_resource_class(self, class_name: Literal['fontable'], default: object = ...) -> type[fontable.Fontable]: ... + def get_resource_class(self, class_name, default = None): + # type: (Literal['fontable'], object) -> type[fontable.Fontable] + pass @overload - def get_resource_class(self, class_name: Literal['font'], default: object = ...) -> type[fontable.Font]: ... + def get_resource_class(self, class_name, default = None): + # type: (Literal['font'], object) -> type[fontable.Font] + pass @overload - def get_resource_class(self, class_name: Literal['gc'], default: object = ...) -> type[fontable.GC]: ... + def get_resource_class(self, class_name, default = None): + # type: (Literal['gc'], object) -> type[fontable.GC] + pass @overload - def get_resource_class(self, class_name: Literal['colormap'], default: object = ...) -> type[colormap.Colormap]: ... + def get_resource_class(self, class_name, default = None): + # type: (Literal['colormap'], object) -> type[colormap.Colormap] + pass @overload - def get_resource_class(self, class_name: Literal['cursor'], default: object) -> type[cursor.Cursor]: ... + def get_resource_class(self, class_name, default): + # type: (Literal['cursor'], object) -> type[cursor.Cursor] + pass @overload - def get_resource_class(self, class_name: str, default: _T) -> type[_ResourceBaseClass] | _T: ... + def get_resource_class(self, class_name, default): + # type: (str, _T) -> type[_ResourceBaseClass] | _T + pass @overload - def get_resource_class(self, class_name: str, default: None = ...) -> type[_ResourceBaseClass] | None: ... - + def get_resource_class(self, class_name, default = None): + # type: (str, None) -> type[_ResourceBaseClass] | None + pass def get_resource_class(self, class_name, default = None): # type: (str, _T | None) -> _T | None """class = d.get_resource_class(class_name, default = None) diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index 4e8293c9..0bb1ef0f 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -333,9 +333,13 @@ def __init__(self, name, codes = (), default = None): if TYPE_CHECKING: @overload - def check_value(self, value: Callable[[], _T]) -> _T: ... + def check_value(self, value): + # type: (Callable[[], _T]) -> _T + pass @overload - def check_value(self, value: _T) -> _T: ... + def check_value(self, value): + # type: (_T) -> _T + pass def check_value(self, value): # type: (Callable[[], _T] | _T) -> _T if hasattr(value, self.cast_function): @@ -449,12 +453,16 @@ def pack_value(self, val): return val_bytes + b'\0' * ((4 - slen % 4) % 4), slen, None else: return val_bytes, slen, None + if TYPE_CHECKING: @overload - def parse_binary_value(self, data: _T, display: object, length: None, format: object) -> tuple[_T, Literal[b'']]: ... + def parse_binary_value(self, data, display, length, format): + # type: (_T, object, None, object) -> tuple[_T, Literal[b'']] + pass @overload - def parse_binary_value(self, data: _SliceableBuffer, display: object, length: int, format: object) -> tuple[_SliceableBuffer, _SliceableBuffer]: ... - + def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, object, int, object) -> tuple[_SliceableBuffer, _SliceableBuffer] + pass def parse_binary_value(self, data, display, length, format): # type: (_SliceableBuffer, object, int, object) -> tuple[_SliceableBuffer, _SliceableBuffer] if length is None: @@ -491,10 +499,13 @@ def pack_value(self, val): if TYPE_CHECKING: @overload - def parse_binary_value(self, data: bytes | bytearray, display: object, length: None, format: object) -> tuple[str, Literal[b'']]: ... + def parse_binary_value(self, data, display, length, format): + # type: (bytes | bytearray, object, None, object) -> tuple[str, Literal[b'']] + pass @overload - def parse_binary_value(self, data: _SliceableBuffer, display: object, length: int, format: object) -> tuple[str, _SliceableBuffer]: ... - + def parse_binary_value(self, data, display, length, format): + # type: (_SliceableBuffer, object, int, object) -> tuple[str, _SliceableBuffer] + pass def parse_binary_value(self, data, display, length, format): # type: (bytes | bytearray, object, int, object) -> tuple[str, bytes | bytearray] if length is None: @@ -554,7 +565,7 @@ class List(ValueField): The type of data objects must be provided as an object with the following attributes and methods: - ... + pass """ @@ -1190,13 +1201,18 @@ def pack_value(self, value): # Structs generate their attributes # TODO: Complete all classes inheriting from Struct # and create a type-only class for all direct instances - def __getattr__(self, __name: str) -> Any: ... + def __getattr__(self, __name): + # type: (str) -> Any + pass @overload - def parse_value(self, val: _SliceableBuffer, display: display.Display | None, rawdict: Literal[True]) -> dict[str, Any]: ... + def parse_value(self, val, display, rawdict): + # type: (_SliceableBuffer, display.Display | None, Literal[True]) -> dict[str, Any] + pass @overload - def parse_value(self, val: _SliceableBuffer, display: display.Display | None, rawdict: Literal[False] = ...) -> DictWrapper:... - + def parse_value(self, val, display, rawdict = False): + # type: (_SliceableBuffer, display.Display | None, Literal[False]) -> DictWrapper + pass def parse_value(self, val, display, rawdict = 0): # type: (_SliceableBuffer, display.Display | None, bool) -> dict[str, Any] | DictWrapper @@ -1243,9 +1259,13 @@ def parse_value(self, val, display, rawdict = 0): if TYPE_CHECKING: @overload - def parse_binary(self, data: _SliceableBuffer, display: display.Display | None, rawdict: Literal[True]) -> tuple[dict[str, Any], _SliceableBuffer]: ... + def parse_binary(self, data, display, rawdict): + # type: (_SliceableBuffer, display.Display | None, Literal[True]) -> tuple[dict[str, Any], _SliceableBuffer] + pass @overload - def parse_binary(self, data: _SliceableBuffer, display: display.Display | None, rawdict: Literal[False] = ...) -> tuple[DictWrapper , _SliceableBuffer]:... + def parse_binary(self, data, display, rawdict = False): + # type: (_SliceableBuffer, display.Display | None, Literal[False]) -> tuple[DictWrapper , _SliceableBuffer] + pass def parse_binary(self, data, display, rawdict = 0): # type: (_SliceableBuffer, display.Display | None, bool) -> tuple[DictWrapper | dict[str, Any], _SliceableBuffer] @@ -1417,7 +1437,9 @@ def __getattr__(self, attr): except KeyError: raise AttributeError(attr) if TYPE_CHECKING: - def __setattr__(self, __name: str, __value: Any) -> None: ... + def __setattr__(self, __name, __value): + # type: (str, Any) -> None + pass class DictWrapper(GetAttrData): def __init__(self, dict): diff --git a/Xlib/rdb.py b/Xlib/rdb.py index b448783f..ee366492 100644 --- a/Xlib/rdb.py +++ b/Xlib/rdb.py @@ -39,10 +39,12 @@ from collections.abc import Iterable, Sequence from _typeshed import SupportsRead, SupportsDunderLT, SupportsDunderGT class SupportsDunderEQ(Protocol): - def __eq__(self, __other: object) -> bool: ... + def __eq__(self, __other: object): + # type: (object) -> bool + pass class SupportsComparisons( SupportsDunderLT[object], SupportsDunderGT[object], SupportsDunderEQ, Protocol - ): ... + ): pass from Xlib import display _T = TypeVar("_T") _C = TypeVar("_C", bound=SupportsComparisons) @@ -328,10 +330,13 @@ def __getitem__(self, keys_tuple): if TYPE_CHECKING: @overload - def get(self, res: str, cls: str, default: None = ...) -> Any: ... + def get(self, res, cls, default = None): + # type: (str, str, None) -> Any + pass @overload - def get(self, res: str, cls: str, default: _T) -> _T: ... - + def get(self, res, cls, default): + # type: (str, str, _T) -> _T + pass def get(self, res, cls, default = None): # type: (str, str, object) -> Any """get(name, class [, default]) diff --git a/Xlib/support/connect.py b/Xlib/support/connect.py index ae0363c4..411ecc28 100644 --- a/Xlib/support/connect.py +++ b/Xlib/support/connect.py @@ -28,6 +28,10 @@ except ImportError: TYPE_CHECKING = False if TYPE_CHECKING: + if sys.platform == 'OpenVMS': + from Xlib.support.vms_connect import get_display as get_display, get_socket as get_socket + else: + from Xlib.support.unix_connect import get_display as get_display, get_socket as get_socket import socket from Xlib.support.unix_connect import _Protocol _Address = Union[tuple[Any, ...], str] @@ -64,12 +68,6 @@ def _relative_import(modname): return importlib.import_module('..' + modname, __name__) -if TYPE_CHECKING: - if sys.platform == 'OpenVMS': - from Xlib.support.vms_connect import get_display as get_display, get_socket as get_socket - else: - from Xlib.support.unix_connect import get_display as get_display, get_socket as get_socket - def get_display(display): # type: (str | None) -> tuple[str, str | None, str | None, int, int] """dname, protocol, host, dno, screen = get_display(display) From ddb1e77eb4376c24f4f0a75d8c625ce258bf4973 Mon Sep 17 00:00:00 2001 From: Avasam Date: Fri, 18 Nov 2022 17:50:24 -0500 Subject: [PATCH 09/17] Remove from __future__ --- Xlib/protocol/display.py | 2 -- Xlib/protocol/rq.py | 2 -- Xlib/rdb.py | 1 - Xlib/support/connect.py | 1 - Xlib/xauth.py | 1 - 5 files changed, 7 deletions(-) diff --git a/Xlib/protocol/display.py b/Xlib/protocol/display.py index 9f4ccb6b..910efdbc 100644 --- a/Xlib/protocol/display.py +++ b/Xlib/protocol/display.py @@ -21,8 +21,6 @@ # Suite 330, # Boston, MA 02111-1307 USA -from __future__ import annotations - # Standard modules import errno import math diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index 0bb1ef0f..e868ea8d 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -20,12 +20,10 @@ # Boston, MA 02111-1307 USA # Standard modules -from __future__ import annotations import sys import traceback import struct from array import array -import types # Python 2/3 compatibility. from six import binary_type, byte2int, indexbytes, iterbytes diff --git a/Xlib/rdb.py b/Xlib/rdb.py index ee366492..9a870271 100644 --- a/Xlib/rdb.py +++ b/Xlib/rdb.py @@ -22,7 +22,6 @@ # See end of file for an explanation of the algorithm and # data structures used. -from __future__ import annotations # Standard modules import re diff --git a/Xlib/support/connect.py b/Xlib/support/connect.py index 411ecc28..b58dd874 100644 --- a/Xlib/support/connect.py +++ b/Xlib/support/connect.py @@ -18,7 +18,6 @@ # 59 Temple Place, # Suite 330, # Boston, MA 02111-1307 USA -from __future__ import annotations import sys import importlib diff --git a/Xlib/xauth.py b/Xlib/xauth.py index 3fd78b96..335d1802 100644 --- a/Xlib/xauth.py +++ b/Xlib/xauth.py @@ -18,7 +18,6 @@ # 59 Temple Place, # Suite 330, # Boston, MA 02111-1307 USA -from __future__ import annotations import os import struct From ad71f6c1b1af47df167ad5c713fa82ed5ca779ab Mon Sep 17 00:00:00 2001 From: Avasam Date: Fri, 18 Nov 2022 18:17:53 -0500 Subject: [PATCH 10/17] Update commetns and spacing --- Xlib/XK.py | 1 + Xlib/ext/damage.py | 2 +- Xlib/ext/ge.py | 1 + Xlib/ext/record.py | 1 + Xlib/ext/security.py | 1 + Xlib/ext/shape.py | 1 + Xlib/protocol/rq.py | 12 ++++++++---- Xlib/rdb.py | 1 + Xlib/support/connect.py | 2 ++ 9 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Xlib/XK.py b/Xlib/XK.py index be2c3e2f..6b3c6ec5 100644 --- a/Xlib/XK.py +++ b/Xlib/XK.py @@ -24,6 +24,7 @@ # definition modules in the Xlib/keysymdef directory. from Xlib.X import NoSymbol + try: from typing import TYPE_CHECKING except ImportError: diff --git a/Xlib/ext/damage.py b/Xlib/ext/damage.py index c68ba920..c4bc9023 100644 --- a/Xlib/ext/damage.py +++ b/Xlib/ext/damage.py @@ -22,9 +22,9 @@ from Xlib import X from Xlib.protocol import rq, structs, request +from Xlib.xobject import resource from Xlib.error import XError from Xlib.display import Display -from Xlib.xobject import resource extname = 'DAMAGE' diff --git a/Xlib/ext/ge.py b/Xlib/ext/ge.py index 89badb6a..62355a53 100644 --- a/Xlib/ext/ge.py +++ b/Xlib/ext/ge.py @@ -25,6 +25,7 @@ ''' from Xlib.protocol import rq + try: from typing import TYPE_CHECKING, Union, Any except ImportError: diff --git a/Xlib/ext/record.py b/Xlib/ext/record.py index e433058f..64c5050e 100644 --- a/Xlib/ext/record.py +++ b/Xlib/ext/record.py @@ -21,6 +21,7 @@ from Xlib import X from Xlib.protocol import rq + try: from typing import TYPE_CHECKING, Any, TypeVar except ImportError: diff --git a/Xlib/ext/security.py b/Xlib/ext/security.py index 786e4f6f..c19d6edc 100644 --- a/Xlib/ext/security.py +++ b/Xlib/ext/security.py @@ -26,6 +26,7 @@ ''' from Xlib.protocol import rq + try: from typing import TYPE_CHECKING, Any, Union except ImportError: diff --git a/Xlib/ext/shape.py b/Xlib/ext/shape.py index 8102e0c1..31781207 100644 --- a/Xlib/ext/shape.py +++ b/Xlib/ext/shape.py @@ -2,6 +2,7 @@ # Generated from: /usr/share/xcb/shape.xml from Xlib.protocol import rq, structs + try: from typing import TYPE_CHECKING except ImportError: diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index e868ea8d..4da3797d 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -132,7 +132,6 @@ class Field(object): """ name = None # type: str default = None # type: int | None - pack_value = None # type: Callable[[Any], tuple[Any, int | None, int | None]] | None structcode = None # type: str | None structvalues = 0 @@ -347,6 +346,8 @@ def check_value(self, value): def parse_value(self, value, display): # type: (int, _BaseDisplay | None) -> int | _ResourceBaseClass + # if not display: + # return value if value in self.codes: return value @@ -563,7 +564,7 @@ class List(ValueField): The type of data objects must be provided as an object with the following attributes and methods: - pass + ... """ @@ -995,6 +996,8 @@ def __init__(self, class_name): def parse_value(self, value, display): # type: (int, _BaseDisplay | None) -> int | _ResourceBaseClass + # if not display: + # return value if not display: return value c = display.get_resource_class(self.class_name) @@ -1121,8 +1124,8 @@ def to_binary(self, *varargs, **keys): formats = {} for f in self.var_fields: - if f.keyword_args: - v, l, fm = f.pack_value(field_args[f.name], keys) # ValueList + if f.keyword_args: # f is ValueList + v, l, fm = f.pack_value(field_args[f.name], keys) else: v, l, fm = f.pack_value(field_args[f.name]) var_vals[f.name] = v @@ -1195,6 +1198,7 @@ def pack_value(self, value): else: raise BadDataError('%s is not a tuple or a list' % (value)) + if TYPE_CHECKING: # Structs generate their attributes # TODO: Complete all classes inheriting from Struct diff --git a/Xlib/rdb.py b/Xlib/rdb.py index 9a870271..31f4eeed 100644 --- a/Xlib/rdb.py +++ b/Xlib/rdb.py @@ -23,6 +23,7 @@ # See end of file for an explanation of the algorithm and # data structures used. + # Standard modules import re import sys diff --git a/Xlib/support/connect.py b/Xlib/support/connect.py index b58dd874..9fe78873 100644 --- a/Xlib/support/connect.py +++ b/Xlib/support/connect.py @@ -67,6 +67,7 @@ def _relative_import(modname): return importlib.import_module('..' + modname, __name__) + def get_display(display): # type: (str | None) -> tuple[str, str | None, str | None, int, int] """dname, protocol, host, dno, screen = get_display(display) @@ -85,6 +86,7 @@ def get_display(display): mod = _relative_import(modname) return mod.get_display(display) + def get_socket(dname, protocol, host, dno): # type: (_Address, _Protocol, _Address | None, int) -> socket.socket """socket = get_socket(dname, protocol, host, dno) From 830f0c5f2806607c6120333a6b767fc48b7014ec Mon Sep 17 00:00:00 2001 From: Avasam Date: Fri, 18 Nov 2022 18:36:57 -0500 Subject: [PATCH 11/17] __getattr__ change --- Xlib/protocol/rq.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index 4da3797d..f5236806 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -1203,7 +1203,7 @@ def pack_value(self, value): # Structs generate their attributes # TODO: Complete all classes inheriting from Struct # and create a type-only class for all direct instances - def __getattr__(self, __name): + def __getattr__(self, attr): # type: (str) -> Any pass @@ -1432,11 +1432,8 @@ class GetAttrData(object): def __getattr__(self, attr): # type: (str) -> Any try: - if self._data: - return self._data[attr] - else: - raise AttributeError(attr) - except KeyError: + return self._data[attr] + except (KeyError, AttributeError): raise AttributeError(attr) if TYPE_CHECKING: def __setattr__(self, __name, __value): From 035edd43107892851219567b25beefb24c7cfb4d Mon Sep 17 00:00:00 2001 From: Avasam Date: Fri, 18 Nov 2022 18:50:53 -0500 Subject: [PATCH 12/17] syntax error --- .gitignore | 2 ++ Xlib/rdb.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d8efd36c..90c7ea24 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,8 @@ nosetests.xml coverage.xml *,cover .hypothesis/ +Coverage_report/ +profilex_output # Translations *.mo diff --git a/Xlib/rdb.py b/Xlib/rdb.py index 31f4eeed..ccbcbe18 100644 --- a/Xlib/rdb.py +++ b/Xlib/rdb.py @@ -39,7 +39,7 @@ from collections.abc import Iterable, Sequence from _typeshed import SupportsRead, SupportsDunderLT, SupportsDunderGT class SupportsDunderEQ(Protocol): - def __eq__(self, __other: object): + def __eq__(self, __other): # type: (object) -> bool pass class SupportsComparisons( From 909a748de53f16411b1686913f681ecf57032d19 Mon Sep 17 00:00:00 2001 From: Avasam Date: Fri, 18 Nov 2022 18:57:30 -0500 Subject: [PATCH 13/17] test with comments? --- Xlib/protocol/display.py | 6 +++--- Xlib/protocol/rq.py | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Xlib/protocol/display.py b/Xlib/protocol/display.py index 910efdbc..0811facd 100644 --- a/Xlib/protocol/display.py +++ b/Xlib/protocol/display.py @@ -78,9 +78,9 @@ def __len__(self): return len(self.view) if TYPE_CHECKING: - def __contains__(self, other): - # type: (object) -> bool - pass + # def __contains__(self, other): + # # type: (object) -> bool + # pass @overload def __getitem__(self, key): diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index f5236806..3b35975d 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -1203,9 +1203,9 @@ def pack_value(self, value): # Structs generate their attributes # TODO: Complete all classes inheriting from Struct # and create a type-only class for all direct instances - def __getattr__(self, attr): - # type: (str) -> Any - pass + # def __getattr__(self, attr): + # # type: (str) -> Any + # pass @overload def parse_value(self, val, display, rawdict): @@ -1435,10 +1435,10 @@ def __getattr__(self, attr): return self._data[attr] except (KeyError, AttributeError): raise AttributeError(attr) - if TYPE_CHECKING: - def __setattr__(self, __name, __value): - # type: (str, Any) -> None - pass + # if TYPE_CHECKING: + # def __setattr__(self, __name, __value): + # # type: (str, Any) -> None + # pass class DictWrapper(GetAttrData): def __init__(self, dict): From f46b72c1ea353e03f5c0d829c5559bb693cd0a11 Mon Sep 17 00:00:00 2001 From: Avasam Date: Fri, 18 Nov 2022 21:02:25 -0500 Subject: [PATCH 14/17] probably fixed --- Xlib/protocol/display.py | 7 +++---- Xlib/protocol/rq.py | 22 +++++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Xlib/protocol/display.py b/Xlib/protocol/display.py index 0811facd..bbeb170f 100644 --- a/Xlib/protocol/display.py +++ b/Xlib/protocol/display.py @@ -78,9 +78,9 @@ def __len__(self): return len(self.view) if TYPE_CHECKING: - # def __contains__(self, other): - # # type: (object) -> bool - # pass + def __contains__(self, other): + # type: (object) -> bool + pass @overload def __getitem__(self, key): @@ -110,7 +110,6 @@ class Display(object): extension_major_opcodes = {} # type: dict[str, int] error_classes = error.xerror_class.copy() # type: dict[int, type[error.XError]] event_classes = event.event_class.copy() # type: dict[int, type[rq.Event] | dict[int, type[rq.Event]]] - resource_classes = {} # type: _BaseClasses def __init__(self, display = None): # type: (str | None) -> None diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index 3b35975d..c1220b4f 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -1203,9 +1203,9 @@ def pack_value(self, value): # Structs generate their attributes # TODO: Complete all classes inheriting from Struct # and create a type-only class for all direct instances - # def __getattr__(self, attr): - # # type: (str) -> Any - # pass + def __getattr__(self, attr): + # type: (str) -> Any + pass @overload def parse_value(self, val, display, rawdict): @@ -1432,13 +1432,16 @@ class GetAttrData(object): def __getattr__(self, attr): # type: (str) -> Any try: - return self._data[attr] - except (KeyError, AttributeError): + if self._data: + return self._data[attr] + else: + raise AttributeError(attr) + except KeyError: raise AttributeError(attr) - # if TYPE_CHECKING: - # def __setattr__(self, __name, __value): - # # type: (str, Any) -> None - # pass + if TYPE_CHECKING: + def __setattr__(self, __name, __value): + # type: (str, Any) -> None + pass class DictWrapper(GetAttrData): def __init__(self, dict): @@ -1513,6 +1516,7 @@ def __init__(self, display, defer = 0, *args, **keys): self._display = display self._binary = self._request.to_binary(*args, **keys) self._serial = None # type: int | None + self._data = None self._error = None self._response_lock = lock.allocate_lock() From dfdf8c1eda5397f35f02813d23b294a549fb6e21 Mon Sep 17 00:00:00 2001 From: Avasam Date: Fri, 18 Nov 2022 22:43:46 -0500 Subject: [PATCH 15/17] Nonable length --- Xlib/ext/xinput.py | 2 +- Xlib/protocol/rq.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Xlib/ext/xinput.py b/Xlib/ext/xinput.py index 297976c1..ed06566a 100644 --- a/Xlib/ext/xinput.py +++ b/Xlib/ext/xinput.py @@ -335,7 +335,7 @@ def __init__(self, name): rq.ValueField.__init__(self, name) def parse_binary_value(self, data, display, length, fmt): - # type: (_SliceableBuffer, object, int, object) -> tuple[ButtonMask, _SliceableBuffer] + # type: (_SliceableBuffer, object, int | None, object) -> tuple[ButtonMask, _SliceableBuffer] # Mask: bitfield of button states. mask_len = 4 * ((((length + 7) >> 3) + 3) >> 2) mask_data = data[:mask_len] diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index c1220b4f..89898fa7 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -145,7 +145,7 @@ def __init__(self): pass def parse_binary_value(self, data, display, length, format): - # type: (_SliceableBuffer, display.Display | None, int, int) -> tuple[Any, _SliceableBuffer] + # type: (_SliceableBuffer, display.Display | None, int | None, int) -> tuple[Any, _SliceableBuffer] """value, remaindata = f.parse_binary_value(data, display, length, format) Decode a value for this field from the binary string DATA. @@ -463,7 +463,7 @@ def parse_binary_value(self, data, display, length, format): # type: (_SliceableBuffer, object, int, object) -> tuple[_SliceableBuffer, _SliceableBuffer] pass def parse_binary_value(self, data, display, length, format): - # type: (_SliceableBuffer, object, int, object) -> tuple[_SliceableBuffer, _SliceableBuffer] + # type: (_SliceableBuffer, object, int | None, object) -> tuple[_SliceableBuffer, _SliceableBuffer] if length is None: return data, b'' @@ -506,7 +506,7 @@ def parse_binary_value(self, data, display, length, format): # type: (_SliceableBuffer, object, int, object) -> tuple[str, _SliceableBuffer] pass def parse_binary_value(self, data, display, length, format): - # type: (bytes | bytearray, object, int, object) -> tuple[str, bytes | bytearray] + # type: (bytes | bytearray, object, int | None, object) -> tuple[str, bytes | bytearray] if length is None: return decode_string(data), b'' @@ -544,7 +544,7 @@ def pack_value(self, val): return struct.pack('>' + 'H' * slen, *val) + pad, slen, None def parse_binary_value(self, data, display, length, format): - # type: (_SliceableBuffer, object, int | Literal['odd', 'even'], object) -> tuple[tuple[Any, ...], _SliceableBuffer] + # type: (_SliceableBuffer, object, int | Literal['odd', 'even'] | None, object) -> tuple[tuple[Any, ...], _SliceableBuffer] if length == 'odd': length = len(data) // 2 - 1 elif length == 'even': From 14e620dda872a43d65439824c97b9e2693191570 Mon Sep 17 00:00:00 2001 From: Avasam Date: Sun, 27 Nov 2022 15:03:36 -0500 Subject: [PATCH 16/17] Update some buffer types --- Xlib/ext/security.py | 7 ++----- Xlib/protocol/display.py | 19 ++++++++++++++----- Xlib/protocol/rq.py | 2 +- Xlib/xobject/drawable.py | 7 ++----- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/Xlib/ext/security.py b/Xlib/ext/security.py index c19d6edc..c0ed4069 100644 --- a/Xlib/ext/security.py +++ b/Xlib/ext/security.py @@ -28,15 +28,12 @@ from Xlib.protocol import rq try: - from typing import TYPE_CHECKING, Any, Union + from typing import TYPE_CHECKING except ImportError: TYPE_CHECKING = False if TYPE_CHECKING: - from mmap import mmap from Xlib.display import Display from Xlib.xobject import resource - from array import array - _SliceableBuffer = Union[bytes, bytearray, memoryview, array[Any], mmap] extname = 'SECURITY' @@ -102,7 +99,7 @@ class SecurityGenerateAuthorization(rq.ReplyRequest): def generate_authorization(self, auth_proto, auth_data=b'', timeout=None, trust_level=None, group=None, event_mask=None): - # type: (Display | resource.Resource, str, _SliceableBuffer, int | None, int | None, int | None, int | None) -> SecurityGenerateAuthorization + # type: (Display | resource.Resource, str, bytes | bytearray, int | None, int | None, int | None, int | None) -> SecurityGenerateAuthorization value_mask = 0 values = [] if timeout is not None: diff --git a/Xlib/protocol/display.py b/Xlib/protocol/display.py index bbeb170f..7b46acb5 100644 --- a/Xlib/protocol/display.py +++ b/Xlib/protocol/display.py @@ -51,19 +51,28 @@ from array import array from mmap import mmap from collections.abc import Callable - from Xlib.display import _resource_baseclasses, _ResourceBaseClass + from Xlib.display import _ResourceBaseClass from Xlib.xobject import cursor, colormap, fontable, drawable, resource + from pickle import PickleBuffer + from ctypes import _CData _T = TypeVar("_T") - _BaseClasses = type(_resource_baseclasses) - _SliceableBuffer = Union[bytes, bytearray, memoryview, array[Any], mmap] + _BufferWithLen = Union[bytes, bytearray, memoryview, array[Any], mmap, _CData, PickleBuffer] _ErrorHandler = Callable[[error.XError, Optional[rq.Request]], _T] if sys.version_info[0] == 3: class bytesview(object): - + if TYPE_CHECKING: + @overload + def __init__(self, data, offset, size): + # type: (bytes | bytesview, int, int) -> None + pass + @overload + def __init__(self, data, offset=0, size=None): + # type: (_BufferWithLen, int, None) -> None + pass def __init__(self, data, offset=0, size=None): - # type: (_SliceableBuffer | bytesview, int, int | None) -> None + # type: (_BufferWithLen | bytesview, int, int | None) -> None if size is None: size = len(data)-offset if isinstance(data, bytes): diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index 89898fa7..05a75a30 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -1017,7 +1017,7 @@ def pack_value(self, val): return (chr(len(val)) + val).encode() def parse_binary(self, data, display): - # type: (bytes | bytearray, object) -> tuple[str, _SliceableBuffer] + # type: (bytes | bytearray, object) -> tuple[str, bytes | bytearray] slen = byte2int(data) + 1 return decode_string(data[1:slen]), data[slen:] diff --git a/Xlib/xobject/drawable.py b/Xlib/xobject/drawable.py index 32c83ceb..beb32cf3 100644 --- a/Xlib/xobject/drawable.py +++ b/Xlib/xobject/drawable.py @@ -32,17 +32,14 @@ from . import icccm try: - from typing import TYPE_CHECKING, TypeVar, Optional, Union, Any + from typing import TYPE_CHECKING, TypeVar, Optional except ImportError: TYPE_CHECKING = False if TYPE_CHECKING: from collections.abc import Callable, Sequence, Iterable from Xlib.error import XError from PIL import Image - from array import array - from mmap import mmap _T = TypeVar("_T") - _SliceableBuffer = Union[bytes, bytearray, memoryview, array[Any], mmap] _ErrorHandler = Callable[[XError, Optional[rq.Request]], _T] class Drawable(resource.Resource): @@ -227,7 +224,7 @@ def fill_arc(self, gc, x, y, width, height, angle1, angle2, onerror = None): def put_image(self, gc, x, y, width, height, format, depth, left_pad, data, onerror = None): - # type: (int, int, int, int, int, int, int, int, _SliceableBuffer, _ErrorHandler[object] | None) -> None + # type: (int, int, int, int, int, int, int, int, bytes | bytearray, _ErrorHandler[object] | None) -> None request.PutImage(display = self.display, onerror = onerror, format = format, From d1797a31c868a3d53d8e86d1cfde8cff4a282d02 Mon Sep 17 00:00:00 2001 From: Avasam Date: Wed, 30 Nov 2022 17:37:07 -0500 Subject: [PATCH 17/17] Type comments update --- Xlib/protocol/rq.py | 3 +-- Xlib/rdb.py | 28 ++++++++++++---------------- Xlib/support/connect.py | 4 ++-- Xlib/support/unix_connect.py | 4 ++-- Xlib/support/vms_connect.py | 6 ++---- 5 files changed, 19 insertions(+), 26 deletions(-) diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py index 05a75a30..527f0969 100644 --- a/Xlib/protocol/rq.py +++ b/Xlib/protocol/rq.py @@ -1201,8 +1201,7 @@ def pack_value(self, value): if TYPE_CHECKING: # Structs generate their attributes - # TODO: Complete all classes inheriting from Struct - # and create a type-only class for all direct instances + # TODO: Create a specific type-only class for all instances of `Struct` def __getattr__(self, attr): # type: (str) -> Any pass diff --git a/Xlib/rdb.py b/Xlib/rdb.py index ccbcbe18..3368bc67 100644 --- a/Xlib/rdb.py +++ b/Xlib/rdb.py @@ -36,19 +36,15 @@ except ImportError: TYPE_CHECKING = False if TYPE_CHECKING: - from collections.abc import Iterable, Sequence + from collections.abc import Iterable, Sequence, Mapping from _typeshed import SupportsRead, SupportsDunderLT, SupportsDunderGT - class SupportsDunderEQ(Protocol): - def __eq__(self, __other): - # type: (object) -> bool - pass - class SupportsComparisons( - SupportsDunderLT[object], SupportsDunderGT[object], SupportsDunderEQ, Protocol - ): pass from Xlib import display _T = TypeVar("_T") - _C = TypeVar("_C", bound=SupportsComparisons) + _T_contra = TypeVar("_T", contravariant=True) + class SupportsComparisons(SupportsDunderLT[_T_contra], SupportsDunderGT[_T_contra], Protocol): pass _DB = dict[str, tuple["_DB", ...]] + # This can be a bit annoying due to dict invariance, so making a parameter-specific alias + _DB_Param = dict[str, Any] # Set up a few regexpes for parsing string representation of resources @@ -377,7 +373,7 @@ def output(self): return text def getopt(self, name, argv, opts): - # type: (str, Sequence[str], dict[str, Option]) -> Sequence[str] + # type: (str, Sequence[str], Mapping[str, Option]) -> Sequence[str] """getopt(name, argv, opts) Parse X command line options, inserting the recognised options @@ -489,7 +485,7 @@ def value(self): # def bin_insert(list, element): - # type: (list[_C], _C) -> None + # type: (list[SupportsComparisons[_T]], SupportsComparisons[_T]) -> None """bin_insert(list, element) Insert ELEMENT into LIST. LIST must be sorted, and ELEMENT will @@ -525,7 +521,7 @@ def bin_insert(list, element): # def update_db(dest, src): - # type: (_DB, _DB) -> None + # type: (_DB_Param, _DB_Param) -> None for comp, group in src.items(): # DEST already contains this component, update it @@ -546,11 +542,11 @@ def update_db(dest, src): dest[comp] = copy_group(group) def copy_group(group): - # type: (tuple[_DB, ...]) -> tuple[_DB, ...] + # type: (tuple[_DB_Param, ...]) -> tuple[_DB, ...] return (copy_db(group[0]), copy_db(group[1])) + group[2:] def copy_db(db): - # type: (_DB) -> _DB + # type: (_DB_Param) -> _DB newdb = {} for comp, group in db.items(): newdb[comp] = copy_group(group) @@ -563,7 +559,7 @@ def copy_db(db): # def output_db(prefix, db): - # type: (str, _DB) -> str + # type: (str, _DB_Param) -> str res = '' for comp, group in db.items(): @@ -682,7 +678,7 @@ def parse(self, name, db, args): def get_display_opts(options, argv = sys.argv): - # type: (dict[str, Option], Sequence[str]) -> tuple[display.Display, str, ResourceDB, Sequence[str]] + # type: (Mapping[str, Option], Sequence[str]) -> tuple[display.Display, str, ResourceDB, Sequence[str]] """display, name, db, args = get_display_opts(options, [argv]) Parse X OPTIONS from ARGV (or sys.argv if not provided). diff --git a/Xlib/support/connect.py b/Xlib/support/connect.py index 9fe78873..ba2b6351 100644 --- a/Xlib/support/connect.py +++ b/Xlib/support/connect.py @@ -23,7 +23,7 @@ import importlib try: - from typing import TYPE_CHECKING, Any, Union + from typing import TYPE_CHECKING except ImportError: TYPE_CHECKING = False if TYPE_CHECKING: @@ -33,7 +33,7 @@ from Xlib.support.unix_connect import get_display as get_display, get_socket as get_socket import socket from Xlib.support.unix_connect import _Protocol - _Address = Union[tuple[Any, ...], str] + from _socket import _Address # List the modules which contain the corresponding functions diff --git a/Xlib/support/unix_connect.py b/Xlib/support/unix_connect.py index dab4d7e9..be7d93d2 100644 --- a/Xlib/support/unix_connect.py +++ b/Xlib/support/unix_connect.py @@ -40,12 +40,12 @@ SUPPORTED_PROTOCOLS = (None, 'tcp', 'unix') try: - from typing import TYPE_CHECKING, Any, Union + from typing import TYPE_CHECKING except ImportError: TYPE_CHECKING = False if TYPE_CHECKING: _Protocol = type(SUPPORTED_PROTOCOLS) - _Address = Union[tuple[Any, ...], str] + from _socket import _Address # Darwin funky socket. if sys.platform == 'darwin' and ([int(x) for x in platform.release().split('.')] >= [9, 0]): diff --git a/Xlib/support/vms_connect.py b/Xlib/support/vms_connect.py index d445e9ee..d1c7dc65 100644 --- a/Xlib/support/vms_connect.py +++ b/Xlib/support/vms_connect.py @@ -25,11 +25,9 @@ from Xlib import error try: - from typing import TYPE_CHECKING, Any, Union + from _socket import _Address except ImportError: - TYPE_CHECKING = False -if TYPE_CHECKING: - _Address = Union[tuple[Any, ...], str] + pass display_re = re.compile(r'^([-a-zA-Z0-9._]*):([0-9]+)(\.([0-9]+))?$') pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy