mtg_python_deckbuilder/code/web/services/interfaces.py

318 lines
7.7 KiB
Python

"""Service interfaces using Protocol for structural typing.
Defines contracts for different types of services without requiring inheritance.
Use these for type hints and dependency injection.
"""
from __future__ import annotations
from typing import Protocol, Any, Dict, List, Optional, TypeVar, runtime_checkable
import pandas as pd
T = TypeVar("T")
K = TypeVar("K")
V = TypeVar("V")
@runtime_checkable
class SessionService(Protocol):
"""Interface for session management services."""
def new_session_id(self) -> str:
"""Create a new session ID.
Returns:
Unique session identifier
"""
...
def get_session(self, session_id: Optional[str]) -> Dict[str, Any]:
"""Get or create session state.
Args:
session_id: Session identifier (creates new if None)
Returns:
Session state dictionary
"""
...
def set_value(self, session_id: str, key: str, value: Any) -> None:
"""Set a value in session state.
Args:
session_id: Session identifier
key: State key
value: Value to store
"""
...
def get_value(self, session_id: str, key: str, default: Any = None) -> Any:
"""Get a value from session state.
Args:
session_id: Session identifier
key: State key
default: Default value if key not found
Returns:
Stored value or default
"""
...
def cleanup_expired(self) -> int:
"""Clean up expired sessions.
Returns:
Number of sessions cleaned up
"""
...
@runtime_checkable
class CardLoaderService(Protocol):
"""Interface for card data loading services."""
def get_cards(self, force_reload: bool = False) -> pd.DataFrame:
"""Get card data.
Args:
force_reload: Force reload from source
Returns:
DataFrame with card data
"""
...
def is_loaded(self) -> bool:
"""Check if card data is loaded.
Returns:
True if data is loaded
"""
...
@runtime_checkable
class CatalogService(Protocol):
"""Interface for catalog services (commanders, themes, etc.)."""
def get_catalog(self, force_reload: bool = False) -> pd.DataFrame:
"""Get catalog data.
Args:
force_reload: Force reload from source
Returns:
DataFrame with catalog data
"""
...
def search(self, query: str, **filters: Any) -> pd.DataFrame:
"""Search catalog with filters.
Args:
query: Search query string
**filters: Additional filters
Returns:
Filtered DataFrame
"""
...
@runtime_checkable
class OwnedCardsService(Protocol):
"""Interface for owned cards management."""
def get_owned_names(self) -> List[str]:
"""Get list of owned card names.
Returns:
List of card names
"""
...
def add_owned_names(self, names: List[str]) -> None:
"""Add card names to owned list.
Args:
names: Card names to add
"""
...
def remove_owned_name(self, name: str) -> bool:
"""Remove a card name from owned list.
Args:
name: Card name to remove
Returns:
True if removed, False if not found
"""
...
def clear_owned(self) -> None:
"""Clear all owned cards."""
...
def import_from_file(self, file_content: str, format_type: str) -> int:
"""Import owned cards from file content.
Args:
file_content: File content to parse
format_type: Format type (csv, txt, etc.)
Returns:
Number of cards imported
"""
...
@runtime_checkable
class CacheService(Protocol[K, V]):
"""Interface for caching services."""
def get(self, key: K, default: Optional[V] = None) -> Optional[V]:
"""Get cached value.
Args:
key: Cache key
default: Default value if not found
Returns:
Cached value or default
"""
...
def set(self, key: K, value: V, ttl: Optional[int] = None) -> None:
"""Set cached value.
Args:
key: Cache key
value: Value to cache
ttl: Time-to-live in seconds (None = no expiration)
"""
...
def invalidate(self, key: Optional[K] = None) -> None:
"""Invalidate cache entry or entire cache.
Args:
key: Cache key (None = invalidate all)
"""
...
def cleanup_expired(self) -> int:
"""Remove expired cache entries.
Returns:
Number of entries removed
"""
...
@runtime_checkable
class BuildOrchestratorService(Protocol):
"""Interface for deck build orchestration."""
def orchestrate_build(
self,
session_id: str,
commander_name: str,
theme_tags: List[str],
**options: Any
) -> Dict[str, Any]:
"""Orchestrate a deck build.
Args:
session_id: Session identifier
commander_name: Commander card name
theme_tags: List of theme tags
**options: Additional build options
Returns:
Build result dictionary
"""
...
def get_build_status(self, session_id: str) -> Dict[str, Any]:
"""Get build status for a session.
Args:
session_id: Session identifier
Returns:
Build status dictionary
"""
...
@runtime_checkable
class ValidationService(Protocol):
"""Interface for validation services."""
def validate_commander(self, name: str) -> tuple[bool, Optional[str]]:
"""Validate commander name.
Args:
name: Card name
Returns:
(is_valid, error_message) tuple
"""
...
def validate_themes(self, themes: List[str]) -> tuple[bool, List[str]]:
"""Validate theme tags.
Args:
themes: List of theme tags
Returns:
(is_valid, invalid_themes) tuple
"""
...
def normalize_card_name(self, name: str) -> str:
"""Normalize card name for lookups.
Args:
name: Raw card name
Returns:
Normalized card name
"""
...
@runtime_checkable
class TelemetryService(Protocol):
"""Interface for telemetry/metrics services."""
def record_event(self, event_type: str, properties: Optional[Dict[str, Any]] = None) -> None:
"""Record a telemetry event.
Args:
event_type: Type of event
properties: Event properties
"""
...
def record_timing(self, operation: str, duration_ms: float) -> None:
"""Record operation timing.
Args:
operation: Operation name
duration_ms: Duration in milliseconds
"""
...
def increment_counter(self, counter_name: str, value: int = 1) -> None:
"""Increment a counter.
Args:
counter_name: Counter name
value: Increment value
"""
...