import re from typing import Dict, List, Set, Type, Union from uuid import uuid4 TMP_THREADS = [] def is_list_or_tuple(obj) -> bool: return isinstance(obj, (list, tuple)) def select_attributes(obj: Dict, attributes: List[str]) -> Dict: """Select a subset of attributes from the given dict (returns a copy)""" attributes = attributes if is_list_or_tuple(attributes) else [attributes] return {k: v for k, v in obj.items() if k in attributes} class SubtypesInstanceManager: """Simple instance manager base class that scans the subclasses of a base type for concrete named implementations, and lazily creates and returns (singleton) instances on demand.""" _instances: Dict[str, "SubtypesInstanceManager"] @classmethod def get(cls, subtype_name: str, raise_if_missing: bool = False): instances = cls.instances() base_type = cls.get_base_type() instance = instances.get(subtype_name) if instance is None: # lazily load subtype instance (required if new plugins are dynamically loaded at runtime) for clazz in get_all_subclasses(base_type): impl_name = clazz.impl_name() if impl_name not in instances: instances[impl_name] = clazz() instance = instances.get(subtype_name) return instance @classmethod def instances(cls) -> Dict[str, "SubtypesInstanceManager"]: base_type = cls.get_base_type() if not hasattr(base_type, "_instances"): base_type._instances = {} return base_type._instances @staticmethod def impl_name() -> str: """Name of this concrete subtype - to be implemented by subclasses.""" raise NotImplementedError @classmethod def get_base_type(cls) -> Type: """Get the base class for which instances are being managed - can be customized by subtypes.""" return cls def to_str(obj, encoding: str = "utf-8", errors="strict") -> str: """If ``obj`` is an instance of ``binary_type``, return ``obj.decode(encoding, errors)``, otherwise return ``obj``""" return obj.decode(encoding, errors) if isinstance(obj, bytes) else obj def to_bytes(obj: Union[str, bytes], encoding: str = "utf-8", errors="strict") -> bytes: """If ``obj`` is an instance of ``text_type``, return ``obj.encode(encoding, errors)``, otherwise return ``obj``""" return obj.encode(encoding, errors) if isinstance(obj, str) else obj _re_camel_to_snake_case = re.compile("((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))") def camel_to_snake_case(string: str) -> str: return _re_camel_to_snake_case.sub(r"_\1", string).replace("__", "_").lower() def snake_to_camel_case(string: str, capitalize_first: bool = True) -> str: components = string.split("_") start_idx = 0 if capitalize_first else 1 components = [x.title() for x in components[start_idx:]] return "".join(components) def get_all_subclasses(clazz: Type) -> Set[Type]: """Recursively get all subclasses of the given class.""" result = set() subs = clazz.__subclasses__() for sub in subs: result.add(sub) result.update(get_all_subclasses(sub)) return result def long_uid() -> str: return str(uuid4())
Memory