style: apply black and isort formatting across entire codebase

- Standardize quote style (single to double quotes)
- Reorder and group imports alphabetically
- Fix line breaks and indentation for consistency
- Apply PEP 8 formatting standards

Also updated Makefile to exclude both venv and .venv from code quality checks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-28 19:30:17 +01:00
parent 13f0094743
commit 21c13ca39b
236 changed files with 8450 additions and 6545 deletions

View File

@@ -6,179 +6,109 @@ This module provides frontend-friendly exceptions with consistent error codes,
messages, and HTTP status mappings.
"""
# Base exceptions
from .base import (
WizamartException,
ValidationException,
AuthenticationException,
AuthorizationException,
ResourceNotFoundException,
ConflictException,
BusinessLogicException,
ExternalServiceException,
RateLimitException,
ServiceUnavailableException,
)
# Authentication exceptions
from .auth import (
InvalidCredentialsException,
TokenExpiredException,
InvalidTokenException,
InsufficientPermissionsException,
UserNotActiveException,
AdminRequiredException,
UserAlreadyExistsException
)
# Admin exceptions
from .admin import (
UserNotFoundException,
UserStatusChangeException,
VendorVerificationException,
AdminOperationException,
CannotModifyAdminException,
CannotModifySelfException,
InvalidAdminActionException,
BulkOperationException,
ConfirmationRequiredException,
)
# Marketplace import job exceptions
from .marketplace_import_job import (
MarketplaceImportException,
ImportJobNotFoundException,
ImportJobNotOwnedException,
InvalidImportDataException,
ImportJobCannotBeCancelledException,
ImportJobCannotBeDeletedException,
MarketplaceConnectionException,
MarketplaceDataParsingException,
ImportRateLimitException,
InvalidMarketplaceException,
ImportJobAlreadyProcessingException,
)
# Marketplace product exceptions
from .marketplace_product import (
MarketplaceProductNotFoundException,
MarketplaceProductAlreadyExistsException,
InvalidMarketplaceProductDataException,
MarketplaceProductValidationException,
InvalidGTINException,
MarketplaceProductCSVImportException,
)
# Inventory exceptions
from .inventory import (
InventoryNotFoundException,
InsufficientInventoryException,
InvalidInventoryOperationException,
InventoryValidationException,
NegativeInventoryException,
InvalidQuantityException,
LocationNotFoundException
)
# Vendor exceptions
from .vendor import (
VendorNotFoundException,
VendorAlreadyExistsException,
VendorNotActiveException,
VendorNotVerifiedException,
UnauthorizedVendorAccessException,
InvalidVendorDataException,
MaxVendorsReachedException,
VendorValidationException,
)
# Vendor domain exceptions
from .vendor_domain import (
VendorDomainNotFoundException,
VendorDomainAlreadyExistsException,
InvalidDomainFormatException,
ReservedDomainException,
DomainNotVerifiedException,
DomainVerificationFailedException,
DomainAlreadyVerifiedException,
MultiplePrimaryDomainsException,
DNSVerificationException,
MaxDomainsReachedException,
UnauthorizedDomainAccessException,
)
# Vendor theme exceptions
from .vendor_theme import (
VendorThemeNotFoundException,
InvalidThemeDataException,
ThemePresetNotFoundException,
ThemeValidationException,
ThemePresetAlreadyAppliedException,
InvalidColorFormatException,
InvalidFontFamilyException,
ThemeOperationException,
)
# Customer exceptions
from .customer import (
CustomerNotFoundException,
CustomerAlreadyExistsException,
DuplicateCustomerEmailException,
CustomerNotActiveException,
InvalidCustomerCredentialsException,
CustomerValidationException,
CustomerAuthorizationException,
)
# Team exceptions
from .team import (
TeamMemberNotFoundException,
TeamMemberAlreadyExistsException,
TeamInvitationNotFoundException,
TeamInvitationExpiredException,
TeamInvitationAlreadyAcceptedException,
UnauthorizedTeamActionException,
CannotRemoveOwnerException,
CannotModifyOwnRoleException,
RoleNotFoundException,
InvalidRoleException,
InsufficientTeamPermissionsException,
MaxTeamMembersReachedException,
TeamValidationException,
InvalidInvitationDataException,
InvalidInvitationTokenException,
)
# Product exceptions
from .product import (
ProductNotFoundException,
ProductAlreadyExistsException,
ProductNotInCatalogException,
ProductNotActiveException,
InvalidProductDataException,
ProductValidationException,
CannotDeleteProductWithInventoryException,
CannotDeleteProductWithOrdersException,
)
# Order exceptions
from .order import (
OrderNotFoundException,
OrderAlreadyExistsException,
OrderValidationException,
InvalidOrderStatusException,
OrderCannotBeCancelledException,
)
from .admin import (AdminOperationException, BulkOperationException,
CannotModifyAdminException, CannotModifySelfException,
ConfirmationRequiredException, InvalidAdminActionException,
UserNotFoundException, UserStatusChangeException,
VendorVerificationException)
# Authentication exceptions
from .auth import (AdminRequiredException, InsufficientPermissionsException,
InvalidCredentialsException, InvalidTokenException,
TokenExpiredException, UserAlreadyExistsException,
UserNotActiveException)
# Base exceptions
from .base import (AuthenticationException, AuthorizationException,
BusinessLogicException, ConflictException,
ExternalServiceException, RateLimitException,
ResourceNotFoundException, ServiceUnavailableException,
ValidationException, WizamartException)
# Cart exceptions
from .cart import (
CartItemNotFoundException,
EmptyCartException,
CartValidationException,
InsufficientInventoryForCartException,
InvalidCartQuantityException,
ProductNotAvailableForCartException,
)
from .cart import (CartItemNotFoundException, CartValidationException,
EmptyCartException, InsufficientInventoryForCartException,
InvalidCartQuantityException,
ProductNotAvailableForCartException)
# Customer exceptions
from .customer import (CustomerAlreadyExistsException,
CustomerAuthorizationException,
CustomerNotActiveException, CustomerNotFoundException,
CustomerValidationException,
DuplicateCustomerEmailException,
InvalidCustomerCredentialsException)
# Inventory exceptions
from .inventory import (InsufficientInventoryException,
InvalidInventoryOperationException,
InvalidQuantityException, InventoryNotFoundException,
InventoryValidationException,
LocationNotFoundException, NegativeInventoryException)
# Marketplace import job exceptions
from .marketplace_import_job import (ImportJobAlreadyProcessingException,
ImportJobCannotBeCancelledException,
ImportJobCannotBeDeletedException,
ImportJobNotFoundException,
ImportJobNotOwnedException,
ImportRateLimitException,
InvalidImportDataException,
InvalidMarketplaceException,
MarketplaceConnectionException,
MarketplaceDataParsingException,
MarketplaceImportException)
# Marketplace product exceptions
from .marketplace_product import (InvalidGTINException,
InvalidMarketplaceProductDataException,
MarketplaceProductAlreadyExistsException,
MarketplaceProductCSVImportException,
MarketplaceProductNotFoundException,
MarketplaceProductValidationException)
# Order exceptions
from .order import (InvalidOrderStatusException, OrderAlreadyExistsException,
OrderCannotBeCancelledException, OrderNotFoundException,
OrderValidationException)
# Product exceptions
from .product import (CannotDeleteProductWithInventoryException,
CannotDeleteProductWithOrdersException,
InvalidProductDataException,
ProductAlreadyExistsException, ProductNotActiveException,
ProductNotFoundException, ProductNotInCatalogException,
ProductValidationException)
# Team exceptions
from .team import (CannotModifyOwnRoleException, CannotRemoveOwnerException,
InsufficientTeamPermissionsException,
InvalidInvitationDataException,
InvalidInvitationTokenException, InvalidRoleException,
MaxTeamMembersReachedException, RoleNotFoundException,
TeamInvitationAlreadyAcceptedException,
TeamInvitationExpiredException,
TeamInvitationNotFoundException,
TeamMemberAlreadyExistsException,
TeamMemberNotFoundException, TeamValidationException,
UnauthorizedTeamActionException)
# Vendor exceptions
from .vendor import (InvalidVendorDataException, MaxVendorsReachedException,
UnauthorizedVendorAccessException,
VendorAlreadyExistsException, VendorNotActiveException,
VendorNotFoundException, VendorNotVerifiedException,
VendorValidationException)
# Vendor domain exceptions
from .vendor_domain import (DNSVerificationException,
DomainAlreadyVerifiedException,
DomainNotVerifiedException,
DomainVerificationFailedException,
InvalidDomainFormatException,
MaxDomainsReachedException,
MultiplePrimaryDomainsException,
ReservedDomainException,
UnauthorizedDomainAccessException,
VendorDomainAlreadyExistsException,
VendorDomainNotFoundException)
# Vendor theme exceptions
from .vendor_theme import (InvalidColorFormatException,
InvalidFontFamilyException,
InvalidThemeDataException, ThemeOperationException,
ThemePresetAlreadyAppliedException,
ThemePresetNotFoundException,
ThemeValidationException,
VendorThemeNotFoundException)
__all__ = [
# Base exceptions
@@ -192,7 +122,6 @@ __all__ = [
"ExternalServiceException",
"RateLimitException",
"ServiceUnavailableException",
# Auth exceptions
"InvalidCredentialsException",
"TokenExpiredException",
@@ -201,7 +130,6 @@ __all__ = [
"UserNotActiveException",
"AdminRequiredException",
"UserAlreadyExistsException",
# Customer exceptions
"CustomerNotFoundException",
"CustomerAlreadyExistsException",
@@ -210,7 +138,6 @@ __all__ = [
"InvalidCustomerCredentialsException",
"CustomerValidationException",
"CustomerAuthorizationException",
# Team exceptions
"TeamMemberNotFoundException",
"TeamMemberAlreadyExistsException",
@@ -227,7 +154,6 @@ __all__ = [
"TeamValidationException",
"InvalidInvitationDataException",
"InvalidInvitationTokenException",
# Inventory exceptions
"InventoryNotFoundException",
"InsufficientInventoryException",
@@ -236,7 +162,6 @@ __all__ = [
"NegativeInventoryException",
"InvalidQuantityException",
"LocationNotFoundException",
# Vendor exceptions
"VendorNotFoundException",
"VendorAlreadyExistsException",
@@ -246,7 +171,6 @@ __all__ = [
"InvalidVendorDataException",
"MaxVendorsReachedException",
"VendorValidationException",
# Vendor Domain
"VendorDomainNotFoundException",
"VendorDomainAlreadyExistsException",
@@ -259,7 +183,6 @@ __all__ = [
"DNSVerificationException",
"MaxDomainsReachedException",
"UnauthorizedDomainAccessException",
# Vendor Theme
"VendorThemeNotFoundException",
"InvalidThemeDataException",
@@ -269,7 +192,6 @@ __all__ = [
"InvalidColorFormatException",
"InvalidFontFamilyException",
"ThemeOperationException",
# Product exceptions
"ProductNotFoundException",
"ProductAlreadyExistsException",
@@ -279,14 +201,12 @@ __all__ = [
"ProductValidationException",
"CannotDeleteProductWithInventoryException",
"CannotDeleteProductWithOrdersException",
# Order exceptions
"OrderNotFoundException",
"OrderAlreadyExistsException",
"OrderValidationException",
"InvalidOrderStatusException",
"OrderCannotBeCancelledException",
# Cart exceptions
"CartItemNotFoundException",
"EmptyCartException",
@@ -294,7 +214,6 @@ __all__ = [
"InsufficientInventoryForCartException",
"InvalidCartQuantityException",
"ProductNotAvailableForCartException",
# MarketplaceProduct exceptions
"MarketplaceProductNotFoundException",
"MarketplaceProductAlreadyExistsException",
@@ -302,7 +221,6 @@ __all__ = [
"MarketplaceProductValidationException",
"InvalidGTINException",
"MarketplaceProductCSVImportException",
# Marketplace import exceptions
"MarketplaceImportException",
"ImportJobNotFoundException",
@@ -315,7 +233,6 @@ __all__ = [
"ImportRateLimitException",
"InvalidMarketplaceException",
"ImportJobAlreadyProcessingException",
# Admin exceptions
"UserNotFoundException",
"UserStatusChangeException",

View File

@@ -4,12 +4,9 @@ Admin operations specific exceptions.
"""
from typing import Any, Dict, Optional
from .base import (
ResourceNotFoundException,
BusinessLogicException,
AuthorizationException,
ValidationException
)
from .base import (AuthorizationException, BusinessLogicException,
ResourceNotFoundException, ValidationException)
class UserNotFoundException(ResourceNotFoundException):
@@ -35,11 +32,11 @@ class UserStatusChangeException(BusinessLogicException):
"""Raised when user status cannot be changed."""
def __init__(
self,
user_id: int,
current_status: str,
attempted_action: str,
reason: Optional[str] = None,
self,
user_id: int,
current_status: str,
attempted_action: str,
reason: Optional[str] = None,
):
message = f"Cannot {attempted_action} user {user_id} (current status: {current_status})"
if reason:
@@ -61,10 +58,10 @@ class ShopVerificationException(BusinessLogicException):
"""Raised when shop verification fails."""
def __init__(
self,
shop_id: int,
reason: str,
current_verification_status: Optional[bool] = None,
self,
shop_id: int,
reason: str,
current_verification_status: Optional[bool] = None,
):
details = {
"shop_id": shop_id,
@@ -85,11 +82,11 @@ class AdminOperationException(BusinessLogicException):
"""Raised when admin operation fails."""
def __init__(
self,
operation: str,
reason: str,
target_type: Optional[str] = None,
target_id: Optional[str] = None,
self,
operation: str,
reason: str,
target_type: Optional[str] = None,
target_id: Optional[str] = None,
):
message = f"Admin operation '{operation}' failed: {reason}"
@@ -142,10 +139,10 @@ class InvalidAdminActionException(ValidationException):
"""Raised when admin action is invalid."""
def __init__(
self,
action: str,
reason: str,
valid_actions: Optional[list] = None,
self,
action: str,
reason: str,
valid_actions: Optional[list] = None,
):
details = {
"action": action,
@@ -166,11 +163,11 @@ class BulkOperationException(BusinessLogicException):
"""Raised when bulk admin operation fails."""
def __init__(
self,
operation: str,
total_items: int,
failed_items: int,
errors: Optional[Dict[str, Any]] = None,
self,
operation: str,
total_items: int,
failed_items: int,
errors: Optional[Dict[str, Any]] = None,
):
message = f"Bulk {operation} completed with errors: {failed_items}/{total_items} failed"
@@ -195,10 +192,10 @@ class ConfirmationRequiredException(BusinessLogicException):
"""Raised when a destructive operation requires explicit confirmation."""
def __init__(
self,
operation: str,
message: Optional[str] = None,
confirmation_param: str = "confirm"
self,
operation: str,
message: Optional[str] = None,
confirmation_param: str = "confirm",
):
if not message:
message = f"Operation '{operation}' requires confirmation parameter: {confirmation_param}=true"
@@ -217,10 +214,10 @@ class VendorVerificationException(BusinessLogicException):
"""Raised when vendor verification fails."""
def __init__(
self,
vendor_id: int,
reason: str,
current_verification_status: Optional[bool] = None,
self,
vendor_id: int,
reason: str,
current_verification_status: Optional[bool] = None,
):
details = {
"vendor_id": vendor_id,

View File

@@ -4,7 +4,9 @@ Authentication and authorization specific exceptions.
"""
from typing import Optional
from .base import AuthenticationException, AuthorizationException, ConflictException
from .base import (AuthenticationException, AuthorizationException,
ConflictException)
class InvalidCredentialsException(AuthenticationException):
@@ -41,9 +43,9 @@ class InsufficientPermissionsException(AuthorizationException):
"""Raised when user lacks required permissions for an action."""
def __init__(
self,
message: str = "Insufficient permissions for this action",
required_permission: Optional[str] = None,
self,
message: str = "Insufficient permissions for this action",
required_permission: Optional[str] = None,
):
details = {}
if required_permission:
@@ -80,9 +82,9 @@ class UserAlreadyExistsException(ConflictException):
"""Raised when trying to register with existing username/email."""
def __init__(
self,
message: str = "User already exists",
field: Optional[str] = None,
self,
message: str = "User already exists",
field: Optional[str] = None,
):
details = {}
if field:

View File

@@ -1 +1 @@
# Backup/recovery exceptions
# Backup/recovery exceptions

View File

@@ -39,8 +39,6 @@ class WizamartException(Exception):
return result
class ValidationException(WizamartException):
"""Raised when request validation fails."""
@@ -62,8 +60,6 @@ class ValidationException(WizamartException):
)
class AuthenticationException(WizamartException):
"""Raised when authentication fails."""
@@ -97,6 +93,7 @@ class AuthorizationException(WizamartException):
details=details,
)
class ResourceNotFoundException(WizamartException):
"""Raised when a requested resource is not found."""
@@ -122,6 +119,7 @@ class ResourceNotFoundException(WizamartException):
},
)
class ConflictException(WizamartException):
"""Raised when a resource conflict occurs."""
@@ -138,6 +136,7 @@ class ConflictException(WizamartException):
details=details,
)
class BusinessLogicException(WizamartException):
"""Raised when business logic rules are violated."""
@@ -196,6 +195,7 @@ class RateLimitException(WizamartException):
details=rate_limit_details,
)
class ServiceUnavailableException(WizamartException):
"""Raised when service is unavailable."""
@@ -206,6 +206,7 @@ class ServiceUnavailableException(WizamartException):
status_code=503,
)
# Note: Domain-specific exceptions like VendorNotFoundException, UserNotFoundException, etc.
# are defined in their respective domain modules (vendor.py, admin.py, etc.)
# to keep domain-specific logic separate from base exceptions.

View File

@@ -4,11 +4,9 @@ Shopping cart specific exceptions.
"""
from typing import Optional
from .base import (
ResourceNotFoundException,
ValidationException,
BusinessLogicException
)
from .base import (BusinessLogicException, ResourceNotFoundException,
ValidationException)
class CartItemNotFoundException(ResourceNotFoundException):
@@ -19,22 +17,16 @@ class CartItemNotFoundException(ResourceNotFoundException):
resource_type="CartItem",
identifier=str(product_id),
message=f"Product {product_id} not found in cart",
error_code="CART_ITEM_NOT_FOUND"
error_code="CART_ITEM_NOT_FOUND",
)
self.details.update({
"product_id": product_id,
"session_id": session_id
})
self.details.update({"product_id": product_id, "session_id": session_id})
class EmptyCartException(ValidationException):
"""Raised when trying to perform operations on an empty cart."""
def __init__(self, session_id: str):
super().__init__(
message="Cart is empty",
details={"session_id": session_id}
)
super().__init__(message="Cart is empty", details={"session_id": session_id})
self.error_code = "CART_EMPTY"
@@ -82,7 +74,9 @@ class InsufficientInventoryForCartException(BusinessLogicException):
class InvalidCartQuantityException(ValidationException):
"""Raised when cart quantity is invalid."""
def __init__(self, quantity: int, min_quantity: int = 1, max_quantity: Optional[int] = None):
def __init__(
self, quantity: int, min_quantity: int = 1, max_quantity: Optional[int] = None
):
if quantity < min_quantity:
message = f"Quantity must be at least {min_quantity}"
elif max_quantity and quantity > max_quantity:

View File

@@ -4,13 +4,10 @@ Customer management specific exceptions.
"""
from typing import Any, Dict, Optional
from .base import (
ResourceNotFoundException,
ConflictException,
ValidationException,
AuthenticationException,
BusinessLogicException
)
from .base import (AuthenticationException, BusinessLogicException,
ConflictException, ResourceNotFoundException,
ValidationException)
class CustomerNotFoundException(ResourceNotFoundException):
@@ -21,7 +18,7 @@ class CustomerNotFoundException(ResourceNotFoundException):
resource_type="Customer",
identifier=customer_identifier,
message=f"Customer '{customer_identifier}' not found",
error_code="CUSTOMER_NOT_FOUND"
error_code="CUSTOMER_NOT_FOUND",
)
@@ -32,7 +29,7 @@ class CustomerAlreadyExistsException(ConflictException):
super().__init__(
message=f"Customer with email '{email}' already exists",
error_code="CUSTOMER_ALREADY_EXISTS",
details={"email": email}
details={"email": email},
)
@@ -43,10 +40,7 @@ class DuplicateCustomerEmailException(ConflictException):
super().__init__(
message=f"Email '{email}' is already registered for this vendor",
error_code="DUPLICATE_CUSTOMER_EMAIL",
details={
"email": email,
"vendor_code": vendor_code
}
details={"email": email, "vendor_code": vendor_code},
)
@@ -57,7 +51,7 @@ class CustomerNotActiveException(BusinessLogicException):
super().__init__(
message=f"Customer account '{email}' is not active",
error_code="CUSTOMER_NOT_ACTIVE",
details={"email": email}
details={"email": email},
)
@@ -67,7 +61,7 @@ class InvalidCustomerCredentialsException(AuthenticationException):
def __init__(self):
super().__init__(
message="Invalid email or password",
error_code="INVALID_CUSTOMER_CREDENTIALS"
error_code="INVALID_CUSTOMER_CREDENTIALS",
)
@@ -78,13 +72,9 @@ class CustomerValidationException(ValidationException):
self,
message: str = "Customer validation failed",
field: Optional[str] = None,
details: Optional[Dict[str, Any]] = None
details: Optional[Dict[str, Any]] = None,
):
super().__init__(
message=message,
field=field,
details=details
)
super().__init__(message=message, field=field, details=details)
self.error_code = "CUSTOMER_VALIDATION_FAILED"
@@ -95,8 +85,5 @@ class CustomerAuthorizationException(BusinessLogicException):
super().__init__(
message=f"Customer '{customer_email}' not authorized for: {operation}",
error_code="CUSTOMER_NOT_AUTHORIZED",
details={
"customer_email": customer_email,
"operation": operation
}
details={"customer_email": customer_email, "operation": operation},
)

View File

@@ -7,7 +7,7 @@ Handles fallback logic and context-specific customization.
"""
import logging
from pathlib import Path
from typing import Optional, Dict, Any
from typing import Any, Dict, Optional
from fastapi import Request
from fastapi.responses import HTMLResponse
@@ -114,7 +114,7 @@ class ErrorPageRenderer:
"error_code": error_code,
"context": context_type.value,
"template": template_path,
}
},
)
try:
@@ -129,8 +129,7 @@ class ErrorPageRenderer:
)
except Exception as e:
logger.error(
f"Failed to render error template {template_path}: {e}",
exc_info=True
f"Failed to render error template {template_path}: {e}", exc_info=True
)
# Return basic HTML as absolute fallback
return ErrorPageRenderer._render_basic_html_fallback(
@@ -228,7 +227,9 @@ class ErrorPageRenderer:
}
@staticmethod
def _get_context_data(request: Request, context_type: RequestContext) -> Dict[str, Any]:
def _get_context_data(
request: Request, context_type: RequestContext
) -> Dict[str, Any]:
"""Get context-specific data for error templates."""
data = {}
@@ -261,11 +262,19 @@ class ErrorPageRenderer:
# Calculate base_url for shop links
vendor_context = getattr(request.state, "vendor_context", None)
access_method = vendor_context.get('detection_method', 'unknown') if vendor_context else 'unknown'
access_method = (
vendor_context.get("detection_method", "unknown")
if vendor_context
else "unknown"
)
base_url = "/"
if access_method == "path" and vendor:
# Use the full_prefix from vendor_context to determine which pattern was used
full_prefix = vendor_context.get('full_prefix', '/vendor/') if vendor_context else '/vendor/'
full_prefix = (
vendor_context.get("full_prefix", "/vendor/")
if vendor_context
else "/vendor/"
)
base_url = f"{full_prefix}{vendor.subdomain}/"
data["base_url"] = base_url

View File

@@ -13,13 +13,14 @@ This module provides classes and functions for:
import logging
from typing import Union
from fastapi import Request, HTTPException
from fastapi import HTTPException, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse, RedirectResponse
from middleware.context import RequestContext, get_request_context
from .base import WizamartException
from .error_renderer import ErrorPageRenderer
from middleware.context import RequestContext, get_request_context
logger = logging.getLogger(__name__)
@@ -38,8 +39,8 @@ def setup_exception_handlers(app):
extra={
"path": request.url.path,
"accept": request.headers.get("accept", ""),
"method": request.method
}
"method": request.method,
},
)
# Redirect to appropriate login page based on context
@@ -56,15 +57,12 @@ def setup_exception_handlers(app):
"url": str(request.url),
"method": request.method,
"exception_type": type(exc).__name__,
}
},
)
# Check if this is an API request
if _is_api_request(request):
return JSONResponse(
status_code=exc.status_code,
content=exc.to_dict()
)
return JSONResponse(status_code=exc.status_code, content=exc.to_dict())
# Check if this is an HTML page request
if _is_html_page_request(request):
@@ -78,10 +76,7 @@ def setup_exception_handlers(app):
)
# Default to JSON for unknown request types
return JSONResponse(
status_code=exc.status_code,
content=exc.to_dict()
)
return JSONResponse(status_code=exc.status_code, content=exc.to_dict())
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
@@ -96,7 +91,7 @@ def setup_exception_handlers(app):
"url": str(request.url),
"method": request.method,
"exception_type": "HTTPException",
}
},
)
# Check if this is an API request
@@ -107,7 +102,7 @@ def setup_exception_handlers(app):
"error_code": f"HTTP_{exc.status_code}",
"message": exc.detail,
"status_code": exc.status_code,
}
},
)
# Check if this is an HTML page request
@@ -128,11 +123,13 @@ def setup_exception_handlers(app):
"error_code": f"HTTP_{exc.status_code}",
"message": exc.detail,
"status_code": exc.status_code,
}
},
)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
async def validation_exception_handler(
request: Request, exc: RequestValidationError
):
"""Handle Pydantic validation errors with consistent format."""
# Sanitize errors to remove sensitive data from logs
@@ -140,8 +137,8 @@ def setup_exception_handlers(app):
for error in exc.errors():
sanitized_error = error.copy()
# Remove 'input' field which may contain passwords
if 'input' in sanitized_error:
sanitized_error['input'] = '<redacted>'
if "input" in sanitized_error:
sanitized_error["input"] = "<redacted>"
sanitized_errors.append(sanitized_error)
logger.error(
@@ -151,7 +148,7 @@ def setup_exception_handlers(app):
"url": str(request.url),
"method": request.method,
"exception_type": "RequestValidationError",
}
},
)
# Clean up validation errors to ensure JSON serializability
@@ -159,15 +156,17 @@ def setup_exception_handlers(app):
for error in exc.errors():
clean_error = {}
for key, value in error.items():
if key == 'input' and isinstance(value, bytes):
if key == "input" and isinstance(value, bytes):
# Convert bytes to string representation for JSON serialization
clean_error[key] = f"<bytes: {len(value)} bytes>"
elif key == 'ctx' and isinstance(value, dict):
elif key == "ctx" and isinstance(value, dict):
# Handle the 'ctx' field that contains ValueError objects
clean_ctx = {}
for ctx_key, ctx_value in value.items():
if isinstance(ctx_value, Exception):
clean_ctx[ctx_key] = str(ctx_value) # Convert exception to string
clean_ctx[ctx_key] = str(
ctx_value
) # Convert exception to string
else:
clean_ctx[ctx_key] = ctx_value
clean_error[key] = clean_ctx
@@ -186,10 +185,8 @@ def setup_exception_handlers(app):
"error_code": "VALIDATION_ERROR",
"message": "Request validation failed",
"status_code": 422,
"details": {
"validation_errors": clean_errors
}
}
"details": {"validation_errors": clean_errors},
},
)
# Check if this is an HTML page request
@@ -210,10 +207,8 @@ def setup_exception_handlers(app):
"error_code": "VALIDATION_ERROR",
"message": "Request validation failed",
"status_code": 422,
"details": {
"validation_errors": clean_errors
}
}
"details": {"validation_errors": clean_errors},
},
)
@app.exception_handler(Exception)
@@ -227,7 +222,7 @@ def setup_exception_handlers(app):
"url": str(request.url),
"method": request.method,
"exception_type": type(exc).__name__,
}
},
)
# Check if this is an API request
@@ -238,7 +233,7 @@ def setup_exception_handlers(app):
"error_code": "INTERNAL_SERVER_ERROR",
"message": "Internal server error",
"status_code": 500,
}
},
)
# Check if this is an HTML page request
@@ -259,7 +254,7 @@ def setup_exception_handlers(app):
"error_code": "INTERNAL_SERVER_ERROR",
"message": "Internal server error",
"status_code": 500,
}
},
)
@app.exception_handler(404)
@@ -275,11 +270,8 @@ def setup_exception_handlers(app):
"error_code": "ENDPOINT_NOT_FOUND",
"message": f"Endpoint not found: {request.url.path}",
"status_code": 404,
"details": {
"path": request.url.path,
"method": request.method
}
}
"details": {"path": request.url.path, "method": request.method},
},
)
# Check if this is an HTML page request
@@ -300,11 +292,8 @@ def setup_exception_handlers(app):
"error_code": "ENDPOINT_NOT_FOUND",
"message": f"Endpoint not found: {request.url.path}",
"status_code": 404,
"details": {
"path": request.url.path,
"method": request.method
}
}
"details": {"path": request.url.path, "method": request.method},
},
)
@@ -332,8 +321,8 @@ def _is_html_page_request(request: Request) -> bool:
extra={
"path": request.url.path,
"method": request.method,
"accept": request.headers.get("accept", "")
}
"accept": request.headers.get("accept", ""),
},
)
# Don't redirect API calls
@@ -354,7 +343,9 @@ def _is_html_page_request(request: Request) -> bool:
# MUST explicitly accept HTML (strict check)
accept_header = request.headers.get("accept", "")
if "text/html" not in accept_header:
logger.debug(f"Not HTML page: Accept header doesn't include text/html: {accept_header}")
logger.debug(
f"Not HTML page: Accept header doesn't include text/html: {accept_header}"
)
return False
logger.debug("IS HTML page request")
@@ -379,13 +370,21 @@ def _redirect_to_login(request: Request) -> RedirectResponse:
elif context_type == RequestContext.SHOP:
# For shop context, redirect to shop login (customer login)
# Calculate base_url for proper routing (supports domain, subdomain, and path-based access)
vendor = getattr(request.state, 'vendor', None)
vendor_context = getattr(request.state, 'vendor_context', None)
access_method = vendor_context.get('detection_method', 'unknown') if vendor_context else 'unknown'
vendor = getattr(request.state, "vendor", None)
vendor_context = getattr(request.state, "vendor_context", None)
access_method = (
vendor_context.get("detection_method", "unknown")
if vendor_context
else "unknown"
)
base_url = "/"
if access_method == "path" and vendor:
full_prefix = vendor_context.get('full_prefix', '/vendor/') if vendor_context else '/vendor/'
full_prefix = (
vendor_context.get("full_prefix", "/vendor/")
if vendor_context
else "/vendor/"
)
base_url = f"{full_prefix}{vendor.subdomain}/"
login_url = f"{base_url}shop/account/login"
@@ -401,22 +400,28 @@ def _redirect_to_login(request: Request) -> RedirectResponse:
def raise_not_found(resource_type: str, identifier: str) -> None:
"""Convenience function to raise ResourceNotFoundException."""
from .base import ResourceNotFoundException
raise ResourceNotFoundException(resource_type, identifier)
def raise_validation_error(message: str, field: str = None, details: dict = None) -> None:
def raise_validation_error(
message: str, field: str = None, details: dict = None
) -> None:
"""Convenience function to raise ValidationException."""
from .base import ValidationException
raise ValidationException(message, field, details)
def raise_auth_error(message: str = "Authentication failed") -> None:
"""Convenience function to raise AuthenticationException."""
from .base import AuthenticationException
raise AuthenticationException(message)
def raise_permission_error(message: str = "Access denied") -> None:
"""Convenience function to raise AuthorizationException."""
from .base import AuthorizationException
raise AuthorizationException(message)

View File

@@ -4,7 +4,9 @@ Inventory management specific exceptions.
"""
from typing import Any, Dict, Optional
from .base import ResourceNotFoundException, ValidationException, BusinessLogicException
from .base import (BusinessLogicException, ResourceNotFoundException,
ValidationException)
class InventoryNotFoundException(ResourceNotFoundException):
@@ -14,7 +16,9 @@ class InventoryNotFoundException(ResourceNotFoundException):
if identifier_type.lower() == "gtin":
message = f"No inventory found for GTIN '{identifier}'"
else:
message = f"Inventory record with {identifier_type} '{identifier}' not found"
message = (
f"Inventory record with {identifier_type} '{identifier}' not found"
)
super().__init__(
resource_type="Inventory",
@@ -28,11 +32,11 @@ class InsufficientInventoryException(BusinessLogicException):
"""Raised when trying to remove more inventory than available."""
def __init__(
self,
gtin: str,
location: str,
requested: int,
available: int,
self,
gtin: str,
location: str,
requested: int,
available: int,
):
message = f"Insufficient inventory for GTIN '{gtin}' at '{location}'. Requested: {requested}, Available: {available}"
@@ -52,10 +56,10 @@ class InvalidInventoryOperationException(ValidationException):
"""Raised when inventory operation is invalid."""
def __init__(
self,
message: str,
operation: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
self,
message: str,
operation: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
):
if not details:
details = {}
@@ -74,10 +78,10 @@ class InventoryValidationException(ValidationException):
"""Raised when inventory data validation fails."""
def __init__(
self,
message: str = "Inventory validation failed",
field: Optional[str] = None,
validation_errors: Optional[Dict[str, str]] = None,
self,
message: str = "Inventory validation failed",
field: Optional[str] = None,
validation_errors: Optional[Dict[str, str]] = None,
):
details = {}
if validation_errors:

View File

@@ -1 +1 @@
# Import/marketplace exceptions
# Import/marketplace exceptions

View File

@@ -4,24 +4,21 @@ Marketplace import specific exceptions.
"""
from typing import Any, Dict, Optional
from .base import (
ResourceNotFoundException,
ValidationException,
BusinessLogicException,
AuthorizationException,
ExternalServiceException
)
from .base import (AuthorizationException, BusinessLogicException,
ExternalServiceException, ResourceNotFoundException,
ValidationException)
class MarketplaceImportException(BusinessLogicException):
"""Base exception for marketplace import operations."""
def __init__(
self,
message: str,
error_code: str = "MARKETPLACE_IMPORT_ERROR",
marketplace: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
self,
message: str,
error_code: str = "MARKETPLACE_IMPORT_ERROR",
marketplace: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
):
if not details:
details = {}
@@ -67,11 +64,11 @@ class InvalidImportDataException(ValidationException):
"""Raised when import data is invalid."""
def __init__(
self,
message: str = "Invalid import data",
field: Optional[str] = None,
row_number: Optional[int] = None,
details: Optional[Dict[str, Any]] = None,
self,
message: str = "Invalid import data",
field: Optional[str] = None,
row_number: Optional[int] = None,
details: Optional[Dict[str, Any]] = None,
):
if not details:
details = {}
@@ -118,7 +115,9 @@ class ImportJobCannotBeDeletedException(BusinessLogicException):
class MarketplaceConnectionException(ExternalServiceException):
"""Raised when marketplace connection fails."""
def __init__(self, marketplace: str, message: str = "Failed to connect to marketplace"):
def __init__(
self, marketplace: str, message: str = "Failed to connect to marketplace"
):
super().__init__(
service=marketplace,
message=f"{message}: {marketplace}",
@@ -130,10 +129,10 @@ class MarketplaceDataParsingException(ValidationException):
"""Raised when marketplace data cannot be parsed."""
def __init__(
self,
marketplace: str,
message: str = "Failed to parse marketplace data",
details: Optional[Dict[str, Any]] = None,
self,
marketplace: str,
message: str = "Failed to parse marketplace data",
details: Optional[Dict[str, Any]] = None,
):
if not details:
details = {}
@@ -150,10 +149,10 @@ class ImportRateLimitException(BusinessLogicException):
"""Raised when import rate limit is exceeded."""
def __init__(
self,
max_imports: int,
time_window: str,
retry_after: Optional[int] = None,
self,
max_imports: int,
time_window: str,
retry_after: Optional[int] = None,
):
details = {
"max_imports": max_imports,

View File

@@ -4,7 +4,9 @@ MarketplaceProduct management specific exceptions.
"""
from typing import Any, Dict, Optional
from .base import ResourceNotFoundException, ConflictException, ValidationException, BusinessLogicException
from .base import (BusinessLogicException, ConflictException,
ResourceNotFoundException, ValidationException)
class MarketplaceProductNotFoundException(ResourceNotFoundException):
@@ -34,10 +36,10 @@ class InvalidMarketplaceProductDataException(ValidationException):
"""Raised when product data is invalid."""
def __init__(
self,
message: str = "Invalid product data",
field: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
self,
message: str = "Invalid product data",
field: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
):
super().__init__(
message=message,
@@ -51,10 +53,10 @@ class MarketplaceProductValidationException(ValidationException):
"""Raised when product validation fails."""
def __init__(
self,
message: str,
field: Optional[str] = None,
validation_errors: Optional[Dict[str, str]] = None,
self,
message: str,
field: Optional[str] = None,
validation_errors: Optional[Dict[str, str]] = None,
):
details = {}
if validation_errors:
@@ -84,10 +86,10 @@ class MarketplaceProductCSVImportException(BusinessLogicException):
"""Raised when product CSV import fails."""
def __init__(
self,
message: str = "MarketplaceProduct CSV import failed",
row_number: Optional[int] = None,
errors: Optional[Dict[str, Any]] = None,
self,
message: str = "MarketplaceProduct CSV import failed",
row_number: Optional[int] = None,
errors: Optional[Dict[str, Any]] = None,
):
details = {}
if row_number:

View File

@@ -1 +1 @@
# Media/file management exceptions
# Media/file management exceptions

View File

@@ -1 +1 @@
# Monitoring exceptions
# Monitoring exceptions

View File

@@ -1 +1 @@
# Notification exceptions
# Notification exceptions

View File

@@ -4,11 +4,9 @@ Order management specific exceptions.
"""
from typing import Optional
from .base import (
ResourceNotFoundException,
ValidationException,
BusinessLogicException
)
from .base import (BusinessLogicException, ResourceNotFoundException,
ValidationException)
class OrderNotFoundException(ResourceNotFoundException):
@@ -19,7 +17,7 @@ class OrderNotFoundException(ResourceNotFoundException):
resource_type="Order",
identifier=order_identifier,
message=f"Order '{order_identifier}' not found",
error_code="ORDER_NOT_FOUND"
error_code="ORDER_NOT_FOUND",
)
@@ -30,7 +28,7 @@ class OrderAlreadyExistsException(ValidationException):
super().__init__(
message=f"Order with number '{order_number}' already exists",
error_code="ORDER_ALREADY_EXISTS",
details={"order_number": order_number}
details={"order_number": order_number},
)
@@ -39,9 +37,7 @@ class OrderValidationException(ValidationException):
def __init__(self, message: str, details: Optional[dict] = None):
super().__init__(
message=message,
error_code="ORDER_VALIDATION_FAILED",
details=details
message=message, error_code="ORDER_VALIDATION_FAILED", details=details
)
@@ -52,10 +48,7 @@ class InvalidOrderStatusException(BusinessLogicException):
super().__init__(
message=f"Cannot change order status from '{current_status}' to '{new_status}'",
error_code="INVALID_ORDER_STATUS_CHANGE",
details={
"current_status": current_status,
"new_status": new_status
}
details={"current_status": current_status, "new_status": new_status},
)
@@ -66,8 +59,5 @@ class OrderCannotBeCancelledException(BusinessLogicException):
super().__init__(
message=f"Order '{order_number}' cannot be cancelled: {reason}",
error_code="ORDER_CANNOT_BE_CANCELLED",
details={
"order_number": order_number,
"reason": reason
}
details={"order_number": order_number, "reason": reason},
)

View File

@@ -1 +1 @@
# Payment processing exceptions
# Payment processing exceptions

View File

@@ -4,12 +4,9 @@ Product (vendor catalog) specific exceptions.
"""
from typing import Optional
from .base import (
ResourceNotFoundException,
ConflictException,
ValidationException,
BusinessLogicException
)
from .base import (BusinessLogicException, ConflictException,
ResourceNotFoundException, ValidationException)
class ProductNotFoundException(ResourceNotFoundException):

View File

@@ -1 +1 @@
# Search exceptions
# Search exceptions

View File

@@ -4,13 +4,10 @@ Team management specific exceptions.
"""
from typing import Any, Dict, Optional
from .base import (
ResourceNotFoundException,
ConflictException,
ValidationException,
AuthorizationException,
BusinessLogicException
)
from .base import (AuthorizationException, BusinessLogicException,
ConflictException, ResourceNotFoundException,
ValidationException)
class TeamMemberNotFoundException(ResourceNotFoundException):
@@ -20,7 +17,9 @@ class TeamMemberNotFoundException(ResourceNotFoundException):
details = {"user_id": user_id}
if vendor_id:
details["vendor_id"] = vendor_id
message = f"Team member with user ID '{user_id}' not found in vendor {vendor_id}"
message = (
f"Team member with user ID '{user_id}' not found in vendor {vendor_id}"
)
else:
message = f"Team member with user ID '{user_id}' not found"
@@ -84,7 +83,12 @@ class TeamInvitationAlreadyAcceptedException(ConflictException):
class UnauthorizedTeamActionException(AuthorizationException):
"""Raised when user tries to perform team action without permission."""
def __init__(self, action: str, user_id: Optional[int] = None, required_permission: Optional[str] = None):
def __init__(
self,
action: str,
user_id: Optional[int] = None,
required_permission: Optional[str] = None,
):
details = {"action": action}
if user_id:
details["user_id"] = user_id
@@ -147,10 +151,10 @@ class InvalidRoleException(ValidationException):
"""Raised when role data is invalid."""
def __init__(
self,
message: str = "Invalid role data",
field: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
self,
message: str = "Invalid role data",
field: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
):
super().__init__(
message=message,
@@ -164,10 +168,10 @@ class InsufficientTeamPermissionsException(AuthorizationException):
"""Raised when user lacks required team permissions for an action."""
def __init__(
self,
required_permission: str,
user_id: Optional[int] = None,
action: Optional[str] = None,
self,
required_permission: str,
user_id: Optional[int] = None,
action: Optional[str] = None,
):
details = {"required_permission": required_permission}
if user_id:
@@ -202,10 +206,10 @@ class TeamValidationException(ValidationException):
"""Raised when team operation validation fails."""
def __init__(
self,
message: str = "Team operation validation failed",
field: Optional[str] = None,
validation_errors: Optional[Dict[str, str]] = None,
self,
message: str = "Team operation validation failed",
field: Optional[str] = None,
validation_errors: Optional[Dict[str, str]] = None,
):
details = {}
if validation_errors:
@@ -223,10 +227,10 @@ class InvalidInvitationDataException(ValidationException):
"""Raised when team invitation data is invalid."""
def __init__(
self,
message: str = "Invalid invitation data",
field: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
self,
message: str = "Invalid invitation data",
field: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
):
super().__init__(
message=message,
@@ -240,6 +244,7 @@ class InvalidInvitationDataException(ValidationException):
# NEW: Add InvalidInvitationTokenException
# ============================================================================
class InvalidInvitationTokenException(ValidationException):
"""Raised when invitation token is invalid, expired, or already used.
@@ -248,9 +253,9 @@ class InvalidInvitationTokenException(ValidationException):
"""
def __init__(
self,
message: str = "Invalid or expired invitation token",
invitation_token: Optional[str] = None
self,
message: str = "Invalid or expired invitation token",
invitation_token: Optional[str] = None,
):
details = {}
if invitation_token:

View File

@@ -4,13 +4,10 @@ Vendor management specific exceptions.
"""
from typing import Any, Dict, Optional
from .base import (
ResourceNotFoundException,
ConflictException,
ValidationException,
AuthorizationException,
BusinessLogicException
)
from .base import (AuthorizationException, BusinessLogicException,
ConflictException, ResourceNotFoundException,
ValidationException)
class VendorNotFoundException(ResourceNotFoundException):
@@ -82,10 +79,10 @@ class InvalidVendorDataException(ValidationException):
"""Raised when vendor data is invalid or incomplete."""
def __init__(
self,
message: str = "Invalid vendor data",
field: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
self,
message: str = "Invalid vendor data",
field: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
):
super().__init__(
message=message,
@@ -99,10 +96,10 @@ class VendorValidationException(ValidationException):
"""Raised when vendor validation fails."""
def __init__(
self,
message: str = "Vendor validation failed",
field: Optional[str] = None,
validation_errors: Optional[Dict[str, str]] = None,
self,
message: str = "Vendor validation failed",
field: Optional[str] = None,
validation_errors: Optional[Dict[str, str]] = None,
):
details = {}
if validation_errors:
@@ -120,9 +117,9 @@ class IncompleteVendorDataException(ValidationException):
"""Raised when vendor data is missing required fields."""
def __init__(
self,
vendor_code: str,
missing_fields: list,
self,
vendor_code: str,
missing_fields: list,
):
super().__init__(
message=f"Vendor '{vendor_code}' is missing required fields: {', '.join(missing_fields)}",

View File

@@ -4,13 +4,10 @@ Vendor domain management specific exceptions.
"""
from typing import Any, Dict, Optional
from .base import (
ResourceNotFoundException,
ConflictException,
ValidationException,
BusinessLogicException,
ExternalServiceException
)
from .base import (BusinessLogicException, ConflictException,
ExternalServiceException, ResourceNotFoundException,
ValidationException)
class VendorDomainNotFoundException(ResourceNotFoundException):
@@ -64,10 +61,7 @@ class ReservedDomainException(ValidationException):
super().__init__(
message=f"Domain cannot use reserved subdomain: {reserved_part}",
field="domain",
details={
"domain": domain,
"reserved_part": reserved_part
},
details={"domain": domain, "reserved_part": reserved_part},
)
self.error_code = "RESERVED_DOMAIN"
@@ -79,10 +73,7 @@ class DomainNotVerifiedException(BusinessLogicException):
super().__init__(
message=f"Domain '{domain}' must be verified before activation",
error_code="DOMAIN_NOT_VERIFIED",
details={
"domain_id": domain_id,
"domain": domain
},
details={"domain_id": domain_id, "domain": domain},
)
@@ -93,10 +84,7 @@ class DomainVerificationFailedException(BusinessLogicException):
super().__init__(
message=f"Domain verification failed for '{domain}': {reason}",
error_code="DOMAIN_VERIFICATION_FAILED",
details={
"domain": domain,
"reason": reason
},
details={"domain": domain, "reason": reason},
)
@@ -107,10 +95,7 @@ class DomainAlreadyVerifiedException(BusinessLogicException):
super().__init__(
message=f"Domain '{domain}' is already verified",
error_code="DOMAIN_ALREADY_VERIFIED",
details={
"domain_id": domain_id,
"domain": domain
},
details={"domain_id": domain_id, "domain": domain},
)
@@ -133,10 +118,7 @@ class DNSVerificationException(ExternalServiceException):
service_name="DNS",
message=f"DNS verification failed for '{domain}': {reason}",
error_code="DNS_VERIFICATION_ERROR",
details={
"domain": domain,
"reason": reason
},
details={"domain": domain, "reason": reason},
)
@@ -147,10 +129,7 @@ class MaxDomainsReachedException(BusinessLogicException):
super().__init__(
message=f"Maximum number of domains reached ({max_domains})",
error_code="MAX_DOMAINS_REACHED",
details={
"vendor_id": vendor_id,
"max_domains": max_domains
},
details={"vendor_id": vendor_id, "max_domains": max_domains},
)
@@ -161,8 +140,5 @@ class UnauthorizedDomainAccessException(BusinessLogicException):
super().__init__(
message=f"Unauthorized access to domain {domain_id}",
error_code="UNAUTHORIZED_DOMAIN_ACCESS",
details={
"domain_id": domain_id,
"vendor_id": vendor_id
},
details={"domain_id": domain_id, "vendor_id": vendor_id},
)

View File

@@ -4,12 +4,9 @@ Vendor theme management specific exceptions.
"""
from typing import Any, Dict, Optional
from .base import (
ResourceNotFoundException,
ConflictException,
ValidationException,
BusinessLogicException
)
from .base import (BusinessLogicException, ConflictException,
ResourceNotFoundException, ValidationException)
class VendorThemeNotFoundException(ResourceNotFoundException):
@@ -28,10 +25,10 @@ class InvalidThemeDataException(ValidationException):
"""Raised when theme data is invalid."""
def __init__(
self,
message: str = "Invalid theme data",
field: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
self,
message: str = "Invalid theme data",
field: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
):
super().__init__(
message=message,
@@ -62,10 +59,10 @@ class ThemeValidationException(ValidationException):
"""Raised when theme validation fails."""
def __init__(
self,
message: str = "Theme validation failed",
field: Optional[str] = None,
validation_errors: Optional[Dict[str, str]] = None,
self,
message: str = "Theme validation failed",
field: Optional[str] = None,
validation_errors: Optional[Dict[str, str]] = None,
):
details = {}
if validation_errors:
@@ -86,10 +83,7 @@ class ThemePresetAlreadyAppliedException(BusinessLogicException):
super().__init__(
message=f"Preset '{preset_name}' is already applied to vendor '{vendor_code}'",
error_code="THEME_PRESET_ALREADY_APPLIED",
details={
"preset_name": preset_name,
"vendor_code": vendor_code
},
details={"preset_name": preset_name, "vendor_code": vendor_code},
)
@@ -120,18 +114,13 @@ class InvalidFontFamilyException(ValidationException):
class ThemeOperationException(BusinessLogicException):
"""Raised when theme operation fails."""
def __init__(
self,
operation: str,
vendor_code: str,
reason: str
):
def __init__(self, operation: str, vendor_code: str, reason: str):
super().__init__(
message=f"Theme operation '{operation}' failed for vendor '{vendor_code}': {reason}",
error_code="THEME_OPERATION_FAILED",
details={
"operation": operation,
"vendor_code": vendor_code,
"reason": reason
"reason": reason,
},
)