API reference¶
Module contents¶
A speedy LookML parser and serializer implemented in pure Python.
- lkml.cli()¶
Command-line entry point for lkml.
- lkml.dump(obj: dict, file_object: IO | None = None) str | None ¶
Serialize a Python dictionary into LookML.
- Parameters:
obj – The Python dictionary to be serialized to LookML
file_object – An optional file object to save the LookML string to
- Returns:
A LookML string if no file_object is passed
- lkml.load(stream: str | IO) dict ¶
Parse LookML into a Python dictionary.
- Parameters:
stream – File object or string containing LookML to be parsed
- Raises:
TypeError – If stream is neither a string or a file object
- lkml.parse(text: str) DocumentNode ¶
Parse LookML into a parse tree.
- Parameters:
text – The LookML string to be parsed.
- Returns:
A document node, the root of the parse tree.
lkml.keys module¶
Defines constant sequences of LookML keys and helper methods.
lkml.lexer module¶
Splits a LookML string into a sequence of tokens.
- class lkml.lexer.Lexer(text: str)¶
Splits a LookML string into a sequence of tokens.
- text¶
Raw LookML to parse, padded with null character to denote end of stream
- index¶
Position of lexer in characters as it traverses the text
- tokens¶
Sequence of tokens that contain the relevant chunks of text
- line_number¶
Position of lexer in lines as it traverses the text
- advance(length: int = 1) None ¶
Moves the index forward by n characters.
- Parameters:
length – The number of positions forward to move the index.
- static check_for_expression_block(string: str) bool ¶
Returns True if the input string is an expression block.
- peek_multiple(length: int) str ¶
Returns the next n characters from the current index in the text being lexed.
- Parameters:
length – The number of characters to return
- scan() Tuple[Token, ...] ¶
Tokenizes LookML into a sequence of tokens.
This method skips through the text being lexed until it finds a character that indicates the start of a new token. It consumes the relevant characters and adds the tokens to a sequence until it reaches the end of the text.
- scan_comment() CommentToken ¶
Returns a token from a comment.
The initial pound (#) character is consumed in the scan method, so this method only scans for a newline or end of file to indicate the end of the token.
The pound character is added back to the beginning to the token to emphasize the importance of any leading whitespace that follows.
Example
>>> lexer = Lexer(" Disregard this line\n") >>> lexer.scan_comment() CommentToken(# Disregard this line)
- scan_expression_block() ExpressionBlockToken ¶
Returns an token from an expression block string.
This method strips any trailing whitespace from the expression string, since Looker usually adds an extra space before the ;; terminal.
Example
>>> lexer = Lexer("SELECT * FROM ${TABLE} ;;") >>> lexer.scan_expression_block() ExpressionBlockToken(SELECT * FROM ${TABLE})
- scan_literal() LiteralToken ¶
Returns a token from a literal string.
Example
>>> lexer = Lexer("yes") >>> lexer.scan_literal() LiteralToken(yes)
- scan_quoted_literal() QuotedLiteralToken ¶
Returns a token from a quoted literal string.
The initial double quote character is consumed in the scan method, so this method only scans for the trailing quote to indicate the end of the token.
Example
>>> lexer = Lexer('Label"') >>> lexer.scan_quoted_literal() QuotedLiteralToken(Label)
- scan_whitespace() WhitespaceToken ¶
Returns a token from one or more whitespace characters.
- Example:
>>> lexer = Lexer("
- Hello”)
>>> lexer.scan_whitespace() LinebreakToken('
‘, 1)
lkml.parser module¶
Parses a sequence of tokenized LookML into a parse tree.
- class lkml.parser.CommaSeparatedValues(_values: list = <factory>, trailing_comma: ~lkml.tree.Comma | None = None, leading_comma: ~lkml.tree.Comma | None = None)¶
Helper class to store a series of values and a flag for a trailing comma.
- append(value)¶
Add a value to the private _values list.
- class lkml.parser.Parser(stream: Sequence[Token])¶
Parses a sequence of tokenized LookML into a parse tree.
This parser is a recursive descent parser which uses the grammar listed below (in PEG format). Each grammar rule aligns with a corresponding method (e.g. parse_expression).
- Grammar:
expression
←(block / pair / list)*
block
←key literal? "{" expression "}"
pair
←key value
list
←key "[" csv? "]"
csv
←(literal / quoted_literal) ("," (literal / quoted_literal))* ","?
value
←literal / quoted_literal / expression_block
key
←literal ":"
expression_block
←[^;]* ";;"
quoted_literal
←'"' [^\"]+ '"'
literal
←[0-9A-Za-z_]+
- tokens¶
A sequence of tokens to be parsed.
- index¶
The position in the token sequence being parsed.
- progress¶
The farthest index of progress during parsing.
- depth¶
The level of recursion into nested expressions.
- log_debug¶
A flag indicating that debug messages should be logged. This flag exits to turn off logging flow entirely, which provides a small performance gain compared to parsing at a non-debug logging level.
- advance(length: int = 1)¶
Moves the index forward by n characters.
- Parameters:
length – The number of positions forward to move the index.
- check(*token_types: Type[Token], skip_trivia: bool = False) bool ¶
Compares the current index token type to specified token types.
- Parameters:
*token_types – A variable number of token types to check against.
skip_trivia – Ignore trivia tokens when searching for a match.
- Raises:
TypeError – If one or more of the token_types are not actual token types
- Returns:
True if the current token matches one of the token_types.
- consume_token_value() str ¶
Returns the value of the current index token, advancing the index 1 token.
- parse() DocumentNode ¶
Main method of this class and a wrapper for the container parser.
- Returns:
A document node, the root node of the LookML parse tree.
- parse_block() BlockNode | None ¶
Returns a node that represents a LookML block.
Grammar:
block
←key literal? "{" expression "}"
- Returns:
A node with the parsed block or None if the grammar doesn’t match.
- parse_container() ContainerNode ¶
Returns a container node that contains any number of children.
Grammar:
expression
←(block / pair / list)*
- Returns:
A node with the parsed container or None if the grammar doesn’t match.
- Raises:
SyntaxError – If unable to find a matching grammar rule for the stream
- parse_csv() CommaSeparatedValues | None ¶
Returns a CSV object that represents comma-separated LookML values.
- Returns:
A container with the parsed values or None if the grammar doesn’t match
- Grammar:
csv
←","? (literal / quoted_literal) ("," (literal / quoted_literal))* ","?
- parse_key() Tuple[SyntaxToken, Colon] | None ¶
Returns a syntax token that represents a literal key and colon character.
Grammar:
key
←literal ":"
- Returns:
A tuple of syntax tokens with the parsed key and colon or None if the grammar doesn’t match.
- parse_list() ListNode | None ¶
Returns a node that represents a LookML list.
Grammar:
list
←key "[" csv? "]"
- Returns:
A node with the parsed list or None if the grammar doesn’t match
- parse_pair() PairNode | None ¶
Returns a dictionary that represents a LookML key/value pair.
Grammar:
pair
←key value
- Returns:
A dictionary with the parsed pair or None if the grammar doesn’t match.
- parse_value(parse_prefix: bool = False, parse_suffix: bool = False) SyntaxToken | None ¶
Returns a syntax token that represents a value.
Grammar:
value
←literal / quoted_literal / expression_block
- Returns:
A syntax token with the parsed value or None if the grammar doesn’t match.
- lkml.parser.backtrack_if_none(fn)¶
Decorates parsing methods to backtrack to a previous position on failure.
This method sets a marker at the current position before attempting to run a parsing method. If the parsing method fails and returns None, it resets the index to the marker.
It also keeps track of the farthest index of progress in case all parsing methods fail and we need to return a SyntaxError to the user with a character number.
- Parameters:
fn (Callable) – The method to be decorated for backtracking.
lkml.simple module¶
Interface classes between the parse tree and a data structure of primitives.
These classes facilitate parsing and generation to and from simple data structures like lists and dictionaries, and allow users to parse and generate LookML without needing to interact with the parse tree.
- class lkml.simple.DictParser¶
Parses a Python dictionary into a parse tree.
Review the grammar specified for the Parser class to understand how LookML is represented. The grammar details the differences between blocks, pairs, keys, and values.
- parent_key¶
The name of the key at the previous level in a LookML block.
- level¶
The number of indentations appropriate for the current position.
- base_indent¶
Whitespace representing one tab.
- latest_node¶
The type of the last node to be parsed.
- expand_list(key: str, values: Sequence) List[BlockNode | ListNode | PairNode] ¶
Expands and parses a list of values for a repeatable key.
- Parameters:
key – A repeatable LookML field type (e.g. “views” or “dimension_groups”)
values – A sequence of objects to be parsed
- Returns:
A list of block, list, or pair nodes, depending on the list’s contents.
- increase_level() None ¶
Increases the indent level of the current line by one tab.
This also resets the latest node, mainly for formatting reasons.
- is_plural_key(key: str) bool ¶
Returns True if the key is a repeatable key.
For example, dimension can be repeated, but sql cannot be.
The key allowed_value is a special case and changes behavior depending on its parent key. If its parent key is access_grant, it is a list and cannot be repeated. Otherwise, it can be repeated.
The parent key query is also a special case, where children are kept as lists. See issue #53.
- Parameters:
key – The name of the key to test.
- parse(obj: Dict[str, Any]) DocumentNode ¶
Parses a primitive representation of LookML into a parse tree.
- parse_any(key: str, value: str | list | tuple | dict) List[BlockNode | ListNode | PairNode] | BlockNode | ListNode | PairNode ¶
Dynamically serializes a Python object based on its type.
- Parameters:
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
- parse_block(key: str, items: Dict[str, Any], name: str | None = None) BlockNode ¶
Serializes a dictionary to a LookML block.
- Parameters:
key – A LookML field type (e.g. “dimension”)
fields – A dictionary to serialize (e.g. {“sql”: “${TABLE}.order_id”})
name – An optional name of the block (e.g. “order_id”)
- Returns:
A generator of serialized string chunks
- parse_list(key: str, values: Sequence[str | Dict]) ListNode ¶
Serializes a sequence to a LookML block.
- Parameters:
key – A LookML field type (e.g. “fields”)
values – A sequence to serialize (e.g. [“orders.order_id”, “orders.item”])
- Returns:
A generator of serialized string chunks
- parse_pair(key: str, value: str) PairNode ¶
Serializes a key and value to a LookML pair.
- Parameters:
key – A LookML field type (e.g. “hidden”)
value – The value string (e.g. “yes”)
- Returns:
A generator of serialized string chunks
- static parse_token(key: str, value: str, force_quote: bool = False, prefix: str = '', suffix: str = '') SyntaxToken ¶
Parses a value into a token, quoting it if required by the key or forced.
- Parameters:
key – A LookML field type (e.g. “hidden”)
value – The value string (e.g. “yes”)
force_quote – True if value should always be quoted
- Returns:
A generator of serialized string chunks
- resolve_filters(values: List[dict]) List[BlockNode] | ListNode ¶
Parse the key
filters
according to the context.In LookML, the
filters
key is wildly inconsistent and can have three different syntaxes. This method determines the syntax that should be used based on the context and parses the appropriate node.- Parameters:
values – The contents of the
filters
block. Provides context to resolve.- Returns:
A block or list node depending on the resolution.
- class lkml.simple.DictVisitor¶
Creates a primitive representation of the parse tree.
Traverses the parse tree and transforms each node type into a dict. Each dict is combined into one nested dict. Also handles the grouping of fields with plural keys like
dimension
orview
into lists.- depth¶
Tracks the level of nesting.
- update_tree(target: Dict, update: Dict) None ¶
Add one dictionary to an existing dictionary, handling certain repeated keys.
This method is primarily responsible for handling repeated keys in LookML like dimension or set, which can exist more than once in LookML but cannot be repeated in a Python dictionary.
This method checks the list of valid repeated keys and combines the values of that key in target and/or update into a list and assigns a plural key (e.g. dimensions instead of dimension).
- visit(document: DocumentNode) Dict[str, Any] ¶
- visit_block(node: BlockNode) Dict[str, Dict] ¶
Creates a dict from a block node by visiting its children.
- visit_container(node: ContainerNode) Dict[str, Any] ¶
Creates a dict from a container node by visiting its children.
- visit_list(node: ListNode) Dict[str, List] ¶
Creates a dict from a list node by visiting its children.
- visit_pair(node: PairNode) Dict[str, str] ¶
Creates a dict from pair node by visiting its type and value tokens.
- visit_token(token: SyntaxToken) str ¶
Creates a string from a syntax token.
lkml.tokens module¶
Tokens used by the lexer to tokenize LookML.
- class lkml.tokens.ContentToken(value: str, line_number: int)¶
Base class for LookML tokens that contain a string of content.
- class lkml.tokens.ExpressionBlockEndToken(line_number: int)¶
Represents the end of an expression block.
- class lkml.tokens.ExpressionBlockToken(value: str, line_number: int)¶
Contains the value of an expression block.
- class lkml.tokens.InlineWhitespaceToken(value: str, line_number: int)¶
Represents one or more whitespace characters.
- class lkml.tokens.LiteralToken(value: str, line_number: int)¶
Contains the value of an unquoted literal.
- class lkml.tokens.QuotedLiteralToken(value: str, line_number: int)¶
Contains the value of a quoted literal.
- class lkml.tokens.StreamStartToken(line_number: int)¶
Represents the start of a stream of characters.
lkml.tree module¶
Node and token classes that make up the parse tree.
- class lkml.tree.BlockNode(type: SyntaxToken, left_brace: LeftCurlyBrace = LeftCurlyBrace(value='{', line_number=None, prefix='', suffix='\n'), right_brace: RightCurlyBrace = RightCurlyBrace(value='}', line_number=None, prefix='\n', suffix=''), colon: Colon | None = Colon(value=':', line_number=None, prefix='', suffix=' '), name: SyntaxToken | None = None, container: ContainerNode = ContainerNode())¶
A LookML block, enclosed in curly braces. Like
view
ordimension
.- type¶
The field type, the value that precedes the colon.
- Type:
- left_brace¶
A syntax token for the opening brace “{“.
- Type:
- right_brace¶
A syntax token for the closing brace “}”.
- colon¶
An optional Colon SyntaxToken. If not supplied, a default colon is created with a single space suffix after the colon.
- Type:
lkml.tree.Colon | None
- name¶
An optional name token, the value that follows the colon.
- Type:
lkml.tree.SyntaxToken | None
- container¶
A container node that holds the block’s child nodes.
- Type:
- property children: Tuple[BlockNode | PairNode | ListNode, ...]¶
Returns all child SyntaxNodes, but not SyntaxTokens.
- container: ContainerNode = ContainerNode()¶
- left_brace: LeftCurlyBrace = LeftCurlyBrace(value='{', line_number=None, prefix='', suffix='\n')¶
- name: SyntaxToken | None = None¶
- right_brace: RightCurlyBrace = RightCurlyBrace(value='}', line_number=None, prefix='\n', suffix='')¶
- type: SyntaxToken¶
- class lkml.tree.Colon(value: 'str' = ':', line_number: 'Optional[int]' = None, prefix: 'str' = '', suffix: 'str' = '')¶
- class lkml.tree.Comma(value: 'str' = ',', line_number: 'Optional[int]' = None, prefix: 'str' = '', suffix: 'str' = '')¶
- class lkml.tree.ContainerNode(items: Tuple[BlockNode | PairNode | ListNode, ...], top_level: bool = False)¶
A sequence of nodes, either at the top level of a document, or within a block.
- items¶
A tuple of the contained nodes.
- Type:
Tuple[lkml.tree.BlockNode | lkml.tree.PairNode | lkml.tree.ListNode, …]
- Raises:
KeyError – If a key already exists in the tree and would be overwritten.
- accept(visitor: Visitor) Any ¶
Accepts a visitor and calls the visitor’s container method on itself.
- class lkml.tree.DocumentNode(container: ContainerNode, prefix: str = '', suffix: str = '')¶
The root node of the parse tree.
- container¶
The top-level container node.
- Type:
- property children: Tuple[ContainerNode]¶
Returns all child SyntaxNodes, but not SyntaxTokens.
- container: ContainerNode¶
- class lkml.tree.DoubleSemicolon(value: 'str' = ';;', line_number: 'Optional[int]' = None, prefix: 'str' = '', suffix: 'str' = '')¶
- class lkml.tree.ExpressionSyntaxToken(value: 'str', line_number: 'Optional[int]' = None, prefix: 'str' = ' ', suffix: 'str' = '', expr_suffix: 'str' = ' ')¶
- class lkml.tree.LeftBracket(value: 'str' = '[', line_number: 'Optional[int]' = None, prefix: 'str' = '', suffix: 'str' = '')¶
- class lkml.tree.LeftCurlyBrace(value: 'str' = '{', line_number: 'Optional[int]' = None, prefix: 'str' = '', suffix: 'str' = '')¶
- class lkml.tree.ListNode(type: SyntaxToken, items: Tuple[PairNode, ...] | Tuple[SyntaxToken, ...], left_bracket: LeftBracket, right_bracket: RightBracket, colon: Colon = Colon(value=':', line_number=None, prefix='', suffix=' '), leading_comma: Comma | None = None, trailing_comma: Comma | None = None)¶
A LookML list, enclosed in square brackets. Like
fields
orfilters
.- type¶
The field type, the value that precedes the colon.
- Type:
- items¶
A tuple of pair nodes or syntax tokens, depending on the list style.
- Type:
Tuple[lkml.tree.PairNode, …] | Tuple[lkml.tree.SyntaxToken, …]
- left_bracket¶
A syntax token for the opening bracket “[“.
- Type:
- right_bracket¶
A syntax token for the closing bracket “]”.
- Type:
- colon¶
An optional Colon SyntaxToken. If not supplied, a default colon is created with a single space suffix after the colon.
- Type:
- trailing_comma¶
Include a trailing comma after the last item.
- Type:
lkml.tree.Comma | None
- items: Tuple[PairNode, ...] | Tuple[SyntaxToken, ...]¶
- left_bracket: LeftBracket¶
- right_bracket: RightBracket¶
- type: SyntaxToken¶
- class lkml.tree.PairNode(type: SyntaxToken, value: SyntaxToken, colon: Colon = Colon(value=':', line_number=None, prefix='', suffix=' '))¶
A simple LookML field, e.g.
hidden: yes
.- type¶
The field type, the value that precedes the colon.
- Type:
- value¶
The field value, the value that follows the colon.
- Type:
- colon¶
An optional Colon SyntaxToken. If not supplied, a default colon is created with a single space suffix after the colon.
- Type:
- type: SyntaxToken¶
- value: SyntaxToken¶
- class lkml.tree.QuotedSyntaxToken(value: str, line_number: int | None = None, prefix: str = '', suffix: str = '')¶
- class lkml.tree.RightBracket(value: 'str' = ']', line_number: 'Optional[int]' = None, prefix: 'str' = '', suffix: 'str' = '')¶
- class lkml.tree.RightCurlyBrace(value: 'str' = '}', line_number: 'Optional[int]' = None, prefix: 'str' = '', suffix: 'str' = '')¶
- class lkml.tree.SyntaxNode¶
Abstract base class for members of the parse tree that have child nodes.
- abstract accept(visitor: Visitor) Any ¶
Accepts a Visitor that can interact with the node.
The visitor pattern allows for flexible algorithms that can traverse the tree without needing to be defined as methods on the tree itself.
- abstract property children: Tuple[SyntaxNode, ...] | None¶
Returns all child SyntaxNodes, but not SyntaxTokens.
- class lkml.tree.SyntaxToken(value: str, line_number: int | None = None, prefix: str = '', suffix: str = '')¶
Stores a text value with optional prefix or suffix trivia.
For example, a syntax token might represent meaningful punctuation like a curly brace or the type or value of a LookML field. A syntax token can also store trivia, comments or whitespace that precede or follow the token value. The parser attempts to assign these prefixes and suffixes intelligently to the corresponding tokens.
- class lkml.tree.Visitor¶
Abstract base class for visitors that interact with the parse tree.
- abstract visit(document: DocumentNode) Any ¶
- abstract visit_container(node: ContainerNode) Any ¶
- abstract visit_token(token: SyntaxToken) Any ¶
lkml.visitors module¶
- class lkml.visitors.BasicTransformer¶
Bases:
Visitor
Visitor class that returns a new tree, modifying the tree as needed.
- visit(node: DocumentNode) DocumentNode ¶
- visit_container(node: ContainerNode) ContainerNode ¶
- visit_token(token: SyntaxToken) SyntaxToken ¶
- class lkml.visitors.BasicVisitor¶
Bases:
Visitor
Visitor class that calls the
_visit
method for every node type.This class doesn’t actually do anything when visiting a tree other than traverse the nodes. It’s meant to be used as a base class for building more useful and complex visitors. For example, override any of the
visit_
methods for node-type specific behavior.- visit(document: DocumentNode)¶
- visit_container(node: ContainerNode)¶
- visit_token(token: SyntaxToken)¶
- class lkml.visitors.LookMlVisitor¶
Bases:
BasicVisitor
Converts a parse tree into a string by casting every node.