Bug 579636 - [Designer] [codegen] Papyrus should support Python code generation

- Automatically import required classifiers in Python
- Fix relative imports in Python (assuming an invocation with the "-m" option)
   - always use fully qualified imports for package imports
   - use relative paths with a preceding dot, if there is a common ancestor
- Update expected Python code
- Provide common function to check for standard library
   => Minor changes in C and CppGenUtils

Change-Id: I13b3ab865199c827274b31bd65b5c8689487f813
Signed-off-by: aradermache <ansgar.radermacher@cea.fr>
diff --git a/plugins/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/utils/CGenUtils.java b/plugins/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/utils/CGenUtils.java
index 2e3ba8f..ac41af7 100644
--- a/plugins/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/utils/CGenUtils.java
+++ b/plugins/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/utils/CGenUtils.java
@@ -90,14 +90,7 @@
 	 *         types in an identical way, i.e. we use a typedef to the associated primitive C++ type
 	 */
 	public static String getStdtypes(PrimitiveType type) {
-		Object owner = type.getOwner();
-		String owningPkgName = ""; //$NON-NLS-1$
-		if (owner instanceof Package) {
-			owningPkgName = ((Package) owner).getName();
-		}
-		if (owningPkgName.equals("PrimitiveTypes") || // used in UML >= 2.4 //$NON-NLS-1$
-				owningPkgName.equals("UMLPrimitiveTypes") || // used in UML < 2.4 //$NON-NLS-1$
-				owningPkgName.equals("MARTE_PrimitivesTypes")) { //$NON-NLS-1$
+		if (GenUtils.isUMLPrimitiveType(type) || GenUtils.isMARTEPrimitiveType(type)) {
 			String td = null;
 			String name = type.getName();
 
@@ -115,7 +108,7 @@
 				td = "unsigned long"; //$NON-NLS-1$
 			}
 			if (td != null) {
-				return "typedef " + td + " " + name + ";"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				return String.format("typedef %d %d;", td, name); //$NON-NLS-1$
 			}
 			// else unknown within UMLPrimitiveTypes, treat in standard way
 		}
diff --git a/plugins/languages/common/org.eclipse.papyrus.designer.languages.common.base/src/org/eclipse/papyrus/designer/languages/common/base/GenUtils.java b/plugins/languages/common/org.eclipse.papyrus.designer.languages.common.base/src/org/eclipse/papyrus/designer/languages/common/base/GenUtils.java
index c866e93..493fbd1 100644
--- a/plugins/languages/common/org.eclipse.papyrus.designer.languages.common.base/src/org/eclipse/papyrus/designer/languages/common/base/GenUtils.java
+++ b/plugins/languages/common/org.eclipse.papyrus.designer.languages.common.base/src/org/eclipse/papyrus/designer/languages/common/base/GenUtils.java
@@ -223,6 +223,31 @@
 	}
 
 	/**
+	 * Check, if a passed type is a UML primitive type
+	 * 
+	 * @param type
+	 *            a type
+	 * @return true, if UML primitiveType
+	 */
+	public static boolean isUMLPrimitiveType(Classifier type) {
+		String owningPkgName = type.getNearestPackage().getName();
+		return "PrimitiveTypes".equals(owningPkgName) || // used in UML >= 2.4 //$NON-NLS-1$
+				"UMLPrimitiveTypes".equals(owningPkgName); // used in UML < 2.4 //$NON-NLS-1$
+	}
+
+	/**
+	 * Check, if a passed type is a UML primitive type
+	 * 
+	 * @param type
+	 *            a type
+	 * @return true, if UML primitiveType
+	 */
+	public static boolean isMARTEPrimitiveType(Classifier type) {
+		String owningPkgName = type.getNearestPackage().getName();
+		return "MARTE_PrimitivesTypes".equals(owningPkgName); //$NON-NLS-1$
+	}
+
+	/**
 	 * Retrieve a list of types of attributes that belong to the current classifier.
 	 *
 	 * @param current
diff --git a/plugins/languages/cpp/org.eclipse.papyrus.designer.languages.cpp.codegen/src/org/eclipse/papyrus/designer/languages/cpp/codegen/utils/CppGenUtils.java b/plugins/languages/cpp/org.eclipse.papyrus.designer.languages.cpp.codegen/src/org/eclipse/papyrus/designer/languages/cpp/codegen/utils/CppGenUtils.java
index bb8ded1..1eb6980 100644
--- a/plugins/languages/cpp/org.eclipse.papyrus.designer.languages.cpp.codegen/src/org/eclipse/papyrus/designer/languages/cpp/codegen/utils/CppGenUtils.java
+++ b/plugins/languages/cpp/org.eclipse.papyrus.designer.languages.cpp.codegen/src/org/eclipse/papyrus/designer/languages/cpp/codegen/utils/CppGenUtils.java
@@ -181,7 +181,7 @@
 				td = "unsigned long"; //$NON-NLS-1$
 			}
 			if (td != null) {
-				return "typedef " + td + " " + name + ";"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				return String.format("typedef %s %s;", td, name); //$NON-NLS-1$
 			}
 			// else unknown within UMLPrimitiveTypes, treat in standard way
 		}
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/aggregationclass.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/aggregationclass.py
index d3c2616..360077f 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/aggregationclass.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/aggregationclass.py
@@ -1,5 +1,5 @@
-from elementclass2 import ElementClass2
-from elementclass1 import ElementClass1
+from .elementclass2 import ElementClass2
+from .elementclass1 import ElementClass1
 
 class AggregationClass:
 
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/associationclass.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/associationclass.py
index 1bd16f9..d513cb7 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/associationclass.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/associationclass.py
@@ -1,5 +1,3 @@
-from elementclass1 import ElementClass1
-
 class AssociationClass:
 
 	def __init__(self):
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/class2.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/class2.py
index e222cea..686d056 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/class2.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/class2.py
@@ -5,9 +5,9 @@
 	c: complex = 1+1j
 
 
-def main():
-	print(Class2.a+Class2.b+Class2.c)
+	def main():
+		print(Class2.a+Class2.b+Class2.c)
 
 
-if __name__ == '__main__':
-	main()
+	if __name__ == '__main__':
+		main()
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/compositionclass.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/compositionclass.py
index 8dabbfc..26ed48e 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/compositionclass.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/compositionclass.py
@@ -1,9 +1,9 @@
-from elementclass1 import ElementClass1
-from elementclass2 import ElementClass2
+from .elementclass1 import ElementClass1
+from .elementclass2 import ElementClass2
 
 class CompositionClass:
 
 	def __init__(self):
-		self.elementclass1 = [ElementClass1(), ElementClass1(), ElementClass1(), ElementClass1(), ElementClass1()]
+		self.elementclass1 = [ElementClass1(), ElementClass1(), ElementClass1(), ElementClass1(), ElementClass1(), ElementClass1()]
 		self.elementclass2 = ElementClass2()
 
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/daughterclass.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/daughterclass.py
index f1794d6..d1f35c3 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/daughterclass.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/daughterclass.py
@@ -1,6 +1,6 @@
-from superclass3 import SuperClass3
-from superclass2 import SuperClass2
-from superclass1 import SuperClass1
+from .superclass3 import SuperClass3
+from .superclass2 import SuperClass2
+from .superclass1 import SuperClass1
 
 class DaughterClass(SuperClass3, SuperClass2, SuperClass1):
 
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/elementclass1.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/elementclass1.py
index db8b06f..5417007 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/elementclass1.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/elementclass1.py
@@ -1,5 +1,3 @@
-from associationclass import AssociationClass
-
 class ElementClass1:
 
 	def __init__(self):
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/enumerationtest1.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/enumerationtest1.py
index a4db97d..338fa57 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/enumerationtest1.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/enumerationtest1.py
@@ -3,7 +3,7 @@
 
 
 class EnumerationTest1(Enum):
-	
+
 	EnumerationLiteral1 = 0
 	EnumerationLiteral2 = 1
 	EnumerationLiteral3 = 2
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/enumerationtest2.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/enumerationtest2.py
index 4748adf..6683eda 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/enumerationtest2.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/enumerationtest2.py
@@ -1,8 +1,8 @@
 ### Enumeration ###
 from enum import Enum
-from enumerationtest1 import EnumerationTest1
+from .enumerationtest1 import EnumerationTest1
 
 
-class EnumerationTest2(EnumEnumerationTest1):
-	
+class EnumerationTest2(EnumerationTest1):
+
 	EnumerationLiteral4 = 0
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/enumerationtestclass.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/enumerationtestclass.py
index e610531..b6f6862 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/enumerationtestclass.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/enumerationtestclass.py
@@ -1,3 +1,6 @@
+from .enumerationtest1 import EnumerationTest1
+from .enumerationtest2 import EnumerationTest2
+
 class EnumerationTestClass:
 
 	def __init__(self):
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/interfacetestclass.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/interfacetestclass.py
index d364313..8cb7018 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/interfacetestclass.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/interfacetestclass.py
@@ -1,4 +1,4 @@
-from interfacetest import InterfaceTest
+from .interfacetest import InterfaceTest
 
 class InterfaceTestClass:
 
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/dependencytest.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/dependencytest.py
index 13d2b4f..968d41b 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/dependencytest.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/dependencytest.py
@@ -1,6 +1,6 @@
-import package1_1.package1_1_1
-from package1_1.package1_1_1.pack1_1_1class2 import Pack1_1_1Class2
-from package1_1.pack1_1class2 import Pack1_1Class2
+import pythoncodegentest.package1.package1_1.package1_1_1
+from .package1_1.package1_1_1.pack1_1_1class2 import Pack1_1_1Class2
+from .package1_1.pack1_1class2 import Pack1_1Class2
 
 class DependencyTest:
 
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/pack1class1.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/pack1class1.py
index 132ded8..d76d8d3 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/pack1class1.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/pack1class1.py
@@ -1,6 +1,3 @@
-from package1_1.pack1_1class1 import Pack1_1Class1
-from package1_1.package1_1_1.pack1_1_1class1 import Pack1_1_1Class1
-
 class Pack1Class1:
 
 	def __init__(self):
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/pack1class2.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/pack1class2.py
index 7199bc1..0230f6a 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/pack1class2.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/pack1class2.py
@@ -1,5 +1,5 @@
-from package1_1.pack1_1class1 import Pack1_1Class1
-from package1_1.package1_1_1.pack1_1_1class1 import Pack1_1_1Class1
+from .package1_1.pack1_1class1 import Pack1_1Class1
+from .package1_1.package1_1_1.pack1_1_1class1 import Pack1_1_1Class1
 
 class Pack1Class2:
 
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/pack1enumeration1.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/pack1enumeration1.py
index 8e6c445..e36c014 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/pack1enumeration1.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/pack1enumeration1.py
@@ -4,4 +4,4 @@
 
 class Pack1Enumeration1(Enum):
 	pass
-	
+
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/package1_1/pack1_1class1.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/package1_1/pack1_1class1.py
index 95c9013..1d1f8be 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/package1_1/pack1_1class1.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/package1_1/pack1_1class1.py
@@ -1,5 +1,3 @@
-from pack1class1 import Pack1Class1
-
 class Pack1_1Class1:
 
 	def __init__(self):
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/package1_1/pack1_1enumeration1.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/package1_1/pack1_1enumeration1.py
index e971820..0bea5cb 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/package1_1/pack1_1enumeration1.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/package1_1/pack1_1enumeration1.py
@@ -4,4 +4,4 @@
 
 class Pack1_1Enumeration1(Enum):
 	pass
-	
+
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/package1_1/package1_1_1/pack1_1_1class1.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/package1_1/package1_1_1/pack1_1_1class1.py
index 0624d2d..877e382 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/package1_1/package1_1_1/pack1_1_1class1.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/package1/package1_1/package1_1_1/pack1_1_1class1.py
@@ -1,5 +1,4 @@
-from pack1_1class2 import Pack1_1Class2
-from pack1class1 import Pack1Class1
+from ..pack1_1class2 import Pack1_1Class2
 
 class Pack1_1_1Class1:
 
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/specialisedclass1.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/specialisedclass1.py
index 377b4de..c724dfb 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/specialisedclass1.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/specialisedclass1.py
@@ -1,4 +1,4 @@
-from abstractclass import AbstractClass
+from .abstractclass import AbstractClass
 
 class SpecialisedClass1(AbstractClass):
 
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/specialisedclass2.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/specialisedclass2.py
index f4a3b41..71fdbec 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/specialisedclass2.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/specialisedclass2.py
@@ -1,4 +1,4 @@
-from abstractclass import AbstractClass
+from .abstractclass import AbstractClass
 
 class SpecialisedClass2(AbstractClass):
 
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/testmodule.py b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/testmodule.py
index 5d875cb..8d6827c 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/testmodule.py
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/expectedResult/testmodule.py
@@ -1,5 +1,5 @@
-from module_package.module1 import mClass1
-from module_package.module1 import mClass2
+from .module_package.module1 import mClass1
+from .module_package.module1 import mClass2
 
 class testModule:
 
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/resources/PythonCodegenTest.notation b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/resources/PythonCodegenTest.notation
index fa4c707..295f414 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/resources/PythonCodegenTest.notation
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/resources/PythonCodegenTest.notation
@@ -1287,6 +1287,11 @@
       <element xmi:type="uml:Enumeration" href="PythonCodegenTest.uml#_STxNsCzyEe2vkqc4zQtyTg"/>
       <layoutConstraint xmi:type="notation:Bounds" xmi:id="_SUg0kSzyEe2vkqc4zQtyTg" x="460" y="240" width="201"/>
     </children>
+    <children xmi:type="notation:Shape" xmi:id="_e8rkAL3DEe2RoYDZpMQu0g" type="Comment_Shape">
+      <children xmi:type="notation:DecorationNode" xmi:id="_e8syIL3DEe2RoYDZpMQu0g" type="Comment_BodyLabel"/>
+      <element xmi:type="uml:Comment" href="PythonCodegenTest.uml#_e8kPQL3DEe2RoYDZpMQu0g"/>
+      <layoutConstraint xmi:type="notation:Bounds" xmi:id="_e8rkAb3DEe2RoYDZpMQu0g" x="740" y="120" width="221" height="141"/>
+    </children>
     <styles xmi:type="notation:StringValueStyle" xmi:id="_omhwMbzHEeymLfF7IeW-NA" name="diagram_compatibility_version" stringValue="1.4.0"/>
     <styles xmi:type="notation:DiagramStyle" xmi:id="_omhwMrzHEeymLfF7IeW-NA"/>
     <styles xmi:type="style:PapyrusDiagramStyle" xmi:id="_omhwM7zHEeymLfF7IeW-NA" diagramKindId="org.eclipse.papyrus.uml.diagram.class">
@@ -1304,6 +1309,13 @@
       <sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_VbRxMCzyEe2vkqc4zQtyTg" id="(0.4975124378109453,0.0)"/>
       <targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_VbRxMSzyEe2vkqc4zQtyTg" id="(0.4975124378109453,1.0)"/>
     </edges>
+    <edges xmi:type="notation:Connector" xmi:id="_2RXLcL3DEe2RoYDZpMQu0g" type="Comment_AnnotatedElementEdge" source="_e8rkAL3DEe2RoYDZpMQu0g" target="_VaiKUCzyEe2vkqc4zQtyTg">
+      <styles xmi:type="notation:FontStyle" xmi:id="_2RXLcb3DEe2RoYDZpMQu0g"/>
+      <element xsi:nil="true"/>
+      <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_2RXLcr3DEe2RoYDZpMQu0g" points="[740, 200, -643984, -643984]$[560, 186, -643984, -643984]"/>
+      <sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_2RxbIL3DEe2RoYDZpMQu0g" id="(0.0,0.5673758865248227)"/>
+      <targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_2RxbIb3DEe2RoYDZpMQu0g" id="(0.4418604651162791,0.3464566929133858)"/>
+    </edges>
   </notation:Diagram>
   <notation:Diagram xmi:id="_sc2CUMe7Eey0OLBTqXqG0A" type="PapyrusUMLClassDiagram" name="datatypeTest" measurementUnit="Pixel">
     <children xmi:type="notation:Shape" xmi:id="_tBXrsMe7Eey0OLBTqXqG0A" type="DataType_Shape">
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/resources/PythonCodegenTest.uml b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/resources/PythonCodegenTest.uml
index 9ddb386..11d3907 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/resources/PythonCodegenTest.uml
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen.tests/resources/PythonCodegenTest.uml
@@ -1,6 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <xmi:XMI xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:Codegen="http://www.eclipse.org/papyrus/Codegen/1" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:python="http://www.eclipse.org/papyrus/python/1" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML">
   <uml:Model xmi:id="_1_ToYCoNEeOncLSXAkfRBA" name="PythonCodegenTest" visibility="package">
+    <ownedComment xmi:type="uml:Comment" xmi:id="_e8kPQL3DEe2RoYDZpMQu0g" annotatedElement="_VaYZUCzyEe2vkqc4zQtyTg">
+      <body>inheritance from enumeration is not supported by Python, except if the 1st class does not define any literal. I.e. the generated code does not run.
+We keep this test to adapt generation eventually in the future</body>
+    </ownedComment>
     <packageImport xmi:type="uml:PackageImport" xmi:id="_1_ToYSoNEeOncLSXAkfRBA">
       <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
     </packageImport>
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/gen/PyAttributes.xtend b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/gen/PyAttributes.xtend
index a97b4f4..39c0e7f 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/gen/PyAttributes.xtend
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/gen/PyAttributes.xtend
@@ -1,29 +1,31 @@
 /*******************************************************************************
  * Copyright (c) 2022, 2023 CEA LIST
- *
+ * 
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse License 2.0 which
  * accompanies this distribution, and is available at
  * https://www.eclipse.org/legal/epl-2.0/
- *
+ * 
  * SPDX-License-Identifier: EPL-2.0
- *
+ * 
  * Contributors:
  *   Mohamed Harkat - Initial API and implementation
  *   Ansgar Radermacher - Integration and bug fixes
- *
+ * 
  *******************************************************************************/
 
 package org.eclipse.papyrus.designer.languages.python.codegen.gen
 
 import org.eclipse.uml2.uml.Enumeration
 import org.eclipse.uml2.uml.Property
+import org.eclipse.papyrus.designer.infra.base.StringConstants
 
 class PyAttributes {
-	/** Assign the value of the attribute depending on its multiplicity. If the attribute has an infinite multiplicity
+	/**
+	 * Assign the value of the attribute depending on its multiplicity. If the attribute has an infinite multiplicity
 	 * the function returns an empty list. If the multiplicity number is specified, a list of the same size will be
 	 * created containing all the attributes
-	 * */
+	 */
 	def static assignAttributeValue(Property property) {
 		if (!property.multivalued) {
 			return ''' = «getAttributeValue(property)»'''
@@ -31,76 +33,62 @@
 			if (property.upperBound == -1) {
 				return ''' = []'''
 			} else {
-				var str = '['
-				for (var i = 0; i < property.upper; i++) {
-					if (i + 1 == property.upper) {
-						str += getAttributeValue(property)
-					} else {
-						str += getAttributeValue(property) + ", "
-					}
-				}
-				str += "]"
-				return ''' = «str»'''
+				// repeat same value several times (TODO: useful?)
+				return ''' = [«FOR i : 0..property.upper SEPARATOR (', ')»«getAttributeValue(property)»()«ENDFOR»]'''
 			}
 		}
 	}
-	/** Same as the previous method, but it treats composite attributes. For multiple instances, the constructor
+
+	/**
+	 * Same as the previous method, but it treats composite attributes. For multiple instances, the constructor
 	 * of the attribute will be called multiple times in a list
-	 * */
+	 */
 	def static assignCompositeAttributes(Property property) {
-		if (!property.isMultivalued){
+		if (!property.isMultivalued) {
 			return ''' = «property.type.name»()'''
-		}else{
+		} else {
 			if (property.upperBound == -1) {
 				return ''' = []'''
-			}else{
-				var str = '['
-				for (var i = 0; i < property.upper; i++) {
-					if (i + 1 == property.upper) {
-						str += property.type.name + "()"
-					} else {
-						str += property.type.name + "()"+  ", "
-					}
-				}
-				str += "]"
-				return ''' = «str»'''
+			} else {
+				// repeat same value several times (TODO: useful?)
+				return ''' = [«FOR i : 0..property.upper SEPARATOR (', ')»«property.type.name»()«ENDFOR»]'''
 			}
 		}
 	}
-	/** A simple method that adds a type definition for an attribute */
-	def static assignType(Property property){
-		if(property.type === null) {
-			return ''' : None'''
+
+	/**
+	 * A simple method that adds a type definition for an attribute
+	 */
+	def static assignType(Property property) {
+		if (property.type === null) {
+			return " : None"
 		}
-		switch (property.type.name){
-			case (property.type.name == "Integer"): return ''': int'''
-			case (property.type.name == "Boolean"): return ''': bool'''
-			case (property.type.name == "Real"): return ''': float'''
-			case (property.type.name == "String"): return ''': str'''
+		switch (property.type.name) {
+			case (property.type.name == "Integer"): return ": int"
+			case (property.type.name == "Boolean"): return ": bool"
+			case (property.type.name == "Real"): return ": float"
+			case (property.type.name == "String"): return ": str"
 			default: return ''': «property.type.name»'''
 		}
 	}
-	/** A method that assigns the value of the attribute, depending on if the value is assigned in the model or not.*/
-	def static getAttributeValue(Property property){
+
+	/**
+	 * A method that assigns the value of the attribute, depending on if the value is assigned in the model or not.
+	 */
+	def static getAttributeValue(Property property) {
 		if (property.defaultValue !== null && property.type !== null) {
 			switch (property.type.name) {
-				case (property.type.name == "int" || property.type.name == "Integer") : return  property.defaultValue.stringValue
-				case (property.type.name == "bool" || property.type.name == "Boolean"): return property.defaultValue.stringValue.toFirstUpper
-				case (property.type.name == "float" || property.type.name == "Real"): return property.defaultValue.stringValue
-				case "complex": return property.defaultValue.stringValue
-				case (property.type.name == "str" || property.type.name == "String"): return property.defaultValue.stringValue
+				case (property.type.name == "bool" || property.type.name == "Boolean"): return property.defaultValue.
+					stringValue.toFirstUpper
 				case "byte": return "bytes(" + property.defaultValue.stringValue + ")"
-				case "tuple": return property.defaultValue.stringValue
-				case "set": return property.defaultValue.stringValue
-				case "list": return property.defaultValue.stringValue
-				case "dict": return property.defaultValue.stringValue
-				case "range": return property.defaultValue.stringValue
-				case property.type instanceof Enumeration : if(property.defaultValue.isNull){return "None"} else return property.type.name + '.' + property.defaultValue.stringValue
-				default: return "None"
+				case property.type instanceof Enumeration: return property.type.name + '.' +
+					property.defaultValue.stringValue
+				// respect user specified default value in most cases
+				default: return property.defaultValue.stringValue
 			}
-		}else {
-			if(property.type === null) {
-				return  "None"
+		} else {
+			if (property.type === null) {
+				return "None"
 			}
 			switch (property.type.name) {
 				case (property.type.name == "int" || property.type.name == "Integer"): return "0"
@@ -112,21 +100,23 @@
 				case "tuple": return "()"
 				case "set": return "set()"
 				case "list": return "[]"
-				case "dict" : return "{}"
-				case "range" : return "rang(0)"
+				case "dict": return "{}"
+				case "range": return "rang(0)"
 				default: return "None"
 			}
 		}
 	}
-	/**A method that write the visibility of the attribute.
-	* __ for private, _ for protected and nothing for public
-	*/
-	def static writeAttributeVisibility(Property attribute){
-		switch(attribute.visibility.toString){
-			case "private" : return '''__'''
-			case "protected" : return '''_'''
-			case "package" : return '''_'''
-			default : return ''''''
+
+	/**
+	 * A method that write the visibility of the attribute.
+	 * __ for private, _ for protected and nothing for public
+	 */
+	def static writeAttributeVisibility(Property attribute) {
+		switch (attribute.visibility.toString) {
+			case "private": return "__"
+			case "protected": return "_"
+			case "package": return "_"
+			default: return StringConstants.EMPTY
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/gen/PyClasses.xtend b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/gen/PyClasses.xtend
index 56b43d8..deb434b 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/gen/PyClasses.xtend
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/gen/PyClasses.xtend
@@ -28,9 +28,12 @@
 class PyClasses {
 	/**
 	 * The method that writes the whole class, it kind of acts as a main method here
+	 * 
+	 * @param clazz the class to generate code for
+	 * @param useRelativeImports if true, write imports in a relative way
 	 */
-	def static genClassWithNS(Class clazz, boolean relativeImports)'''
-		«val imports = PythonCodeGenUtils.writeImports(clazz, relativeImports)»
+	def static genClassWithNS(Class clazz, boolean useRelativeImports)'''
+		«val imports = PythonCodeGenUtils.writeImports(clazz, useRelativeImports)»
 		«imports»
 		«IF !imports.toString.isBlank» ««« add a blank line, if imports not empty
 
@@ -38,6 +41,7 @@
 		«ENDIF»
 		«clazz.genClass»
 	'''
+
 	/**
 	 * Generate the header and the body of the class
 	 */
@@ -73,21 +77,22 @@
 					pass
 
 			«ENDIF»
-		«IF StereotypeUtil.isApplied(clazz, Main)»
-			«val main = UMLUtil.getStereotypeApplication(clazz, Main)»
+			«IF StereotypeUtil.isApplied(clazz, Main)»
+				«val main = UMLUtil.getStereotypeApplication(clazz, Main)»
 
-			def main():
-				«IF main.body.empty»
-					pass
-				«ELSE»
-					«main.body»
-				«ENDIF»
+				def main():
+					«IF main.body.empty»
+						pass
+					«ELSE»
+						«main.body»
+					«ENDIF»
 
 
-			if __name__ == '__main__':
-				main()
-		«ENDIF»
+				if __name__ == '__main__':
+					main()
+			«ENDIF»
 	'''
+
 	/**
 	 * A method to write static attributes of the class. the attributes should be declared outside the constructor.
 	 */
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/gen/PyEnumeration.xtend b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/gen/PyEnumeration.xtend
index 80cf4c9..ce046af 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/gen/PyEnumeration.xtend
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/gen/PyEnumeration.xtend
@@ -30,7 +30,7 @@
 
 
 		«var int i = 0»
-		class «enumeration.name»(Enum«IF !enumeration.generals.empty»«FOR superEnumeration : enumeration.generals SEPARATOR ', '»«superEnumeration.name»«ENDFOR»«ENDIF»):
+		class «enumeration.name»(«IF enumeration.generals.empty»Enum«ELSE»«FOR superEnumeration : enumeration.generals SEPARATOR ', '»«superEnumeration.name»«ENDFOR»«ENDIF»):
 			«IF enumeration.ownedLiterals.empty»
 				pass
 			«ENDIF»
diff --git a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/transformation/PythonCodeGenUtils.xtend b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/transformation/PythonCodeGenUtils.xtend
index 135556e..886fbbf 100644
--- a/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/transformation/PythonCodeGenUtils.xtend
+++ b/plugins/languages/python/org.eclipse.papyrus.designer.languages.python.codegen/src/org/eclipse/papyrus/designer/languages/python/codegen/transformation/PythonCodeGenUtils.xtend
@@ -21,6 +21,9 @@
 import org.eclipse.papyrus.uml.tools.utils.StereotypeUtil
 import org.eclipse.uml2.uml.Namespace
 import org.eclipse.papyrus.designer.infra.base.StringConstants
+import org.eclipse.papyrus.designer.languages.common.base.ClassUtils
+import static extension org.eclipse.papyrus.designer.languages.common.base.GenUtils.isUMLPrimitiveType
+import org.eclipse.papyrus.uml.tools.utils.PackageUtil
 
 /**
  * Utility method for Python code generation
@@ -39,57 +42,30 @@
 	 * Get the relative path of the target Classifier to the source classifier
 	 * (The classifier type was chosen here because classes, interfaces
 	 * enumerations and datatypes are all specializations of the classifier).
-	 * If the two classifier are in the same package, return an empty string.
+	 * 
+	 * @param src the importing classifier
+	 * @param target the element to import
 	 */
-	def static getPackagePath(Classifier src, NamedElement target) {
-		if (src.allOwningPackages.contains(target.namespace))
-			return target.name.toLowerCase
-		else {
-			// If the src and the target share some parent packages, there is no need to add them, so they are deleted here
-			if (target.allOwningPackages.contains(src.namespace)) {
-				return getPythonQName(target).replaceFirst(getPythonQName(src.namespace) + StringConstants.DOT, '')
-			} else {
-				// if the src and the target have no parent packages in common, return the whole package branch of the target
-				return getPythonQName(target)
-			}
+	def static getRelativePath(Classifier src, NamedElement target) {
+		// find common namespace element
+		var dot = StringConstants.DOT;
+		var ns = src.namespace;
+		while (!target.allNamespaces.contains(ns) && ns !== null) {
+			dot += StringConstants.DOT;
+			ns = ns.namespace;
+		}
+		if (ns !== null) {
+			// use relative path to common element + remove path to this element from qualified name.
+			return dot + getPythonQName(target).replaceFirst(getPythonQName(ns) + StringConstants.DOT, '')
+
+		} else {
+			// no parent packages in common, return the whole package branch of the target
+			return getPythonQName(target)
 		}
 	}
 
 	/**
-	 * In order to avoid importation redundancy, we get all the other ends of the relations
-	 * (generalizations, dependencies, associations, aggregations and compositions) that
-	 * this classifier is involved with.
-	 */
-	def static getAllRelationEnds(Classifier src) {
-		var dp = newArrayList
-		// Get all the generalizing classifiers for this Classifier
-		for (general : src.generals) {
-			dp.add(general)
-		}
-		// Get all classifiers from dependency relations
-		for (dependency : src.clientDependencies) {
-			for (target : dependency.targets.filter[(it instanceof NamedElement) && !(it instanceof Package)]) {
-				dp.add(target as Classifier)
-			}
-		}
-		for (asc : src.associations) {
-			// Get the navigable end of the aggregation and the composition. if it is the same classifier, filter it.
-			if (!asc.memberEnds.filter[it.navigable].empty) {
-				for (end : asc.memberEnds.filter[it.navigable && !it.type.name.equals(src.name)]) {
-					dp.add(end.type as Classifier)
-				}
-			} else {
-				// Get the other end of the association
-				for (end : asc.memberEnds.filter[!it.type.name.equals(src.name)])
-					dp.add(end.type as Classifier)
-			}
-		}
-		// Set conversion to avoid redundant elements in the array
-		return dp.toSet
-	}
-
-	/**
-	 * Returns an arraylist which contains all the packages that the classifier depends on.
+	 * Returns an array list which contains all the packages that the classifier depends on.
 	 */
 	def static getPackageDep(Classifier src) {
 		var packDp = newArrayList
@@ -102,6 +78,18 @@
 	}
 
 	/**
+	 * 
+	 */
+	def static pyRequiredClassifiers(Classifier classifier) {
+		return ClassUtils.requiredClassifiers(classifier).filter[!it.isUMLPrimitiveType && !it.isPythonPrimitiveType]
+	}
+
+	def static isPythonPrimitiveType(Classifier type) {
+		val owningPkgName = type.nearestPackage.name;
+		return "PythonStdLib".equals(owningPkgName)
+	}
+
+	/**
 	 * Write all the necessary importations for the classifier for all the relations.
 	 */
 	def static writeImports(Classifier classifier, boolean useRelativeImports) '''
@@ -109,16 +97,13 @@
 			from abc import ABC, abstractmethod
 		«ENDIF»
 		«FOR pkg : classifier.getPackageDep»
-			«IF useRelativeImports»
-				import «getPackagePath(classifier, pkg)»
-			«ELSE»
-				import «pkg.pythonQName»
-			«ENDIF»
+««« No relative imports on package level
+			import «pkg.pythonQName»
 		«ENDFOR»
-		«FOR dependencyClassifier : getAllRelationEnds(classifier)»
+		«FOR dependencyClassifier : classifier.pyRequiredClassifiers»
 			«val mp = dependencyClassifier.modulePkg»
 			«IF useRelativeImports»
-				from «classifier.getPackagePath(mp)» import «dependencyClassifier.name»
+				from «classifier.getRelativePath(mp)» import «dependencyClassifier.name»
 			«ELSE»
 				from «mp.pythonQName» import «dependencyClassifier.name»
 			«ENDIF»