Skip to content

Commit

Permalink
Merge pull request #48 from tiagocoutinho/linuxpy
Browse files Browse the repository at this point in the history
Replace with linuxpy
  • Loading branch information
tiagocoutinho committed Mar 11, 2024
2 parents 374a140 + d8088a5 commit a75fce2
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 3,807 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:

strategy:
matrix:
python-version: [3.7, 3.8, 3.9, "3.10", "3.11"]
python-version: [3.9, "3.10", "3.11", "3.12"]

steps:
- name: Checkout
Expand All @@ -31,7 +31,7 @@ jobs:
- name: Linting tests
run: |
black --check --diff v4l2py tests examples
ruff check --diff --format=github --show-files .
ruff check --diff --output-format=github --show-files .
- name: Build package
run: |
python -m build
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# v4l2py

**Since version 3.0 this project is now a shim for `linuxpy.video`**

**Please consider using [linuxpy](https/github.com/tiagocoutinho/linuxpy) directly.**

[![V4L2py][pypi-version]](https://pypi.python.org/pypi/v4l2py)
[![Python Versions][pypi-python-versions]](https://pypi.python.org/pypi/v4l2py)
![License][license]
Expand Down
7 changes: 3 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,22 @@ license = {text = "GPL-3.0-or-later"}
authors = [
{ name = "Jose Tiago Macara Coutinho", email = "[email protected]" }
]
requires-python = ">=3.7"
requires-python = ">=3.9"
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Multimedia :: Video",
"Topic :: Multimedia :: Video :: Capture",
]
dependencies = []
dependencies = ["linuxpy>=0.9.0"]
dynamic = ["version", "readme"]

[project.urls]
Expand Down
57 changes: 33 additions & 24 deletions tests/test_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# Copyright (c) 2021 Tiago Coutinho
# Distributed under the GPLv3 license. See LICENSE for more info.

from contextlib import ExitStack
import os
from contextlib import ExitStack, contextmanager
from errno import EINVAL
from inspect import isgenerator
from math import isclose
Expand Down Expand Up @@ -62,11 +63,11 @@ def __init__(self, filename="/dev/video39"):

def __enter__(self):
self.stack = ExitStack()
ioctl = mock.patch("v4l2py.device.fcntl.ioctl", self.ioctl)
opener = mock.patch("v4l2py.io.open", self.open)
mmap = mock.patch("v4l2py.device.mmap.mmap", self.mmap)
select = mock.patch("v4l2py.io.IO.select", self.select)
blocking = mock.patch("v4l2py.device.os.get_blocking", self.get_blocking)
ioctl = mock.patch("linuxpy.ioctl.fcntl.ioctl", self.ioctl)
opener = mock.patch("linuxpy.io.open", self.open)
mmap = mock.patch("linuxpy.video.device.mmap.mmap", self.mmap)
select = mock.patch("linuxpy.io.IO.select", self.select)
blocking = mock.patch("linuxpy.device.os.get_blocking", self.get_blocking)
self.stack.enter_context(ioctl)
self.stack.enter_context(opener)
self.stack.enter_context(mmap)
Expand Down Expand Up @@ -99,45 +100,46 @@ def ioctl(self, fd, ioc, arg): # noqa: C901
if arg.index > 0:
raise OSError(EINVAL, "ups!")
arg.name = self.input0_name
arg.type = raw.V4L2_INPUT_TYPE_CAMERA
arg.type = raw.InputType.CAMERA
elif isinstance(arg, raw.v4l2_query_ext_ctrl):
if arg.index > 0:
raise OSError(EINVAL, "ups!")
arg.name = b"brightness"
arg.type = raw.V4L2_CTRL_TYPE_INTEGER
arg.type = raw.CtrlType.INTEGER
arg.id = 9963776
elif isinstance(arg, raw.v4l2_capability):
arg.driver = self.driver
arg.card = self.card
arg.bus_info = self.bus_info
arg.version = self.version
arg.capabilities = raw.Capability.STREAMING | raw.Capability.VIDEO_CAPTURE
elif isinstance(arg, raw.v4l2_format):
if ioc == raw.VIDIOC_G_FMT:
if ioc == raw.IOC.G_FMT:
arg.fmt.pix.width = 640
arg.fmt.pix.height = 480
arg.fmt.pix.pixelformat = raw.V4L2_PIX_FMT_RGB24
arg.fmt.pix.pixelformat = raw.PixelFormat.RGB24
elif isinstance(arg, raw.v4l2_buffer):
if ioc == raw.VIDIOC_QUERYBUF:
if ioc == raw.IOC.QUERYBUF:
pass
elif ioc == raw.VIDIOC_DQBUF:
elif ioc == raw.IOC.DQBUF:
arg.index = 0
arg.bytesused = len(self.frame)
arg.sequence = 123
arg.timestamp.secs = 123
arg.timestamp.usecs = 456789
elif ioc == raw.VIDIOC_STREAMON:
assert arg.value == raw.V4L2_BUF_TYPE_VIDEO_CAPTURE
elif ioc == raw.IOC.STREAMON:
assert arg.value == raw.BufType.VIDEO_CAPTURE
self.video_capture_state = "ON"
elif ioc == raw.VIDIOC_STREAMOFF:
assert arg.value == raw.V4L2_BUF_TYPE_VIDEO_CAPTURE
elif ioc == raw.IOC.STREAMOFF:
assert arg.value == raw.BufType.VIDEO_CAPTURE
self.video_capture_state = "OFF"
return 0

def mmap(self, fd, length, offset):
assert self.fd == fd
return MemoryMap(self)

def select(self, readers, writers, other):
def select(self, readers, writers, other, timeout=None):
assert readers[0].fileno() == self.fd
return readers, writers, other

Expand Down Expand Up @@ -165,6 +167,18 @@ def assert_frame(frame, camera):
assert numpy.all(frame.array == numpy.frombuffer(camera.frame, dtype="u1"))


@contextmanager
def video_files(paths=("/dev/video99")):
with mock.patch("linuxpy.device.pathlib.Path.glob") as glob:
expected_files = list(paths)
glob.return_value = expected_files
with mock.patch("linuxpy.device.pathlib.Path.is_char_device") as is_char_device:
is_char_device.return_value = True
with mock.patch("linuxpy.device.os.access") as access:
access.return_value = os.R_OK | os.W_OK
yield paths


@test("device number")
def _(
filename=each("/dev/video0", "/dev/video1", "/dev/video999"),
Expand All @@ -175,20 +189,15 @@ def _(

@test("video files")
def _():
with mock.patch("v4l2py.device.pathlib.Path.glob") as glob:
expected_files = ["/dev/video0", "/dev/video55"]
glob.return_value = expected_files

with video_files(["/dev/video0", "/dev/video55"]) as expected_files:
assert list(iter_video_files()) == expected_files


@test("device list")
def _():
assert isgenerator(iter_devices())

with mock.patch("v4l2py.device.pathlib.Path.glob") as glob:
expected_files = ["/dev/video0", "/dev/video55"]
glob.return_value = expected_files
with video_files(["/dev/video0", "/dev/video55"]) as expected_files:
devices = list(iter_devices())
assert len(devices) == 2
for device in devices:
Expand Down
8 changes: 7 additions & 1 deletion v4l2py/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

# ruff: noqa: F401

import warnings

from .device import (
Device,
Frame,
Expand All @@ -19,4 +21,8 @@
)
from .io import IO, GeventIO

__version__ = "2.3.0"
__version__ = "3.0.0"

warnings.warn(
"v4l2py is no longer being maintained. Please consider using linuxpy.video instead"
)
Loading

0 comments on commit a75fce2

Please sign in to comment.