Source code for penman._format

from typing import Iterable, List, Optional, Union

from penman.tree import Tree, is_atomic
from penman.types import BasicTriple


[docs] def format( tree: Tree, indent: Union[int, None] = -1, compact: bool = False, ) -> str: """ Format *tree* into a PENMAN string. Args: tree: a Tree object indent: how to indent formatted strings compact: if ``True``, put initial attributes on the first line Returns: the PENMAN-serialized string of the Tree *t* Example: >>> import penman >>> print(penman.format( ... ('b', [('/', 'bark-01'), ... (':ARG0', ('d', [('/', 'dog')]))]))) (b / bark-01 :ARG0 (d / dog)) """ if not isinstance(tree, Tree): tree = Tree(tree) vars = [var for var, _ in tree.nodes()] if compact else [] parts = [ '# ::{}{}'.format(key, ' ' + value if value else value) for key, value in tree.metadata.items() ] parts.append(_format_node(tree.node, indent, 0, set(vars))) return '\n'.join(parts)
[docs] def format_triples(triples: Iterable[BasicTriple], indent: bool = True) -> str: """ Return the formatted triple conjunction of *triples*. Args: triples: an iterable of triples indent: how to indent formatted strings Returns: the serialized triple conjunction of *triples* Example: >>> import penman >>> g = penman.decode('(b / bark-01 :ARG0 (d / dog))') >>> print(penman.format_triples(g.triples)) instance(b, bark-01) ^ ARG0(b, d) ^ instance(d, dog) """ delim = ' ^\n' if indent else ' ^ ' # need to remove initial : on roles for triples conjunction = [ f'{role.lstrip(":")}({source}, {target})' for source, role, target in triples ] return delim.join(conjunction)
def _format_node( node, indent: Optional[int], column: int, vars: set, ) -> str: """ Format tree *node* into a PENMAN string. """ var, edges = node if not var: return '()' # empty node if not edges: return f'({var!s})' # var-only node # determine appropriate joiner based on value of indent if indent is None: joiner = ' ' else: if indent == -1: column += len(str(var)) + 2 # +2 for ( and a space else: column += indent joiner = '\n' + ' ' * column # format the edges and join them # if vars is non-empty, all initial attributes are compactly # joined on the same line, otherwise they use joiner parts: List[str] = [] compact = bool(vars) for edge in edges: target = edge[1] if compact and (not is_atomic(target) or target in vars): compact = False if parts: parts = [' '.join(parts)] parts.append(_format_edge(edge, indent, column, vars)) # check if all edges can be compactly written if compact: parts = [' '.join(parts)] return f'({var!s} {joiner.join(parts)})' def _format_edge(edge, indent, column, vars): """ Format tree *edge* into a PENMAN string. """ role, target = edge if role != '/' and not role.startswith(':'): role = ':' + role if indent == -1: column += len(role) + 1 # +1 for : sep = ' ' if not target: target = sep = '' elif not is_atomic(target): target = _format_node(target, indent, column, vars) return f'{role}{sep}{target!s}'