refactor: modernize code quality tooling with Ruff
- Replace black, isort, and flake8 with Ruff (all-in-one linter and formatter) - Add comprehensive pyproject.toml configuration - Simplify Makefile code quality targets - Configure exclusions for venv/.venv in pyproject.toml - Auto-fix 1,359 linting issues across codebase Benefits: - Much faster builds (Ruff is written in Rust) - Single tool replaces multiple tools - More comprehensive rule set (UP, B, C4, SIM, PIE, RET, Q) - All configuration centralized in pyproject.toml - Better import sorting and formatting consistency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -7,108 +7,178 @@ messages, and HTTP status mappings.
|
||||
"""
|
||||
|
||||
# Admin exceptions
|
||||
from .admin import (AdminOperationException, BulkOperationException,
|
||||
CannotModifyAdminException, CannotModifySelfException,
|
||||
ConfirmationRequiredException, InvalidAdminActionException,
|
||||
UserNotFoundException, UserStatusChangeException,
|
||||
VendorVerificationException)
|
||||
from .admin import (
|
||||
AdminOperationException,
|
||||
BulkOperationException,
|
||||
CannotModifyAdminException,
|
||||
CannotModifySelfException,
|
||||
ConfirmationRequiredException,
|
||||
InvalidAdminActionException,
|
||||
UserNotFoundException,
|
||||
UserStatusChangeException,
|
||||
VendorVerificationException,
|
||||
)
|
||||
|
||||
# Authentication exceptions
|
||||
from .auth import (AdminRequiredException, InsufficientPermissionsException,
|
||||
InvalidCredentialsException, InvalidTokenException,
|
||||
TokenExpiredException, UserAlreadyExistsException,
|
||||
UserNotActiveException)
|
||||
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)
|
||||
from .base import (
|
||||
AuthenticationException,
|
||||
AuthorizationException,
|
||||
BusinessLogicException,
|
||||
ConflictException,
|
||||
ExternalServiceException,
|
||||
RateLimitException,
|
||||
ResourceNotFoundException,
|
||||
ServiceUnavailableException,
|
||||
ValidationException,
|
||||
WizamartException,
|
||||
)
|
||||
|
||||
# Cart exceptions
|
||||
from .cart import (CartItemNotFoundException, CartValidationException,
|
||||
EmptyCartException, InsufficientInventoryForCartException,
|
||||
InvalidCartQuantityException,
|
||||
ProductNotAvailableForCartException)
|
||||
from .cart import (
|
||||
CartItemNotFoundException,
|
||||
CartValidationException,
|
||||
EmptyCartException,
|
||||
InsufficientInventoryForCartException,
|
||||
InvalidCartQuantityException,
|
||||
ProductNotAvailableForCartException,
|
||||
)
|
||||
|
||||
# Customer exceptions
|
||||
from .customer import (CustomerAlreadyExistsException,
|
||||
CustomerAuthorizationException,
|
||||
CustomerNotActiveException, CustomerNotFoundException,
|
||||
CustomerValidationException,
|
||||
DuplicateCustomerEmailException,
|
||||
InvalidCustomerCredentialsException)
|
||||
from .customer import (
|
||||
CustomerAlreadyExistsException,
|
||||
CustomerAuthorizationException,
|
||||
CustomerNotActiveException,
|
||||
CustomerNotFoundException,
|
||||
CustomerValidationException,
|
||||
DuplicateCustomerEmailException,
|
||||
InvalidCustomerCredentialsException,
|
||||
)
|
||||
|
||||
# Inventory exceptions
|
||||
from .inventory import (InsufficientInventoryException,
|
||||
InvalidInventoryOperationException,
|
||||
InvalidQuantityException, InventoryNotFoundException,
|
||||
InventoryValidationException,
|
||||
LocationNotFoundException, NegativeInventoryException)
|
||||
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)
|
||||
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)
|
||||
from .marketplace_product import (
|
||||
InvalidGTINException,
|
||||
InvalidMarketplaceProductDataException,
|
||||
MarketplaceProductAlreadyExistsException,
|
||||
MarketplaceProductCSVImportException,
|
||||
MarketplaceProductNotFoundException,
|
||||
MarketplaceProductValidationException,
|
||||
)
|
||||
|
||||
# Order exceptions
|
||||
from .order import (InvalidOrderStatusException, OrderAlreadyExistsException,
|
||||
OrderCannotBeCancelledException, OrderNotFoundException,
|
||||
OrderValidationException)
|
||||
from .order import (
|
||||
InvalidOrderStatusException,
|
||||
OrderAlreadyExistsException,
|
||||
OrderCannotBeCancelledException,
|
||||
OrderNotFoundException,
|
||||
OrderValidationException,
|
||||
)
|
||||
|
||||
# Product exceptions
|
||||
from .product import (CannotDeleteProductWithInventoryException,
|
||||
CannotDeleteProductWithOrdersException,
|
||||
InvalidProductDataException,
|
||||
ProductAlreadyExistsException, ProductNotActiveException,
|
||||
ProductNotFoundException, ProductNotInCatalogException,
|
||||
ProductValidationException)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
from .vendor_theme import (
|
||||
InvalidColorFormatException,
|
||||
InvalidFontFamilyException,
|
||||
InvalidThemeDataException,
|
||||
ThemeOperationException,
|
||||
ThemePresetAlreadyAppliedException,
|
||||
ThemePresetNotFoundException,
|
||||
ThemeValidationException,
|
||||
VendorThemeNotFoundException,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
# Base exceptions
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
Admin operations specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
from .base import (AuthorizationException, BusinessLogicException,
|
||||
ResourceNotFoundException, ValidationException)
|
||||
from .base import (
|
||||
AuthorizationException,
|
||||
BusinessLogicException,
|
||||
ResourceNotFoundException,
|
||||
ValidationException,
|
||||
)
|
||||
|
||||
|
||||
class UserNotFoundException(ResourceNotFoundException):
|
||||
@@ -36,7 +40,7 @@ class UserStatusChangeException(BusinessLogicException):
|
||||
user_id: int,
|
||||
current_status: str,
|
||||
attempted_action: str,
|
||||
reason: Optional[str] = None,
|
||||
reason: str | None = None,
|
||||
):
|
||||
message = f"Cannot {attempted_action} user {user_id} (current status: {current_status})"
|
||||
if reason:
|
||||
@@ -61,7 +65,7 @@ class ShopVerificationException(BusinessLogicException):
|
||||
self,
|
||||
shop_id: int,
|
||||
reason: str,
|
||||
current_verification_status: Optional[bool] = None,
|
||||
current_verification_status: bool | None = None,
|
||||
):
|
||||
details = {
|
||||
"shop_id": shop_id,
|
||||
@@ -85,8 +89,8 @@ class AdminOperationException(BusinessLogicException):
|
||||
self,
|
||||
operation: str,
|
||||
reason: str,
|
||||
target_type: Optional[str] = None,
|
||||
target_id: Optional[str] = None,
|
||||
target_type: str | None = None,
|
||||
target_id: str | None = None,
|
||||
):
|
||||
message = f"Admin operation '{operation}' failed: {reason}"
|
||||
|
||||
@@ -142,7 +146,7 @@ class InvalidAdminActionException(ValidationException):
|
||||
self,
|
||||
action: str,
|
||||
reason: str,
|
||||
valid_actions: Optional[list] = None,
|
||||
valid_actions: list | None = None,
|
||||
):
|
||||
details = {
|
||||
"action": action,
|
||||
@@ -167,7 +171,7 @@ class BulkOperationException(BusinessLogicException):
|
||||
operation: str,
|
||||
total_items: int,
|
||||
failed_items: int,
|
||||
errors: Optional[Dict[str, Any]] = None,
|
||||
errors: dict[str, Any] | None = None,
|
||||
):
|
||||
message = f"Bulk {operation} completed with errors: {failed_items}/{total_items} failed"
|
||||
|
||||
@@ -194,7 +198,7 @@ class ConfirmationRequiredException(BusinessLogicException):
|
||||
def __init__(
|
||||
self,
|
||||
operation: str,
|
||||
message: Optional[str] = None,
|
||||
message: str | None = None,
|
||||
confirmation_param: str = "confirm",
|
||||
):
|
||||
if not message:
|
||||
@@ -217,7 +221,7 @@ class VendorVerificationException(BusinessLogicException):
|
||||
self,
|
||||
vendor_id: int,
|
||||
reason: str,
|
||||
current_verification_status: Optional[bool] = None,
|
||||
current_verification_status: bool | None = None,
|
||||
):
|
||||
details = {
|
||||
"vendor_id": vendor_id,
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
Authentication and authorization specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from .base import (AuthenticationException, AuthorizationException,
|
||||
ConflictException)
|
||||
from .base import AuthenticationException, AuthorizationException, ConflictException
|
||||
|
||||
|
||||
class InvalidCredentialsException(AuthenticationException):
|
||||
@@ -45,7 +43,7 @@ class InsufficientPermissionsException(AuthorizationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Insufficient permissions for this action",
|
||||
required_permission: Optional[str] = None,
|
||||
required_permission: str | None = None,
|
||||
):
|
||||
details = {}
|
||||
if required_permission:
|
||||
@@ -84,7 +82,7 @@ class UserAlreadyExistsException(ConflictException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "User already exists",
|
||||
field: Optional[str] = None,
|
||||
field: str | None = None,
|
||||
):
|
||||
details = {}
|
||||
if field:
|
||||
|
||||
@@ -8,7 +8,7 @@ This module provides classes and functions for:
|
||||
- Standardized error response structure
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
|
||||
class WizamartException(Exception):
|
||||
@@ -19,7 +19,7 @@ class WizamartException(Exception):
|
||||
message: str,
|
||||
error_code: str,
|
||||
status_code: int = 400,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
self.message = message
|
||||
self.error_code = error_code
|
||||
@@ -27,7 +27,7 @@ class WizamartException(Exception):
|
||||
self.details = details or {}
|
||||
super().__init__(self.message)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
"""Convert exception to dictionary for JSON response."""
|
||||
result = {
|
||||
"error_code": self.error_code,
|
||||
@@ -45,8 +45,8 @@ class ValidationException(WizamartException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str,
|
||||
field: Optional[str] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
field: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
validation_details = details or {}
|
||||
if field:
|
||||
@@ -67,7 +67,7 @@ class AuthenticationException(WizamartException):
|
||||
self,
|
||||
message: str = "Authentication failed",
|
||||
error_code: str = "AUTHENTICATION_FAILED",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
super().__init__(
|
||||
message=message,
|
||||
@@ -84,7 +84,7 @@ class AuthorizationException(WizamartException):
|
||||
self,
|
||||
message: str = "Access denied",
|
||||
error_code: str = "AUTHORIZATION_FAILED",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
super().__init__(
|
||||
message=message,
|
||||
@@ -101,8 +101,8 @@ class ResourceNotFoundException(WizamartException):
|
||||
self,
|
||||
resource_type: str,
|
||||
identifier: str,
|
||||
message: Optional[str] = None,
|
||||
error_code: Optional[str] = None,
|
||||
message: str | None = None,
|
||||
error_code: str | None = None,
|
||||
):
|
||||
if not message:
|
||||
message = f"{resource_type} with identifier '{identifier}' not found"
|
||||
@@ -127,7 +127,7 @@ class ConflictException(WizamartException):
|
||||
self,
|
||||
message: str,
|
||||
error_code: str = "RESOURCE_CONFLICT",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
super().__init__(
|
||||
message=message,
|
||||
@@ -144,7 +144,7 @@ class BusinessLogicException(WizamartException):
|
||||
self,
|
||||
message: str,
|
||||
error_code: str,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
super().__init__(
|
||||
message=message,
|
||||
@@ -162,7 +162,7 @@ class ExternalServiceException(WizamartException):
|
||||
message: str,
|
||||
service_name: str,
|
||||
error_code: str = "EXTERNAL_SERVICE_ERROR",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
service_details = details or {}
|
||||
service_details["service_name"] = service_name
|
||||
@@ -181,8 +181,8 @@ class RateLimitException(WizamartException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Rate limit exceeded",
|
||||
retry_after: Optional[int] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
retry_after: int | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
rate_limit_details = details or {}
|
||||
if retry_after:
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
Shopping cart specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from .base import (BusinessLogicException, ResourceNotFoundException,
|
||||
ValidationException)
|
||||
from .base import BusinessLogicException, ResourceNotFoundException, ValidationException
|
||||
|
||||
|
||||
class CartItemNotFoundException(ResourceNotFoundException):
|
||||
@@ -36,8 +34,8 @@ class CartValidationException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Cart validation failed",
|
||||
field: Optional[str] = None,
|
||||
details: Optional[dict] = None,
|
||||
field: str | None = None,
|
||||
details: dict | None = None,
|
||||
):
|
||||
super().__init__(
|
||||
message=message,
|
||||
@@ -75,7 +73,7 @@ class InvalidCartQuantityException(ValidationException):
|
||||
"""Raised when cart quantity is invalid."""
|
||||
|
||||
def __init__(
|
||||
self, quantity: int, min_quantity: int = 1, max_quantity: Optional[int] = None
|
||||
self, quantity: int, min_quantity: int = 1, max_quantity: int | None = None
|
||||
):
|
||||
if quantity < min_quantity:
|
||||
message = f"Quantity must be at least {min_quantity}"
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
Customer management specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
from .base import (AuthenticationException, BusinessLogicException,
|
||||
ConflictException, ResourceNotFoundException,
|
||||
ValidationException)
|
||||
from .base import (
|
||||
AuthenticationException,
|
||||
BusinessLogicException,
|
||||
ConflictException,
|
||||
ResourceNotFoundException,
|
||||
ValidationException,
|
||||
)
|
||||
|
||||
|
||||
class CustomerNotFoundException(ResourceNotFoundException):
|
||||
@@ -71,8 +75,8 @@ class CustomerValidationException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Customer validation failed",
|
||||
field: Optional[str] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
field: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
super().__init__(message=message, field=field, details=details)
|
||||
self.error_code = "CUSTOMER_VALIDATION_FAILED"
|
||||
|
||||
@@ -5,9 +5,10 @@ Error Page Renderer
|
||||
Renders context-aware error pages using Jinja2 templates.
|
||||
Handles fallback logic and context-specific customization.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
from fastapi import Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
@@ -60,7 +61,7 @@ class ErrorPageRenderer:
|
||||
status_code: int,
|
||||
error_code: str,
|
||||
message: str,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
show_debug: bool = False,
|
||||
) -> HTMLResponse:
|
||||
"""
|
||||
@@ -190,9 +191,9 @@ class ErrorPageRenderer:
|
||||
status_code: int,
|
||||
error_code: str,
|
||||
message: str,
|
||||
details: Optional[Dict[str, Any]],
|
||||
details: dict[str, Any] | None,
|
||||
show_debug: bool,
|
||||
) -> Dict[str, Any]:
|
||||
) -> dict[str, Any]:
|
||||
"""Prepare data dictionary for error template."""
|
||||
# Get friendly status name
|
||||
status_name = ErrorPageRenderer.STATUS_CODE_NAMES.get(
|
||||
@@ -229,7 +230,7 @@ class ErrorPageRenderer:
|
||||
@staticmethod
|
||||
def _get_context_data(
|
||||
request: Request, context_type: RequestContext
|
||||
) -> Dict[str, Any]:
|
||||
) -> dict[str, Any]:
|
||||
"""Get context-specific data for error templates."""
|
||||
data = {}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ This module provides classes and functions for:
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Union
|
||||
|
||||
from fastapi import HTTPException, Request
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
@@ -280,7 +279,7 @@ def setup_exception_handlers(app):
|
||||
request=request,
|
||||
status_code=404,
|
||||
error_code="ENDPOINT_NOT_FOUND",
|
||||
message=f"The page you're looking for doesn't exist or has been moved.",
|
||||
message="The page you're looking for doesn't exist or has been moved.",
|
||||
details={"path": request.url.path},
|
||||
show_debug=True,
|
||||
)
|
||||
@@ -364,10 +363,10 @@ def _redirect_to_login(request: Request) -> RedirectResponse:
|
||||
if context_type == RequestContext.ADMIN:
|
||||
logger.debug("Redirecting to /admin/login")
|
||||
return RedirectResponse(url="/admin/login", status_code=302)
|
||||
elif context_type == RequestContext.VENDOR_DASHBOARD:
|
||||
if context_type == RequestContext.VENDOR_DASHBOARD:
|
||||
logger.debug("Redirecting to /vendor/login")
|
||||
return RedirectResponse(url="/vendor/login", status_code=302)
|
||||
elif context_type == RequestContext.SHOP:
|
||||
if 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)
|
||||
@@ -390,10 +389,9 @@ def _redirect_to_login(request: Request) -> RedirectResponse:
|
||||
login_url = f"{base_url}shop/account/login"
|
||||
logger.debug(f"Redirecting to {login_url}")
|
||||
return RedirectResponse(url=login_url, status_code=302)
|
||||
else:
|
||||
# Fallback to root for unknown contexts
|
||||
logger.debug("Unknown context, redirecting to /")
|
||||
return RedirectResponse(url="/", status_code=302)
|
||||
# Fallback to root for unknown contexts
|
||||
logger.debug("Unknown context, redirecting to /")
|
||||
return RedirectResponse(url="/", status_code=302)
|
||||
|
||||
|
||||
# Utility functions for common exception scenarios
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
Inventory management specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
from .base import (BusinessLogicException, ResourceNotFoundException,
|
||||
ValidationException)
|
||||
from .base import BusinessLogicException, ResourceNotFoundException, ValidationException
|
||||
|
||||
|
||||
class InventoryNotFoundException(ResourceNotFoundException):
|
||||
@@ -58,8 +57,8 @@ class InvalidInventoryOperationException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str,
|
||||
operation: Optional[str] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
operation: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
if not details:
|
||||
details = {}
|
||||
@@ -80,8 +79,8 @@ class InventoryValidationException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Inventory validation failed",
|
||||
field: Optional[str] = None,
|
||||
validation_errors: Optional[Dict[str, str]] = None,
|
||||
field: str | None = None,
|
||||
validation_errors: dict[str, str] | None = None,
|
||||
):
|
||||
details = {}
|
||||
if validation_errors:
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
Marketplace import specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
from .base import (AuthorizationException, BusinessLogicException,
|
||||
ExternalServiceException, ResourceNotFoundException,
|
||||
ValidationException)
|
||||
from .base import (
|
||||
AuthorizationException,
|
||||
BusinessLogicException,
|
||||
ExternalServiceException,
|
||||
ResourceNotFoundException,
|
||||
ValidationException,
|
||||
)
|
||||
|
||||
|
||||
class MarketplaceImportException(BusinessLogicException):
|
||||
@@ -17,8 +21,8 @@ class MarketplaceImportException(BusinessLogicException):
|
||||
self,
|
||||
message: str,
|
||||
error_code: str = "MARKETPLACE_IMPORT_ERROR",
|
||||
marketplace: Optional[str] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
marketplace: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
if not details:
|
||||
details = {}
|
||||
@@ -48,7 +52,7 @@ class ImportJobNotFoundException(ResourceNotFoundException):
|
||||
class ImportJobNotOwnedException(AuthorizationException):
|
||||
"""Raised when user tries to access import job they don't own."""
|
||||
|
||||
def __init__(self, job_id: int, user_id: Optional[int] = None):
|
||||
def __init__(self, job_id: int, user_id: int | None = None):
|
||||
details = {"job_id": job_id}
|
||||
if user_id:
|
||||
details["user_id"] = user_id
|
||||
@@ -66,9 +70,9 @@ class InvalidImportDataException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Invalid import data",
|
||||
field: Optional[str] = None,
|
||||
row_number: Optional[int] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
field: str | None = None,
|
||||
row_number: int | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
if not details:
|
||||
details = {}
|
||||
@@ -132,7 +136,7 @@ class MarketplaceDataParsingException(ValidationException):
|
||||
self,
|
||||
marketplace: str,
|
||||
message: str = "Failed to parse marketplace data",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
if not details:
|
||||
details = {}
|
||||
@@ -152,7 +156,7 @@ class ImportRateLimitException(BusinessLogicException):
|
||||
self,
|
||||
max_imports: int,
|
||||
time_window: str,
|
||||
retry_after: Optional[int] = None,
|
||||
retry_after: int | None = None,
|
||||
):
|
||||
details = {
|
||||
"max_imports": max_imports,
|
||||
@@ -172,7 +176,7 @@ class ImportRateLimitException(BusinessLogicException):
|
||||
class InvalidMarketplaceException(ValidationException):
|
||||
"""Raised when marketplace is not supported."""
|
||||
|
||||
def __init__(self, marketplace: str, supported_marketplaces: Optional[list] = None):
|
||||
def __init__(self, marketplace: str, supported_marketplaces: list | None = None):
|
||||
details = {"marketplace": marketplace}
|
||||
if supported_marketplaces:
|
||||
details["supported_marketplaces"] = supported_marketplaces
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
MarketplaceProduct management specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
from .base import (BusinessLogicException, ConflictException,
|
||||
ResourceNotFoundException, ValidationException)
|
||||
from .base import (
|
||||
BusinessLogicException,
|
||||
ConflictException,
|
||||
ResourceNotFoundException,
|
||||
ValidationException,
|
||||
)
|
||||
|
||||
|
||||
class MarketplaceProductNotFoundException(ResourceNotFoundException):
|
||||
@@ -38,8 +42,8 @@ class InvalidMarketplaceProductDataException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Invalid product data",
|
||||
field: Optional[str] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
field: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
super().__init__(
|
||||
message=message,
|
||||
@@ -55,8 +59,8 @@ class MarketplaceProductValidationException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str,
|
||||
field: Optional[str] = None,
|
||||
validation_errors: Optional[Dict[str, str]] = None,
|
||||
field: str | None = None,
|
||||
validation_errors: dict[str, str] | None = None,
|
||||
):
|
||||
details = {}
|
||||
if validation_errors:
|
||||
@@ -88,8 +92,8 @@ class MarketplaceProductCSVImportException(BusinessLogicException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "MarketplaceProduct CSV import failed",
|
||||
row_number: Optional[int] = None,
|
||||
errors: Optional[Dict[str, Any]] = None,
|
||||
row_number: int | None = None,
|
||||
errors: dict[str, Any] | None = None,
|
||||
):
|
||||
details = {}
|
||||
if row_number:
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
Order management specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from .base import (BusinessLogicException, ResourceNotFoundException,
|
||||
ValidationException)
|
||||
from .base import BusinessLogicException, ResourceNotFoundException, ValidationException
|
||||
|
||||
|
||||
class OrderNotFoundException(ResourceNotFoundException):
|
||||
@@ -35,7 +33,7 @@ class OrderAlreadyExistsException(ValidationException):
|
||||
class OrderValidationException(ValidationException):
|
||||
"""Raised when order data validation fails."""
|
||||
|
||||
def __init__(self, message: str, details: Optional[dict] = None):
|
||||
def __init__(self, message: str, details: dict | None = None):
|
||||
super().__init__(
|
||||
message=message, error_code="ORDER_VALIDATION_FAILED", details=details
|
||||
)
|
||||
|
||||
@@ -3,16 +3,19 @@
|
||||
Product (vendor catalog) specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from .base import (BusinessLogicException, ConflictException,
|
||||
ResourceNotFoundException, ValidationException)
|
||||
from .base import (
|
||||
BusinessLogicException,
|
||||
ConflictException,
|
||||
ResourceNotFoundException,
|
||||
ValidationException,
|
||||
)
|
||||
|
||||
|
||||
class ProductNotFoundException(ResourceNotFoundException):
|
||||
"""Raised when a product is not found in vendor catalog."""
|
||||
|
||||
def __init__(self, product_id: int, vendor_id: Optional[int] = None):
|
||||
def __init__(self, product_id: int, vendor_id: int | None = None):
|
||||
details = {"product_id": product_id}
|
||||
if vendor_id:
|
||||
details["vendor_id"] = vendor_id
|
||||
@@ -79,8 +82,8 @@ class InvalidProductDataException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Invalid product data",
|
||||
field: Optional[str] = None,
|
||||
details: Optional[dict] = None,
|
||||
field: str | None = None,
|
||||
details: dict | None = None,
|
||||
):
|
||||
super().__init__(
|
||||
message=message,
|
||||
@@ -96,8 +99,8 @@ class ProductValidationException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Product validation failed",
|
||||
field: Optional[str] = None,
|
||||
validation_errors: Optional[dict] = None,
|
||||
field: str | None = None,
|
||||
validation_errors: dict | None = None,
|
||||
):
|
||||
details = {}
|
||||
if validation_errors:
|
||||
|
||||
@@ -3,17 +3,21 @@
|
||||
Team management specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
from .base import (AuthorizationException, BusinessLogicException,
|
||||
ConflictException, ResourceNotFoundException,
|
||||
ValidationException)
|
||||
from .base import (
|
||||
AuthorizationException,
|
||||
BusinessLogicException,
|
||||
ConflictException,
|
||||
ResourceNotFoundException,
|
||||
ValidationException,
|
||||
)
|
||||
|
||||
|
||||
class TeamMemberNotFoundException(ResourceNotFoundException):
|
||||
"""Raised when a team member is not found."""
|
||||
|
||||
def __init__(self, user_id: int, vendor_id: Optional[int] = None):
|
||||
def __init__(self, user_id: int, vendor_id: int | None = None):
|
||||
details = {"user_id": user_id}
|
||||
if vendor_id:
|
||||
details["vendor_id"] = vendor_id
|
||||
@@ -63,7 +67,7 @@ class TeamInvitationExpiredException(BusinessLogicException):
|
||||
|
||||
def __init__(self, invitation_token: str):
|
||||
super().__init__(
|
||||
message=f"Team invitation has expired",
|
||||
message="Team invitation has expired",
|
||||
error_code="TEAM_INVITATION_EXPIRED",
|
||||
details={"invitation_token": invitation_token},
|
||||
)
|
||||
@@ -86,8 +90,8 @@ class UnauthorizedTeamActionException(AuthorizationException):
|
||||
def __init__(
|
||||
self,
|
||||
action: str,
|
||||
user_id: Optional[int] = None,
|
||||
required_permission: Optional[str] = None,
|
||||
user_id: int | None = None,
|
||||
required_permission: str | None = None,
|
||||
):
|
||||
details = {"action": action}
|
||||
if user_id:
|
||||
@@ -130,7 +134,7 @@ class CannotModifyOwnRoleException(BusinessLogicException):
|
||||
class RoleNotFoundException(ResourceNotFoundException):
|
||||
"""Raised when a role is not found."""
|
||||
|
||||
def __init__(self, role_id: int, vendor_id: Optional[int] = None):
|
||||
def __init__(self, role_id: int, vendor_id: int | None = None):
|
||||
details = {"role_id": role_id}
|
||||
if vendor_id:
|
||||
details["vendor_id"] = vendor_id
|
||||
@@ -153,8 +157,8 @@ class InvalidRoleException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Invalid role data",
|
||||
field: Optional[str] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
field: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
super().__init__(
|
||||
message=message,
|
||||
@@ -170,8 +174,8 @@ class InsufficientTeamPermissionsException(AuthorizationException):
|
||||
def __init__(
|
||||
self,
|
||||
required_permission: str,
|
||||
user_id: Optional[int] = None,
|
||||
action: Optional[str] = None,
|
||||
user_id: int | None = None,
|
||||
action: str | None = None,
|
||||
):
|
||||
details = {"required_permission": required_permission}
|
||||
if user_id:
|
||||
@@ -208,8 +212,8 @@ class TeamValidationException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Team operation validation failed",
|
||||
field: Optional[str] = None,
|
||||
validation_errors: Optional[Dict[str, str]] = None,
|
||||
field: str | None = None,
|
||||
validation_errors: dict[str, str] | None = None,
|
||||
):
|
||||
details = {}
|
||||
if validation_errors:
|
||||
@@ -229,8 +233,8 @@ class InvalidInvitationDataException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Invalid invitation data",
|
||||
field: Optional[str] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
field: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
super().__init__(
|
||||
message=message,
|
||||
@@ -255,7 +259,7 @@ class InvalidInvitationTokenException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Invalid or expired invitation token",
|
||||
invitation_token: Optional[str] = None,
|
||||
invitation_token: str | None = None,
|
||||
):
|
||||
details = {}
|
||||
if invitation_token:
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
Vendor management specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
from .base import (AuthorizationException, BusinessLogicException,
|
||||
ConflictException, ResourceNotFoundException,
|
||||
ValidationException)
|
||||
from .base import (
|
||||
AuthorizationException,
|
||||
BusinessLogicException,
|
||||
ConflictException,
|
||||
ResourceNotFoundException,
|
||||
ValidationException,
|
||||
)
|
||||
|
||||
|
||||
class VendorNotFoundException(ResourceNotFoundException):
|
||||
@@ -63,7 +67,7 @@ class VendorNotVerifiedException(BusinessLogicException):
|
||||
class UnauthorizedVendorAccessException(AuthorizationException):
|
||||
"""Raised when user tries to access vendor they don't own."""
|
||||
|
||||
def __init__(self, vendor_code: str, user_id: Optional[int] = None):
|
||||
def __init__(self, vendor_code: str, user_id: int | None = None):
|
||||
details = {"vendor_code": vendor_code}
|
||||
if user_id:
|
||||
details["user_id"] = user_id
|
||||
@@ -81,8 +85,8 @@ class InvalidVendorDataException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Invalid vendor data",
|
||||
field: Optional[str] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
field: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
super().__init__(
|
||||
message=message,
|
||||
@@ -98,8 +102,8 @@ class VendorValidationException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Vendor validation failed",
|
||||
field: Optional[str] = None,
|
||||
validation_errors: Optional[Dict[str, str]] = None,
|
||||
field: str | None = None,
|
||||
validation_errors: dict[str, str] | None = None,
|
||||
):
|
||||
details = {}
|
||||
if validation_errors:
|
||||
@@ -134,7 +138,7 @@ class IncompleteVendorDataException(ValidationException):
|
||||
class MaxVendorsReachedException(BusinessLogicException):
|
||||
"""Raised when user tries to create more vendors than allowed."""
|
||||
|
||||
def __init__(self, max_vendors: int, user_id: Optional[int] = None):
|
||||
def __init__(self, max_vendors: int, user_id: int | None = None):
|
||||
details = {"max_vendors": max_vendors}
|
||||
if user_id:
|
||||
details["user_id"] = user_id
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
Vendor domain management specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from .base import (BusinessLogicException, ConflictException,
|
||||
ExternalServiceException, ResourceNotFoundException,
|
||||
ValidationException)
|
||||
from .base import (
|
||||
BusinessLogicException,
|
||||
ConflictException,
|
||||
ExternalServiceException,
|
||||
ResourceNotFoundException,
|
||||
ValidationException,
|
||||
)
|
||||
|
||||
|
||||
class VendorDomainNotFoundException(ResourceNotFoundException):
|
||||
@@ -30,7 +33,7 @@ class VendorDomainNotFoundException(ResourceNotFoundException):
|
||||
class VendorDomainAlreadyExistsException(ConflictException):
|
||||
"""Raised when trying to add a domain that already exists."""
|
||||
|
||||
def __init__(self, domain: str, existing_vendor_id: Optional[int] = None):
|
||||
def __init__(self, domain: str, existing_vendor_id: int | None = None):
|
||||
details = {"domain": domain}
|
||||
if existing_vendor_id:
|
||||
details["existing_vendor_id"] = existing_vendor_id
|
||||
@@ -104,7 +107,7 @@ class MultiplePrimaryDomainsException(BusinessLogicException):
|
||||
|
||||
def __init__(self, vendor_id: int):
|
||||
super().__init__(
|
||||
message=f"Vendor can only have one primary domain",
|
||||
message="Vendor can only have one primary domain",
|
||||
error_code="MULTIPLE_PRIMARY_DOMAINS",
|
||||
details={"vendor_id": vendor_id},
|
||||
)
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
Vendor theme management specific exceptions.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
from .base import (BusinessLogicException, ConflictException,
|
||||
ResourceNotFoundException, ValidationException)
|
||||
from .base import (
|
||||
BusinessLogicException,
|
||||
ResourceNotFoundException,
|
||||
ValidationException,
|
||||
)
|
||||
|
||||
|
||||
class VendorThemeNotFoundException(ResourceNotFoundException):
|
||||
@@ -27,8 +30,8 @@ class InvalidThemeDataException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Invalid theme data",
|
||||
field: Optional[str] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
field: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
):
|
||||
super().__init__(
|
||||
message=message,
|
||||
@@ -41,7 +44,7 @@ class InvalidThemeDataException(ValidationException):
|
||||
class ThemePresetNotFoundException(ResourceNotFoundException):
|
||||
"""Raised when a theme preset is not found."""
|
||||
|
||||
def __init__(self, preset_name: str, available_presets: Optional[list] = None):
|
||||
def __init__(self, preset_name: str, available_presets: list | None = None):
|
||||
details = {"preset_name": preset_name}
|
||||
if available_presets:
|
||||
details["available_presets"] = available_presets
|
||||
@@ -61,8 +64,8 @@ class ThemeValidationException(ValidationException):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Theme validation failed",
|
||||
field: Optional[str] = None,
|
||||
validation_errors: Optional[Dict[str, str]] = None,
|
||||
field: str | None = None,
|
||||
validation_errors: dict[str, str] | None = None,
|
||||
):
|
||||
details = {}
|
||||
if validation_errors:
|
||||
|
||||
Reference in New Issue
Block a user