import copy from enum import Enum import orjson as json import os from datetime import datetime, timedelta from typing import Any, Callable, Iterable, Sequence def read_json_from_file(filename: str) -> list or dict: """Read json from file.""" with open(f"{os.path.dirname(__file__)}/{filename}.json", "r") as f: data = f.read() return json.loads(data) def check_fields(first, second, include: Iterable[str] = None, exclude: Iterable[str] = None): def is_to_check(key: str, _include, _exclude) -> bool: if include and key in include: return True if exclude and key in exclude: return False return True def _check_fields(_first, _second, _include=include, _exclude=exclude): if isinstance(_first, list): for i, item in enumerate(_first): _check_fields(item, _second[i], _include=_include, _exclude=_exclude) elif isinstance(_first, dict): for k, v in _first.items(): if not is_to_check(k, _include, _exclude): continue _check_fields(v, _second.get(k), _include=_include, _exclude=_exclude) else: assert _first == _second if include and exclude: raise ValueError( f"Only one of 'include', 'exclude' should be set. " f"Got include={include}, exclude={exclude}" ) include = include and set(include) exclude = exclude and set(exclude) _check_fields(first, second, _include=include, _exclude=exclude) class FieldFabricator: """Helpers to generate response""" @staticmethod def _get_song_id(i: (int, str)) -> str: return f"song_id_{i}" @staticmethod def _get_artist_id(i: (int, str)) -> str: return f"artist_id_{i}" @staticmethod def _get_song_name(i: (int, str)) -> str: return f"song_name_{i}" @staticmethod def _get_artists_name(i: (int, str)) -> str: return f"artists_name_{i}" @staticmethod def _get_image_url(i: (int, str)) -> str: return f"https://image_url_{i}" @staticmethod def _get_last_visit_datetime(i: int, as_string: bool = True): _datetime = datetime.now() - timedelta(days=i) if as_string: _datetime = datetime.strftime(_datetime, "%Y-%m-%dT%H:%M:%S") return _datetime @staticmethod def get_deepcopy(*args): response = [copy.deepcopy(item) for item in args] return response class BaseFieldFabricator: @staticmethod def get_string_field(name: str = "fake_field", i: int = 0): return f"{name}_{i}" def named_str(name: str, delimiter: str = "_"): def _named_str(s: str): return f"{name}{delimiter}{s}" return _named_str def seq(f, n=5, start=1, items=None): return [f(i) for i in (items or range(start, n + start))] def value_from(values: Sequence[Any], with_none: bool = False) -> Callable[[int], Any]: _values = [*values] if with_none: _values.append(None) mod_to_value = {mod: v for mod, v in enumerate(_values)} div = len(_values) def get_value(i: int) -> Any: return mod_to_value[i % div] return get_value def value_from_enum(enum: Enum, with_none: bool = False) -> Callable[[int], Any]: return value_from([i.value for i in enum], with_none=with_none)