example.py 3.42 KB
Newer Older
carignani's avatar
carignani committed
#!/bin/python3
'''
Class and utilities to parse and export examples of data models in TOSCA
'''
import re
import traceback

from docx.text.paragraph import Paragraph
from docx.table import Table
carignani's avatar
carignani committed

class Example():

    def __init__(self, filename, text):
        self.filename = filename
        self.text = text

def is_start_of_example(line: str):
    '''
    Returns true if the line marks the start of an examples.
    Check if lines starts with "tosca_definitions_version:"
    '''
    if not isinstance(line, str):
        raise ValueError("NOT A STRING")

    return line.startswith("tosca_definitions_version:")

def is_body_of_example(line: str):
    '''
    Returns true if the line is part of the body of an example.
    '''
            line.startswith(".") or \
            line.startswith("#") or \
            line.startswith(" ") or \
            bool(re.match(r'^[a-zA-Z_]*:',line))
            
def is_last_line(line: str, txt):
    '''
    Returns true if it is the last line of the text.
    '''
    return line == txt[len(txt)-1]
carignani's avatar
carignani committed

def get_example_file_name(line: str):
    '''
    Looks for the YAML filename in the line of text
carignani's avatar
carignani committed
    '''
    matches = re.search(r'[a-zA-Z0-9_.]*.yaml', line)
    if matches is not None:
        return matches.group(0)
    return ""

def is_heading(txt :str):
    '''
    Returns true if text is a heading, i.e. the text starts with 'A.'
    (Previously this predicate was used: ("Heading" in line.style.name) but 
    not all headings have the correct style
    '''
    return (txt.startswith("A.")) or (txt.startswith("E."))
def is_example_table(tab):
    return len(tab.rows) == 1 and len(tab.rows[0].cells) == 1

carignani's avatar
carignani committed
def parse_all_examples(txt):
    '''
    Parses TOSCA examples. Txt is a list of Docx items (Paragraph, etc.).
    Returns a list of Example objects
    '''

    res = []
    new_example = ""
    filename = ""
    i = 1
    clause = ""
    for line in txt:
        if isinstance(line, Paragraph):
            linetext = str(line.text)
            if is_heading(linetext):
carignani's avatar
carignani committed
                clause = linetext.split("\t")[0]
                i = 1
        elif isinstance(line, Table):
            if is_example_table(line):
                linetext = str(line.rows[0].cells[0].text)
carignani's avatar
carignani committed
        elif isinstance(line, str):
            if line != '\r\n' and line != '\n':
                linetext = line
carignani's avatar
carignani committed
        else:
            continue

        if is_start_of_example(linetext):
            filename = get_example_file_name(previous_line) 
            if filename == "":
                filename = "{:02d}".format(i) + ".yaml" 
                i = i + 1
carignani's avatar
carignani committed
            new_example = "# " + filename + "\n" + linetext
        elif new_example != "" and is_body_of_example(linetext):
            new_example = new_example + "\n" + linetext
            if is_last_line(line, txt):
                res.append(Example(filename, new_example))
carignani's avatar
carignani committed
        elif len(new_example) > 0:
            res.append(Example(filename, new_example))
            new_example = ""

        previous_line = linetext

    return res

def generate_examples_between(a_id, b_id, content, EXAMPLES):

    try:
        examples = parse_all_examples(content[a_id:b_id])
    except:
        track = traceback.format_exc()
        print(track)
        return 0

    for example in examples:
        EXAMPLES[example.filename] = example

    return len(examples)