#!/usr/bin/python2.7 ''' Parses a TOSCA template and generates a docx file ''' import sys import toscaparser.utils.yamlparser as yaml import docx from docx.enum.text import WD_PARAGRAPH_ALIGNMENT PRINT_TRESHOLD = 1 TEMPLATES = {} FNS = { 'VNFD' : 'etsi_nfv_sol001_vnfd_2_5_1_types.yaml', 'NSD' : 'etsi_nfv_sol001_nsd_2_5_1_types.yaml', 'PNFD' : 'etsi_nfv_sol001_pnfd_2_5_1_types.yaml' } TOSCA_TYPES = [ 'data_types', 'artifact_types', 'capability_types', 'requirements_types', 'relationship_types', 'interface_types', 'node_types', 'group_types', 'policy_types' ] TOSCA_TYPES_PRETTYPRINT = { 'data_types': 'Data Types', 'artifact_types': 'Artifact Types', 'capability_types': 'Capability Types', 'requirements_types': 'Requirements types', 'relationship_types': 'Relationship Types', 'interface_types': 'Interface Types', 'node_types': 'Node Types', 'group_types': 'Group Types', 'policy_types': 'Policy Types' } IDS = [6, 2, 1, 1] def load_template(file_path, templs, key): ''' Loads the content of the file at file_patch into the YAML templates array ''' yaml_data = open(file_path).read() #print("+++++++++++++++++++++++++++++++++++++") #print(yaml_data) #print("+++++++++++++++++++++++++++++++++++++") templs[key] = yaml.simple_ordered_parse(yaml_data) def print_lvl(num, txt): if num + 1 > PRINT_TRESHOLD: return index = ".".join(map(str, IDS[:(num+1)])) print index + " " + ('-'*(num+1)) + ' ' + txt def add_heading_with_num(num, txt, doc): ''' Add a new heading to the document, with the calculated index number ''' index = ".".join(map(str, IDS[:(num+1)])) doc.add_heading(index + " " + txt, num) def cell_text_bold(cell): cell.paragraphs[0].runs[0].font.bold = True def cell_text_centered(cell): cell.paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER def mk_props_table_hdr(table): hdr_cells = table.rows[0].cells hdr_cells[0].text = 'Name' hdr_cells[1].text = 'Required' hdr_cells[2].text = 'Type' hdr_cells[3].text = 'Constraints' hdr_cells[4].text = 'Description' map(cell_text_bold, hdr_cells) map(cell_text_centered, hdr_cells) def dt_name_from_path(dt_path): return dt_path.split('.')[-1] def prop_field_to_str(prop_field): if type(prop_field) == bool: return 'yes' if prop_field else 'no' return str(prop_field) def add_prop_row(prop_name, prop_fields, table): ''' Add a row to table and fills it with info from prop ''' nrow = table.add_row() prop_cells = nrow.cells prop_cells[0].text = prop_name all_fields = ['required', 'type', 'constraints', 'description'] counter = 1 for field in all_fields: if field in prop_fields: prop_cells[counter].text = prop_field_to_str(prop_fields[field]) counter = counter + 1 def print_all_types(templ, lvl, doc): for tosca_type in TOSCA_TYPES: if not tosca_type in templ: continue print_lvl(lvl, tosca_type) add_heading_with_num(lvl, TOSCA_TYPES_PRETTYPRINT[tosca_type], doc) for data_type in templ[tosca_type]: print_lvl(lvl + 1, data_type) add_heading_with_num(lvl + 1, data_type, doc) if 'description' in templ[tosca_type][data_type]: print_lvl(lvl + 2, 'Description') add_heading_with_num(lvl + 2, 'Description', doc) doc.add_paragraph(templ[tosca_type][data_type]['description']) IDS[lvl+2] = IDS[lvl+2] + 1 if 'properties' in templ[tosca_type][data_type]: print_lvl(lvl + 2, 'Properties') add_heading_with_num(lvl + 2, 'Properties', doc) # num_row = templ[tosca_type][data_type]['properties'].items() doc.add_paragraph("The properties of the "+ dt_name_from_path(data_type) +" data type shall comply with the provisions set out in table REF_TBD.") table = doc.add_table(rows=1, cols=5) mk_props_table_hdr(table) for prop in templ[tosca_type][data_type]['properties']: # print "PROP: " + prop + ", VAL: " + str(templ[tosca_type][data_type]['properties'][prop]) add_prop_row(prop, templ[tosca_type][data_type]['properties'][prop], table) IDS[lvl+2] = IDS[lvl+2] + 1 print_lvl(lvl + 2, 'Definition') add_heading_with_num(lvl + 2, 'Definition', doc) doc.add_paragraph("The syntax of the "+ dt_name_from_path(data_type)+ " data type shall comply with the following definition:") def_table = doc.add_table(rows=1, cols=1) def_table.rows[0].cells[0].text = 'TBD' IDS[lvl+2] = IDS[lvl+2] + 1 print_lvl(lvl + 2, 'Examples') add_heading_with_num(lvl + 2, 'Examples', doc) def_table = doc.add_table(rows=1, cols=1) def_table.rows[0].cells[0].text = 'TBD' IDS[lvl+2] = IDS[lvl+2] + 1 print_lvl(lvl + 2, 'Additional Requirements') add_heading_with_num(lvl + 2, 'Additional Requirements', doc) doc.add_paragraph("None.") IDS[lvl+2] = IDS[lvl+2] + 1 IDS[lvl+1] = IDS[lvl+1] + 1 IDS[lvl+2] = 1 IDS[lvl+1] = 1 IDS[lvl] = IDS[lvl] + 1 IDS[lvl] = 2 def generate_from_file(fn, doc, fpath): load_template(fpath, TEMPLATES, fn) print_lvl(0, fn) add_heading_with_num(0, fn, doc) print_all_types(TEMPLATES[fn], 1, doc) #print TEMPLATES[fn] if __name__ == "__main__": doc = docx.Document() if len(sys.argv) < 2: print "Usage: robot2doc <robot_file_or_dir> [<out_file> [spec_section_title]]" sys.exit() FOLDR = sys.argv[1] print "Using folder: " + sys.argv[1] for fn in ['VNFD', 'NSD', 'PNFD']: generate_from_file(fn, doc, FOLDR + '/' + FNS[fn]) IDS[0] = IDS[0] + 1 doc.save('sol001.docx')