Skip to content

Commit ec6fe40

Browse files
Merge pull request #75 from tiagocoutinho/video-qt
Video qt
2 parents 11e9a6c + 37abdae commit ec6fe40

File tree

13 files changed

+719
-105
lines changed

13 files changed

+719
-105
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414

1515
strategy:
1616
matrix:
17-
python-version: ["3.10", "3.11", "3.12", "3.13"]
17+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
1818

1919
steps:
2020
- name: Checkout
@@ -44,7 +44,7 @@ jobs:
4444
- name: Install dependencies
4545
if: steps.cache.outputs.cache-hit != 'true'
4646
run: |
47-
pip install --disable-pip-version-check -e . --group=dev
47+
pip install --disable-pip-version-check -e . --group=dev_no_qt
4848
- name: Linting
4949
run: |
5050
ruff check --diff --output-format=github linuxpy tests examples
@@ -56,7 +56,7 @@ jobs:
5656
- name: Tests
5757
id: tests
5858
run: |
59-
pytest
59+
pytest -k "not qt"
6060
6161
- name: Upload coverage data
6262
uses: actions/upload-artifact@v4

linuxpy/codegen/video.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class StandardID(enum.IntFlag):
120120
CEnum("TimeCodeType", "V4L2_TC_TYPE_"),
121121
CEnum("TimeCodeFlag", "V4L2_TC_FLAG_", "IntFlag"),
122122
CEnum("EventSubscriptionFlag", "V4L2_EVENT_SUB_FL_", "IntFlag"),
123-
CEnum("EventControlChange", "V4L2_EVENT_CTRL_CH_"),
123+
CEnum("EventControlChange", "V4L2_EVENT_CTRL_CH_", "IntFlag"),
124124
CEnum("EventType", "V4L2_EVENT_"),
125125
CEnum("MbusFrameFormatFlag", "V4L2_MBUS_FRAMEFMT_", "IntFlag"),
126126
# It is very dificult to match just only these two values using prefix, so put whole name there

linuxpy/device.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,11 @@ class BaseDevice(ReentrantOpen):
8181

8282
PREFIX = None
8383

84-
def __init__(self, name_or_file, read_write=True, io=IO):
84+
def __init__(self, name_or_file, read_write=True, io=IO, blocking=False):
8585
super().__init__()
8686
self.io = io
87-
if isinstance(name_or_file, (str, pathlib.Path)):
87+
self.blocking = blocking
88+
if isinstance(name_or_file, str | pathlib.Path):
8889
filename = pathlib.Path(name_or_file)
8990
self._read_write = read_write
9091
self._fobj = None
@@ -121,12 +122,12 @@ def open(self):
121122
"""Open the device if not already open. Triggers _on_open after the underlying OS open has succeeded"""
122123
if not self._fobj:
123124
self.log.info("opening %s", self.filename)
124-
self._fobj = self.io.open(self.filename, self._read_write)
125+
self._fobj = self.io.open(self.filename, self._read_write, blocking=self.blocking)
125126
self._on_open()
126127
self.log.info("opened %s", self.filename)
127128

128129
def close(self):
129-
"""Closes the device if not already closed. Triggers _on_close before the underlying OS open has succeeded"""
130+
"""Closes the device if not already closed. Triggers _on_close before the underlying OS close has succeeded"""
130131
if not self.closed:
131132
self._on_close()
132133
self.log.info("closing %s", self.filename)
@@ -149,4 +150,12 @@ def is_blocking(self) -> bool:
149150
True if the underlying OS is opened in blocking mode.
150151
Raises error if device is not opened.
151152
"""
152-
return os.get_blocking(self.fileno())
153+
return self.io.os.get_blocking(self.fileno())
154+
155+
def set_blocking(self, yes_no: bool) -> None:
156+
"""
157+
Turns on/off blocking mode.
158+
Raises error if device is not opened.
159+
"""
160+
self.io.os.set_blocking(self.fileno(), yes_no)
161+
self.blocking = yes_no

linuxpy/io.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# Distributed under the GPLv3 license. See LICENSE for more info.
66

77
import functools
8+
import importlib
89
import os
910
import select
1011

@@ -33,19 +34,34 @@ def opener(path, flags):
3334

3435
class IO:
3536
open = functools.partial(fopen, blocking=False)
36-
select = select.select
37+
os = os
38+
select = select
39+
40+
41+
class GeventModule:
42+
def __init__(self, name):
43+
self.name = name
44+
self._module = None
45+
46+
@property
47+
def module(self):
48+
if self._module is None:
49+
self._module = importlib.import_module(f"gevent.{self.name}")
50+
return self._module
51+
52+
def __getattr__(self, name):
53+
attr = getattr(self.module, name)
54+
setattr(self, name, attr)
55+
return attr
3756

3857

3958
class GeventIO:
4059
@staticmethod
41-
def open(path, rw=False):
60+
def open(path, rw=False, blocking=False):
4261
mode = "rb+" if rw else "rb"
4362
import gevent.fileobject
4463

4564
return gevent.fileobject.FileObject(path, mode, buffering=0)
4665

47-
@staticmethod
48-
def select(*args, **kwargs):
49-
import gevent.select
50-
51-
return gevent.select.select(*args, **kwargs)
66+
os = GeventModule("os")
67+
select = GeventModule("select")

linuxpy/ioctl.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
"""ioctl helper functions"""
88

9+
import enum
910
import fcntl
1011
import logging
1112

@@ -34,7 +35,7 @@ def IOC(direction, magic, number, size):
3435
magic = ord(magic)
3536
if isinstance(size, str):
3637
size = calcsize(size)
37-
elif size == int:
38+
elif size is int:
3839
size = 4
3940
elif not isinstance(size, int):
4041
size = sizeof(size)
@@ -63,6 +64,7 @@ def IOWR(magic, number, size):
6364

6465

6566
def ioctl(fd, request, *args):
66-
log.debug("%s, request=%s, arg=%s", fd, request, args)
67+
req = request.name if isinstance(request, enum.Enum) else request
68+
log.debug("request=%s, arg=%s", req, args)
6769
fcntl.ioctl(fd, request, *args)
6870
return args and args[0] or None

linuxpy/midi/device.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ def wait_read(self) -> Sequence["Event"]:
529529
non-blocking variants transperently
530530
"""
531531
if self.io.select is not None:
532-
self.io.select((self,), (), ())
532+
self.io.select.select((self,), (), ())
533533
return self.raw_read()
534534

535535
def read(self) -> Sequence["Event"]:

0 commit comments

Comments
 (0)