Skip to content

Commit

Permalink
Fix status inheritance (#125)
Browse files Browse the repository at this point in the history
* save current code state

* added Singleton metaclass, Status converted to singleton

* Move Status to the own namespace

* Remove Status from the inheritance

* Split Mood enum to the own file

* Status renamed to Logger

* Introduce and implement LoggerMixin stub instead of previous Status implementation

* Implementing own logging model

* tests for LoggerMixin

* tests for SelectiveLogger

* Code formatted

* Logger adjusments

* Delete Logger and tests

* Use different formatters for stdout/file logging

* Return previous status logging code

* Comment debug code

* remove default argument

* PEP 8 style

* type hint

* set_position() fixed for negative coordinates

* tests for LoggerMixin

* LoggerMixin renamed to StatusMixin

* Status documentation part removed from documentation
  • Loading branch information
pozitronik authored Oct 14, 2024
1 parent f6fd9cf commit 393ea09
Show file tree
Hide file tree
Showing 23 changed files with 199 additions and 220 deletions.
4 changes: 0 additions & 4 deletions docs/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@
* `--processors`, `--frame-processor`, `--processor`: the frame processor module or modules that you want to apply to your files. See the [Built-in frame processors](../README.md#built-in-frame-processors) documentation for the list of built-in modules and their possibilities.
* `--keep-frames`: keeps processed frames in the temp directory after finishing. Defaults to `false`.

# Status: The status messaging module
* `--logfile`, `--log`: optional path to a logfile where all status messages will be logged (if ignored, no logs will be stored).
* `--enable-emoji`: enable modules emoji prefixes in their message statuses, if supported in the current console.
*
# GUI: GUI module
* `--frames-widget`, `--show-frames-widget`: show processed frames widget. It shows all stages of selected frame processing.
* `--frames-widget-width`, `--fw-width`: processed widget maximum width, -1 to set as 10% of original image size.
Expand Down
7 changes: 4 additions & 3 deletions sinner/BatchProcessingCore.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@
from tqdm import tqdm

from sinner.models.State import State
from sinner.Status import Status, Mood
from sinner.handlers.frame.BaseFrameHandler import BaseFrameHandler
from sinner.handlers.frame.DirectoryHandler import DirectoryHandler
from sinner.handlers.frame.ImageHandler import ImageHandler
from sinner.handlers.frame.VideoHandler import VideoHandler
from sinner.models.NumberedFrame import NumberedFrame
from sinner.models.status.StatusMixin import StatusMixin
from sinner.models.status.Mood import Mood
from sinner.processors.frame.BaseFrameProcessor import BaseFrameProcessor
from sinner.typing import Frame
from sinner.utilities import list_class_descendants, resolve_relative_path, is_image, is_video, get_mem_usage, suggest_max_memory, path_exists, is_dir, normalize_path, suggest_execution_threads, suggest_temp_dir
from sinner.validators.AttributeLoader import Rules
from sinner.validators.AttributeLoader import Rules, AttributeLoader


class BatchProcessingCore(Status):
class BatchProcessingCore(AttributeLoader, StatusMixin):
target_path: str
output_path: str
frame_processor: List[str]
Expand Down
6 changes: 3 additions & 3 deletions sinner/Benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
import torch

from sinner.BatchProcessingCore import BatchProcessingCore
from sinner.Status import Status
from sinner.models.status.StatusMixin import StatusMixin
from sinner.utilities import resolve_relative_path, get_app_dir, suggest_execution_providers, decode_execution_providers, list_class_descendants
from sinner.validators.AttributeLoader import Rules
from sinner.validators.AttributeLoader import Rules, AttributeLoader


class Benchmark(Status):
class Benchmark(AttributeLoader, StatusMixin):
emoji: str = '📏'

source_path: str
Expand Down
10 changes: 10 additions & 0 deletions sinner/Singleton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from typing import Any


class Singleton(type):
_instances: dict[type, Any] = {}

def __call__(cls, *args: Any, **kwargs: Any) -> Any:
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
126 changes: 0 additions & 126 deletions sinner/Status.py

This file was deleted.

5 changes: 2 additions & 3 deletions sinner/gui/GUIForm.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

from sinner.gui.controls.FramePlayer.BaseFramePlayer import ROTATE_90_CLOCKWISE, ROTATE_180, ROTATE_90_COUNTERCLOCKWISE
from sinner.models.Event import Event as SinnerEvent
from sinner.Status import Status
from sinner.gui.GUIModel import GUIModel
from sinner.gui.controls.FramePosition.BaseFramePosition import BaseFramePosition
from sinner.gui.controls.FramePosition.SliderFramePosition import SliderFramePosition
Expand All @@ -21,12 +20,12 @@
from sinner.models.Config import Config
from sinner.models.audio.BaseAudioBackend import BaseAudioBackend
from sinner.utilities import is_int, get_app_dir, get_type_extensions, is_image, is_dir, get_directory_file_list, halt
from sinner.validators.AttributeLoader import Rules
from sinner.validators.AttributeLoader import Rules, AttributeLoader


# GUI View

class GUIForm(Status):
class GUIForm(AttributeLoader):
# class attributes
parameters: Namespace
GUIModel: GUIModel
Expand Down
14 changes: 7 additions & 7 deletions sinner/gui/GUIModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
import time
from argparse import Namespace
from concurrent.futures import ThreadPoolExecutor, Future
from logging import DEBUG
from tkinter import IntVar
from typing import List, Callable, Any

from sinner.BatchProcessingCore import BatchProcessingCore
from sinner.Status import Status, Mood
from sinner.gui.controls.FramePlayer.BaseFramePlayer import BaseFramePlayer
from sinner.gui.controls.FramePlayer.PygameFramePlayer import PygameFramePlayer
from sinner.gui.controls.ProgressBarManager import ProgressBarManager
Expand All @@ -23,17 +21,19 @@
from sinner.models.PerfCounter import PerfCounter
from sinner.models.State import State
from sinner.models.audio.BaseAudioBackend import BaseAudioBackend
from sinner.models.status.StatusMixin import StatusMixin
from sinner.models.status.Mood import Mood
from sinner.processors.frame.BaseFrameProcessor import BaseFrameProcessor
from sinner.processors.frame.FrameExtractor import FrameExtractor
from sinner.typing import FramesList
from sinner.utilities import list_class_descendants, resolve_relative_path, suggest_execution_threads, suggest_temp_dir, seconds_to_hmsms, normalize_path, get_mem_usage
from sinner.validators.AttributeLoader import Rules
from sinner.validators.AttributeLoader import Rules, AttributeLoader

BUFFERING_PROGRESS_NAME = "Buffering"
EXTRACTING_PROGRESS_NAME = "Extracting"


class GUIModel(Status):
class GUIModel(AttributeLoader, StatusMixin):
# configuration variables
frame_processor: List[str]
_source_path: str
Expand Down Expand Up @@ -456,7 +456,7 @@ def process_done(future_: Future[tuple[float, int] | None]) -> None:
if step < 1: # preventing going backwards
step = 1
next_frame += step
self.log(level=DEBUG, msg=f"NEXT: {next_frame}, STEP: {step}, DELTA: {processing_delta}, LAST: {self.TimeLine.last_added_index}, AVG: {self._average_frame_skip.get_average()} ")
# self.status.debug(msg=f"NEXT: {next_frame}, STEP: {step}, DELTA: {processing_delta}, LAST: {self.TimeLine.last_added_index}, AVG: {self._average_frame_skip.get_average()} ")

def _process_frame(self, frame_index: int) -> tuple[float, int] | None:
"""
Expand All @@ -473,7 +473,7 @@ def _process_frame(self, frame_index: int) -> tuple[float, int] | None:
with PerfCounter() as frame_render_time:
for _, processor in self.processors.items():
n_frame.frame = processor.process_frame(n_frame.frame)
self.log(level=DEBUG, msg=f"DONE: {n_frame.index}")
# self.status.debug(msg=f"DONE: {n_frame.index}")
self.TimeLine.add_frame(n_frame)
return frame_render_time.execution_time, n_frame.index

Expand All @@ -489,7 +489,7 @@ def _show_frames(self) -> None:
break
if n_frame is not None:
if n_frame.index != last_shown_frame_index: # check if frame is really changed
self.log(level=DEBUG, msg=f"REQ: {self.TimeLine.last_requested_index}, SHOW: {n_frame.index}, ASYNC: {self.TimeLine.last_requested_index - n_frame.index}")
# self.status.debug(msg=f"REQ: {self.TimeLine.last_requested_index}, SHOW: {n_frame.index}, ASYNC: {self.TimeLine.last_requested_index - n_frame.index}")
self.Player.show_frame(n_frame.frame)
last_shown_frame_index = n_frame.index
if self.TimeLine.last_returned_index is None:
Expand Down
6 changes: 3 additions & 3 deletions sinner/handlers/frame/BaseFrameHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
from argparse import Namespace
from typing import List

from sinner.Status import Status
from sinner.models.NumberedFrame import NumberedFrame
from sinner.validators.AttributeLoader import Rules
from sinner.models.status.StatusMixin import StatusMixin
from sinner.validators.AttributeLoader import Rules, AttributeLoader
from sinner.typing import NumeratedFramePath
from sinner.utilities import load_class, get_file_name, is_file, normalize_path


class BaseFrameHandler(Status, ABC):
class BaseFrameHandler(AttributeLoader, ABC, StatusMixin):
current_frame_index: int = 0

_target_path: str
Expand Down
2 changes: 1 addition & 1 deletion sinner/handlers/frame/CV2VideoHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from cv2 import VideoCapture
from tqdm import tqdm

from sinner.Status import Mood
from sinner.models.status.Mood import Mood
from sinner.handlers.frame.BaseFrameHandler import BaseFrameHandler
from sinner.handlers.frame.EOutOfRange import EOutOfRange
from sinner.helpers.FrameHelper import write_to_image, read_from_image
Expand Down
4 changes: 2 additions & 2 deletions sinner/handlers/frame/FFmpegVideoHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
import cv2
from numpy import uint8, frombuffer

from sinner.Status import Mood
from sinner.handlers.frame.BaseFrameHandler import BaseFrameHandler
from sinner.handlers.frame.EOutOfRange import EOutOfRange
from sinner.models.NumberedFrame import NumberedFrame
from sinner.models.status.Mood import Mood
from sinner.typing import NumeratedFramePath
from sinner.validators.AttributeLoader import Rules

Expand Down Expand Up @@ -93,7 +93,7 @@ def resolution(self) -> tuple[int, int]:
if self._resolution is None:
try:
command = ['ffprobe', '-v', 'error', '-select_streams', 'v:0', '-show_entries', 'stream=width,height', '-of', 'csv=s=x:p=0', self._target_path]
output = subprocess.check_output(command, stderr=subprocess.STDOUT).decode('utf-8').strip() # can be very slow!
output = subprocess.check_output(command, stderr=subprocess.STDOUT).decode().strip() # can be very slow!
if 'N/A' == output:
self._resolution = (0, 0) # non-frame files, still processable
w, h = output.split('x')
Expand Down
2 changes: 1 addition & 1 deletion sinner/handlers/frame/ImageHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from pathlib import Path
from typing import List

from sinner.Status import Mood
from sinner.models.status.Mood import Mood
from sinner.handlers.frame.BaseFrameHandler import BaseFrameHandler
from sinner.handlers.frame.EOutOfRange import EOutOfRange
from sinner.helpers.FrameHelper import read_from_image
Expand Down
7 changes: 4 additions & 3 deletions sinner/models/State.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
from pathlib import Path
from typing import Any, Dict, List

from sinner.Status import Status, Mood
from sinner.helpers.FrameHelper import write_to_image, EmptyFrame
from sinner.models.NumberedFrame import NumberedFrame
from sinner.models.status.StatusMixin import StatusMixin
from sinner.models.status.Mood import Mood
from sinner.utilities import is_absolute_path, format_sequences, path_exists, is_file, normalize_path
from sinner.validators.AttributeLoader import Rules
from sinner.validators.AttributeLoader import Rules, AttributeLoader


class State(Status):
class State(AttributeLoader, StatusMixin):
emoji: str = '👀'
source_path: str | None = None
initial_target_path: str | None = None
Expand Down
5 changes: 3 additions & 2 deletions sinner/models/audio/BaseAudioBackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
from argparse import Namespace
from typing import Any

from sinner.Status import Status
from sinner.models.status.StatusMixin import StatusMixin
from sinner.utilities import normalize_path, load_class, list_class_descendants
from sinner.validators.AttributeLoader import AttributeLoader


class BaseAudioBackend(Status, ABC):
class BaseAudioBackend(AttributeLoader, ABC, StatusMixin):
_media_path: str | None = None

@staticmethod
Expand Down
2 changes: 1 addition & 1 deletion sinner/models/audio/PygameAudioBackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from moviepy.editor import AudioFileClip
import pygame

from sinner.Status import Mood
from sinner.models.status.Mood import Mood
from sinner.models.audio.BaseAudioBackend import BaseAudioBackend
from sinner.utilities import get_file_name, normalize_path

Expand Down
11 changes: 11 additions & 0 deletions sinner/models/status/Mood.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from enum import Enum
from colorama import Fore, Back


class Mood(Enum):
GOOD = (0, f'{Fore.LIGHTWHITE_EX}{Back.BLACK}')
BAD = (1, f'{Fore.BLACK}{Back.RED}')
NEUTRAL = (2, f'{Fore.YELLOW}{Back.BLACK}')

def __str__(self) -> str:
return self.value[1]
Loading

0 comments on commit 393ea09

Please sign in to comment.