Dieser Commit ist enthalten in:
Claude Project Manager
2025-08-01 23:50:28 +02:00
Commit 04585e95b6
290 geänderte Dateien mit 64086 neuen und 0 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,229 @@
"""
Operation Result Value Object - Standardisierte Ergebnisstruktur
Backward-compatible Wrapper für konsistente Fehlerbehandlung
"""
from dataclasses import dataclass
from typing import Optional, Any, Dict, Union
from datetime import datetime
import traceback
@dataclass
class OperationResult:
"""
Standardisierte Ergebnisstruktur für alle Operationen.
Kompatibel mit bestehenden boolean und dict returns.
"""
success: bool
data: Optional[Any] = None
error_message: Optional[str] = None
error_code: Optional[str] = None
metadata: Optional[Dict[str, Any]] = None
timestamp: Optional[datetime] = None
legacy_result: Optional[Any] = None # Für backward compatibility
def __post_init__(self):
if self.timestamp is None:
self.timestamp = datetime.now()
@classmethod
def success_result(cls, data: Any = None, metadata: Dict[str, Any] = None, legacy_result: Any = None):
"""Erstellt ein Erfolgsergebnis"""
return cls(
success=True,
data=data,
metadata=metadata or {},
legacy_result=legacy_result if legacy_result is not None else data
)
@classmethod
def error_result(cls, message: str, code: str = None,
metadata: Dict[str, Any] = None, legacy_result: Any = None):
"""Erstellt ein Fehlerergebnis"""
return cls(
success=False,
error_message=message,
error_code=code,
metadata=metadata or {},
legacy_result=legacy_result if legacy_result is not None else False
)
@classmethod
def from_exception(cls, exception: Exception, code: str = None,
metadata: Dict[str, Any] = None):
"""Erstellt Fehlerergebnis aus Exception"""
metadata = metadata or {}
metadata.update({
'exception_type': type(exception).__name__,
'traceback': traceback.format_exc()
})
return cls(
success=False,
error_message=str(exception),
error_code=code or type(exception).__name__,
metadata=metadata,
legacy_result=False
)
@classmethod
def from_legacy_boolean(cls, result: bool, success_data: Any = None, error_message: str = None):
"""Konvertiert legacy boolean zu OperationResult"""
if result:
return cls.success_result(data=success_data, legacy_result=result)
else:
return cls.error_result(
message=error_message or "Operation failed",
legacy_result=result
)
@classmethod
def from_legacy_dict(cls, result: Dict[str, Any]):
"""Konvertiert legacy dict zu OperationResult"""
success = result.get('success', False)
if success:
return cls.success_result(
data=result.get('data'),
metadata=result.get('metadata', {}),
legacy_result=result
)
else:
return cls.error_result(
message=result.get('error', 'Operation failed'),
code=result.get('error_code'),
metadata=result.get('metadata', {}),
legacy_result=result
)
def is_success(self) -> bool:
"""Prüft ob Operation erfolgreich war"""
return self.success
def is_error(self) -> bool:
"""Prüft ob Operation fehlgeschlagen ist"""
return not self.success
def get_legacy_result(self) -> Any:
"""Gibt das ursprüngliche Result-Format zurück für backward compatibility"""
return self.legacy_result
def to_dict(self) -> Dict[str, Any]:
"""Konvertiert zu Dictionary für API/JSON Serialisierung"""
result = {
'success': self.success,
'timestamp': self.timestamp.isoformat() if self.timestamp else None
}
if self.data is not None:
result['data'] = self.data
if self.error_message:
result['error'] = self.error_message
if self.error_code:
result['error_code'] = self.error_code
if self.metadata:
result['metadata'] = self.metadata
return result
def to_legacy_dict(self) -> Dict[str, Any]:
"""Konvertiert zu legacy dict format"""
return {
'success': self.success,
'data': self.data,
'error': self.error_message,
'error_code': self.error_code,
'metadata': self.metadata
}
def __bool__(self) -> bool:
"""Ermöglicht if result: syntax"""
return self.success
def __str__(self) -> str:
if self.success:
return f"Success: {self.data}"
else:
return f"Error: {self.error_message} ({self.error_code})"
class ResultWrapper:
"""
Utility-Klasse für backward-compatible Wrapping von bestehenden Methoden
"""
@staticmethod
def wrap_boolean_method(method, *args, **kwargs) -> OperationResult:
"""Wrapper für bestehende boolean-Methoden"""
try:
success = method(*args, **kwargs)
return OperationResult.from_legacy_boolean(
result=success,
success_data=success,
error_message="Operation failed" if not success else None
)
except Exception as e:
return OperationResult.from_exception(e)
@staticmethod
def wrap_dict_method(method, *args, **kwargs) -> OperationResult:
"""Wrapper für bestehende dict-Methoden"""
try:
result = method(*args, **kwargs)
if isinstance(result, dict):
return OperationResult.from_legacy_dict(result)
else:
return OperationResult.success_result(data=result, legacy_result=result)
except Exception as e:
return OperationResult.from_exception(e)
@staticmethod
def wrap_any_method(method, *args, **kwargs) -> OperationResult:
"""Universal wrapper für beliebige Methoden"""
try:
result = method(*args, **kwargs)
if isinstance(result, bool):
return OperationResult.from_legacy_boolean(result)
elif isinstance(result, dict) and 'success' in result:
return OperationResult.from_legacy_dict(result)
elif result is None:
return OperationResult.error_result("Method returned None", legacy_result=result)
else:
return OperationResult.success_result(data=result, legacy_result=result)
except Exception as e:
return OperationResult.from_exception(e)
# Error Codes für häufige Fehlertypen
class CommonErrorCodes:
"""Häufig verwendete Fehlercodes"""
# Instagram spezifisch
CAPTCHA_REQUIRED = "CAPTCHA_REQUIRED"
EMAIL_TIMEOUT = "EMAIL_TIMEOUT"
SMS_NOT_IMPLEMENTED = "SMS_NOT_IMPLEMENTED"
USERNAME_TAKEN = "USERNAME_TAKEN"
SELECTOR_NOT_FOUND = "SELECTOR_NOT_FOUND"
BIRTHDAY_SELECTOR_FAILED = "BIRTHDAY_SELECTOR_FAILED"
# Allgemein
PROXY_ERROR = "PROXY_ERROR"
RATE_LIMITED = "RATE_LIMITED"
NETWORK_TIMEOUT = "NETWORK_TIMEOUT"
BROWSER_ERROR = "BROWSER_ERROR"
# Fingerprint spezifisch
FINGERPRINT_GENERATION_FAILED = "FINGERPRINT_GENERATION_FAILED"
FINGERPRINT_RACE_CONDITION = "FINGERPRINT_RACE_CONDITION"
FINGERPRINT_NOT_FOUND = "FINGERPRINT_NOT_FOUND"
# Session spezifisch
SESSION_EXPIRED = "SESSION_EXPIRED"
SESSION_INVALID = "SESSION_INVALID"
SESSION_SAVE_FAILED = "SESSION_SAVE_FAILED"