""" Helper functions for the YouTube API Client. """ import itertools import json from asyncio.tasks import Task from typing import Any, Callable from ... import logger from ...environment_vars import YT_CMS_FALLBACK_CREDENTIALS from ...utils.strings import snake_case_mapping logger = logger.new_logger(__name__) def batch_worker(): """Return a worker that can be used to process batches of requests concurrently. The status of each worker will be logged. """ counter = itertools.count(start=1) async def wrapped(task: Task): worker_number: int = next(counter) logger.debug(f"Batch worker: starting worker no. {worker_number}...") result = await task logger.debug(f"Batch worker: worker no. {worker_number} finished the job.") return result return wrapped def to_response_object(mapping: dict[str, Any], obj_factory: Callable) -> Any: """Converts a response mapping to an object constructed by the given factory. It will also transform the camel case keys to snake case. Args: mapping: A mapping of response data. obj_factory: A callable that accepts keyword arguments and returns an object. Can also be a dataclass constructor. Returns: An object constructed by the given factory. """ as_snake_case = snake_case_mapping(mapping) return obj_factory(**as_snake_case) def load_credentials(service_account_file_path: str = None) -> dict[str, Any]: """Load credentials from the provided service account file. If no file is provided or the file is not found, the credentials will be attempted to be loaded from the fallback environment variables. Args: service_account_file_path: Path to the service account file, if any. Returns: A dictionary with the credentials. """ yt_fallback_creds_msg = ( "YT API Service account file not found. Using YT API fallback credentials." ) if service_account_file_path is None: logger.debug(yt_fallback_creds_msg) return YT_CMS_FALLBACK_CREDENTIALS try: with open(service_account_file_path, encoding="utf-8") as file: content = json.load(file) logger.debug( "Using YT API credentials file located at {}", service_account_file_path ) return content except FileNotFoundError: logger.debug(yt_fallback_creds_msg) return YT_CMS_FALLBACK_CREDENTIALS