from typing import Callable, Dict, Iterable, Iterator, List from src.constants import AUTH0_PREFIX def iter_chunk(iterable: list, chunk_size: int = 1) -> Iterator: """Split collection of items on chunks. Args: iterable: Collection of items. chunk_size: Size of chunks. Returns: Iterator of chunks. """ for i in range(0, len(iterable), chunk_size): yield iterable[i: i + chunk_size] def request_in_chunks(chunk_size: int, items_key: str, sum_func: Callable) -> Callable: """Execute API requests for chunks of items. Args: chunk_size: A size of a chunk. items_key: Args list key. sum_func: Sum chunks results. Returns: Wrapped function. """ def wrapper(f: Callable): def wrapped(*args, **kwargs): if items_key not in kwargs or not chunk_size: return f(*args, **kwargs) items = kwargs[items_key] result = None for sequential_chunk in iter_chunk(items, chunk_size): kwargs[items_key] = sequential_chunk chunk_result = f(*args, **kwargs) result = sum_func(result, chunk_result) return result return wrapped return wrapper def sum_lists(result: list, chunk_result: list) -> list: """Sum results lists. Args: result: Result. chunk_result: New result chunk. Returns: Result sum. """ if result is None: return chunk_result return result + chunk_result def sum_delete_dicts(result: Dict[str, List[int]], chunk_result: Dict[str, List[int]]) -> Dict[str, List[int]]: """Sum delete results dicts. Args: result: Result. chunk_result: New result chunk. Returns: Result sum. """ if result is None: return chunk_result for key, value_list in chunk_result.items(): if key not in result: result[key] = value_list else: result[key].extend(value_list) return result def check_delete_dict_is_empty(result: Dict[str, List[int]]) -> bool: """Check if delete result dict is empty. Args: result: Result. Returns: Is empty flag. """ for value_list in result.values(): if value_list: return False return True def request_with_limit(limit: int, sum_func: Callable, is_empty_func: Callable) -> Callable: """Execute API requests with limit until empty result. Args: limit: Chunk size. sum_func: Sum chunks results. is_empty_func: Check chunks result is empty. Returns: Wrapped function. """ def wrapper(f: Callable): def wrapped(*args, **kwargs): if not limit: return f(*args, **kwargs) result = None while True: chunk_result = f(*args, **kwargs) if is_empty_func(chunk_result): break result = sum_func(result, chunk_result) return result return wrapped return wrapper def sum_get_users(result: List[dict], chunk_result: List[dict]) -> List[dict]: """Sum get users statuses results. Args: result: Result. chunk_result: New result chunk. Returns: Result sum. """ if result is None: return chunk_result result.extend(chunk_result) return result def add_auth0_prefix(user_id_list: List[str]) -> List[str]: """Add Auth0 prefix for user ID list. Args: user_id_list: User ID list. Returns: User ID list with prefix. """ return [(i if i.startswith(AUTH0_PREFIX) else f"{AUTH0_PREFIX}{i}") for i in user_id_list] def remove_auth0_prefix(user_id_list: Iterable[str], original_user_id_list: Iterable[str] = None) -> List[str]: """Remove Auth0 prefix from user ID list. Args: user_id_list: User ID list with prefix. original_user_id_list: Original list to validate that prefix was not there. Returns: User ID list without prefix. """ return [ ( i[len(AUTH0_PREFIX):] if i.startswith(AUTH0_PREFIX) and (not original_user_id_list or i not in original_user_id_list) else i ) for i in user_id_list ]