SEBA-225 Throw exception if wrapper has syntax error

Change-Id: I084ebe33aeeee5272ab4a4f36e8a163fd2609d8c
diff --git a/VERSION b/VERSION
index 63a1a1c..8dbb0f2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.1.9
+2.1.10
diff --git a/containers/xos/Dockerfile.client b/containers/xos/Dockerfile.client
index 9230250..299cb90 100644
--- a/containers/xos/Dockerfile.client
+++ b/containers/xos/Dockerfile.client
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/xos-client
-FROM xosproject/xos-libraries:2.1.9
+FROM xosproject/xos-libraries:2.1.10
 
 # Install XOS client
 COPY xos/xos_client /tmp/xos_client
diff --git a/containers/xos/Dockerfile.libraries b/containers/xos/Dockerfile.libraries
index e26a00c..1a150d9 100644
--- a/containers/xos/Dockerfile.libraries
+++ b/containers/xos/Dockerfile.libraries
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM xosproject/xos-base:2.1.9
+FROM xosproject/xos-base:2.1.10
 
 # Add libraries
 COPY lib /opt/xos/lib
diff --git a/containers/xos/Dockerfile.synchronizer-base b/containers/xos/Dockerfile.synchronizer-base
index 7270bea..14913a5 100644
--- a/containers/xos/Dockerfile.synchronizer-base
+++ b/containers/xos/Dockerfile.synchronizer-base
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/xos-synchronizer-base
-FROM xosproject/xos-client:2.1.9
+FROM xosproject/xos-client:2.1.10
 
 COPY xos/synchronizers/new_base /opt/xos/synchronizers/new_base
 COPY xos/xos/logger.py /opt/xos/xos/logger.py
diff --git a/containers/xos/Dockerfile.xos-core b/containers/xos/Dockerfile.xos-core
index c8e384d..0d28235 100644
--- a/containers/xos/Dockerfile.xos-core
+++ b/containers/xos/Dockerfile.xos-core
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/xos-core
-FROM xosproject/xos-libraries:2.1.9
+FROM xosproject/xos-libraries:2.1.10
 
 # Install XOS
 ADD xos /opt/xos
diff --git a/xos/coreapi/dynamicbuild.py b/xos/coreapi/dynamicbuild.py
index b35fcab..3a4c8e4 100644
--- a/xos/coreapi/dynamicbuild.py
+++ b/xos/coreapi/dynamicbuild.py
@@ -17,6 +17,7 @@
 import hashlib
 import os
 import shutil
+import tempfile
 from xosgenx.generator import XOSProcessor
 
 from xosconfig import Config
@@ -43,6 +44,16 @@
         if "/" in item.filename:
             raise Exception("illegal character in filename %s" % item.filename)
 
+    def pre_validate_python(self, item):
+        (handle, fn) = tempfile.mkstemp()
+        try:
+            os.write(handle, item.contents)
+            os.close(handle)
+            if (os.system("python -m py_compile %s" % fn) != 0):
+                raise Exception("python file %s failed compile test" % item.filename)
+        finally:
+            os.remove(fn)
+
     def pre_validate_models(self, request):
         # do whatever validation we can before saving the files
         for item in request.xprotos:
@@ -54,6 +65,10 @@
         for item in request.attics:
             self.pre_validate_file(item)
 
+        for item in request.convenience_methods:
+            self.pre_validate_file(item)
+            self.pre_validate_python(item)
+
     def get_manifests(self):
         if not os.path.exists(self.manifest_dir):
             return []
diff --git a/xos/coreapi/test_dynamicbuild.py b/xos/coreapi/test_dynamicbuild.py
index 476edf6..ce65e40 100644
--- a/xos/coreapi/test_dynamicbuild.py
+++ b/xos/coreapi/test_dynamicbuild.py
@@ -184,6 +184,36 @@
         self.assertEqual(manifest["dest_dir"], service_dir)
         self.assertEqual(len(manifest["xprotos"]), 1)
 
+    def test_pre_validate_python_good(self):
+        good_python = \
+"""
+import foo
+
+x=1
+y="abc"
+"""
+        python_item = DynamicLoadItem(filename="somefile.py",
+                                      contents=good_python)
+
+        self.builder.pre_validate_python(python_item)
+
+    def test_pre_validate_python_bad(self):
+        bad_python = \
+"""
+import foo
+
+this is not valid code
+y="abc"
+"""
+        python_item = DynamicLoadItem(filename="somefile.py",
+                                      contents=bad_python)
+
+        with self.assertRaises(Exception) as e:
+             self.builder.pre_validate_python(python_item)
+
+        self.assertEqual(e.exception.message, "python file somefile.py failed compile test")
+
+
 def main():
     unittest.main()