From 4fc2afc4466e87318e16d20bb5a17a4d1674314b Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Sun, 17 Nov 2024 20:43:55 +0000 Subject: [PATCH] fixed some more imports --- videoarchiver/core/base.py | 106 ++++++++---------- .../core/commands/archiver_commands.py | 12 +- videoarchiver/core/response_handler.py | 82 +++++++------- 3 files changed, 93 insertions(+), 107 deletions(-) diff --git a/videoarchiver/core/base.py b/videoarchiver/core/base.py index 3a20f50..f2ee096 100644 --- a/videoarchiver/core/base.py +++ b/videoarchiver/core/base.py @@ -8,42 +8,42 @@ from typing import Dict, Any, Optional, TypedDict, ClassVar, List, Set, Union from datetime import datetime from pathlib import Path -import discord # type: ignore -from redbot.core.bot import Red # type: ignore -from redbot.core.commands import GroupCog, Context # type: ignore +import discord # type: ignore +from redbot.core.bot import Red # type: ignore +from redbot.core.commands import GroupCog, Context # type: ignore from .settings import Settings from .lifecycle import LifecycleManager, LifecycleState from .component_manager import ComponentManager, ComponentState from .error_handler import error_manager, handle_command_error -from .response_handler import response_manager +from .response_handler import ResponseManager from .commands.archiver_commands import setup_archiver_commands from .commands.database_commands import setup_database_commands from .commands.settings_commands import setup_settings_commands from .events import setup_events, EventManager -from ..processor.core import Processor -from ..queue.manager import QueueManager +from ..processor.core import VideoProcessor +from ..queue.manager import EnhancedVideoQueueManager from ..ffmpeg.ffmpeg_manager import FFmpegManager from ..database.video_archive_db import VideoArchiveDB from ..config_manager import ConfigManager -from ..utils.exceptions import ( - CogError, - ErrorContext, - ErrorSeverity -) +from ..utils.exceptions import CogError, ErrorContext, ErrorSeverity logger = logging.getLogger("VideoArchiver") + class CogHealthCheck(TypedDict): """Type definition for health check status""" + name: str status: bool last_check: str details: Optional[Dict[str, Any]] + class CogStatus(TypedDict): """Type definition for cog status""" + uptime: float last_error: Optional[str] error_count: int @@ -53,6 +53,7 @@ class CogStatus(TypedDict): state: str ready: bool + class StatusTracker: """Tracks cog status and health""" @@ -78,17 +79,14 @@ class StatusTracker: self.last_command_time = datetime.utcnow() def update_health_check( - self, - name: str, - status: bool, - details: Optional[Dict[str, Any]] = None + self, name: str, status: bool, details: Optional[Dict[str, Any]] = None ) -> None: """Update health check status""" self.health_checks[name] = CogHealthCheck( name=name, status=status, last_check=datetime.utcnow().isoformat(), - details=details + details=details, ) def get_status(self) -> CogStatus: @@ -98,10 +96,12 @@ class StatusTracker: last_error=self.last_error, error_count=self.error_count, command_count=self.command_count, - last_command=self.last_command_time.isoformat() if self.last_command_time else None, + last_command=( + self.last_command_time.isoformat() if self.last_command_time else None + ), health_checks=self.health_checks.copy(), state="healthy" if self.is_healthy() else "unhealthy", - ready=True + ready=True, ) def is_healthy(self) -> bool: @@ -110,6 +110,7 @@ class StatusTracker: return False return all(check["status"] for check in self.health_checks.values()) + class ComponentAccessor: """Provides safe access to components""" @@ -119,10 +120,10 @@ class ComponentAccessor: def get_component(self, name: str) -> Optional[Any]: """ Get a component with state validation. - + Args: name: Component name - + Returns: Component instance if ready, None otherwise """ @@ -134,15 +135,16 @@ class ComponentAccessor: def get_component_status(self, name: str) -> Dict[str, Any]: """ Get component status. - + Args: name: Component name - + Returns: Component status dictionary """ return self._component_manager.get_component_status().get(name, {}) + class VideoArchiver(GroupCog, Settings): """Archive videos from Discord channels""" @@ -151,7 +153,7 @@ class VideoArchiver(GroupCog, Settings): super().__init__() self.bot = bot self.ready = asyncio.Event() - + # Initialize managers self.lifecycle_manager = LifecycleManager(self) self.component_manager = ComponentManager(self) @@ -164,7 +166,7 @@ class VideoArchiver(GroupCog, Settings): self._cleanup_task: Optional[asyncio.Task] = None self._queue_task: Optional[asyncio.Task] = None self._health_tasks: Set[asyncio.Task] = set() - + # Initialize component storage self.components: Dict[int, Dict[str, Any]] = {} self.update_checker = None @@ -184,7 +186,7 @@ class VideoArchiver(GroupCog, Settings): async def cog_load(self) -> None: """ Handle cog loading. - + Raises: CogError: If loading fails """ @@ -198,17 +200,14 @@ class VideoArchiver(GroupCog, Settings): raise CogError( error, context=ErrorContext( - "VideoArchiver", - "cog_load", - None, - ErrorSeverity.CRITICAL - ) + "VideoArchiver", "cog_load", None, ErrorSeverity.CRITICAL + ), ) async def cog_unload(self) -> None: """ Handle cog unloading. - + Raises: CogError: If unloading fails """ @@ -226,18 +225,11 @@ class VideoArchiver(GroupCog, Settings): raise CogError( error, context=ErrorContext( - "VideoArchiver", - "cog_unload", - None, - ErrorSeverity.CRITICAL - ) + "VideoArchiver", "cog_unload", None, ErrorSeverity.CRITICAL + ), ) - async def cog_command_error( - self, - ctx: Context, - error: Exception - ) -> None: + async def cog_command_error(self, ctx: Context, error: Exception) -> None: """Handle command errors""" self.status_tracker.record_error(str(error)) await handle_command_error(ctx, error) @@ -249,12 +241,8 @@ class VideoArchiver(GroupCog, Settings): async def _start_health_monitoring(self) -> None: """Start health monitoring tasks""" - self._health_tasks.add( - asyncio.create_task(self._monitor_component_health()) - ) - self._health_tasks.add( - asyncio.create_task(self._monitor_system_health()) - ) + self._health_tasks.add(asyncio.create_task(self._monitor_component_health())) + self._health_tasks.add(asyncio.create_task(self._monitor_system_health())) async def _monitor_component_health(self) -> None: """Monitor component health""" @@ -265,7 +253,7 @@ class VideoArchiver(GroupCog, Settings): self.status_tracker.update_health_check( f"component_{name}", status["state"] == ComponentState.READY.name, - status + status, ) except Exception as e: logger.error(f"Error monitoring component health: {e}", exc_info=True) @@ -281,34 +269,28 @@ class VideoArchiver(GroupCog, Settings): self.status_tracker.update_health_check( "queue_health", queue_status["active"] and not queue_status["stalled"], - queue_status + queue_status, ) # Check processor health if processor := self.processor: processor_status = await processor.get_status() self.status_tracker.update_health_check( - "processor_health", - processor_status["active"], - processor_status + "processor_health", processor_status["active"], processor_status ) # Check database health if db := self.db: db_status = await db.get_status() self.status_tracker.update_health_check( - "database_health", - db_status["connected"], - db_status + "database_health", db_status["connected"], db_status ) # Check event system health if self.event_manager: event_stats = self.event_manager.get_stats() self.status_tracker.update_health_check( - "event_health", - event_stats["health"], - event_stats + "event_health", event_stats["health"], event_stats ) except Exception as e: @@ -334,7 +316,7 @@ class VideoArchiver(GroupCog, Settings): def get_status(self) -> Dict[str, Any]: """ Get comprehensive cog status. - + Returns: Dictionary containing cog status information """ @@ -343,17 +325,17 @@ class VideoArchiver(GroupCog, Settings): "lifecycle": self.lifecycle_manager.get_status(), "components": self.component_manager.get_component_status(), "errors": error_manager.tracker.get_error_stats(), - "events": self.event_manager.get_stats() if self.event_manager else None + "events": self.event_manager.get_stats() if self.event_manager else None, } # Component property accessors @property - def processor(self) -> Optional[Processor]: + def processor(self) -> Optional[VideoProcessor]: """Get the processor component""" return self.component_accessor.get_component("processor") @property - def queue_manager(self) -> Optional[QueueManager]: + def queue_manager(self) -> Optional[EnhancedVideoQueueManager]: """Get the queue manager component""" return self.component_accessor.get_component("queue_manager") diff --git a/videoarchiver/core/commands/archiver_commands.py b/videoarchiver/core/commands/archiver_commands.py index 042f73b..08cc9a1 100644 --- a/videoarchiver/core/commands/archiver_commands.py +++ b/videoarchiver/core/commands/archiver_commands.py @@ -4,13 +4,13 @@ import logging from enum import Enum, auto from typing import Optional, Any, Dict, TypedDict, Callable, Awaitable -import discord # type: ignore -from discord import app_commands # type: ignore -from redbot.core import commands # type: ignore -from redbot.core.commands import Context, hybrid_group, guild_only, admin_or_permissions # type: ignore +import discord # type: ignore +from discord import app_commands # type: ignore +from redbot.core import commands # type: ignore +from redbot.core.commands import Context, hybrid_group, guild_only, admin_or_permissions # type: ignore -from core.response_handler import handle_response, ResponseType -from utils.exceptions import CommandError, ErrorContext, ErrorSeverity +from ...core.response_handler import handle_response, ResponseType +from ...utils.exceptions import CommandError, ErrorContext, ErrorSeverity logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/core/response_handler.py b/videoarchiver/core/response_handler.py index 2276ac5..bbf81f4 100644 --- a/videoarchiver/core/response_handler.py +++ b/videoarchiver/core/response_handler.py @@ -4,15 +4,17 @@ import logging from enum import Enum, auto from typing import Optional, Union, Dict, Any, TypedDict, ClassVar from datetime import datetime -import discord # type: ignore -from redbot.core.commands import Context # type: ignore +import discord # type: ignore +from redbot.core.commands import Context # type: ignore from ..utils.exceptions import ErrorSeverity logger = logging.getLogger("VideoArchiver") + class ResponseType(Enum): """Types of responses""" + NORMAL = auto() SUCCESS = auto() ERROR = auto() @@ -20,17 +22,22 @@ class ResponseType(Enum): INFO = auto() DEBUG = auto() + class ResponseTheme(TypedDict): """Type definition for response theme""" + emoji: str color: discord.Color + class ResponseFormat(TypedDict): """Type definition for formatted response""" + content: str color: discord.Color timestamp: str + class ResponseFormatter: """Formats responses for consistency""" @@ -39,29 +46,27 @@ class ResponseFormatter: ResponseType.ERROR: ResponseTheme(emoji="❌", color=discord.Color.red()), ResponseType.WARNING: ResponseTheme(emoji="⚠️", color=discord.Color.gold()), ResponseType.INFO: ResponseTheme(emoji="ℹ️", color=discord.Color.blue()), - ResponseType.DEBUG: ResponseTheme(emoji="🔧", color=discord.Color.greyple()) + ResponseType.DEBUG: ResponseTheme(emoji="🔧", color=discord.Color.greyple()), } SEVERITY_MAPPING: ClassVar[Dict[ErrorSeverity, ResponseType]] = { ErrorSeverity.LOW: ResponseType.INFO, ErrorSeverity.MEDIUM: ResponseType.WARNING, ErrorSeverity.HIGH: ResponseType.ERROR, - ErrorSeverity.CRITICAL: ResponseType.ERROR + ErrorSeverity.CRITICAL: ResponseType.ERROR, } @classmethod def format_response( - cls, - message: str, - response_type: ResponseType = ResponseType.NORMAL + cls, message: str, response_type: ResponseType = ResponseType.NORMAL ) -> ResponseFormat: """ Format a response message. - + Args: message: Message to format response_type: Type of response - + Returns: Formatted response dictionary """ @@ -69,28 +74,29 @@ class ResponseFormatter: if theme: return ResponseFormat( content=f"{theme['emoji']} {message}", - color=theme['color'], - timestamp=datetime.utcnow().isoformat() + color=theme["color"], + timestamp=datetime.utcnow().isoformat(), ) return ResponseFormat( content=message, color=discord.Color.default(), - timestamp=datetime.utcnow().isoformat() + timestamp=datetime.utcnow().isoformat(), ) @classmethod def get_response_type(cls, severity: ErrorSeverity) -> ResponseType: """ Get response type for error severity. - + Args: severity: Error severity level - + Returns: Appropriate response type """ return cls.SEVERITY_MAPPING.get(severity, ResponseType.ERROR) + class InteractionHandler: """Handles slash command interactions""" @@ -98,45 +104,49 @@ class InteractionHandler: self, interaction: discord.Interaction, content: Optional[str] = None, - embed: Optional[discord.Embed] = None + embed: Optional[discord.Embed] = None, ) -> bool: """ Send initial interaction response. - + Args: interaction: Discord interaction content: Optional message content embed: Optional embed - + Returns: True if response was sent successfully """ try: if not interaction.response.is_done(): if embed: - await interaction.response.send_message(content=content, embed=embed) + await interaction.response.send_message( + content=content, embed=embed + ) else: await interaction.response.send_message(content=content) return True return False except Exception as e: - logger.error(f"Error sending initial interaction response: {e}", exc_info=True) + logger.error( + f"Error sending initial interaction response: {e}", exc_info=True + ) return False async def send_followup( self, interaction: discord.Interaction, content: Optional[str] = None, - embed: Optional[discord.Embed] = None + embed: Optional[discord.Embed] = None, ) -> bool: """ Send interaction followup. - + Args: interaction: Discord interaction content: Optional message content embed: Optional embed - + Returns: True if followup was sent successfully """ @@ -150,6 +160,7 @@ class InteractionHandler: logger.error(f"Error sending interaction followup: {e}", exc_info=True) return False + class ResponseManager: """Manages command responses""" @@ -162,11 +173,11 @@ class ResponseManager: ctx: Context, content: Optional[str] = None, embed: Optional[discord.Embed] = None, - response_type: Union[ResponseType, str, ErrorSeverity] = ResponseType.NORMAL + response_type: Union[ResponseType, str, ErrorSeverity] = ResponseType.NORMAL, ) -> None: """ Send a response to a command. - + Args: ctx: Command context content: Optional message content @@ -191,7 +202,7 @@ class ResponseManager: if not embed: embed = discord.Embed( color=formatted["color"], - timestamp=datetime.fromisoformat(formatted["timestamp"]) + timestamp=datetime.fromisoformat(formatted["timestamp"]), ) # Handle response @@ -209,10 +220,7 @@ class ResponseManager: return hasattr(ctx, "interaction") and ctx.interaction is not None async def _handle_interaction_response( - self, - ctx: Context, - content: Optional[str], - embed: Optional[discord.Embed] + self, ctx: Context, content: Optional[str], embed: Optional[discord.Embed] ) -> None: """Handle interaction response""" try: @@ -236,10 +244,7 @@ class ResponseManager: await self._send_fallback_response(ctx, content, embed) async def _handle_regular_response( - self, - ctx: Context, - content: Optional[str], - embed: Optional[discord.Embed] + self, ctx: Context, content: Optional[str], embed: Optional[discord.Embed] ) -> None: """Handle regular command response""" try: @@ -252,10 +257,7 @@ class ResponseManager: await self._send_fallback_response(ctx, content, embed) async def _send_fallback_response( - self, - ctx: Context, - content: Optional[str], - embed: Optional[discord.Embed] + self, ctx: Context, content: Optional[str], embed: Optional[discord.Embed] ) -> None: """Send fallback response when other methods fail""" try: @@ -266,18 +268,20 @@ class ResponseManager: except Exception as e: logger.error(f"Failed to send fallback response: {e}", exc_info=True) + # Global response manager instance response_manager = ResponseManager() + async def handle_response( ctx: Context, content: Optional[str] = None, embed: Optional[discord.Embed] = None, - response_type: Union[ResponseType, str, ErrorSeverity] = ResponseType.NORMAL + response_type: Union[ResponseType, str, ErrorSeverity] = ResponseType.NORMAL, ) -> None: """ Helper function to handle responses using the response manager. - + Args: ctx: Command context content: Optional message content