Skip to content

Commit 7916a7b

Browse files
Fill in some type annotations (#237)
1 parent 6523e3f commit 7916a7b

File tree

3 files changed

+68
-55
lines changed

3 files changed

+68
-55
lines changed

src/evdev/device.py

+19-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import contextlib
22
import os
3-
from typing import NamedTuple, Tuple, Union
3+
from typing import Dict, Iterator, List, Literal, NamedTuple, Tuple, Union, overload
44

55
from . import _input, ecodes, util
66

@@ -95,7 +95,7 @@ class DeviceInfo(NamedTuple):
9595
product: int
9696
version: int
9797

98-
def __str__(self):
98+
def __str__(self) -> str:
9999
msg = "bus: {:04x}, vendor {:04x}, product {:04x}, version {:04x}"
100100
return msg.format(*self) # pylint: disable=not-an-iterable
101101

@@ -151,7 +151,7 @@ def __init__(self, dev: Union[str, bytes, os.PathLike]):
151151
#: The number of force feedback effects the device can keep in its memory.
152152
self.ff_effects_count = _input.ioctl_EVIOCGEFFECTS(self.fd)
153153

154-
def __del__(self):
154+
def __del__(self) -> None:
155155
if hasattr(self, "fd") and self.fd is not None:
156156
try:
157157
self.close()
@@ -176,7 +176,13 @@ def _capabilities(self, absinfo: bool = True):
176176

177177
return res
178178

179-
def capabilities(self, verbose: bool = False, absinfo: bool = True):
179+
@overload
180+
def capabilities(self, verbose: Literal[False] = ..., absinfo: bool = ...) -> Dict[int, List[int]]:
181+
...
182+
@overload
183+
def capabilities(self, verbose: Literal[True], absinfo: bool = ...) -> Dict[Tuple[str, int], List[Tuple[str, int]]]:
184+
...
185+
def capabilities(self, verbose: bool = False, absinfo: bool = True) -> Union[Dict[int, List[int]], Dict[Tuple[str, int], List[Tuple[str, int]]]]:
180186
"""
181187
Return the event types that this device supports as a mapping of
182188
supported event types to lists of handled event codes.
@@ -263,7 +269,7 @@ def leds(self, verbose: bool = False):
263269

264270
return leds
265271

266-
def set_led(self, led_num: int, value: int):
272+
def set_led(self, led_num: int, value: int) -> None:
267273
"""
268274
Set the state of the selected LED.
269275
@@ -279,26 +285,26 @@ def __eq__(self, other):
279285
"""
280286
return isinstance(other, self.__class__) and self.info == other.info and self.path == other.path
281287

282-
def __str__(self):
288+
def __str__(self) -> str:
283289
msg = 'device {}, name "{}", phys "{}", uniq "{}"'
284290
return msg.format(self.path, self.name, self.phys, self.uniq or "")
285291

286-
def __repr__(self):
292+
def __repr__(self) -> str:
287293
msg = (self.__class__.__name__, self.path)
288294
return "{}({!r})".format(*msg)
289295

290296
def __fspath__(self):
291297
return self.path
292298

293-
def close(self):
299+
def close(self) -> None:
294300
if self.fd > -1:
295301
try:
296302
super().close()
297303
os.close(self.fd)
298304
finally:
299305
self.fd = -1
300306

301-
def grab(self):
307+
def grab(self) -> None:
302308
"""
303309
Grab input device using ``EVIOCGRAB`` - other applications will
304310
be unable to receive events until the device is released. Only
@@ -311,7 +317,7 @@ def grab(self):
311317

312318
_input.ioctl_EVIOCGRAB(self.fd, 1)
313319

314-
def ungrab(self):
320+
def ungrab(self) -> None:
315321
"""
316322
Release device if it has been already grabbed (uses `EVIOCGRAB`).
317323
@@ -324,7 +330,7 @@ def ungrab(self):
324330
_input.ioctl_EVIOCGRAB(self.fd, 0)
325331

326332
@contextlib.contextmanager
327-
def grab_context(self):
333+
def grab_context(self) -> Iterator[None]:
328334
"""
329335
A context manager for the duration of which only the current
330336
process will be able to receive events from the device.
@@ -342,7 +348,7 @@ def upload_effect(self, effect: "ff.Effect"):
342348
ff_id = _input.upload_effect(self.fd, data)
343349
return ff_id
344350

345-
def erase_effect(self, ff_id):
351+
def erase_effect(self, ff_id) -> None:
346352
"""
347353
Erase a force effect from a force feedback device. This also
348354
stops the effect.
@@ -402,7 +408,7 @@ def absinfo(self, axis_num: int):
402408
"""
403409
return AbsInfo(*_input.ioctl_EVIOCGABS(self.fd, axis_num))
404410

405-
def set_absinfo(self, axis_num: int, value=None, min=None, max=None, fuzz=None, flat=None, resolution=None):
411+
def set_absinfo(self, axis_num: int, value=None, min=None, max=None, fuzz=None, flat=None, resolution=None) -> None:
406412
"""
407413
Update :class:`AbsInfo` values. Only specified values will be overwritten.
408414

src/evdev/eventio_async.py

+47-40
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,57 @@
11
import asyncio
22
import select
3+
import sys
34

45
from . import eventio
6+
from .events import InputEvent
57

68
# needed for compatibility
79
from .eventio import EvdevError
810

11+
if sys.version_info >= (3, 11):
12+
from typing import Self
13+
else:
14+
from typing import Any as Self
15+
16+
17+
class ReadIterator:
18+
def __init__(self, device):
19+
self.current_batch = iter(())
20+
self.device = device
21+
22+
# Standard iterator protocol.
23+
def __iter__(self) -> Self:
24+
return self
25+
26+
def __next__(self) -> InputEvent:
27+
try:
28+
# Read from the previous batch of events.
29+
return next(self.current_batch)
30+
except StopIteration:
31+
r, w, x = select.select([self.device.fd], [], [])
32+
self.current_batch = self.device.read()
33+
return next(self.current_batch)
34+
35+
def __aiter__(self) -> Self:
36+
return self
37+
38+
def __anext__(self) -> "asyncio.Future[InputEvent]":
39+
future = asyncio.Future()
40+
try:
41+
# Read from the previous batch of events.
42+
future.set_result(next(self.current_batch))
43+
except StopIteration:
44+
45+
def next_batch_ready(batch):
46+
try:
47+
self.current_batch = batch.result()
48+
future.set_result(next(self.current_batch))
49+
except Exception as e:
50+
future.set_exception(e)
51+
52+
self.device.async_read().add_done_callback(next_batch_ready)
53+
return future
54+
955

1056
class EventIO(eventio.EventIO):
1157
def _do_when_readable(self, callback):
@@ -42,7 +88,7 @@ def async_read(self):
4288
self._do_when_readable(lambda: self._set_result(future, self.read))
4389
return future
4490

45-
def async_read_loop(self):
91+
def async_read_loop(self) -> ReadIterator:
4692
"""
4793
Return an iterator that yields input events. This iterator is
4894
compatible with the ``async for`` syntax.
@@ -58,42 +104,3 @@ def close(self):
58104
# no event loop present, so there is nothing to
59105
# remove the reader from. Ignore
60106
pass
61-
62-
63-
class ReadIterator:
64-
def __init__(self, device):
65-
self.current_batch = iter(())
66-
self.device = device
67-
68-
# Standard iterator protocol.
69-
def __iter__(self):
70-
return self
71-
72-
def __next__(self):
73-
try:
74-
# Read from the previous batch of events.
75-
return next(self.current_batch)
76-
except StopIteration:
77-
r, w, x = select.select([self.device.fd], [], [])
78-
self.current_batch = self.device.read()
79-
return next(self.current_batch)
80-
81-
def __aiter__(self):
82-
return self
83-
84-
def __anext__(self):
85-
future = asyncio.Future()
86-
try:
87-
# Read from the previous batch of events.
88-
future.set_result(next(self.current_batch))
89-
except StopIteration:
90-
91-
def next_batch_ready(batch):
92-
try:
93-
self.current_batch = batch.result()
94-
future.set_result(next(self.current_batch))
95-
except Exception as e:
96-
future.set_exception(e)
97-
98-
self.device.async_read().add_done_callback(next_batch_ready)
99-
return future

src/evdev/util.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from typing import Union, List
77

88
from . import ecodes
9-
from .events import event_factory
9+
from .events import InputEvent, event_factory
1010

1111

1212
def list_devices(input_device_dir: Union[str, bytes, os.PathLike] = "/dev/input") -> List[str]:
@@ -32,7 +32,7 @@ def is_device(fn: Union[str, bytes, os.PathLike]) -> bool:
3232
return True
3333

3434

35-
def categorize(event):
35+
def categorize(event: InputEvent) -> InputEvent:
3636
"""
3737
Categorize an event according to its type.
3838

0 commit comments

Comments
 (0)