test updates to take into account exception management

This commit is contained in:
2025-09-27 13:47:36 +02:00
parent 3e720212d9
commit 6b9817f179
38 changed files with 2951 additions and 871 deletions

View File

@@ -8,9 +8,10 @@ This module provides classes and functions for:
- Stock information integration
- CSV export functionality
"""
import csv
import logging
from datetime import datetime, timezone
from io import StringIO
from typing import Generator, List, Optional, Tuple
from sqlalchemy.exc import IntegrityError
@@ -41,21 +42,7 @@ class ProductService:
self.price_processor = PriceProcessor()
def create_product(self, db: Session, product_data: ProductCreate) -> Product:
"""
Create a new product with validation.
Args:
db: Database session
product_data: Product creation data
Returns:
Created Product object
Raises:
ProductAlreadyExistsException: If product with ID already exists
InvalidProductDataException: If product data is invalid
ProductValidationException: If validation fails
"""
"""Create a new product with validation."""
try:
# Process and validate GTIN if provided
if product_data.gtin:
@@ -73,8 +60,9 @@ class ProductService:
if parsed_price:
product_data.price = parsed_price
product_data.currency = currency
except Exception as e:
raise InvalidProductDataException(f"Invalid price format: {str(e)}", field="price")
except ValueError as e:
# Convert ValueError to domain-specific exception
raise InvalidProductDataException(str(e), field="price")
# Set default marketplace if not provided
if not product_data.marketplace:
@@ -199,25 +187,8 @@ class ProductService:
logger.error(f"Error getting products with filters: {str(e)}")
raise ValidationException("Failed to retrieve products")
def update_product(
self, db: Session, product_id: str, product_update: ProductUpdate
) -> Product:
"""
Update product with validation.
Args:
db: Database session
product_id: Product ID to update
product_update: Update data
Returns:
Updated Product object
Raises:
ProductNotFoundException: If product doesn't exist
InvalidProductDataException: If update data is invalid
ProductValidationException: If validation fails
"""
def update_product(self, db: Session, product_id: str, product_update: ProductUpdate) -> Product:
"""Update product with validation."""
try:
product = self.get_product_by_id_or_raise(db, product_id)
@@ -240,8 +211,9 @@ class ProductService:
if parsed_price:
update_data["price"] = parsed_price
update_data["currency"] = currency
except Exception as e:
raise InvalidProductDataException(f"Invalid price format: {str(e)}", field="price")
except ValueError as e:
# Convert ValueError to domain-specific exception
raise InvalidProductDataException(str(e), field="price")
# Validate required fields if being updated
if "title" in update_data and (not update_data["title"] or not update_data["title"].strip()):
@@ -329,6 +301,11 @@ class ProductService:
logger.error(f"Error getting stock info for GTIN {gtin}: {str(e)}")
return None
import csv
from io import StringIO
from typing import Generator, Optional
from sqlalchemy.orm import Session
def generate_csv_export(
self,
db: Session,
@@ -336,7 +313,7 @@ class ProductService:
shop_name: Optional[str] = None,
) -> Generator[str, None, None]:
"""
Generate CSV export with streaming for memory efficiency.
Generate CSV export with streaming for memory efficiency and proper CSV escaping.
Args:
db: Database session
@@ -344,14 +321,25 @@ class ProductService:
shop_name: Optional shop name filter
Yields:
CSV content as strings
CSV content as strings with proper escaping
"""
try:
# CSV header
yield (
"product_id,title,description,link,image_link,availability,price,currency,brand,"
"gtin,marketplace,shop_name\n"
)
# Create a StringIO buffer for CSV writing
output = StringIO()
writer = csv.writer(output, quoting=csv.QUOTE_MINIMAL)
# Write header row
headers = [
"product_id", "title", "description", "link", "image_link",
"availability", "price", "currency", "brand", "gtin",
"marketplace", "shop_name"
]
writer.writerow(headers)
yield output.getvalue()
# Clear buffer for reuse
output.seek(0)
output.truncate(0)
batch_size = 1000
offset = 0
@@ -370,14 +358,28 @@ class ProductService:
break
for product in products:
# Create CSV row with marketplace fields
row = (
f'"{product.product_id}","{product.title or ""}","{product.description or ""}",'
f'"{product.link or ""}","{product.image_link or ""}","{product.availability or ""}",'
f'"{product.price or ""}","{product.currency or ""}","{product.brand or ""}",'
f'"{product.gtin or ""}","{product.marketplace or ""}","{product.shop_name or ""}"\n'
)
yield row
# Create CSV row with proper escaping
row_data = [
product.product_id or "",
product.title or "",
product.description or "",
product.link or "",
product.image_link or "",
product.availability or "",
product.price or "",
product.currency or "",
product.brand or "",
product.gtin or "",
product.marketplace or "",
product.shop_name or "",
]
writer.writerow(row_data)
yield output.getvalue()
# Clear buffer for next row
output.seek(0)
output.truncate(0)
offset += batch_size