pylint fixes for the camera plugin.

This commit is contained in:
Fabio Manganiello 2023-06-16 15:40:05 +02:00
parent 9aa8e4538a
commit 2f4229d7b1
Signed by: blacklight
GPG Key ID: D90FBA7F76362774
2 changed files with 37 additions and 61 deletions

View File

@ -7,6 +7,7 @@ import time
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from contextlib import contextmanager from contextlib import contextmanager
from dataclasses import asdict
from datetime import datetime from datetime import datetime
from multiprocessing import Process from multiprocessing import Process
from queue import Queue from queue import Queue
@ -152,21 +153,21 @@ class CameraPlugin(Plugin, ABC):
""" """
super().__init__(**kwargs) super().__init__(**kwargs)
self.workdir = os.path.join( workdir = Config.get('workdir')
Config.get('workdir'), get_plugin_name_by_class(self) plugin_name = get_plugin_name_by_class(self)
) assert isinstance(workdir, str) and plugin_name
self.workdir = os.path.join(workdir, plugin_name)
pathlib.Path(self.workdir).mkdir(mode=0o755, exist_ok=True, parents=True) pathlib.Path(self.workdir).mkdir(mode=0o755, exist_ok=True, parents=True)
# noinspection PyArgumentList
self.camera_info = self._camera_info_class( self.camera_info = self._camera_info_class(
device, device,
color_transform=color_transform, color_transform=color_transform,
warmup_frames=warmup_frames, warmup_frames=warmup_frames,
warmup_seconds=warmup_seconds, warmup_seconds=warmup_seconds or 0,
rotate=rotate, rotate=rotate,
scale_x=scale_x, scale_x=scale_x,
scale_y=scale_y, scale_y=scale_y,
capture_timeout=capture_timeout, capture_timeout=capture_timeout or 20,
fps=fps, fps=fps,
input_format=input_format, input_format=input_format,
output_format=output_format, output_format=output_format,
@ -227,13 +228,12 @@ class CameraPlugin(Plugin, ABC):
camera.start_event.clear() camera.start_event.clear()
camera.capture_thread = None camera.capture_thread = None
else: else:
# noinspection PyArgumentList
camera = self._camera_class(info=info) camera = self._camera_class(info=info)
camera.info.set(**params) camera.info.set(**params)
camera.object = self.prepare_device(camera) camera.object = self.prepare_device(camera)
if stream: if stream and camera.info.stream_format:
writer_class = StreamWriter.get_class_by_name(camera.info.stream_format) writer_class = StreamWriter.get_class_by_name(camera.info.stream_format)
camera.stream = writer_class( camera.stream = writer_class(
camera=camera, plugin=self, redis_queue=redis_queue camera=camera, plugin=self, redis_queue=redis_queue
@ -283,7 +283,7 @@ class CameraPlugin(Plugin, ABC):
def open( def open(
self, self,
device: Optional[Union[int, str]] = None, device: Optional[Union[int, str]] = None,
stream: bool = None, stream: bool = False,
redis_queue: Optional[str] = None, redis_queue: Optional[str] = None,
**info, **info,
) -> Generator[Camera, None, None]: ) -> Generator[Camera, None, None]:
@ -304,7 +304,8 @@ class CameraPlugin(Plugin, ABC):
) )
yield camera yield camera
finally: finally:
self.close_device(camera) if camera:
self.close_device(camera)
@abstractmethod @abstractmethod
def prepare_device(self, device: Camera): def prepare_device(self, device: Camera):
@ -333,7 +334,6 @@ class CameraPlugin(Plugin, ABC):
""" """
raise NotImplementedError() raise NotImplementedError()
# noinspection PyShadowingBuiltins
@staticmethod @staticmethod
def store_frame(frame, filepath: str, format: Optional[str] = None): def store_frame(frame, filepath: str, format: Optional[str] = None):
""" """
@ -347,7 +347,7 @@ class CameraPlugin(Plugin, ABC):
if isinstance(frame, bytes): if isinstance(frame, bytes):
frame = list(frame) frame = list(frame)
elif not isinstance(frame, Image.Image): if not isinstance(frame, Image.Image):
frame = Image.fromarray(frame) frame = Image.fromarray(frame)
save_args = {} save_args = {}
@ -571,7 +571,7 @@ class CameraPlugin(Plugin, ABC):
video_file: Optional[str] = None, video_file: Optional[str] = None,
preview: bool = False, preview: bool = False,
**camera, **camera,
) -> Union[str, dict]: ) -> Optional[Union[str, dict]]:
""" """
Capture a video. Capture a video.
@ -596,7 +596,7 @@ class CameraPlugin(Plugin, ABC):
self.wait_capture(camera) self.wait_capture(camera)
return video_file return video_file
return self.status(camera.info.device) return self.status(camera.info.device).output
@action @action
def stop_capture(self, device: Optional[Union[int, str]] = None): def stop_capture(self, device: Optional[Union[int, str]] = None):
@ -606,12 +606,12 @@ class CameraPlugin(Plugin, ABC):
:param device: Name/path/ID of the device to stop (default: all the active devices). :param device: Name/path/ID of the device to stop (default: all the active devices).
""" """
devices = self._devices.copy() devices = self._devices.copy()
stop_devices = list(devices.values())[:] stop_devices = list(devices.values())
if device: if device:
stop_devices = [self._devices[device]] if device in self._devices else [] stop_devices = [self._devices[device]] if device in self._devices else []
for device in stop_devices: for dev in stop_devices:
self.close_device(device) self.close_device(dev)
@action @action
def capture_image(self, image_file: str, preview: bool = False, **camera) -> str: def capture_image(self, image_file: str, preview: bool = False, **camera) -> str:
@ -635,9 +635,8 @@ class CameraPlugin(Plugin, ABC):
return image_file return image_file
# noinspection PyUnusedLocal
@action @action
def take_picture(self, image_file: str, preview: bool = False, **camera) -> str: def take_picture(self, image_file: str, **camera) -> str:
""" """
Alias for :meth:`.capture_image`. Alias for :meth:`.capture_image`.
@ -646,7 +645,7 @@ class CameraPlugin(Plugin, ABC):
:param preview: Show a preview of the camera frames. :param preview: Show a preview of the camera frames.
:return: The local path to the saved image. :return: The local path to the saved image.
""" """
return self.capture_image(image_file, **camera) return str(self.capture_image(image_file, **camera).output)
@action @action
def capture_sequence( def capture_sequence(
@ -655,7 +654,7 @@ class CameraPlugin(Plugin, ABC):
n_frames: Optional[int] = None, n_frames: Optional[int] = None,
preview: bool = False, preview: bool = False,
**camera, **camera,
) -> str: ) -> Optional[str]:
""" """
Capture a sequence of frames from a camera and store them to a directory. Capture a sequence of frames from a camera and store them to a directory.
@ -687,7 +686,7 @@ class CameraPlugin(Plugin, ABC):
""" """
camera = self.open_device(frames_dir=None, **camera) camera = self.open_device(frames_dir=None, **camera)
self.start_camera(camera, duration=duration, n_frames=n_frames, preview=True) self.start_camera(camera, duration=duration, n_frames=n_frames, preview=True)
return self.status(camera.info.device) return self.status(camera.info.device) # type: ignore
@staticmethod @staticmethod
def _prepare_server_socket(camera: Camera) -> socket.socket: def _prepare_server_socket(camera: Camera) -> socket.socket:
@ -729,10 +728,11 @@ class CameraPlugin(Plugin, ABC):
continue continue
if camera.info.device not in self._devices: if camera.info.device not in self._devices:
info = camera.info.to_dict() info = asdict(camera.info)
info['stream_format'] = stream_format info['stream_format'] = stream_format
camera = self.open_device(stream=True, **info) camera = self.open_device(stream=True, **info)
assert camera.stream, 'No camera stream available'
camera.stream.sock = sock camera.stream.sock = sock
self.start_camera( self.start_camera(
camera, duration=duration, frames_dir=None, image_file=None camera, duration=duration, frames_dir=None, image_file=None
@ -741,7 +741,9 @@ class CameraPlugin(Plugin, ABC):
self._cleanup_stream(camera, server_socket, sock) self._cleanup_stream(camera, server_socket, sock)
self.logger.info('Stopped camera stream') self.logger.info('Stopped camera stream')
def _cleanup_stream(self, camera: Camera, server_socket: socket.socket, client: IO): def _cleanup_stream(
self, camera: Camera, server_socket: socket.socket, client: Optional[IO]
):
if client: if client:
try: try:
client.close() client.close()
@ -772,7 +774,7 @@ class CameraPlugin(Plugin, ABC):
:return: The status of the device. :return: The status of the device.
""" """
camera = self.open_device(stream=True, stream_format=stream_format, **camera) camera = self.open_device(stream=True, stream_format=stream_format, **camera)
return self._start_streaming(camera, duration, stream_format) return self._start_streaming(camera, duration, stream_format) # type: ignore
def _start_streaming( def _start_streaming(
self, camera: Camera, duration: Optional[float], stream_format: str self, camera: Camera, duration: Optional[float], stream_format: str
@ -781,6 +783,7 @@ class CameraPlugin(Plugin, ABC):
assert ( assert (
not camera.stream_event.is_set() and camera.info.device not in self._streams not camera.stream_event.is_set() and camera.info.device not in self._streams
), f'A streaming session is already running for device {camera.info.device}' ), f'A streaming session is already running for device {camera.info.device}'
assert camera.info.device, 'No device name available'
self._streams[camera.info.device] = camera self._streams[camera.info.device] = camera
camera.stream_event.set() camera.stream_event.set()
@ -804,12 +807,12 @@ class CameraPlugin(Plugin, ABC):
:param device: Name/path/ID of the device to stop (default: all the active devices). :param device: Name/path/ID of the device to stop (default: all the active devices).
""" """
streams = self._streams.copy() streams = self._streams.copy()
stop_devices = list(streams.values())[:] stop_devices = list(streams.values())
if device: if device:
stop_devices = [self._streams[device]] if device in self._streams else [] stop_devices = [self._streams[device]] if device in self._streams else []
for device in stop_devices: for dev in stop_devices:
self._stop_streaming(device) self._stop_streaming(dev)
def _stop_streaming(self, camera: Camera): def _stop_streaming(self, camera: Camera):
camera.stream_event.clear() camera.stream_event.clear()
@ -825,7 +828,7 @@ class CameraPlugin(Plugin, ABC):
return {} return {}
return { return {
**camera.info.to_dict(), **asdict(camera.info),
'active': bool(camera.capture_thread and camera.capture_thread.is_alive()), 'active': bool(camera.capture_thread and camera.capture_thread.is_alive()),
'capturing': bool( 'capturing': bool(
camera.capture_thread camera.capture_thread

View File

@ -1,6 +1,6 @@
import math import math
import threading import threading
from dataclasses import dataclass from dataclasses import asdict, dataclass
from typing import Optional, Union, Tuple, Set from typing import Optional, Union, Tuple, Set
import numpy as np import numpy as np
@ -17,8 +17,8 @@ from platypush.plugins.camera.model.writer.preview import PreviewWriter
class CameraInfo: class CameraInfo:
device: Optional[Union[int, str]] device: Optional[Union[int, str]]
bind_address: Optional[str] = None bind_address: Optional[str] = None
capture_timeout: float = 20.0 capture_timeout: float = 0
color_transform: Optional[str] = None color_transform: Optional[Union[int, str]] = None
ffmpeg_bin: Optional[str] = None ffmpeg_bin: Optional[str] = None
fps: Optional[float] = None fps: Optional[float] = None
frames_dir: Optional[str] = None frames_dir: Optional[str] = None
@ -36,42 +36,15 @@ class CameraInfo:
stream_format: Optional[str] = None stream_format: Optional[str] = None
vertical_flip: bool = False vertical_flip: bool = False
warmup_frames: int = 0 warmup_frames: int = 0
warmup_seconds: float = 0.0 warmup_seconds: float = 0
def set(self, **kwargs): def set(self, **kwargs):
for k, v in kwargs.items(): for k, v in kwargs.items():
if hasattr(self, k): if hasattr(self, k):
setattr(self, k, v) setattr(self, k, v)
def to_dict(self) -> dict:
return {
'bind_address': self.bind_address,
'capture_timeout': self.capture_timeout,
'color_transform': self.color_transform,
'device': self.device,
'ffmpeg_bin': self.ffmpeg_bin,
'fps': self.fps,
'frames_dir': self.frames_dir,
'grayscale': self.grayscale,
'horizontal_flip': self.horizontal_flip,
'input_codec': self.input_codec,
'input_format': self.input_format,
'listen_port': self.listen_port,
'output_codec': self.output_codec,
'output_format': self.output_format,
'resolution': list(self.resolution or ()),
'rotate': self.rotate,
'scale_x': self.scale_x,
'scale_y': self.scale_y,
'stream_format': self.stream_format,
'vertical_flip': self.vertical_flip,
'warmup_frames': self.warmup_frames,
'warmup_seconds': self.warmup_seconds,
}
def clone(self): def clone(self):
# noinspection PyArgumentList return self.__class__(**asdict(self))
return self.__class__(**self.to_dict())
@dataclass @dataclass