Refactor test files for improved readability and consistency
- Removed unnecessary blank lines and adjusted formatting in test files. - Ensured consistent use of commas in function calls and assertions across various test cases. - Updated import statements for better organization and clarity. - Enhanced mock setups in tests for better isolation and reliability. - Improved assertions to follow a consistent style for better readability.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"""Player API endpoints."""
|
||||
|
||||
from typing import Annotated, Any
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
|
||||
@@ -214,4 +214,4 @@ async def get_state(
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to get player state",
|
||||
) from e
|
||||
) from e
|
||||
|
||||
@@ -10,12 +10,12 @@ from app.core.dependencies import get_current_active_user_flexible
|
||||
from app.models.credit_action import CreditActionType
|
||||
from app.models.user import User
|
||||
from app.repositories.sound import SoundRepository
|
||||
from app.services.extraction import ExtractionInfo, ExtractionService
|
||||
from app.services.credit import CreditService, InsufficientCreditsError
|
||||
from app.services.extraction import ExtractionInfo, ExtractionService
|
||||
from app.services.extraction_processor import extraction_processor
|
||||
from app.services.sound_normalizer import NormalizationResults, SoundNormalizerService
|
||||
from app.services.sound_scanner import ScanResults, SoundScannerService
|
||||
from app.services.vlc_player import get_vlc_player_service, VLCPlayerService
|
||||
from app.services.vlc_player import VLCPlayerService, get_vlc_player_service
|
||||
|
||||
router = APIRouter(prefix="/sounds", tags=["sounds"])
|
||||
|
||||
@@ -125,13 +125,13 @@ async def scan_custom_directory(
|
||||
async def normalize_all_sounds(
|
||||
current_user: Annotated[User, Depends(get_current_active_user_flexible)],
|
||||
normalizer_service: Annotated[
|
||||
SoundNormalizerService, Depends(get_sound_normalizer_service)
|
||||
SoundNormalizerService, Depends(get_sound_normalizer_service),
|
||||
],
|
||||
force: bool = Query(
|
||||
False, description="Force normalization of already normalized sounds"
|
||||
False, description="Force normalization of already normalized sounds",
|
||||
),
|
||||
one_pass: bool | None = Query(
|
||||
None, description="Use one-pass normalization (overrides config)"
|
||||
None, description="Use one-pass normalization (overrides config)",
|
||||
),
|
||||
) -> dict[str, NormalizationResults | str]:
|
||||
"""Normalize all unnormalized sounds."""
|
||||
@@ -163,13 +163,13 @@ async def normalize_sounds_by_type(
|
||||
sound_type: str,
|
||||
current_user: Annotated[User, Depends(get_current_active_user_flexible)],
|
||||
normalizer_service: Annotated[
|
||||
SoundNormalizerService, Depends(get_sound_normalizer_service)
|
||||
SoundNormalizerService, Depends(get_sound_normalizer_service),
|
||||
],
|
||||
force: bool = Query(
|
||||
False, description="Force normalization of already normalized sounds"
|
||||
False, description="Force normalization of already normalized sounds",
|
||||
),
|
||||
one_pass: bool | None = Query(
|
||||
None, description="Use one-pass normalization (overrides config)"
|
||||
None, description="Use one-pass normalization (overrides config)",
|
||||
),
|
||||
) -> dict[str, NormalizationResults | str]:
|
||||
"""Normalize all sounds of a specific type (SDB, TTS, EXT)."""
|
||||
@@ -210,13 +210,13 @@ async def normalize_sound_by_id(
|
||||
sound_id: int,
|
||||
current_user: Annotated[User, Depends(get_current_active_user_flexible)],
|
||||
normalizer_service: Annotated[
|
||||
SoundNormalizerService, Depends(get_sound_normalizer_service)
|
||||
SoundNormalizerService, Depends(get_sound_normalizer_service),
|
||||
],
|
||||
force: bool = Query(
|
||||
False, description="Force normalization of already normalized sound"
|
||||
False, description="Force normalization of already normalized sound",
|
||||
),
|
||||
one_pass: bool | None = Query(
|
||||
None, description="Use one-pass normalization (overrides config)"
|
||||
None, description="Use one-pass normalization (overrides config)",
|
||||
),
|
||||
) -> dict[str, str]:
|
||||
"""Normalize a specific sound by ID."""
|
||||
@@ -283,7 +283,7 @@ async def create_extraction(
|
||||
)
|
||||
|
||||
extraction_info = await extraction_service.create_extraction(
|
||||
url, current_user.id
|
||||
url, current_user.id,
|
||||
)
|
||||
|
||||
# Queue the extraction for background processing
|
||||
@@ -398,7 +398,7 @@ async def play_sound_with_vlc(
|
||||
await credit_service.validate_and_reserve_credits(
|
||||
current_user.id,
|
||||
CreditActionType.VLC_PLAY_SOUND,
|
||||
{"sound_id": sound_id, "sound_name": sound.name}
|
||||
{"sound_id": sound_id, "sound_name": sound.name},
|
||||
)
|
||||
except InsufficientCreditsError as e:
|
||||
raise HTTPException(
|
||||
@@ -408,7 +408,7 @@ async def play_sound_with_vlc(
|
||||
|
||||
# Play the sound using VLC
|
||||
success = await vlc_player.play_sound(sound)
|
||||
|
||||
|
||||
# Deduct credits based on success
|
||||
await credit_service.deduct_credits(
|
||||
current_user.id,
|
||||
@@ -416,7 +416,7 @@ async def play_sound_with_vlc(
|
||||
success,
|
||||
{"sound_id": sound_id, "sound_name": sound.name},
|
||||
)
|
||||
|
||||
|
||||
if not success:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
|
||||
@@ -118,4 +118,4 @@ def get_all_credit_actions() -> dict[CreditActionType, CreditAction]:
|
||||
Dictionary of all credit actions
|
||||
|
||||
"""
|
||||
return CREDIT_ACTIONS.copy()
|
||||
return CREDIT_ACTIONS.copy()
|
||||
|
||||
@@ -26,4 +26,4 @@ class CreditTransaction(BaseModel, table=True):
|
||||
metadata_json: str | None = Field(default=None)
|
||||
|
||||
# relationships
|
||||
user: "User" = Relationship(back_populates="credit_transactions")
|
||||
user: "User" = Relationship(back_populates="credit_transactions")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlmodel import Field, Relationship, UniqueConstraint
|
||||
from sqlmodel import Field, Relationship
|
||||
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ __all__ = [
|
||||
"UserResponse",
|
||||
# Common schemas
|
||||
"HealthResponse",
|
||||
"MessageResponse",
|
||||
"MessageResponse",
|
||||
"StatusResponse",
|
||||
# Player schemas
|
||||
"PlayerModeRequest",
|
||||
|
||||
@@ -18,4 +18,4 @@ class StatusResponse(BaseModel):
|
||||
class HealthResponse(BaseModel):
|
||||
"""Health check response."""
|
||||
|
||||
status: str = Field(description="Health status")
|
||||
status: str = Field(description="Health status")
|
||||
|
||||
@@ -30,10 +30,10 @@ class PlayerStateResponse(BaseModel):
|
||||
|
||||
status: str = Field(description="Player status (playing, paused, stopped)")
|
||||
current_sound: dict[str, Any] | None = Field(
|
||||
None, description="Current sound information"
|
||||
None, description="Current sound information",
|
||||
)
|
||||
playlist: dict[str, Any] | None = Field(
|
||||
None, description="Current playlist information"
|
||||
None, description="Current playlist information",
|
||||
)
|
||||
position: int = Field(description="Current position in milliseconds")
|
||||
duration: int | None = Field(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Playlist schemas."""
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.models.playlist import Playlist
|
||||
from app.models.sound import Sound
|
||||
|
||||
@@ -30,7 +30,7 @@ class InsufficientCreditsError(Exception):
|
||||
self.required = required
|
||||
self.available = available
|
||||
super().__init__(
|
||||
f"Insufficient credits: {required} required, {available} available"
|
||||
f"Insufficient credits: {required} required, {available} available",
|
||||
)
|
||||
|
||||
|
||||
@@ -138,10 +138,10 @@ class CreditService:
|
||||
|
||||
"""
|
||||
action = get_credit_action(action_type)
|
||||
|
||||
|
||||
# Only deduct if action requires success and was successful, or doesn't require success
|
||||
should_deduct = (action.requires_success and success) or not action.requires_success
|
||||
|
||||
|
||||
if not should_deduct:
|
||||
logger.info(
|
||||
"Skipping credit deduction for user %s: action %s failed and requires success",
|
||||
@@ -150,7 +150,7 @@ class CreditService:
|
||||
)
|
||||
# Still create a transaction record for auditing
|
||||
return await self._create_transaction_record(
|
||||
user_id, action, 0, success, metadata
|
||||
user_id, action, 0, success, metadata,
|
||||
)
|
||||
|
||||
session = self.db_session_factory()
|
||||
@@ -380,4 +380,4 @@ class CreditService:
|
||||
raise ValueError(msg)
|
||||
return user.credits
|
||||
finally:
|
||||
await session.close()
|
||||
await session.close()
|
||||
|
||||
@@ -10,7 +10,6 @@ from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.logging import get_logger
|
||||
from app.models.extraction import Extraction
|
||||
from app.models.sound import Sound
|
||||
from app.repositories.extraction import ExtractionRepository
|
||||
from app.repositories.sound import SoundRepository
|
||||
@@ -155,7 +154,7 @@ class ExtractionService:
|
||||
|
||||
# Check if extraction already exists for this service
|
||||
existing = await self.extraction_repo.get_by_service_and_id(
|
||||
service_info["service"], service_info["service_id"]
|
||||
service_info["service"], service_info["service_id"],
|
||||
)
|
||||
if existing and existing.id != extraction_id:
|
||||
error_msg = (
|
||||
@@ -180,7 +179,7 @@ class ExtractionService:
|
||||
|
||||
# Extract audio and thumbnail
|
||||
audio_file, thumbnail_file = await self._extract_media(
|
||||
extraction_id, extraction_url
|
||||
extraction_id, extraction_url,
|
||||
)
|
||||
|
||||
# Move files to final locations
|
||||
@@ -238,7 +237,7 @@ class ExtractionService:
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
logger.exception(
|
||||
"Failed to process extraction %d: %s", extraction_id, error_msg
|
||||
"Failed to process extraction %d: %s", extraction_id, error_msg,
|
||||
)
|
||||
|
||||
# Update extraction with error
|
||||
@@ -262,14 +261,14 @@ class ExtractionService:
|
||||
}
|
||||
|
||||
async def _extract_media(
|
||||
self, extraction_id: int, extraction_url: str
|
||||
self, extraction_id: int, extraction_url: str,
|
||||
) -> tuple[Path, Path | None]:
|
||||
"""Extract audio and thumbnail using yt-dlp."""
|
||||
temp_dir = Path(settings.EXTRACTION_TEMP_DIR)
|
||||
|
||||
# Create unique filename based on extraction ID
|
||||
output_template = str(
|
||||
temp_dir / f"extraction_{extraction_id}_%(title)s.%(ext)s"
|
||||
temp_dir / f"extraction_{extraction_id}_%(title)s.%(ext)s",
|
||||
)
|
||||
|
||||
# Configure yt-dlp options
|
||||
@@ -304,8 +303,8 @@ class ExtractionService:
|
||||
# Find the extracted files
|
||||
audio_files = list(
|
||||
temp_dir.glob(
|
||||
f"extraction_{extraction_id}_*.{settings.EXTRACTION_AUDIO_FORMAT}"
|
||||
)
|
||||
f"extraction_{extraction_id}_*.{settings.EXTRACTION_AUDIO_FORMAT}",
|
||||
),
|
||||
)
|
||||
thumbnail_files = (
|
||||
list(temp_dir.glob(f"extraction_{extraction_id}_*.webp"))
|
||||
@@ -342,7 +341,7 @@ class ExtractionService:
|
||||
"""Move extracted files to their final locations."""
|
||||
# Generate clean filename based on title and service
|
||||
safe_title = self._sanitize_filename(
|
||||
title or f"{service or 'unknown'}_{service_id or 'unknown'}"
|
||||
title or f"{service or 'unknown'}_{service_id or 'unknown'}",
|
||||
)
|
||||
|
||||
# Move audio file
|
||||
|
||||
@@ -46,9 +46,9 @@ class ExtractionProcessor:
|
||||
if self.processor_task and not self.processor_task.done():
|
||||
try:
|
||||
await asyncio.wait_for(self.processor_task, timeout=30.0)
|
||||
except asyncio.TimeoutError:
|
||||
except TimeoutError:
|
||||
logger.warning(
|
||||
"Extraction processor did not stop gracefully, cancelling..."
|
||||
"Extraction processor did not stop gracefully, cancelling...",
|
||||
)
|
||||
self.processor_task.cancel()
|
||||
try:
|
||||
@@ -66,7 +66,7 @@ class ExtractionProcessor:
|
||||
# The processor will pick it up on the next cycle
|
||||
else:
|
||||
logger.warning(
|
||||
"Extraction %d is already being processed", extraction_id
|
||||
"Extraction %d is already being processed", extraction_id,
|
||||
)
|
||||
|
||||
async def _process_queue(self) -> None:
|
||||
@@ -81,7 +81,7 @@ class ExtractionProcessor:
|
||||
try:
|
||||
await asyncio.wait_for(self.shutdown_event.wait(), timeout=5.0)
|
||||
break # Shutdown requested
|
||||
except asyncio.TimeoutError:
|
||||
except TimeoutError:
|
||||
continue # Continue processing
|
||||
|
||||
except Exception as e:
|
||||
@@ -90,7 +90,7 @@ class ExtractionProcessor:
|
||||
try:
|
||||
await asyncio.wait_for(self.shutdown_event.wait(), timeout=10.0)
|
||||
break # Shutdown requested
|
||||
except asyncio.TimeoutError:
|
||||
except TimeoutError:
|
||||
continue
|
||||
|
||||
logger.info("Extraction queue processor stopped")
|
||||
@@ -125,13 +125,13 @@ class ExtractionProcessor:
|
||||
|
||||
# Start processing this extraction in the background
|
||||
task = asyncio.create_task(
|
||||
self._process_single_extraction(extraction_id)
|
||||
self._process_single_extraction(extraction_id),
|
||||
)
|
||||
task.add_done_callback(
|
||||
lambda t, eid=extraction_id: self._on_extraction_completed(
|
||||
eid,
|
||||
t,
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
logger.info(
|
||||
|
||||
@@ -49,7 +49,7 @@ class PlaylistService:
|
||||
if not main_playlist:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Main playlist not found. Make sure to run database seeding."
|
||||
detail="Main playlist not found. Make sure to run database seeding.",
|
||||
)
|
||||
|
||||
return main_playlist
|
||||
@@ -179,7 +179,7 @@ class PlaylistService:
|
||||
return await self.playlist_repo.get_playlist_sounds(playlist_id)
|
||||
|
||||
async def add_sound_to_playlist(
|
||||
self, playlist_id: int, sound_id: int, user_id: int, position: int | None = None
|
||||
self, playlist_id: int, sound_id: int, user_id: int, position: int | None = None,
|
||||
) -> None:
|
||||
"""Add a sound to a playlist."""
|
||||
# Verify playlist exists
|
||||
@@ -202,11 +202,11 @@ class PlaylistService:
|
||||
|
||||
await self.playlist_repo.add_sound_to_playlist(playlist_id, sound_id, position)
|
||||
logger.info(
|
||||
"Added sound %s to playlist %s for user %s", sound_id, playlist_id, user_id
|
||||
"Added sound %s to playlist %s for user %s", sound_id, playlist_id, user_id,
|
||||
)
|
||||
|
||||
async def remove_sound_from_playlist(
|
||||
self, playlist_id: int, sound_id: int, user_id: int
|
||||
self, playlist_id: int, sound_id: int, user_id: int,
|
||||
) -> None:
|
||||
"""Remove a sound from a playlist."""
|
||||
# Verify playlist exists
|
||||
@@ -228,7 +228,7 @@ class PlaylistService:
|
||||
)
|
||||
|
||||
async def reorder_playlist_sounds(
|
||||
self, playlist_id: int, user_id: int, sound_positions: list[tuple[int, int]]
|
||||
self, playlist_id: int, user_id: int, sound_positions: list[tuple[int, int]],
|
||||
) -> None:
|
||||
"""Reorder sounds in a playlist."""
|
||||
# Verify playlist exists
|
||||
@@ -262,7 +262,7 @@ class PlaylistService:
|
||||
await self._unset_current_playlist(user_id)
|
||||
await self._set_main_as_current(user_id)
|
||||
logger.info(
|
||||
"Unset current playlist and set main as current for user %s", user_id
|
||||
"Unset current playlist and set main as current for user %s", user_id,
|
||||
)
|
||||
|
||||
async def get_playlist_stats(self, playlist_id: int) -> dict[str, Any]:
|
||||
@@ -290,7 +290,7 @@ class PlaylistService:
|
||||
|
||||
# Check if sound is already in main playlist
|
||||
if not await self.playlist_repo.is_sound_in_playlist(
|
||||
main_playlist.id, sound_id
|
||||
main_playlist.id, sound_id,
|
||||
):
|
||||
await self.playlist_repo.add_sound_to_playlist(main_playlist.id, sound_id)
|
||||
logger.info(
|
||||
|
||||
@@ -141,7 +141,7 @@ class SoundNormalizerService:
|
||||
ffmpeg.run(stream, quiet=True, overwrite_output=True)
|
||||
logger.info("One-pass normalization completed: %s", output_path)
|
||||
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.exception("One-pass normalization failed for %s", input_path)
|
||||
raise
|
||||
|
||||
@@ -153,7 +153,7 @@ class SoundNormalizerService:
|
||||
"""Normalize audio using two-pass loudnorm for better quality."""
|
||||
try:
|
||||
logger.info(
|
||||
"Starting two-pass normalization: %s -> %s", input_path, output_path
|
||||
"Starting two-pass normalization: %s -> %s", input_path, output_path,
|
||||
)
|
||||
|
||||
# First pass: analyze
|
||||
@@ -193,7 +193,7 @@ class SoundNormalizerService:
|
||||
json_match = re.search(r'\{[^{}]*"input_i"[^{}]*\}', analysis_output)
|
||||
if not json_match:
|
||||
logger.error(
|
||||
"Could not find JSON in loudnorm output: %s", analysis_output
|
||||
"Could not find JSON in loudnorm output: %s", analysis_output,
|
||||
)
|
||||
raise ValueError("Could not extract loudnorm analysis data")
|
||||
|
||||
@@ -260,7 +260,7 @@ class SoundNormalizerService:
|
||||
)
|
||||
raise
|
||||
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.exception("Two-pass normalization failed for %s", input_path)
|
||||
raise
|
||||
|
||||
@@ -428,7 +428,7 @@ class SoundNormalizerService:
|
||||
"type": sound.type,
|
||||
"is_normalized": sound.is_normalized,
|
||||
"name": sound.name,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
# Process each sound using captured data
|
||||
@@ -476,7 +476,7 @@ class SoundNormalizerService:
|
||||
"normalized_hash": None,
|
||||
"id": sound_id,
|
||||
"error": str(e),
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
logger.info("Normalization completed: %s", results)
|
||||
@@ -517,7 +517,7 @@ class SoundNormalizerService:
|
||||
"type": sound.type,
|
||||
"is_normalized": sound.is_normalized,
|
||||
"name": sound.name,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
# Process each sound using captured data
|
||||
@@ -565,7 +565,7 @@ class SoundNormalizerService:
|
||||
"normalized_hash": None,
|
||||
"id": sound_id,
|
||||
"error": str(e),
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
logger.info("Type normalization completed: %s", results)
|
||||
|
||||
@@ -132,7 +132,7 @@ class SoundScannerService:
|
||||
"id": None,
|
||||
"error": str(e),
|
||||
"changes": None,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
# Delete sounds that no longer exist in directory
|
||||
@@ -153,7 +153,7 @@ class SoundScannerService:
|
||||
"id": sound.id,
|
||||
"error": None,
|
||||
"changes": None,
|
||||
}
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception("Error deleting sound %s", filename)
|
||||
@@ -169,7 +169,7 @@ class SoundScannerService:
|
||||
"id": sound.id,
|
||||
"error": str(e),
|
||||
"changes": None,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
logger.info("Sync completed: %s", results)
|
||||
@@ -219,7 +219,7 @@ class SoundScannerService:
|
||||
"id": sound.id,
|
||||
"error": None,
|
||||
"changes": None,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
elif existing_sound.hash != file_hash:
|
||||
@@ -246,7 +246,7 @@ class SoundScannerService:
|
||||
"id": existing_sound.id,
|
||||
"error": None,
|
||||
"changes": ["hash", "duration", "size", "name"],
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
else:
|
||||
@@ -264,7 +264,7 @@ class SoundScannerService:
|
||||
"id": existing_sound.id,
|
||||
"error": None,
|
||||
"changes": None,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
async def scan_soundboard_directory(self) -> ScanResults:
|
||||
|
||||
@@ -6,7 +6,6 @@ from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from sqlmodel import select
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from app.core.logging import get_logger
|
||||
|
||||
@@ -5,7 +5,7 @@ from collections.abc import Awaitable, Callable
|
||||
from typing import Any, TypeVar
|
||||
|
||||
from app.models.credit_action import CreditActionType
|
||||
from app.services.credit import CreditService, InsufficientCreditsError
|
||||
from app.services.credit import CreditService
|
||||
|
||||
F = TypeVar("F", bound=Callable[..., Awaitable[Any]])
|
||||
|
||||
@@ -69,7 +69,7 @@ def requires_credits(
|
||||
|
||||
# Validate credits before execution
|
||||
await credit_service.validate_and_reserve_credits(
|
||||
user_id, action_type, metadata
|
||||
user_id, action_type, metadata,
|
||||
)
|
||||
|
||||
# Execute the function
|
||||
@@ -85,7 +85,7 @@ def requires_credits(
|
||||
finally:
|
||||
# Deduct credits based on success
|
||||
await credit_service.deduct_credits(
|
||||
user_id, action_type, success, metadata
|
||||
user_id, action_type, success, metadata,
|
||||
)
|
||||
|
||||
return wrapper # type: ignore[return-value]
|
||||
@@ -173,7 +173,7 @@ class CreditManager:
|
||||
async def __aenter__(self) -> "CreditManager":
|
||||
"""Enter context manager - validate credits."""
|
||||
await self.credit_service.validate_and_reserve_credits(
|
||||
self.user_id, self.action_type, self.metadata
|
||||
self.user_id, self.action_type, self.metadata,
|
||||
)
|
||||
self.validated = True
|
||||
return self
|
||||
@@ -184,9 +184,9 @@ class CreditManager:
|
||||
# If no exception occurred, consider it successful
|
||||
success = exc_type is None and self.success
|
||||
await self.credit_service.deduct_credits(
|
||||
self.user_id, self.action_type, success, self.metadata
|
||||
self.user_id, self.action_type, success, self.metadata,
|
||||
)
|
||||
|
||||
def mark_success(self) -> None:
|
||||
"""Mark the operation as successful."""
|
||||
self.success = True
|
||||
self.success = True
|
||||
|
||||
Reference in New Issue
Block a user