python-package/lets_plot/geo_data/gis/fluent_dict.py (152 lines of code) (raw):

from enum import Enum from typing import Union, Callable, Any, Dict, Optional, Type, List, Generic, TypeVar class FluentDict: def __init__(self, dict: Optional[Dict] = None): if dict is not None: self._dict = dict else: self._dict = {} def contains(self, key: Union[str, Enum]) -> bool: str_key: str = self._key_to_str(key) return str_key in self._dict and self.get(str_key) is not None def put(self, key: Union[str, Enum], value: Any) -> 'FluentDict': if value is None: pass elif isinstance(value, (int, float, str, dict)): pass elif isinstance(value, FluentDict): value = value.to_dict() elif isinstance(value, Enum): value = value.value elif isinstance(value, (list, tuple)): if len(value) > 0: if isinstance(value[0], Enum): value = list(map(lambda enum: enum.value, value)) else: raise ValueError('Not supported type: ' + str(value.__class__)) self._dict[self._key_to_str(key)] = value return self def visit(self, key: Union[str, Enum], consumer: Callable[[Any], Any]) -> 'FluentDict': consumer(self._dict[self._key_to_str(key)]) return self def visit_str(self, key: Union[str, Enum], consumer: Callable[[str], Any]) -> 'FluentDict': consumer(str(self.get(key))) return self def visit_str_existing(self, key: Union[str, Enum], consumer: Callable[[str], Any]) -> 'FluentDict': if self._is_not_none(key): consumer(self.get(key)) return self def visit_int(self, key: Union[str, Enum], consumer: Callable[[int], Any]) -> 'FluentDict': consumer(int(self.get(key))) return self def get_float(self, key: Union[str, Enum]) -> float: return float(self.get(key)) def visit_float(self, key: Union[str, Enum], consumer: Callable[[float], Any]) -> 'FluentDict': consumer(self.get_float(key)) return self def visit_float_optional(self, key: Union[str, Enum], consumer: Callable[[float], Any]) -> 'FluentDict': if self._is_not_none(key): self.visit_float(key, consumer) return self def visit_int_optional(self, key: Union[str, Enum], consumer: Callable[[int], Any]) -> 'FluentDict': if self._is_not_none(key): self.visit_int(key, consumer) return self def visit_dict(self, key: Union[str, Enum], consumer: Callable[['FluentDict'], Any]) -> 'FluentDict': consumer(self.get_object(key)) return self def visit_object_optional(self, key: Union[str, Enum], consumer: Callable[['FluentDict'], Any]) -> 'FluentDict': if self._is_not_none(key): self.visit_dict(key, consumer) return self def visit_list_optional(self, key: Union[str, Enum], consumer: Callable[['FluentList'], Any]) -> 'FluentDict': if self._is_not_none(key): self.visit_list(key, consumer) return self def get_enum(self, key: Union[str, Enum], enum_type: Type[Enum]): return self._to_enum(self.get(key), enum_type) def visit_enum(self, key: Union[str, Enum], enum_type: Type[Enum], consumer: Callable[[Enum], Any]) -> 'FluentDict': consumer(self.get_enum(key, enum_type)) return self def visit_enums(self, key: Union[str, Enum], enum_type: Type[Enum], consumer: Callable[[List[Enum]], Any]) -> 'FluentDict': consumer( self.get_fluent_list(key) .map(lambda enum_str: self._to_enum(enum_str, enum_type)) .list() ) return self def visit_enum_existing(self, key: Union[str, Enum], enum_type: Type[Enum], consumer: Callable[[Enum], Any]) -> 'FluentDict': if self._is_not_none(key): consumer(self.get_enum(key, enum_type)) return self def visit_objects(self, key: Union[str, Enum], consumer: Callable[['FluentDict'], Any]) -> 'FluentDict': for d in self.get(key): consumer(FluentDict(d)) return self def visit_object(self, key: Union[str, Enum], consumer: Callable[['FluentDict'], Any]) -> 'FluentDict': consumer(FluentDict(self.get(key))) return self def visit_list(self, key: Union[str, Enum], consumer: Callable[['FluentList'], Any]) -> 'FluentDict': consumer(self.get_fluent_list(key)) return self def get(self, key: Union[str, Enum]) -> Any: return self._dict[self._key_to_str(key)] def get_bool(self, key: Union[str, Enum]) -> bool: return bool(self.get(key)) def visit_bool(self, key: Union[str, Enum], consumer: Callable[[bool], Any]) -> 'FluentDict': consumer(self.get_bool(key)) return self def get_fluent_list(self, key: Union[str, Enum]) -> 'FluentList': return FluentList(self.get(key)) def get_list(self, key: Union[str, Enum]) -> list: value = self.get(key) assert isinstance(value, list) return value def get_object(self, key: Union[str, Enum]) -> 'FluentDict': return FluentDict(self.get(key)) def get_objects(self, key: Union[str, Enum]) -> 'FluentList[FluentDict]': return FluentList(self._dict[self._key_to_str(key)]).map(lambda v: FluentDict(v)) def to_dict(self) -> Dict: return self._dict def _is_not_none(self, key: Union[str, Enum]): return self._key_to_str(key) in self._dict and self.get(key) is not None @staticmethod def _key_to_str(key: Union[str, Enum]) -> str: if isinstance(key, str): return key elif isinstance(key, Enum): return key.value else: raise ValueError('Unknown key type: ' + str(key.__class__)) @staticmethod def _to_enum(enum_str: str, enum_type: Type[Enum]): for e in enum_type: if e.value == enum_str: return e raise ValueError('Unknown emum value: ' + enum_str) def visit_str_list(self, key: Union[str, Enum], consumer: Callable[[List[str]], Any]) -> 'FluentDict': consumer(self.get(key)) return self def visit_str_list_optional(self, key: Union[str, Enum], consumer: Callable[[List[str]], Any]) -> 'FluentDict': if self._is_not_none(key): consumer(self.get(key)) return self T = TypeVar('T') TOut = TypeVar('TOut') class FluentList(Generic[T]): def __init__(self, list: List[T] = None): if list is None: self._list: List[T] = [] else: self._list: List[T] = list def add(self, obj: T) -> 'FluentList[T]': self._list.append(obj) return self def list(self) -> List[T]: return self._list TOut = TypeVar('TOut') def map(self, func: Callable[[T], TOut]) -> 'FluentList[TOut]': out = [] for v in self._list: out.append(func(v)) return FluentList(out)