mycopunk-swag/cli/mycopunk/pod/base.py

153 lines
3.6 KiB
Python

"""
Base class for POD provider integrations.
"""
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Optional, Any
from dataclasses import dataclass
@dataclass
class ProductResult:
"""Result of a product creation/update operation."""
success: bool
product_id: Optional[str] = None
error: Optional[str] = None
data: Optional[dict] = None
@dataclass
class MockupResult:
"""Result of a mockup generation operation."""
success: bool
image_url: Optional[str] = None
local_path: Optional[Path] = None
error: Optional[str] = None
class PODProvider(ABC):
"""Abstract base class for print-on-demand providers."""
name: str = "base"
def __init__(self, api_key: str, sandbox: bool = False) -> None:
self.api_key = api_key
self.sandbox = sandbox
self._validate_credentials()
@abstractmethod
def _validate_credentials(self) -> None:
"""Validate API credentials."""
pass
@abstractmethod
async def create_product(
self,
design_path: Path,
metadata: dict,
product_config: dict,
) -> ProductResult:
"""
Create a new product on the POD service.
Args:
design_path: Path to the design file (PNG)
metadata: Design metadata from metadata.yaml
product_config: Product configuration from products.yaml
Returns:
ProductResult with product_id if successful
"""
pass
@abstractmethod
async def update_product(
self,
product_id: str,
design_path: Path,
metadata: dict,
) -> ProductResult:
"""
Update an existing product.
Args:
product_id: Provider's product ID
design_path: Path to updated design file
metadata: Updated metadata
Returns:
ProductResult indicating success/failure
"""
pass
@abstractmethod
async def generate_mockup(
self,
product_id: str,
variant: Optional[str] = None,
) -> MockupResult:
"""
Generate a product mockup.
Args:
product_id: Provider's product ID
variant: Optional variant (color, size) for mockup
Returns:
MockupResult with image URL or local path
"""
pass
@abstractmethod
async def get_product(self, product_id: str) -> Optional[dict]:
"""
Get product details from the provider.
Args:
product_id: Provider's product ID
Returns:
Product data dict or None if not found
"""
pass
@abstractmethod
async def list_products(self, limit: int = 100) -> list[dict]:
"""
List products from the provider.
Args:
limit: Maximum number of products to return
Returns:
List of product data dicts
"""
pass
@abstractmethod
async def get_catalog(self, product_type: Optional[str] = None) -> list[dict]:
"""
Get available products from provider catalog.
Args:
product_type: Optional filter by type (sticker, tshirt, etc)
Returns:
List of catalog items
"""
pass
@abstractmethod
async def upload_file(self, file_path: Path) -> Optional[str]:
"""
Upload a file to the provider.
Args:
file_path: Local path to file
Returns:
File URL or ID from provider, or None on failure
"""
pass