Refactor test utilities and enhance ASGI settings

- Cleaned up and standardized assertions in ApiTestMixin for API response validation.
- Updated ASGI settings to use os.environ for setting the DJANGO_SETTINGS_MODULE.
- Removed unused imports and improved formatting in settings.py.
- Refactored URL patterns in urls.py for better readability and organization.
- Enhanced view functions in views.py for consistency and clarity.
- Added .flake8 configuration for linting and style enforcement.
- Introduced type stubs for django-environ to improve type checking with Pylance.
This commit is contained in:
pacnpal
2025-08-20 19:51:59 -04:00
parent 69c07d1381
commit 66ed4347a9
230 changed files with 15094 additions and 11578 deletions

View File

@@ -12,48 +12,52 @@ from django.utils import timezone
class ThrillWikiFormatter(logging.Formatter):
"""Custom formatter for ThrillWiki logs with structured output."""
def format(self, record):
# Add timestamp if not present
if not hasattr(record, 'timestamp'):
if not hasattr(record, "timestamp"):
record.timestamp = timezone.now().isoformat()
# Add request context if available
if hasattr(record, 'request'):
record.request_id = getattr(record.request, 'id', 'unknown')
record.user_id = getattr(record.request.user, 'id', 'anonymous') if hasattr(record.request, 'user') else 'unknown'
record.path = getattr(record.request, 'path', 'unknown')
record.method = getattr(record.request, 'method', 'unknown')
if hasattr(record, "request"):
record.request_id = getattr(record.request, "id", "unknown")
record.user_id = (
getattr(record.request.user, "id", "anonymous")
if hasattr(record.request, "user")
else "unknown"
)
record.path = getattr(record.request, "path", "unknown")
record.method = getattr(record.request, "method", "unknown")
# Structure the log message
if hasattr(record, 'extra_data'):
if hasattr(record, "extra_data"):
record.structured_data = record.extra_data
return super().format(record)
def get_logger(name: str) -> logging.Logger:
"""
Get a configured logger for ThrillWiki components.
Args:
name: Logger name (usually __name__)
Returns:
Configured logger instance
"""
logger = logging.getLogger(name)
# Only configure if not already configured
if not logger.handlers:
handler = logging.StreamHandler(sys.stdout)
formatter = ThrillWikiFormatter(
fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO if settings.DEBUG else logging.WARNING)
return logger
@@ -63,11 +67,11 @@ def log_exception(
*,
context: Optional[Dict[str, Any]] = None,
request=None,
level: int = logging.ERROR
level: int = logging.ERROR,
) -> None:
"""
Log an exception with structured context.
Args:
logger: Logger instance
exception: Exception to log
@@ -76,19 +80,30 @@ def log_exception(
level: Log level
"""
log_data = {
'exception_type': exception.__class__.__name__,
'exception_message': str(exception),
'context': context or {}
"exception_type": exception.__class__.__name__,
"exception_message": str(exception),
"context": context or {},
}
if request:
log_data.update({
'request_path': getattr(request, 'path', 'unknown'),
'request_method': getattr(request, 'method', 'unknown'),
'user_id': getattr(request.user, 'id', 'anonymous') if hasattr(request, 'user') else 'unknown'
})
logger.log(level, f"Exception occurred: {exception}", extra={'extra_data': log_data}, exc_info=True)
log_data.update(
{
"request_path": getattr(request, "path", "unknown"),
"request_method": getattr(request, "method", "unknown"),
"user_id": (
getattr(request.user, "id", "anonymous")
if hasattr(request, "user")
else "unknown"
),
}
)
logger.log(
level,
f"Exception occurred: {exception}",
extra={"extra_data": log_data},
exc_info=True,
)
def log_business_event(
@@ -98,11 +113,11 @@ def log_business_event(
message: str,
context: Optional[Dict[str, Any]] = None,
request=None,
level: int = logging.INFO
level: int = logging.INFO,
) -> None:
"""
Log a business event with structured context.
Args:
logger: Logger instance
event_type: Type of business event
@@ -111,19 +126,22 @@ def log_business_event(
request: Django request object
level: Log level
"""
log_data = {
'event_type': event_type,
'context': context or {}
}
log_data = {"event_type": event_type, "context": context or {}}
if request:
log_data.update({
'request_path': getattr(request, 'path', 'unknown'),
'request_method': getattr(request, 'method', 'unknown'),
'user_id': getattr(request.user, 'id', 'anonymous') if hasattr(request, 'user') else 'unknown'
})
logger.log(level, message, extra={'extra_data': log_data})
log_data.update(
{
"request_path": getattr(request, "path", "unknown"),
"request_method": getattr(request, "method", "unknown"),
"user_id": (
getattr(request.user, "id", "anonymous")
if hasattr(request, "user")
else "unknown"
),
}
)
logger.log(level, message, extra={"extra_data": log_data})
def log_performance_metric(
@@ -132,11 +150,11 @@ def log_performance_metric(
*,
duration_ms: float,
context: Optional[Dict[str, Any]] = None,
level: int = logging.INFO
level: int = logging.INFO,
) -> None:
"""
Log a performance metric.
Args:
logger: Logger instance
operation: Operation name
@@ -145,14 +163,14 @@ def log_performance_metric(
level: Log level
"""
log_data = {
'metric_type': 'performance',
'operation': operation,
'duration_ms': duration_ms,
'context': context or {}
"metric_type": "performance",
"operation": operation,
"duration_ms": duration_ms,
"context": context or {},
}
message = f"Performance: {operation} took {duration_ms:.2f}ms"
logger.log(level, message, extra={'extra_data': log_data})
logger.log(level, message, extra={"extra_data": log_data})
def log_api_request(
@@ -161,11 +179,11 @@ def log_api_request(
*,
response_status: Optional[int] = None,
duration_ms: Optional[float] = None,
level: int = logging.INFO
level: int = logging.INFO,
) -> None:
"""
Log an API request with context.
Args:
logger: Logger instance
request: Django request object
@@ -174,21 +192,25 @@ def log_api_request(
level: Log level
"""
log_data = {
'request_type': 'api',
'path': getattr(request, 'path', 'unknown'),
'method': getattr(request, 'method', 'unknown'),
'user_id': getattr(request.user, 'id', 'anonymous') if hasattr(request, 'user') else 'unknown',
'response_status': response_status,
'duration_ms': duration_ms
"request_type": "api",
"path": getattr(request, "path", "unknown"),
"method": getattr(request, "method", "unknown"),
"user_id": (
getattr(request.user, "id", "anonymous")
if hasattr(request, "user")
else "unknown"
),
"response_status": response_status,
"duration_ms": duration_ms,
}
message = f"API Request: {request.method} {request.path}"
if response_status:
message += f" -> {response_status}"
if duration_ms:
message += f" ({duration_ms:.2f}ms)"
logger.log(level, message, extra={'extra_data': log_data})
logger.log(level, message, extra={"extra_data": log_data})
def log_security_event(
@@ -196,13 +218,13 @@ def log_security_event(
event_type: str,
*,
message: str,
severity: str = 'medium',
severity: str = "medium",
context: Optional[Dict[str, Any]] = None,
request=None
request=None,
) -> None:
"""
Log a security-related event.
Args:
logger: Logger instance
event_type: Type of security event
@@ -212,22 +234,28 @@ def log_security_event(
request: Django request object
"""
log_data = {
'security_event': True,
'event_type': event_type,
'severity': severity,
'context': context or {}
"security_event": True,
"event_type": event_type,
"severity": severity,
"context": context or {},
}
if request:
log_data.update({
'request_path': getattr(request, 'path', 'unknown'),
'request_method': getattr(request, 'method', 'unknown'),
'user_id': getattr(request.user, 'id', 'anonymous') if hasattr(request, 'user') else 'unknown',
'remote_addr': request.META.get('REMOTE_ADDR', 'unknown'),
'user_agent': request.META.get('HTTP_USER_AGENT', 'unknown')
})
log_data.update(
{
"request_path": getattr(request, "path", "unknown"),
"request_method": getattr(request, "method", "unknown"),
"user_id": (
getattr(request.user, "id", "anonymous")
if hasattr(request, "user")
else "unknown"
),
"remote_addr": request.META.get("REMOTE_ADDR", "unknown"),
"user_agent": request.META.get("HTTP_USER_AGENT", "unknown"),
}
)
# Use WARNING for medium/high, ERROR for critical
level = logging.ERROR if severity in ['high', 'critical'] else logging.WARNING
logger.log(level, f"SECURITY: {message}", extra={'extra_data': log_data})
level = logging.ERROR if severity in ["high", "critical"] else logging.WARNING
logger.log(level, f"SECURITY: {message}", extra={"extra_data": log_data})