fix: ruff lint + format fixes in tests, ESLint fixes in frontend

This commit is contained in:
2026-07-17 21:28:58 +02:00
parent 341d0c6f38
commit fbb1b39b57
56 changed files with 1399 additions and 721 deletions
+5 -5
View File
@@ -39,7 +39,9 @@ async def get_user_by_id(db: AsyncSession, user_id: uuid.UUID) -> Optional[User]
return result.scalar_one_or_none()
async def authenticate_user(db: AsyncSession, email: str, password: str) -> Optional[User]:
async def authenticate_user(
db: AsyncSession, email: str, password: str
) -> Optional[User]:
"""Authenticate a user by email and password."""
user = await get_user_by_email(db, email)
if user is None:
@@ -67,6 +69,7 @@ def generate_token_pair(user: User) -> dict:
lang=user.language,
)
from app.config import settings
return {
"access_token": access_token,
"refresh_token": refresh_token,
@@ -135,10 +138,7 @@ async def list_users(
offset = (page - 1) * page_size
result = await db.execute(
select(User)
.order_by(User.created_at.desc())
.offset(offset)
.limit(page_size)
select(User).order_by(User.created_at.desc()).offset(offset).limit(page_size)
)
users = list(result.scalars().all())
return users, total
+3 -9
View File
@@ -137,24 +137,18 @@ async def list_contacts(
return contacts, total
async def get_contact_by_id(
db: AsyncSession, contact_id: uuid.UUID
) -> Contact | None:
async def get_contact_by_id(db: AsyncSession, contact_id: uuid.UUID) -> Contact | None:
"""Get a single contact by ID, excluding soft-deleted. Eager-loads contact persons."""
stmt = (
select(Contact)
.options(selectinload(Contact.contact_persons))
.where(
and_(Contact.id == contact_id, Contact.deleted_at.is_(None))
)
.where(and_(Contact.id == contact_id, Contact.deleted_at.is_(None)))
)
result = await db.execute(stmt)
return result.scalar_one_or_none()
async def create_contact(
db: AsyncSession, data: dict[str, Any]
) -> Contact:
async def create_contact(db: AsyncSession, data: dict[str, Any]) -> Contact:
"""Create a new contact with optional nested contact persons.
The data dict may contain a 'contact_persons' list of dicts.
+9 -5
View File
@@ -74,10 +74,12 @@ def _parse_ai_response(raw_content: str) -> dict[str, Any]:
valid_actions = []
for action in actions:
if isinstance(action, dict) and "type" in action:
valid_actions.append({
"type": action["type"],
"params": action.get("params", {}),
})
valid_actions.append(
{
"type": action["type"],
"params": action.get("params", {}),
}
)
return {"response": response_text, "actions": valid_actions}
@@ -172,7 +174,9 @@ async def chat(
6. Save the assistant message
7. Return response with actions and IDs
"""
session = await _get_or_create_session(db, user_id, session_id, first_message=message)
session = await _get_or_create_session(
db, user_id, session_id, first_message=message
)
# Save user message
user_msg = CopilotChat(
+4 -4
View File
@@ -60,9 +60,7 @@ async def create_export(
csv_content = generate_datev_csv(sales)
# Calculate total amount
total_amount = sum(
(s.sale_price or Decimal("0")) for s in sales
)
total_amount = sum((s.sale_price or Decimal("0")) for s in sales)
# Save CSV file
os.makedirs(output_dir, exist_ok=True)
@@ -111,7 +109,9 @@ async def list_exports(
return exports, total
async def get_export_csv(db: AsyncSession, export_id: uuid.UUID) -> tuple[str, bytes] | None:
async def get_export_csv(
db: AsyncSession, export_id: uuid.UUID
) -> tuple[str, bytes] | None:
"""Get the CSV content for a DATEV export.
Args:
+4 -4
View File
@@ -98,7 +98,9 @@ async def upload_file(
"""
# Validate MIME type
if not validate_mime_type(mime_type, original_filename):
raise ValueError(f"Unsupported MIME type: {mime_type} for file: {original_filename}")
raise ValueError(
f"Unsupported MIME type: {mime_type} for file: {original_filename}"
)
# Validate file size (20MB limit for uploads)
file_size = len(file_content)
@@ -173,9 +175,7 @@ async def list_files(
Returns (files, total_count).
"""
# Count total files for this vehicle
count_stmt = select(func.count(File.id)).where(
File.vehicle_id == vehicle_id
)
count_stmt = select(func.count(File.id)).where(File.vehicle_id == vehicle_id)
count_result = await db.execute(count_stmt)
total = count_result.scalar_one()
+3 -8
View File
@@ -48,9 +48,7 @@ def _get_status_url(listing_id: str) -> str:
return f"{_MOBILE_DE_API_BASE}/api/seller/listings/{listing_id}/status"
async def push_listing(
db: AsyncSession, vehicle: Vehicle
) -> MobileDeListing:
async def push_listing(db: AsyncSession, vehicle: Vehicle) -> MobileDeListing:
"""Push a vehicle listing to mobile.de.
Creates a MobileDeListing record with status 'pending',
@@ -150,9 +148,7 @@ async def update_listing(
return listing
async def delete_listing(
db: AsyncSession, listing: MobileDeListing
) -> MobileDeListing:
async def delete_listing(db: AsyncSession, listing: MobileDeListing) -> MobileDeListing:
"""Delete a listing from mobile.de.
Sends DELETE /api/seller/listings/{id}.
@@ -228,8 +224,7 @@ async def retry_failed_listing(
if retry_count >= MAX_RETRIES:
listing.sync_status = "fehler"
listing.error_log = (
f"Max retries ({MAX_RETRIES}) exceeded. "
f"Last error: {listing.error_log}"
f"Max retries ({MAX_RETRIES}) exceeded. Last error: {listing.error_log}"
)
await db.flush()
await db.refresh(listing)
+6 -4
View File
@@ -46,12 +46,12 @@ async def upload_file(
Validates MIME type and file size before saving.
"""
if not validate_mime_type(mime_type):
raise ValueError(f"Invalid MIME type: {mime_type}. Allowed: {ALLOWED_MIME_TYPES}")
raise ValueError(
f"Invalid MIME type: {mime_type}. Allowed: {ALLOWED_MIME_TYPES}"
)
if not validate_file_size(len(file_bytes)):
raise ValueError(
f"File size exceeds limit of {settings.MAX_FILE_SIZE_MB} MB"
)
raise ValueError(f"File size exceeds limit of {settings.MAX_FILE_SIZE_MB} MB")
# Ensure upload directory exists
upload_dir = settings.UPLOAD_DIR
@@ -173,6 +173,7 @@ async def apply_to_vehicle(
if ocr_field == "first_registration" and isinstance(value, str):
try:
from datetime import datetime as dt
parsed = dt.strptime(value, "%d.%m.%Y").date()
setattr(vehicle, vehicle_field, parsed)
updated_fields.append(vehicle_field)
@@ -180,6 +181,7 @@ async def apply_to_vehicle(
except ValueError:
try:
from datetime import date
parsed = date.fromisoformat(value)
setattr(vehicle, vehicle_field, parsed)
updated_fields.append(vehicle_field)
@@ -82,7 +82,9 @@ async def compare_prices(
# Calculate average price
if listings:
average_price = round(sum(listing.price for listing in listings) / len(listings), 2)
average_price = round(
sum(listing.price for listing in listings) / len(listings), 2
)
else:
average_price = None
+11 -3
View File
@@ -80,7 +80,9 @@ def generate_retouch_prompt(vehicle_info: dict[str, Any] | None = None) -> str:
if make and model:
parts.append(f"The vehicle is a {make} {model}.")
if color:
parts.append(f"The vehicle color is {color}; ensure it looks accurate and rich.")
parts.append(
f"The vehicle color is {color}; ensure it looks accurate and rich."
)
return " ".join(parts)
return base_prompt
@@ -98,7 +100,9 @@ async def upload_retouch_file(
Raises ValueError for invalid MIME type or file size.
"""
if not validate_mime_type(mime_type):
raise ValueError(f"Invalid MIME type: {mime_type}. Only image/* types are allowed.")
raise ValueError(
f"Invalid MIME type: {mime_type}. Only image/* types are allowed."
)
if not validate_file_size(len(file_bytes)):
raise ValueError(f"File size exceeds limit of {settings.MAX_FILE_SIZE_MB} MB")
@@ -151,7 +155,11 @@ async def list_results(
total = total_result.scalar_one()
offset = (page - 1) * page_size
data_stmt = data_stmt.order_by(RetouchResult.created_at.desc()).offset(offset).limit(page_size)
data_stmt = (
data_stmt.order_by(RetouchResult.created_at.desc())
.offset(offset)
.limit(page_size)
)
result = await db.execute(data_stmt)
items = list(result.scalars().all())
+4 -12
View File
@@ -131,9 +131,7 @@ async def list_vehicles(
return vehicles, total
async def get_vehicle_by_id(
db: AsyncSession, vehicle_id: uuid.UUID
) -> Vehicle | None:
async def get_vehicle_by_id(db: AsyncSession, vehicle_id: uuid.UUID) -> Vehicle | None:
"""Get a single vehicle by ID, excluding soft-deleted."""
stmt = select(Vehicle).where(
and_(Vehicle.id == vehicle_id, Vehicle.deleted_at.is_(None))
@@ -142,20 +140,14 @@ async def get_vehicle_by_id(
return result.scalar_one_or_none()
async def get_vehicle_by_fin(
db: AsyncSession, fin: str
) -> Vehicle | None:
async def get_vehicle_by_fin(db: AsyncSession, fin: str) -> Vehicle | None:
"""Get a single vehicle by FIN, excluding soft-deleted."""
stmt = select(Vehicle).where(
and_(Vehicle.fin == fin, Vehicle.deleted_at.is_(None))
)
stmt = select(Vehicle).where(and_(Vehicle.fin == fin, Vehicle.deleted_at.is_(None)))
result = await db.execute(stmt)
return result.scalar_one_or_none()
async def create_vehicle(
db: AsyncSession, data: dict[str, Any]
) -> Vehicle:
async def create_vehicle(db: AsyncSession, data: dict[str, Any]) -> Vehicle:
"""Create a new vehicle.
Raises ValueError if FIN already exists.