SEBA-419 allow legacy to be specified on a per-model basis;
Deprecate "legacy" in favor of "custom_python"

Change-Id: I44625ff18ee7796996ae25ad700e58a0b36e7398
diff --git a/lib/xos-genx/xos-genx-tests/test_generator.py b/lib/xos-genx/xos-genx-tests/test_generator.py
index 8212d51..b3710cd 100644
--- a/lib/xos-genx/xos-genx-tests/test_generator.py
+++ b/lib/xos-genx/xos-genx-tests/test_generator.py
@@ -45,6 +45,12 @@
 FILTERTEST_XPROTO = os.path.abspath(
     os.path.dirname(os.path.realpath(__file__)) + "/xproto/filtertest.xproto"
 )
+CUSTOM_TEST1_XPROTO = os.path.abspath(
+    os.path.dirname(os.path.realpath(__file__)) + "/xproto/custom_test1.xproto"
+)
+CUSTOM_TEST2_XPROTO = os.path.abspath(
+    os.path.dirname(os.path.realpath(__file__)) + "/xproto/custom_test2.xproto"
+)
 SKIP_DJANGO_XPROTO = os.path.abspath(
     os.path.dirname(os.path.realpath(__file__)) + "/xproto/skip_django.xproto"
 )
@@ -114,25 +120,25 @@
         output = XOSProcessor.process(args)
 
         # xosmodel has custom header attic
-        self.assertIn("from xosmodel_header import *", output["XOSModel"])
-        self.assertIn("class XOSModel(XOSBase):", output["XOSModel"])
+        self.assertIn("from core.models.xosbase import *", output["XOSModel"])
+        self.assertIn("class XOSModel_decl(XOSBase):", output["XOSModel"])
 
         # vrouter port use the default header
-        self.assertIn("header import *", output["VRouterPort"])
-        self.assertIn("class VRouterPort(XOSBase):", output["VRouterPort"])
+        self.assertIn("from core.models.xosbase import *", output["VRouterPort"])
+        self.assertIn("class VRouterPort_decl(XOSBase):", output["VRouterPort"])
 
         # verify files
         xosmodel = OUTPUT_DIR + "/xosmodel.py"
         self.assertTrue(os.path.isfile(xosmodel))
         xmf = open(xosmodel).read()
-        self.assertIn("from xosmodel_header import *", xmf)
-        self.assertIn("class XOSModel(XOSBase):", xmf)
+        self.assertIn("from core.models.xosbase import *", xmf)
+        self.assertIn("class XOSModel_decl(XOSBase):", xmf)
 
         vrouterport = OUTPUT_DIR + "/vrouterport.py"
         self.assertTrue(os.path.isfile(vrouterport))
         vrpf = open(vrouterport).read()
-        self.assertIn("header import *", vrpf)
-        self.assertIn("class VRouterPort(XOSBase):", vrpf)
+        self.assertIn("from core.models.xosbase import *", vrpf)
+        self.assertIn("class VRouterPort_decl(XOSBase):", vrpf)
 
     def test_django_with_base(self):
         args = XOSProcessorArgs(
@@ -149,14 +155,14 @@
         xosmodel = OUTPUT_DIR + "/xosmodel.py"
         self.assertTrue(os.path.isfile(xosmodel))
         xmf = open(xosmodel).read()
-        self.assertIn("from xosmodel_header import *", xmf)
-        self.assertIn("class XOSModel(XOSBase):", xmf)
+        self.assertIn("from core.models.xosbase import *", xmf)
+        self.assertIn("class XOSModel_decl(XOSBase):", xmf)
 
         xosbase = OUTPUT_DIR + "/xosbase.py"
         self.assertTrue(os.path.isfile(xosbase))
         xbf = open(xosbase).read()
-        self.assertIn("header import *", xbf)
-        self.assertIn("class XOSBase(models.Model, PlModelMixIn):", xbf)
+        self.assertIn("from core.models.xosbase import *", xbf)
+        self.assertIn("class XOSBase_decl(models.Model, PlModelMixIn):", xbf)
 
     def test_write_multiple_files(self):
         """
@@ -312,6 +318,74 @@
 
         self.assertEqual(output, "Model1,Model2,")
 
+    def test_django_custom_test1(self):
+        args = XOSProcessorArgs(
+            files=[CUSTOM_TEST1_XPROTO, BASE_XPROTO],
+            target="django.xtarget",
+            attic=TEST_ATTICS,
+            output=OUTPUT_DIR,
+            dest_extension="py",
+            write_to_file="model",
+        )
+        output = XOSProcessor.process(args)
+
+        # verify files
+        xosmodel = OUTPUT_DIR + "/xosmodel_decl.py"
+        self.assertTrue(os.path.isfile(xosmodel))
+        xmf = open(xosmodel).read()
+        self.assertIn("class XOSModel_decl(XOSBase):", xmf)
+
+        xosmodel = OUTPUT_DIR + "/xosmodel2_decl.py"
+        self.assertTrue(os.path.isfile(xosmodel))
+        xmf = open(xosmodel).read()
+        self.assertIn("class XOSModel2_decl(XOSBase):", xmf)
+
+    def test_django_custom_test2(self):
+        args = XOSProcessorArgs(
+            files=[CUSTOM_TEST2_XPROTO, BASE_XPROTO],
+            target="django.xtarget",
+            attic=TEST_ATTICS,
+            output=OUTPUT_DIR,
+            dest_extension="py",
+            write_to_file="model",
+        )
+        output = XOSProcessor.process(args)
+
+        # verify files
+        xosmodel = OUTPUT_DIR + "/xosmodel_decl.py"
+        self.assertTrue(os.path.isfile(xosmodel))
+        xmf = open(xosmodel).read()
+        self.assertIn("class XOSModel_decl(XOSBase):", xmf)
+        self.assertNotIn("class XOSModel(XOSModel_decl):", xmf)
+
+        xosmodel = OUTPUT_DIR + "/xosmodel2.py"
+        self.assertTrue(os.path.isfile(xosmodel))
+        xmf = open(xosmodel).read()
+        self.assertIn("class XOSModel2_decl(XOSBase):", xmf)
+        self.assertIn("class XOSModel2(XOSModel2_decl):", xmf)
+
+    def test_service_custom_test1(self):
+        args = XOSProcessorArgs(
+            files=[CUSTOM_TEST1_XPROTO, BASE_XPROTO],
+            target="service.xtarget",
+            attic=TEST_ATTICS,
+            output=OUTPUT_DIR,
+            dest_extension="py",
+            write_to_file="target",
+        )
+        output = XOSProcessor.process(args)
+
+        # verify files
+        xosmodel = OUTPUT_DIR + "/models_decl.py"
+        self.assertTrue(os.path.isfile(xosmodel))
+        xmf = open(xosmodel).read()
+        self.assertIn("class XOSModel_decl(XOSBase_decl):", xmf)
+
+        xosmodel = OUTPUT_DIR + "/models_decl.py"
+        self.assertTrue(os.path.isfile(xosmodel))
+        xmf = open(xosmodel).read()
+        self.assertIn("class XOSModel2_decl(XOSBase_decl):", xmf)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/lib/xos-genx/xos-genx-tests/test_jinja2_base.py b/lib/xos-genx/xos-genx-tests/test_jinja2_base.py
index 3b988e5..b2cbdef 100644
--- a/lib/xos-genx/xos-genx-tests/test_jinja2_base.py
+++ b/lib/xos-genx/xos-genx-tests/test_jinja2_base.py
@@ -16,6 +16,7 @@
 from __future__ import absolute_import
 import unittest
 from xosgenx.jinja2_extensions.base import *
+from jinja2.runtime import Undefined
 
 
 # Several of the base functions require a Field object.
@@ -79,6 +80,24 @@
             xproto_singularize(_field("sheep", singular="turtle")), "turtle"
         )
 
+    def test_xproto_first_non_empty(self):
+        self.assertEqual(xproto_first_non_empty(["a"]), "a")
+        self.assertEqual(xproto_first_non_empty([None,"a"]), "a")
+        self.assertEqual(xproto_first_non_empty([None]), None)
+        self.assertEqual(xproto_first_non_empty([]), None)
+        self.assertEqual(xproto_first_non_empty([False, True]), False)
+        self.assertEqual(xproto_first_non_empty([None, "Foo", True]), "Foo")
+        self.assertEqual(xproto_first_non_empty(["", "Foo", True]), "Foo")
+        self.assertEqual(xproto_first_non_empty([Undefined(), "Foo", True]), "Foo")
+
+    def test_list_evaluates_true(self):
+        self.assertTrue(xproto_list_evaluates_true([True]))
+        self.assertTrue(xproto_list_evaluates_true(["True"]))
+        self.assertTrue(xproto_list_evaluates_true(['"True"']))
+        self.assertFalse(xproto_list_evaluates_true([False, True]))
+        self.assertFalse(xproto_list_evaluates_true([]))
+        self.assertFalse(xproto_list_evaluates_true([False]))
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/lib/xos-genx/xos-genx-tests/xproto/custom_test1.xproto b/lib/xos-genx/xos-genx-tests/xproto/custom_test1.xproto
new file mode 100644
index 0000000..753500f
--- /dev/null
+++ b/lib/xos-genx/xos-genx-tests/xproto/custom_test1.xproto
@@ -0,0 +1,13 @@
+// custom_python at the root level should override both models
+
+option custom_python = True;
+
+message XOSModel (XOSBase) {
+     required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Help Name", null = False, db_index = False];
+     required string files = 2 [max_length = 1024, content_type = "stripped", blank = False, help_text = "Help Files", null = False, db_index = False];
+}
+
+message XOSModel2 (XOSBase) {
+     required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Help Name", null = False, db_index = False];
+     required string files = 2 [max_length = 1024, content_type = "stripped", blank = False, help_text = "Help Files", null = False, db_index = False];
+}
\ No newline at end of file
diff --git a/lib/xos-genx/xos-genx-tests/xproto/custom_test2.xproto b/lib/xos-genx/xos-genx-tests/xproto/custom_test2.xproto
new file mode 100644
index 0000000..f3877ee
--- /dev/null
+++ b/lib/xos-genx/xos-genx-tests/xproto/custom_test2.xproto
@@ -0,0 +1,12 @@
+// custom_python at the model level should override only one model
+
+message XOSModel (XOSBase) {
+     option custom_python = True;
+     required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Help Name", null = False, db_index = False];
+     required string files = 2 [max_length = 1024, content_type = "stripped", blank = False, help_text = "Help Files", null = False, db_index = False];
+}
+
+message XOSModel2 (XOSBase) {
+     required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Help Name", null = False, db_index = False];
+     required string files = 2 [max_length = 1024, content_type = "stripped", blank = False, help_text = "Help Files", null = False, db_index = False];
+}
\ No newline at end of file