From 19350c70564030d16bfd88b9692d5b66579b3b3a Mon Sep 17 00:00:00 2001
From: Michele Carignani <michele.carignani@etsi.org>
Date: Wed, 27 Feb 2019 23:39:10 +0100
Subject: [PATCH] produce docx

---
 main.py | 213 +++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 165 insertions(+), 48 deletions(-)

diff --git a/main.py b/main.py
index 0591013..a7f437f 100755
--- a/main.py
+++ b/main.py
@@ -1,65 +1,182 @@
 #!/usr/bin/python2.7
+'''
+Parses a TOSCA template and generates a docx file
+'''
+
 
-import toscaparser
 import sys
-import os
-#import toscaparser.tosca_template
 import toscaparser.utils.yamlparser as yaml
 
-print "Opening file " + sys.argv[1]
-#res = toscaparser.validate(sys.argv[1])
-#templ = toscaparser.tosca_template.ToscaTemplate(os.path.join(
-#            os.path.dirname(os.path.abspath(__file__)),
-#           'data',
-#            sys.argv[1]))
+import docx
+from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
 
 TEMPLATES = {}
 
-def load_template(fn, templs, key):
-	yaml_data = open(fn).read()
-	templs[key] = yaml.simple_ordered_parse(yaml_data)
-
-tosca_types = [ 
-	'data_types', 
-	'artifact_types', 
-	'capability_types',
-	'requirements_types',
-	'relationship_types',
-	'interface_types',
-	'node_types',
-	'group_types',
-	'policy_types'
+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'
 ]
 
-ids = [ 6, 2, 1]
+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]
+
+doc = docx.Document()
+
+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()
+    templs[key] = yaml.simple_ordered_parse(yaml_data)
+
+def print_lvl(num, txt):
+    index = ".".join(map(str, IDS[:(num+1)]))
+    print index +  " " + ('-'*(num+1)) + ' ' + txt
+
+def add_heading_with_num(num, txt):
+    '''
+    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 print_lvl(n, txt):
-	index = ".".join(map(str,ids[:(n+1)]))
-	print index +  " " + ('-'*(n+1)) + ' ' + txt
+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):
-	for tt in tosca_types:
-        	if not tt in templ:
-			continue
-		print_lvl(lvl, tt)
-		for dt in templ[tt]:
-			print_lvl(lvl + 1, dt)
-			ids[lvl+1] = ids[lvl+1] + 1
-		ids[lvl+1] = 1
-		ids[lvl] = ids[lvl] + 1
-		print
-	ids[lvl] = 2
+    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])
+        for data_type in templ[tosca_type]:
+            print_lvl(lvl + 1, data_type)
+            add_heading_with_num(lvl + 1, data_type)
+
+            if 'description' in templ[tosca_type][data_type]:
+                print_lvl(lvl + 2, 'Description')
+                add_heading_with_num(lvl + 2, 'Description')
+                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')
+                # 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.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')
+            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.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
 
 FOLDR = sys.argv[1]
 
-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'
-}
+if __name__ == "__main__":
+
+    if len(sys.argv) < 2:
+        print "Usage: robot2doc <robot_file_or_dir> [<out_file> [spec_section_title]]"
+
+
+    print "Using folder: " + sys.argv[1]
+
+    for fn in ['VNFD', 'NSD', 'PNFD']:
+        load_template(FOLDR + '/' + FNS[fn], TEMPLATES, fn)
+        print_lvl(0, fn)
+        add_heading_with_num(0, fn)
+        print_all_types(TEMPLATES[fn], 1)
+        IDS[0] = IDS[0] + 1
 
-for fn in ['VNFD', 'NSD', 'PNFD']:
-	load_template(FOLDR + '/' + fns[fn], TEMPLATES, fn)
-	print_lvl(0, fn)
-	print_all_types(TEMPLATES[fn], 1)
-	ids[0] = ids[0] + 1
+    doc.save('sol001.docx')
-- 
GitLab