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»