generator/lkml_update.py (29 lines of code) (raw):
"""An updated lkml parser to handle explore queries."""
from typing import List, Union
from lkml.keys import KEYS_WITH_NAME_FIELDS
from lkml.simple import DictParser
from lkml.tree import BlockNode, DocumentNode, ListNode, PairNode
def dump(obj: dict) -> str:
"""Dump an object as LookML."""
parser = UpdatedDictParser()
tree: DocumentNode = parser.parse(obj)
return str(tree)
class UpdatedDictParser(DictParser):
"""An updated DictParser that properly handles queries."""
def parse_any(
self, key: str, value: Union[str, list, tuple, dict]
) -> Union[
List[Union[BlockNode, ListNode, PairNode]], BlockNode, ListNode, PairNode
]:
"""Dynamically serializes a Python object based on its type.
Args:
key: A LookML field type (e.g. "suggestions" or "hidden")
value: A string, tuple, or list to serialize
Raises:
TypeError: If input value is not of a valid type
Returns:
A generator of serialized string chunks
"""
if isinstance(value, str):
return self.parse_pair(key, value)
elif isinstance(value, (list, tuple)):
if self.is_plural_key(key) and not self.parent_key == "query":
# See https://github.com/joshtemple/lkml/issues/53
# We check that the parent is not a query to ensure the
# query fields don't get unnested
return self.expand_list(key, value)
else:
return self.parse_list(key, value)
elif isinstance(value, dict):
if key in KEYS_WITH_NAME_FIELDS or "name" not in value.keys():
name = None
else:
name = value.pop("name")
return self.parse_block(key, value, name)
else:
raise TypeError("Value must be a string, list, tuple, or dict.")