From 89e2eea5ac6e7c9f653f3696be6816bfc098e749 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lukas=20M=C3=BCller?= <l.muller@student.tudelft.nl>
Date: Wed, 23 Aug 2017 11:22:24 +0200
Subject: [PATCH] Implemented organization dictionary in Python (with saving to
 CMDOWS)

Former-commit-id: e72bd516385e907f5b33585a9fc641c7f5fc5f54
---
 examples/scripts/sellar_problem.py | 10 ++++++++++
 kadmos/graph/graph_kadmos.py       |  3 +++
 kadmos/utilities/general.py        | 20 ++++++++++++++++++++
 kadmos/utilities/xml.py            | 29 ++++++++++++++++++++++++++---
 4 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/examples/scripts/sellar_problem.py b/examples/scripts/sellar_problem.py
index dd4b9ceaa..6a916b1a4 100644
--- a/examples/scripts/sellar_problem.py
+++ b/examples/scripts/sellar_problem.py
@@ -31,6 +31,7 @@ import os
 import logging
 
 from lxml import etree
+from collections import OrderedDict
 
 from kadmos.graph import FundamentalProblemGraph
 from kadmos.knowledgebase import KnowledgeBase
@@ -99,6 +100,15 @@ RCG.add_equation('F1', 'x1**2+z2+y1+exp(-y2)', 'Python')
 RCG.add_equation('F1', 'x1^2+z2+y1+e^{-y2}', 'LaTeX')
 RCG.add_equation('F1', '<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi><msup><mn>1</mn><mn>2</mn></msup><mo>+</mo><mi>z</mi><mn>2</mn><mo>+</mo><mi>y</mi><mn>1</mn><mo>+</mo><msup><mi>e</mi><mrow><mo>-</mo><mi>y</mi><mn>2</mn></mrow></msup></math>', 'MathML')
 
+print 'Adding an oranization node to the graph for illustration purposes...'
+contacts = [OrderedDict([('u_i_d', 'ivangent'), ('name', 'Imco van Gent'), ('email', 'i.vangent@tudelft.nl'), ('company', 'TU Delft')]),
+            OrderedDict([('u_i_d', 'lmuller'), ('name', 'Lukas Muller'), ('email', 'l.muller@student.tudelft.nl'), ('company', 'TU Delft')])]
+architects = [{'contact_u_i_d': 'ivangent'}, {'contact_u_i_d': 'lmuller'}]
+integrators = [{'contact_u_i_d': 'ivangent'}]
+RCG.graph['organization'] = OrderedDict([('contacts', contacts),
+                                         ('organigram', OrderedDict([('architects', architects),
+                                                                     ('integrators', integrators)]))])
+
 print 'Scripting RCG...'
 # Plot RCG
 if show_plots:
diff --git a/kadmos/graph/graph_kadmos.py b/kadmos/graph/graph_kadmos.py
index 54bfb2159..59bff1761 100644
--- a/kadmos/graph/graph_kadmos.py
+++ b/kadmos/graph/graph_kadmos.py
@@ -793,6 +793,9 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin):
         cmdows_update.add('fileVersion', version)
         cmdows_update.add('cmdowsVersion', cmdows_version)
 
+        # Create header/organization
+        cmdows_header.add_dict('organization', self.graph.get('organization'))
+
         return cmdows_header
 
     def _create_cmdows_executables(self):
diff --git a/kadmos/utilities/general.py b/kadmos/utilities/general.py
index cd8111462..a61bd9fdc 100644
--- a/kadmos/utilities/general.py
+++ b/kadmos/utilities/general.py
@@ -317,6 +317,26 @@ def make_plural(string):
     return string
 
 
+def make_singular(string):
+    """
+    Function to convert a string to its singular form.
+
+    :param string: initial string
+    :type string: str
+    :return: singular string
+    :rtype: str
+    """
+
+    if string[-2:] == 'es':
+        # e.g. 'analyses' should become 'analysis'
+        string = string[:-2] + 'is'
+    elif string[-1:] == 's':
+        # e.g. 'variables' should become 'variable'
+        string = string[:-1]
+
+    return string
+
+
 def make_camel_case(string, make_plural_option=False):
     """
     Function to make a string camelCase.
diff --git a/kadmos/utilities/xml.py b/kadmos/utilities/xml.py
index dcaa584eb..4a0b9774a 100644
--- a/kadmos/utilities/xml.py
+++ b/kadmos/utilities/xml.py
@@ -2,10 +2,11 @@ import re
 import ast
 import logging
 
+from collections import OrderedDict
 from lxml import etree
 from lxml.etree import SubElement
 
-from general import make_camel_case, unmake_camel_case, string_eval
+from general import make_camel_case, unmake_camel_case, string_eval, make_singular, make_plural
 
 
 # Settings for the logger
@@ -288,14 +289,36 @@ class ExtendedElement(etree.ElementBase):
         child = SubElement(self, tag, attrib, **extra)
 
         if type(dictionary) == dict:
-            for key, value in dictionary.iteritems():
-                if type(value) == dict:
+            iterator = dictionary.iteritems()
+        elif type(dictionary) == OrderedDict:
+            iterator = dictionary.items()
+
+        if  type(dictionary) == dict or type(dictionary) == OrderedDict:
+            for key, value in iterator:
+                if type(value) == dict or type(value) == OrderedDict:
                     child.add_dict(make_camel_case(key), value)
+                elif type(value) == list:
+                    child.add_array(make_singular(make_camel_case(key)), value)
+                elif make_camel_case(key) == 'uID':
+                    child.set(make_camel_case(key), value)
                 else:
                     child.add(make_camel_case(key), value)
 
         return child
 
+    def add_array(self, tag, array, attrib={}, **extra):
+
+        child = SubElement(self, make_plural(tag), attrib, **extra)
+
+        for item in array:
+            if type(item) == dict or type(item) == OrderedDict:
+                child.add_dict(tag, item)
+            elif type(item) == list:
+                child.add_array(tag, item)
+            else:
+                child.add(item)
+
+
     def add_sequence(self, data, data_keys=None, data_dict=None):
         """Method extending the previously defined add function such that sequences can easily be created
 
-- 
GitLab