Source code for rolling_pin.toml_etl

from typing import Any, Type, TypeVar, Union  # noqa: F401

from copy import deepcopy
from pathlib import Path
import os

from lunchbox.enforce import Enforce
import toml

from rolling_pin.blob_etl import BlobETL
from toml.decoder import TomlDecodeError

T = TypeVar('T', bound='TomlETL')
# ------------------------------------------------------------------------------


[docs]class TomlETL:
[docs] @classmethod def from_string(cls, text): # type: (Type[T], str) -> T ''' Creates a TomlETL instance from a given TOML string. Args: text (str): TOML string. Returns: TomlETL: TomlETL instance. ''' return cls(toml.loads(text))
[docs] @classmethod def from_toml(cls, filepath): # type: (Type[T], Union[str, Path]) -> T ''' Creates a TomlETL instance from a given TOML file. Args: filepath (str or Path): TOML file. Returns: TomlETL: TomlETL instance. ''' return cls(toml.load(filepath))
[docs] def __init__(self, data): # type: (dict[str, Any]) -> None ''' Creates a TomlETL instance from a given dictionary. Args: data (dict): Dictionary. ''' self._data = data
[docs] def to_dict(self): # type: () -> dict ''' Converts instance to dictionary copy. Returns: dict: Dictionary copy of instance. ''' return deepcopy(self._data)
[docs] def to_string(self): # type: () -> str ''' Converts instance to a TOML formatted string. Returns: str: TOML string. ''' return toml.dumps( self._data, encoder=toml.TomlArraySeparatorEncoder(separator=',') )
[docs] def write(self, filepath): # type: (Union[str, Path]) -> None ''' Writes instance to given TOML file. Args: filepath (str or Path): Target filepath. ''' filepath = Path(filepath) os.makedirs(filepath.parent, exist_ok=True) with open(filepath, 'w') as f: toml.dump( self._data, f, encoder=toml.TomlArraySeparatorEncoder(separator=',') )
[docs] def edit(self, patch): # type: (str) -> TomlETL ''' Apply edit to internal data given TOML patch. Patch is always of the form '[key]=[value]' and in TOML format. Args: patch (str): TOML patch to be applied. Raises: TOMLDecoderError: If patch cannot be decoded. EnforceError: If '=' not found in patch. Returns: TomlETL: New TomlETL instance with edits. ''' msg = 'Edit patch must be a TOML parsable key value snippet with a "=" ' msg += 'character.' try: toml.loads(patch) except TomlDecodeError as e: msg += ' ' + e.msg raise TomlDecodeError(msg, e.doc, e.pos) Enforce('=', 'in', patch, message=msg) # ---------------------------------------------------------------------- key, val = patch.split('=', maxsplit=1) val = toml.loads(f'x={val}')['x'] data = BlobETL(self._data, separator='.').to_flat_dict() data[key] = val data = BlobETL(data, separator='.').to_dict() return TomlETL(data)
[docs] def delete(self, regex): # type: (str) -> TomlETL ''' Returns portion of data whose keys fo not match a given regular expression. Args: regex (str): Regular expression applied to keys. Returns: TomlETL: New TomlETL instance. ''' data = BlobETL(self._data, separator='.') \ .query(regex, ignore_case=False, invert=True) \ .to_dict() return TomlETL(data)
[docs] def search(self, regex): # type: (str) -> TomlETL ''' Returns portion of data whose keys match a given regular expression. Args: regex (str): Regular expression applied to keys. Returns: TomlETL: New TomlETL instance. ''' data = BlobETL(self._data, separator='.') \ .query(regex, ignore_case=False) \ .to_dict() return TomlETL(data)