Repository navigation
Conversation
sezanzeb
left a comment
There was a problem hiding this comment.
Thanks. The change works for me, it raises a TypeError as excpected via the code sample in #261:
Python 3.14.4 (main, Aug 20 2026, 10:41:58) [GCC 15.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import evdev._input
...
... evdev._input.upload_effect(0, None)
...
Traceback (most recent call last):
File "<python-input-0>", line 3, in <module>
evdev._input.upload_effect(0, None)
~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
TypeError: expected bytes, NoneType found
>>>
pipeline passed
| pass | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("data", [bytes(ff.Effect()), bytes(ff.Effect()) + b"extra", EffectBytes(bytes(ff.Effect()))]) |
There was a problem hiding this comment.
wrapping bytes(ff.Effect()) in EffectBytes seems to be redundant
There was a problem hiding this comment.
This prints true:
from evdev import _input, device, ff
class EffectBytes(bytes):
pass
a = EffectBytes(bytes(ff.Effect()))
b = bytes(ff.Effect())
c = EffectBytes(ff.Effect())
print(a)
print(b)
print(c)
print(a == b == c)There was a problem hiding this comment.
Or is there something I'm missing?
There was a problem hiding this comment.
The subclass case is intentional: equal payloads still reach the extension as different Python types. The first case covers plain bytes; EffectBytes checks that validation continues to accept bytes subclasses, and the extra-data case preserves trailing-byte acceptance.
You are right that the inner bytes() conversion is redundant: EffectBytes(ff.Effect()) produces the same subclass and payload. I checked all three expressions locally; each reaches ioctl and raises EBADF with fd -1. The subclass wrapper is what adds coverage here.
_input.upload_effect()callsPyBytes_AsString()and copies from its result even when conversion failed, so a non-bytes argument crashes the interpreter. Check conversion and require enough bytes forstruct ff_effectbefore copying. Complete byte strings (including subclasses and trailing data), ioctl errors, and theInputDevice.upload_effect()serialization path retain their behavior.Fixes #261.
Validation: all 13 new native-extension tests pass on Python 3.14. On current main, six non-bytes cases terminate subprocesses with SIGSEGV and three short-buffer cases fail; four preservation controls pass. All 20 tests outside the uinput module pass. The full suite has 24 passes and six failures because this runner has no
/dev/uinput; the same six fail on clean main. Native build, wheel/sdist build, pylint error check and changed-test Ruff pass. Documentation builds with two missingecodes_generatedwarnings. No actual force-feedback/input hardware was tested.