Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
include:
- os: ubuntu-latest
python-version: "3.7"
python-version: "3.8"

steps:
- uses: actions/checkout@v4
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Lint

on:
- push
- pull_request

jobs:
pylint:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: ["3.12"]

steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Check for pylint errors
run: |
python -m pip install pylint setuptools
python setup.py build
python -m pylint --disable=no-member --verbose -E build/lib*/evdev
29 changes: 29 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Test

on:
- push
- pull_request

jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: ["3.12"]

steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Run pytest tests
# pip install -e . builds _ecodes and such into the evdev directory
# sudo required to write to uinputs
run: |
sudo python -m pip install pytest setuptools
sudo python -m pip install -e .
sudo python -m pytest tests
1 change: 1 addition & 0 deletions evdev/ecodes.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# pylint: disable=undefined-variable
"""
This modules exposes the integer constants defined in ``linux/input.h`` and
``linux/input-event-codes.h``.
Expand Down
2 changes: 2 additions & 0 deletions evdev/eventio.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ def read(self):
for event in events:
yield InputEvent(*event)

# pylint: disable=no-self-argument
def need_write(func):
"""
Decorator that raises :class:`EvdevError` if there is no write access to the
Expand All @@ -82,6 +83,7 @@ def need_write(func):
def wrapper(*args):
fd = args[0].fd
if fcntl.fcntl(fd, fcntl.F_GETFL) & os.O_RDWR:
# pylint: disable=not-callable
return func(*args)
msg = 'no write access to device "%s"' % args[0].path
raise EvdevError(msg)
Expand Down
24 changes: 12 additions & 12 deletions evdev/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ def timestamp(self):
"""Return event timestamp as a float."""
return self.sec + (self.usec / 1000000.0)

def __str__(s):
def __str__(self):
msg = "event at {:f}, code {:02d}, type {:02d}, val {:02d}"
return msg.format(s.timestamp(), s.code, s.type, s.value)
return msg.format(self.timestamp(), self.code, self.type, self.value)

def __repr__(s):
def __repr__(self):
msg = "{}({!r}, {!r}, {!r}, {!r}, {!r})"
return msg.format(s.__class__.__name__, s.sec, s.usec, s.type, s.code, s.value)
return msg.format(self.__class__.__name__, self.sec, self.usec, self.type, self.code, self.value)


class KeyEvent:
Expand Down Expand Up @@ -119,8 +119,8 @@ def __str__(self):
msg = "key event at {:f}, {} ({}), {}"
return msg.format(self.event.timestamp(), self.scancode, self.keycode, ks)

def __repr__(s):
return "{}({!r})".format(s.__class__.__name__, s.event)
def __repr__(self):
return "{}({!r})".format(self.__class__.__name__, self.event)


class RelEvent:
Expand All @@ -136,8 +136,8 @@ def __str__(self):
msg = "relative axis event at {:f}, {}"
return msg.format(self.event.timestamp(), REL[self.event.code])

def __repr__(s):
return "{}({!r})".format(s.__class__.__name__, s.event)
def __repr__(self):
return "{}({!r})".format(self.__class__.__name__, self.event)


class AbsEvent:
Expand All @@ -153,8 +153,8 @@ def __str__(self):
msg = "absolute axis event at {:f}, {}"
return msg.format(self.event.timestamp(), ABS[self.event.code])

def __repr__(s):
return "{}({!r})".format(s.__class__.__name__, s.event)
def __repr__(self):
return "{}({!r})".format(self.__class__.__name__, self.event)


class SynEvent:
Expand All @@ -173,8 +173,8 @@ def __str__(self):
msg = "synchronization event at {:f}, {}"
return msg.format(self.event.timestamp(), SYN[self.event.code])

def __repr__(s):
return "{}({!r})".format(s.__class__.__name__, s.event)
def __repr__(self):
return "{}({!r})".format(self.__class__.__name__, self.event)


#: A mapping of event types to :class:`InputEvent` sub-classes. Used
Expand Down
2 changes: 1 addition & 1 deletion evdev/uinput.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ def _verify(self):
try:
m = os.stat(self.devnode)[stat.ST_MODE]
if not stat.S_ISCHR(m):
raise
raise OSError
except (IndexError, OSError):
msg = '"{}" does not exist or is not a character device file ' "- verify that the uinput module is loaded"
raise UInputError(msg.format(self.devnode))
Expand Down
20 changes: 14 additions & 6 deletions tests/test_uinput.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# encoding: utf-8

import stat
from select import select
from pytest import raises, fixture
from unittest.mock import patch

from evdev import uinput, ecodes, events, device, util
import pytest
from pytest import raises, fixture

from evdev import uinput, ecodes, device, UInputError

# -----------------------------------------------------------------------------
uinput_options = {
Expand Down Expand Up @@ -66,12 +68,12 @@ def test_enable_events(c):

def test_abs_values(c):
e = ecodes
c["events"] = {
c = {
e.EV_KEY: [e.KEY_A, e.KEY_B],
e.EV_ABS: [(e.ABS_X, (0, 255, 0, 0)), (e.ABS_Y, device.AbsInfo(0, 255, 5, 10, 0, 0))],
e.EV_ABS: [(e.ABS_X, (0, 0, 255, 0, 0)), (e.ABS_Y, device.AbsInfo(0, 0, 255, 5, 10, 0))],
}

with uinput.UInput(**c) as ui:
with uinput.UInput(events=c) as ui:
c = ui.capabilities()
abs = device.AbsInfo(value=0, min=0, max=255, fuzz=0, flat=0, resolution=0)
assert c[e.EV_ABS][0] == (0, abs)
Expand Down Expand Up @@ -114,3 +116,9 @@ def test_write(c):
assert evs[3].code == ecodes.KEY_A and evs[3].value == 2
assert evs[4].code == ecodes.KEY_A and evs[4].value == 0
break


@patch.object(stat, 'S_ISCHR', return_value=False)
def test_not_a_character_device(c):
with pytest.raises(UInputError):
uinput.UInput(**c)
Loading