浏览代码

Fix MANUAL operations in the wrapper as well

Yentl Van Tendeloo 8 年之前
父节点
当前提交
f4b932d774
共有 3 个文件被更改,包括 132 次插入423 次删除
  1. 1 1
      core/mini_modify.alc
  2. 56 403
      integration/test_mvc.py
  3. 75 19
      wrappers/modelverse.py

+ 1 - 1
core/mini_modify.alc

@@ -374,7 +374,7 @@ Element function modify(model : Element, write : Boolean):
 		elif (cmd == "read_association_destination"):
 			output(cmd_read_association_destination(write, model, single_input("Name?")))
 		else:
-			output("Unknown command: " + cast_v2s(cmd))
+			output("Unknown command while modelling: " + cast_v2s(cmd))
 			output("Use command 'help' to get a list of available commands")
 	return model!
 

+ 56 - 403
integration/test_mvc.py

@@ -95,7 +95,6 @@ class TestModelverseCore(unittest.TestCase):
 
         def callback(value):
             log.append(value)
-            return None
 
         model_add("PetriNet", "SimpleClassDiagrams", open("integration/code/pn_runtime.mvc", "r").read())
         model_add("my_pn", "PetriNet", open("integration/code/pn_runtime_model.mvc", "r").read())
@@ -137,7 +136,6 @@ class TestModelverseCore(unittest.TestCase):
 
         def callback(value):
             log.append(value)
-            return None
 
         model_add("PetriNet", "SimpleClassDiagrams", open("integration/code/pn_design.mvc", "r").read())
         model_add("PetriNet_Runtime", "SimpleClassDiagrams", open("integration/code/pn_runtime.mvc", "r").read())
@@ -177,7 +175,6 @@ class TestModelverseCore(unittest.TestCase):
 
         def callback(value):
             log.append(value)
-            return None
 
         model_add("PetriNet", "SimpleClassDiagrams", open("integration/code/pn_design.mvc", "r").read())
         model_add("PetriNet_Runtime", "SimpleClassDiagrams", open("integration/code/pn_runtime.mvc", "r").read())
@@ -213,407 +210,63 @@ class TestModelverseCore(unittest.TestCase):
                                 '"p3" --> 5'])
 
     def test_transform_add_MANUAL_pn_simulate(self):
-        self.assertTrue(run_file(all_files,
-            [ "admin", "admin", "admin", 
-                "model_add",
-                    "SimpleClassDiagrams",
-                    "PetriNets",
-                    ] + get_model_constructor(open("integration/code/pn_design.mvc", "r").read()) + [
-                "model_add",
-                    "SimpleClassDiagrams",
-                    "PetriNets_Runtime",
-                    ] + get_model_constructor(open("integration/code/pn_runtime.mvc", "r").read()) + [
-                "model_add",
-                    "PetriNets",
-                    "my_pn",
-                    ] + get_model_constructor(open("integration/code/pn_design_model.mvc", "r").read()) + [
-                "model_list",
-                "transformation_add_MT_language",
-                    "PetriNets_Runtime",
-                    "PetriNets",
-                    "",
-                    "PetriNets_RAM",
-                "model_list",
-                "model_modify",
-                    "__merged_PetriNets_RAM",
-                        "instantiate",
-                            "Association",
-                            "D2R_PlaceLink",
-                            "PetriNets/Place",
-                            "PetriNets_Runtime/Place",
-                        "instantiate",
-                            "Association",
-                            "D2R_TransitionLink",
-                            "PetriNets/Transition",
-                            "PetriNets_Runtime/Transition",
-                        "instantiate",
-                            "Association",
-                            "R2D_PlaceLink",
-                            "PetriNets_Runtime/Place",
-                            "PetriNets/Place",
-                        "instantiate",
-                            "Association",
-                            "R2D_TransitionLink",
-                            "PetriNets_Runtime/Transition",
-                            "PetriNets/Transition",
-                        "exit",
-                "transformation_RAMify",
-                    "__merged_PetriNets_RAM",
-                    "PetriNets_RAM",
-                "transformation_add_MANUAL",
-                    "PetriNets",
-                    "",
-                    "PetriNets_Runtime",
-                    "",
-                    "pn_design_to_runtime",
-                "transformation_add_MT",
-                    "PetriNets_RAM",
-                    "PetriNets_Runtime",
-                    "",
-                    "PetriNets",
-                    "",
-                    "pn_runtime_to_design",
-                    ] + get_model_constructor(open("integration/code/pn_runtime_to_design.mvc", "r").read()) + [
-                "transformation_add_MT",
-                    "PetriNets_RAM",
-                    "PetriNets_Runtime",
-                    "",
-                    "PetriNets_Runtime",
-                    "",
-                    "pn_step",
-                    ] + get_model_constructor(open("integration/code/pn_simulate.mvc", "r").read()) + [
-                "transformation_add_MT",
-                    "PetriNets_RAM",
-                    "PetriNets",
-                    "",
-                    "",
-                    "pn_print",
-                    ] + get_model_constructor(open("integration/code/pn_print.mvc", "r").read()) + [
-                "model_list",
-                "transformation_list",
-                "transformation_execute",
-                "pn_print",
-                "my_pn",
-                "transformation_execute",
-                "pn_design_to_runtime",
-                "my_pn",
-                "my_pn_runtime",
-                "instantiate", "PetriNets_Runtime/Place", "1",
-                "attr_add", "1", "tokens", 1,
-                "attr_add", "1", "name", "p1",
-                "instantiate", "PetriNets_Runtime/Place", "2",
-                "attr_add", "p2", "tokens", 2,
-                "attr_add", "p2", "name", "p2",
-                "instantiate", "PetriNets_Runtime/Place", "3",
-                "attr_add", "p3", "tokens", 3,
-                "attr_add", "p3", "name", "p3",
-                "instantiate", "PetriNets_Runtime/Transition", "4",
-                "attr_add", "4", "name", "t1",
-                "instantiate", "PetriNets_Runtime/P2T", "5", "1", "4",
-                "attr_add", "5", "weight", 1,
-                "instantiate", "PetriNets_Runtime/P2T", "6", "2", "4",
-                "attr_add", "6", "weight", 1,
-                "instantiate", "PetriNets_Runtime/T2P", "7", "4", "3",
-                "attr_add", "7", "weight", 2,
-                "exit",
-                "transformation_execute",
-                "pn_step",
-                "my_pn_runtime",
-                "my_pn_runtime",
-                "transformation_execute",
-                "pn_runtime_to_design",
-                "my_pn_runtime",
-                "my_pn",
-                "transformation_execute",
-                "pn_print",
-                "my_pn",
-            ],
+        log = []
 
-            [   # bootup phase
-                "Desired username for admin user?",
-                "Desired password for admin user?",
-                "Please repeat the password",
-                "Passwords match!",
-                "Welcome to the Model Management Interface v2.0!",
-                "Use the 'help' command for a list of possible commands",
-                "Ready for command...",
-                # model_add
-                "Creating new model!",
-                "Model type?",
-                "Model name?",
-                "Waiting for model constructors...",
-                "Model upload success!",
-                "Ready for command...",
-                # model_add
-                "Creating new model!",
-                "Model type?",
-                "Model name?",
-                "Waiting for model constructors...",
-                "Model upload success!",
-                "Ready for command...",
-                # model_add
-                "Creating new model!",
-                "Model type?",
-                "Model name?",
-                "Waiting for model constructors...",
-                "Model upload success!",
-                "Ready for command...",
-                # model_list
-                set(model_list) |
-                set([
-                     "  PetriNets : SimpleClassDiagrams",
-                     "  my_pn : PetriNets",
-                     "  PetriNets_Runtime : SimpleClassDiagrams",]),
-                "Ready for command...",
-                # transformation_add_MT_language
-                "Formalisms to include (terminate with empty string)?",
-                "Name of the RAMified transformation metamodel?",
-                "Ready for command...",
-                # model_list
-                set(model_list) |
-                set([
-                     "  PetriNets_Runtime : SimpleClassDiagrams",
-                     "  PetriNets : SimpleClassDiagrams",
-                     "  __merged_PetriNets_RAM : SimpleClassDiagrams",
-                     "  PetriNets_RAM : SimpleClassDiagrams",
-                     "  my_pn : PetriNets",]),
-                "Ready for command...",
-                # model_modify
-                "Which model do you want to modify?",
-                "Model loaded, ready for commands!",
-                "Mode: r/w",
-                "Use 'help' command for a list of possible commands",
-                "Please give your command.",
-                # instantiate 1
-                "Type to instantiate?",
-                "Name of new element?",
-                "Source name?",
-                "Destination name?",
-                "Instantiation successful!",
-                None,
-                "Please give your command.",
-                # instantiate 2
-                "Type to instantiate?",
-                "Name of new element?",
-                "Source name?",
-                "Destination name?",
-                "Instantiation successful!",
-                None,
-                "Please give your command.",
-                # instantiate 3
-                "Type to instantiate?",
-                "Name of new element?",
-                "Source name?",
-                "Destination name?",
-                "Instantiation successful!",
-                None,
-                "Please give your command.",
-                # instantiate 4
-                "Type to instantiate?",
-                "Name of new element?",
-                "Source name?",
-                "Destination name?",
-                "Instantiation successful!",
-                None,
-                "Please give your command.",
-                "Ready for command...",
-                # transformation_RAMify
-                "Which metamodel do you want to RAMify?",
-                "Where do you want to store the RAMified metamodel?",
-                "Ready for command...",
-                # transformation_add_MANUAL
-                "Which metamodels do you want to use as source for the operation (empty string to finish)?",
-                "Which metamodels do you want to use as target for the operation (empty string to finish)?",
-                "Name of operation model?",
-                "Ready for command...",
-                # transformation_add_MT
-                "RAMified metamodel to use?",
-                "Supported metamodels:",
-                set(["  PetriNets",
-                     "  PetriNets_Runtime",
-                    ]),
-                "Which metamodels do you want to use as source for the operation (empty string to finish)?",
-                "Which metamodels do you want to use as target for the operation (empty string to finish)?",
-                "Name of new operation?",
-                "Waiting for model constructors...",
-                "Ready for command...",
-                # transformation_add_MT
-                "RAMified metamodel to use?",
-                "Supported metamodels:",
-                set(["  PetriNets",
-                     "  PetriNets_Runtime",
-                    ]),
-                "Which metamodels do you want to use as source for the operation (empty string to finish)?",
-                "Which metamodels do you want to use as target for the operation (empty string to finish)?",
-                "Name of new operation?",
-                "Waiting for model constructors...",
-                "Ready for command...",
-                # transformation_add_MT
-                "RAMified metamodel to use?",
-                "Supported metamodels:",
-                set(["  PetriNets",
-                     "  PetriNets_Runtime",
-                    ]),
-                "Which metamodels do you want to use as source for the operation (empty string to finish)?",
-                "Which metamodels do you want to use as target for the operation (empty string to finish)?",
-                "Name of new operation?",
-                "Waiting for model constructors...",
-                "Ready for command...",
-                # model_list
-                set(model_list) |
-                set([
-                     "  PetriNets_Runtime : SimpleClassDiagrams",
-                     "  PetriNets : SimpleClassDiagrams",
-                     "  pn_print : PetriNets_RAM",
-                     "  pn_design_to_runtime : ManualOperation",
-                     "  pn_runtime_to_design : PetriNets_RAM",
-                     "  pn_step : PetriNets_RAM",
-                     "  __merged_pn_design_to_runtime : SimpleClassDiagrams",
-                     "  __merged_PetriNets_RAM : SimpleClassDiagrams",
-                     "  PetriNets_RAM : SimpleClassDiagrams",
-                     "  my_pn : PetriNets",]),
-                "Ready for command...",
-                # transformation_list
-                set(["[ModelTransformation] pn_print : PetriNets_RAM",
-                     "[ManualOperation] pn_design_to_runtime : ManualOperation",
-                     "[ModelTransformation] pn_runtime_to_design : PetriNets_RAM",
-                     "[ModelTransformation] pn_step : PetriNets_RAM"]),
-                "Ready for command...",
-                # transformation_execute (pn_print)
-                "Which transformation do you want to execute?",
-                "Which model to bind for source type PetriNets",
-                set(['"p1" --> 1',
-                     '"p2" --> 2',
-                     '"p3" --> 3',
-                    ]),
-                "Ready for command...",
-                # transformation_execute (pn_design_to_runtime)
-                "Which transformation do you want to execute?",
-                "Which model to bind for source type PetriNets",
-                "Which model to create for target type PetriNets_Runtime",
-                "Please perform manual operation \"pn_design_to_runtime\"",
-                "Model loaded, ready for commands!",
-                "Mode: r/w",
-                "Use 'help' command for a list of possible commands",
-                "Please give your command.",
-                # instantiate p1
-                    "Type to instantiate?",
-                    "Name of new element?",
-                    "Instantiation successful!",
-                None,
-                    "Please give your command.",
-                    "Which element do you want to assign an attribute to?",
-                    "Which attribute do you wish to assign?",
-                    "Value of attribute?",
-                    "Added attribute!",
-                    "Please give your command.",
-                    "Which element do you want to assign an attribute to?",
-                    "Which attribute do you wish to assign?",
-                    "Value of attribute?",
-                    "Added attribute!",
-                    "Please give your command.",
-                # instantiate p2
-                    "Type to instantiate?",
-                    "Name of new element?",
-                    "Instantiation successful!",
-                None,
-                    "Please give your command.",
-                    "Which element do you want to assign an attribute to?",
-                    "Which attribute do you wish to assign?",
-                    "Value of attribute?",
-                    "Added attribute!",
-                    "Please give your command.",
-                    "Which element do you want to assign an attribute to?",
-                    "Which attribute do you wish to assign?",
-                    "Value of attribute?",
-                    "Added attribute!",
-                    "Please give your command.",
-                # instantiate p3
-                    "Type to instantiate?",
-                    "Name of new element?",
-                    "Instantiation successful!",
-                None,
-                    "Please give your command.",
-                    "Which element do you want to assign an attribute to?",
-                    "Which attribute do you wish to assign?",
-                    "Value of attribute?",
-                    "Added attribute!",
-                    "Please give your command.",
-                    "Which element do you want to assign an attribute to?",
-                    "Which attribute do you wish to assign?",
-                    "Value of attribute?",
-                    "Added attribute!",
-                    "Please give your command.",
-                # instantiate t1
-                    "Type to instantiate?",
-                    "Name of new element?",
-                    "Instantiation successful!",
-                None,
-                    "Please give your command.",
-                    "Which element do you want to assign an attribute to?",
-                    "Which attribute do you wish to assign?",
-                    "Value of attribute?",
-                    "Added attribute!",
-                    "Please give your command.",
-                # instantiate p2t1
-                    "Type to instantiate?",
-                    "Name of new element?",
-                    "Source name?",
-                    "Destination name?",
-                    "Instantiation successful!",
-                None,
-                    "Please give your command.",
-                    "Which element do you want to assign an attribute to?",
-                    "Which attribute do you wish to assign?",
-                    "Value of attribute?",
-                    "Added attribute!",
-                    "Please give your command.",
-                # instantiate p2t2
-                    "Type to instantiate?",
-                    "Name of new element?",
-                    "Source name?",
-                    "Destination name?",
-                    "Instantiation successful!",
-                None,
-                    "Please give your command.",
-                    "Which element do you want to assign an attribute to?",
-                    "Which attribute do you wish to assign?",
-                    "Value of attribute?",
-                    "Added attribute!",
-                    "Please give your command.",
-                # instantiate t2p1
-                    "Type to instantiate?",
-                    "Name of new element?",
-                    "Source name?",
-                    "Destination name?",
-                    "Instantiation successful!",
-                None,
-                    "Please give your command.",
-                    "Which element do you want to assign an attribute to?",
-                    "Which attribute do you wish to assign?",
-                    "Value of attribute?",
-                    "Added attribute!",
-                    "Please give your command.",
-                "Ready for command...",
-                # transformation_execute (pn_step)
-                "Which transformation do you want to execute?",
-                "Which model to bind for source type PetriNets_Runtime",
-                "Which model to create for target type PetriNets_Runtime",
-                "Ready for command...",
-                # transformation_execute (pn_runtime_to_design)
-                "Which transformation do you want to execute?",
-                "Which model to bind for source type PetriNets_Runtime",
-                "Which model to create for target type PetriNets",
-                "Ready for command...",
-                # transformation_execute (pn_print)
-                "Which transformation do you want to execute?",
-                "Which model to bind for source type PetriNets",
-                set(['"p1" --> 0',
-                     '"p2" --> 1',
-                     '"p3" --> 5',
-                    ]),
-                "Ready for command...",
-            ]))
+        def callback(value):
+            log.append(value)
+
+        def manual_callback():
+            p1 = instantiate(None, "PetriNet_Runtime/Place")
+            attr_assign(None, p1, "tokens", 1)
+            attr_assign(None, p1, "name", "p1")
+            p2 = instantiate(None, "PetriNet_Runtime/Place")
+            attr_assign(None, p2, "tokens", 2)
+            attr_assign(None, p2, "name", "p2")
+            p3 = instantiate(None, "PetriNet_Runtime/Place")
+            attr_assign(None, p3, "tokens", 3)
+            attr_assign(None, p3, "name", "p3")
+            t1 = instantiate(None, "PetriNet_Runtime/Transition")
+            attr_assign(None, t1, "name", "t1")
+            attr_assign(None, t1, "executing", False)
+            p2t1 = instantiate(None, "PetriNet_Runtime/P2T", (p1, t1))
+            attr_assign(None, p2t1, "weight", 1)
+            p2t2 = instantiate(None, "PetriNet_Runtime/P2T", (p2, t1))
+            attr_assign(None, p2t2, "weight", 1)
+            t2p1 = instantiate(None, "PetriNet_Runtime/T2P", (t1, p3))
+            attr_assign(None, t2p1, "weight", 2)
+
+        model_add("PetriNet", "SimpleClassDiagrams", open("integration/code/pn_design.mvc", "r").read())
+        model_add("PetriNet_Runtime", "SimpleClassDiagrams", open("integration/code/pn_runtime.mvc", "r").read())
+
+        model_add("my_pn", "PetriNet", open("integration/code/pn_design_model.mvc", "r").read())
+
+        transformation_add_MT_language(["PetriNet", "PetriNet_Runtime"], "PetriNet_RAM")
+        instantiate("__merged_PetriNet_RAM", "Association", ("PetriNet/Place", "PetriNet_Runtime/Place"), ID="D2R_PlaceLink")
+        instantiate("__merged_PetriNet_RAM", "Association", ("PetriNet/Transition", "PetriNet_Runtime/Transition"), ID="D2R_TransitionLink")
+        instantiate("__merged_PetriNet_RAM", "Association", ("PetriNet_Runtime/Place", "PetriNet/Place"), ID="R2D_PlaceLink")
+        instantiate("__merged_PetriNet_RAM", "Association", ("PetriNet_Runtime/Transition", "PetriNet/Transition"), ID="R2D_TransitionLink")
+        transformation_RAMify("__merged_PetriNet_RAM", "PetriNet_RAM")
+
+        transformation_add_MT("PetriNet_RAM", ["PetriNet"], [], "print_pn", open("integration/code/pn_print.mvc").read())
+        transformation_add_MANUAL(["PetriNet"], ["PetriNet_Runtime"], "pn_design_to_runtime")
+        transformation_add_AL(["PetriNet_Runtime"], ["PetriNet_Runtime"], "pn_simulate", open("integration/code/pn_simulate.alc").read())
+        transformation_add_MT("PetriNet_RAM", ["PetriNet_Runtime"], ["PetriNet"], "pn_runtime_to_design", open("integration/code/pn_runtime_to_design.mvc").read())
+
+        log = []
+        assert transformation_execute_MT("print_pn", {"PetriNet": "my_pn"}, {}, callback) == True
+        assert set(log) == set(['"p1" --> 1',
+                                '"p2" --> 2',
+                                '"p3" --> 3'])
+
+        assert transformation_execute_MANUAL("pn_design_to_runtime", {"PetriNet": "my_pn"}, {"PetriNet_Runtime": "my_pn_RT"}, manual_callback) == True
+        assert transformation_execute_AL("pn_simulate", {"PetriNet_Runtime": "my_pn_RT"}, {"PetriNet_Runtime": "my_pn_RT"}) == True
+        assert transformation_execute_MT("pn_runtime_to_design", {"PetriNet_Runtime": "my_pn_RT"}, {"PetriNet": "my_pn"}) == True
+
+        log = []
+        assert transformation_execute_MT("print_pn", {"PetriNet": "my_pn"}, {}, callback) == True
+        assert set(log) == set(['"p1" --> 0',
+                                '"p2" --> 1',
+                                '"p3" --> 5'])
 
     def test_process_model_trivial_pn(self):
         self.assertTrue(run_file(all_files,

+ 75 - 19
wrappers/modelverse.py

@@ -12,6 +12,7 @@ MODE_UNAUTHORIZED = 1
 MODE_MODELLING = 2
 MODE_MODIFY = 3
 MODE_DIALOG = 4
+MODE_MANUAL = 5
 
 # Bind to the compiler (might have to update path manually!)
 sys.path.append(COMPILER_PATH)
@@ -65,6 +66,7 @@ taskname = random.random()
 address = None
 last_output = None
 mode = MODE_UNCONNECTED
+prev_mode = None
 
 def _input(value):
     # Ugly json encoding of primitives
@@ -117,7 +119,6 @@ def _output(expected=None):
     try:
         global last_output
         last_output = json.loads(urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "taskname": taskname}))).read())
-        #print("Got output: " + str(last_output))
     except:
         raise UnknownError()
     if expected is not None and last_output != expected:
@@ -218,7 +219,7 @@ def model_add(model_name, metamodel_name, model_code=None):
     # raises UnknownError
     # raises PermissionDenied
     # raises CompilationError
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
     # Do this before creating the model, as otherwise compilation errors would make us inconsistent
     if model_code is not None:
@@ -241,8 +242,16 @@ def model_modify(model_name):
     # raises PermissionDenied
     # raises UnknownError
     global mode
-    if  mode != MODE_MODELLING:
+    global prev_mode
+
+    if mode == MODE_MANUAL:
+        prev_mode = MODE_MANUAL
+        mode = MODE_MODIFY
+        return None
+
+    if mode != MODE_MODELLING:
         raise InvalidMode()
+    prev_mode = MODE_MODELLING
 
     _input(["model_modify", model_name])
     _handle_output("Success")
@@ -260,7 +269,7 @@ def model_list():
     """List all models."""
     # return [(model1, metamodel1), (model2, metamodel2), ...]
     # raises UnknownError
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
     _input("model_list")
     output = _handle_output("Success: ", split=" ")
@@ -281,7 +290,7 @@ def model_list_full():
     """List full information on all models."""
     # return [(model1, metamodel1, owner1, group1, permissions1), (model2, metamodel2, owner2, group2, permissions2), ...]
     # raises UnknownError
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
     _input("model_list_full")
     output = _handle_output("Success: ", split=" ")
@@ -305,7 +314,7 @@ def verify(model):
     # return "verification_result"
     # raises UnknownError
     # raises UnknownModel
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
     _input(["verify", model])
     return _handle_output("Success: ", split=" ")
@@ -317,7 +326,7 @@ def model_overwrite(model_name, new_model=None):
     # raises PermissionDenied
     # raises CompilationError
     # raises UnknownError
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
 
     if new_model is not None:
@@ -338,7 +347,7 @@ def user_logout():
     # return None
     # raises UnknownError
     global mode
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
     _input("exit")
     mode = MODE_UNCONNECTED
@@ -348,7 +357,7 @@ def user_delete():
     # return None
     # raises UnknownError
     global mode
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
     _input("self-destruct")
     mode = MODE_UNCONNECTED
@@ -360,7 +369,7 @@ def model_render(model, mapper):
     # raises UnknownIdentifier
     # raises InterfaceMismatch
     global mode
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
 
     _input(["model_render", model, mapper])
@@ -368,7 +377,7 @@ def model_render(model, mapper):
 
 def transformation_between(source, target):
     global mode
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
 
     _input(["transformation_between", source, target])
@@ -380,7 +389,7 @@ def transformation_between(source, target):
 def transformation_add_MT_language(metamodels, RAMified_name):
     """Create a new Model Transformation language out of a set of metamodels."""
     global mode
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
 
     _input(["transformation_add_MT_language"] + metamodels + ["", RAMified_name])
@@ -389,7 +398,7 @@ def transformation_add_MT_language(metamodels, RAMified_name):
 def transformation_add_MT(RAMified_metamodel, source_metamodels, target_metamodels, operation_name, code):
     """Create a new model transformation."""
     global mode
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
 
     try:
@@ -405,7 +414,7 @@ def transformation_add_MT(RAMified_metamodel, source_metamodels, target_metamode
 def transformation_add_AL(source_metamodels, target_metamodels, operation_name, code):
     """Create a new action language model, which can be executed."""
     global mode
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
 
     try:
@@ -418,14 +427,19 @@ def transformation_add_AL(source_metamodels, target_metamodels, operation_name,
     _input(compiled)
     _output("Success")
 
-def transformation_add_MANUAL():
+def transformation_add_MANUAL(source_metamodels, target_metamodels, operation_name):
     """Create a new manual model operation."""
-    raise NotImplementedError()
+    global mode
+    if mode != MODE_MODELLING:
+        raise InvalidMode()
+
+    _input(["transformation_add_MANUAL"] + source_metamodels + [""] + target_metamodels + [""] + [operation_name])
+    _handle_output("Success")
 
 def transformation_execute_AL(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
     """Execute an existing model operation."""
     global mode
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
 
     mv_dict_rep = []
@@ -453,10 +467,46 @@ def transformation_execute_AL(operation_name, input_models_dict, output_models_d
     else:
         return False
 
+def transformation_execute_MANUAL(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
+    """Execute an existing model operation."""
+    global mode
+    if mode != MODE_MODELLING:
+        raise InvalidMode()
+
+    mv_dict_rep = []
+    for key, value in input_models_dict.items():
+        mv_dict_rep += [key, value]
+    mv_dict_rep += [""]
+    for key, value in output_models_dict.items():
+        mv_dict_rep += [key, value]
+    mv_dict_rep += [""]
+
+    _input(["transformation_execute", operation_name] + mv_dict_rep)
+    _handle_output("Success: ready for MANUAL execution")
+
+    # Skip over the begin of mini_modify
+    _output()
+    _output()
+    _output()
+    _output()
+
+    # We are now executing, so everything we get is part of the dialog, except if it is the string for transformation termination
+    mode = MODE_MANUAL
+    callback()
+    # Finished, so leave
+    _input("exit")
+    mode = MODE_MODELLING
+
+    # Got termination message, so we are done!
+    if _output() == "Success":
+        return True
+    else:
+        return False
+
 def transformation_execute_MT(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
     """Execute an existing model operation."""
     global mode
-    if  mode != MODE_MODELLING:
+    if mode != MODE_MODELLING:
         raise InvalidMode()
 
     mv_dict_rep = []
@@ -472,7 +522,6 @@ def transformation_execute_MT(operation_name, input_models_dict, output_models_d
 
     # We are now executing, so everything we get is part of the dialog, except if it is the string for transformation termination
     while _output() not in ["Success", "Failure"]:
-        print("Got output: " + str(_last_output()))
         reply = callback(_last_output())
         if reply is not None:
             _input(reply)
@@ -883,8 +932,15 @@ def model_exit():
     # return None
     # raises UnknownError
     global mode
+    global prev_mode
+
+    if prev_mode == MODE_MANUAL:
+        mode = MODE_MANUAL
+        return
+
     if mode != MODE_MODIFY:
         raise InvalidMode()
+
     _input("exit")
     _output("Success")
     mode = MODE_MODELLING