- 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>
204 lines
5.9 KiB
Python
204 lines
5.9 KiB
Python
# app/exceptions/marketplace_import_job.py
|
|
"""
|
|
Marketplace import specific exceptions.
|
|
"""
|
|
|
|
from typing import Any
|
|
|
|
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: str | None = None,
|
|
details: dict[str, Any] | None = None,
|
|
):
|
|
if not details:
|
|
details = {}
|
|
|
|
if marketplace:
|
|
details["marketplace"] = marketplace
|
|
|
|
super().__init__(
|
|
message=message,
|
|
error_code=error_code,
|
|
details=details,
|
|
)
|
|
|
|
|
|
class ImportJobNotFoundException(ResourceNotFoundException):
|
|
"""Raised when import job is not found."""
|
|
|
|
def __init__(self, job_id: int):
|
|
super().__init__(
|
|
resource_type="ImportJob",
|
|
identifier=str(job_id),
|
|
message=f"Import job with ID '{job_id}' not found",
|
|
error_code="IMPORT_JOB_NOT_FOUND",
|
|
)
|
|
|
|
|
|
class ImportJobNotOwnedException(AuthorizationException):
|
|
"""Raised when user tries to access import job they don't own."""
|
|
|
|
def __init__(self, job_id: int, user_id: int | None = None):
|
|
details = {"job_id": job_id}
|
|
if user_id:
|
|
details["user_id"] = user_id
|
|
|
|
super().__init__(
|
|
message=f"Unauthorized access to import job '{job_id}'",
|
|
error_code="IMPORT_JOB_NOT_OWNED",
|
|
details=details,
|
|
)
|
|
|
|
|
|
class InvalidImportDataException(ValidationException):
|
|
"""Raised when import data is invalid."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str = "Invalid import data",
|
|
field: str | None = None,
|
|
row_number: int | None = None,
|
|
details: dict[str, Any] | None = None,
|
|
):
|
|
if not details:
|
|
details = {}
|
|
|
|
if row_number:
|
|
details["row_number"] = row_number
|
|
|
|
super().__init__(
|
|
message=message,
|
|
field=field,
|
|
details=details,
|
|
)
|
|
self.error_code = "INVALID_IMPORT_DATA"
|
|
|
|
|
|
class ImportJobCannotBeCancelledException(BusinessLogicException):
|
|
"""Raised when trying to cancel job that cannot be cancelled."""
|
|
|
|
def __init__(self, job_id: int, current_status: str):
|
|
super().__init__(
|
|
message=f"Import job '{job_id}' cannot be cancelled (current status: {current_status})",
|
|
error_code="IMPORT_JOB_CANNOT_BE_CANCELLED",
|
|
details={
|
|
"job_id": job_id,
|
|
"current_status": current_status,
|
|
},
|
|
)
|
|
|
|
|
|
class ImportJobCannotBeDeletedException(BusinessLogicException):
|
|
"""Raised when trying to delete job that cannot be deleted."""
|
|
|
|
def __init__(self, job_id: int, current_status: str):
|
|
super().__init__(
|
|
message=f"Import job '{job_id}' cannot be deleted (current status: {current_status})",
|
|
error_code="IMPORT_JOB_CANNOT_BE_DELETED",
|
|
details={
|
|
"job_id": job_id,
|
|
"current_status": current_status,
|
|
},
|
|
)
|
|
|
|
|
|
class MarketplaceConnectionException(ExternalServiceException):
|
|
"""Raised when marketplace connection fails."""
|
|
|
|
def __init__(
|
|
self, marketplace: str, message: str = "Failed to connect to marketplace"
|
|
):
|
|
super().__init__(
|
|
service=marketplace,
|
|
message=f"{message}: {marketplace}",
|
|
error_code="MARKETPLACE_CONNECTION_FAILED",
|
|
)
|
|
|
|
|
|
class MarketplaceDataParsingException(ValidationException):
|
|
"""Raised when marketplace data cannot be parsed."""
|
|
|
|
def __init__(
|
|
self,
|
|
marketplace: str,
|
|
message: str = "Failed to parse marketplace data",
|
|
details: dict[str, Any] | None = None,
|
|
):
|
|
if not details:
|
|
details = {}
|
|
details["marketplace"] = marketplace
|
|
|
|
super().__init__(
|
|
message=f"{message} from {marketplace}",
|
|
details=details,
|
|
)
|
|
self.error_code = "MARKETPLACE_DATA_PARSING_FAILED"
|
|
|
|
|
|
class ImportRateLimitException(BusinessLogicException):
|
|
"""Raised when import rate limit is exceeded."""
|
|
|
|
def __init__(
|
|
self,
|
|
max_imports: int,
|
|
time_window: str,
|
|
retry_after: int | None = None,
|
|
):
|
|
details = {
|
|
"max_imports": max_imports,
|
|
"time_window": time_window,
|
|
}
|
|
|
|
if retry_after:
|
|
details["retry_after"] = retry_after
|
|
|
|
super().__init__(
|
|
message=f"Import rate limit exceeded: {max_imports} imports per {time_window}",
|
|
error_code="IMPORT_RATE_LIMIT_EXCEEDED",
|
|
details=details,
|
|
)
|
|
|
|
|
|
class InvalidMarketplaceException(ValidationException):
|
|
"""Raised when marketplace is not supported."""
|
|
|
|
def __init__(self, marketplace: str, supported_marketplaces: list | None = None):
|
|
details = {"marketplace": marketplace}
|
|
if supported_marketplaces:
|
|
details["supported_marketplaces"] = supported_marketplaces
|
|
|
|
super().__init__(
|
|
message=f"Unsupported marketplace: {marketplace}",
|
|
field="marketplace",
|
|
details=details,
|
|
)
|
|
self.error_code = "INVALID_MARKETPLACE"
|
|
|
|
|
|
class ImportJobAlreadyProcessingException(BusinessLogicException):
|
|
"""Raised when trying to start import while another is already processing."""
|
|
|
|
def __init__(self, vendor_code: str, existing_job_id: int):
|
|
super().__init__(
|
|
message=f"Import already in progress for vendor '{vendor_code}'",
|
|
error_code="IMPORT_JOB_ALREADY_PROCESSING",
|
|
details={
|
|
"vendor_code": vendor_code,
|
|
"existing_job_id": existing_job_id,
|
|
},
|
|
)
|