Explorar el Código

Merge pull request #256 from kalliope-project/draft_FIFO

use a LIFO to run synapse
Monf hace 8 años
padre
commit
d75e5ce79a
Se han modificado 43 ficheros con 1850 adiciones y 676 borrados
  1. 79 46
      Docs/rest_api.md
  2. 63 0
      Tests/brains/lifo_buffer_test_brain.yml
  3. 0 140
      Tests/test_launchers.py
  4. 358 0
      Tests/test_lifo_buffer.py
  5. 484 0
      Tests/test_models.py
  6. 90 0
      Tests/test_neuron_launcher.py
  7. 0 40
      Tests/test_neuron_model.py
  8. 11 56
      Tests/test_neuron_module.py
  9. 8 1
      Tests/test_order_analyser.py
  10. 68 80
      Tests/test_rest_api.py
  11. 81 36
      Tests/test_synapse_launcher.py
  12. 31 0
      Tests/test_trigger_launcher.py
  13. 5 4
      kalliope/__init__.py
  14. 0 8
      kalliope/core/ConfigurationManager/BrainLoader.py
  15. 0 4
      kalliope/core/ConfigurationManager/SettingLoader.py
  16. 1 1
      kalliope/core/EventManager.py
  17. 193 0
      kalliope/core/LIFOBuffer.py
  18. 4 1
      kalliope/core/MainController.py
  19. 23 0
      kalliope/core/Models/APIResponse.py
  20. 1 5
      kalliope/core/Models/Dna.py
  21. 1 3
      kalliope/core/Models/Event.py
  22. 55 0
      kalliope/core/Models/MatchedSynapse.py
  23. 8 4
      kalliope/core/Models/Neuron.py
  24. 1 1
      kalliope/core/Models/Order.py
  25. 1 5
      kalliope/core/Models/Resources.py
  26. 24 9
      kalliope/core/Models/RestAPI.py
  27. 33 3
      kalliope/core/Models/Settings.py
  28. 7 1
      kalliope/core/Models/Stt.py
  29. 1 8
      kalliope/core/Models/Synapse.py
  30. 7 1
      kalliope/core/Models/Trigger.py
  31. 7 1
      kalliope/core/Models/Tts.py
  32. 28 32
      kalliope/core/NeuronLauncher.py
  33. 40 36
      kalliope/core/NeuronModule.py
  34. 11 1
      kalliope/core/OrderAnalyser.py
  35. 32 27
      kalliope/core/RestAPI/FlaskAPI.py
  36. 1 1
      kalliope/core/ShellGui.py
  37. 50 56
      kalliope/core/SynapseLauncher.py
  38. 0 27
      kalliope/core/TTS/TTSLauncher.py
  39. 1 0
      kalliope/core/TTS/__init__.py
  40. 2 1
      kalliope/core/Utils/Utils.py
  41. 3 3
      kalliope/core/__init__.py
  42. 14 5
      kalliope/neurons/neurotransmitter/neurotransmitter.py
  43. 23 29
      kalliope/neurons/neurotransmitter/tests/test_neurotransmitter.py

+ 79 - 46
Docs/rest_api.md

@@ -130,23 +130,20 @@ curl -i --user admin:secret -X POST  http://localhost:5000/synapses/start/id/say
 Output example:
 Output example:
 ```JSON
 ```JSON
 {
 {
-  "synapses": {
-    "name": "say-hello",
-    "neurons": [
-      {
-        "say": {
-          "message": [
-            "Bonjour monsieur"
-          ]
+  "matched_synapses": [
+    {
+      "matched_order": null,
+      "neuron_module_list": [
+        {
+          "generated_message": "Bonjour monsieur",
+          "neuron_name": "Say"
         }
         }
-      }
-    ],
-    "signals": [
-      {
-        "order": "bonjour"
-      }
-    ]
-  }
+      ],
+      "synapse_name": "say-hello-fr"
+    }
+  ],
+  "status": "complete",
+  "user_order": null
 }
 }
 ```
 ```
 
 
@@ -174,31 +171,49 @@ curl -i --user admin:secret -H "Content-Type: application/json" -X POST --data @
 Output example if the order have matched and so launched synapses:
 Output example if the order have matched and so launched synapses:
 ```JSON
 ```JSON
 {
 {
-  "synapses": [
+  "matched_synapses": [
     {
     {
-      "name": "Say-hello", 
-      "neurons": [
+      "matched_order": "Bonjour",
+      "neuron_module_list": [
         {
         {
-          "name": "say", 
-          "parameters": "{'message': ['Hello sir']}"
+          "generated_message": "Bonjour monsieur",
+          "neuron_name": "Say"
         }
         }
-      ], 
-      "signals": [
+      ],
+      "synapse_name": "say-hello-fr"
+    }
+  ],
+  "status": "complete",
+  "user_order": "bonjour"
+}
+```
+
+If the order haven't match any synapses it will try to run the default synapse if it exists in your settings:
+```JSON
+{
+  "matched_synapses": [
+    {
+      "matched_order": null,
+      "neuron_module_list": [
         {
         {
-          "order": "hello"
+          "generated_message": "Je n'ai pas compris votre ordre",
+          "neuron_name": "Say"
         }
         }
-      ]
+      ],
+      "synapse_name": "default-synapse"
     }
     }
-  ]
+  ],
+  "status": "complete",
+  "user_order": "not existing order"
 }
 }
 ```
 ```
 
 
-If the order haven't match any synapses:
-```JSON
+Or return an empty list of matched synapse
+```
 {
 {
-  "error": {
-    "error": "The given order doesn't match any synapses"
-  }
+  "matched_synapses": [],
+  "status": null,
+  "user_order": "not existing order"
 }
 }
 ```
 ```
 
 
@@ -217,30 +232,48 @@ curl -i --user admin:secret -X POST  http://localhost:5000/synapses/start/audio
 Output example if the order inside the audio have matched and so launched synapses:
 Output example if the order inside the audio have matched and so launched synapses:
 ```JSON
 ```JSON
 {
 {
-  "synapses": [
+  "matched_synapses": [
     {
     {
-      "name": "Say-hello", 
-      "neurons": [
+      "matched_order": "Bonjour",
+      "neuron_module_list": [
         {
         {
-          "name": "say", 
-          "parameters": "{'message': ['Hello sir']}"
+          "generated_message": "Bonjour monsieur",
+          "neuron_name": "Say"
         }
         }
-      ], 
-      "signals": [
+      ],
+      "synapse_name": "say-hello-fr"
+    }
+  ],
+  "status": "complete",
+  "user_order": "bonjour"
+}
+```
+
+If the order haven't match any synapses it will try to run the default synapse if it exists in your settings:
+```JSON
+{
+  "matched_synapses": [
+    {
+      "matched_order": null,
+      "neuron_module_list": [
         {
         {
-          "order": "hello"
+          "generated_message": "Je n'ai pas compris votre ordre",
+          "neuron_name": "Say"
         }
         }
-      ]
+      ],
+      "synapse_name": "default-synapse"
     }
     }
-  ]
+  ],
+  "status": "complete",
+  "user_order": "not existing order"
 }
 }
 ```
 ```
 
 
-If the order haven't match any synapses:
-```JSON
+Or return an empty list of matched synapse
+```
 {
 {
-  "error": {
-    "error": "The given order doesn't match any synapses"
-  }
+  "matched_synapses": [],
+  "status": null,
+  "user_order": "not existing order"
 }
 }
 ```
 ```

+ 63 - 0
Tests/brains/lifo_buffer_test_brain.yml

@@ -0,0 +1,63 @@
+- name: "synapse1"
+  signals:
+    - order: "enter in synapse 1"
+  neurons:
+    - say:
+        message: "question in synapse 1"
+    - neurotransmitter:
+        from_answer_link:
+          - synapse: "synapse2"
+            answers:
+              - "answer synapse1"
+          - synapse: "synapse3"
+            answers:
+              - "other answer synapse1"
+        default: "synapse4"
+    - say:
+        message: "last neuron in synapse 1"
+
+- name: "synapse2"
+  signals:
+    - order: "synapse2"
+  neurons:
+    - say:
+        message: "enter synapse 2"
+    - neurotransmitter:
+        from_answer_link:
+          - synapse: "synapse5"
+            answers:
+              - "synapse5"
+        default: "synapse4"
+
+- name: "synapse3"
+  signals:
+    - order: "synapse3"
+  neurons:
+    - say:
+        message: "I enter in synapse 3"
+
+- name: "synapse4"
+  signals:
+    - order: "synapse4"
+  neurons:
+    - say:
+        message: "not understood"
+
+
+- name: "synapse5"
+  signals:
+    - order: "synapse5"
+  neurons:
+    - say:
+        message: "execution of synapse 5"
+
+- name: "synapse6"
+  signals:
+    - order: "synapse6"
+  neurons:
+    - neurotransmitter:
+        from_answer_link:
+          - synapse: "synapse5"
+            answers:
+              - "synapse 6 answer"
+        default: "synapse4"

+ 0 - 140
Tests/test_launchers.py

@@ -1,140 +0,0 @@
-import unittest
-import mock
-
-from kalliope.core.Models.Resources import Resources
-from kalliope.core.NeuronLauncher import NeuronLauncher
-from kalliope.core.SynapseLauncher import SynapseLauncher, SynapseNameNotFound
-from kalliope.core.TriggerLauncher import TriggerLauncher
-from kalliope.core.ConfigurationManager import SettingLoader
-from kalliope.core.Models.Settings import Settings
-
-from kalliope.core.Models.Trigger import Trigger
-from kalliope.core.Models.Neuron import Neuron
-from kalliope.core.Models.Order import Order
-from kalliope.core.Models.Brain import Brain
-from kalliope.core.Models.Synapse import Synapse
-
-
-class TestLaunchers(unittest.TestCase):
-    """
-    Class to test Launchers Classes (TriggerLauncher, SynapseLauncher, NeuronLauncher) and methods
-    """
-
-    def setUp(self):
-        pass
-
-    ####
-    # Trigger Launcher
-    def test_get_trigger(self):
-        """
-        Test the Trigger Launcher trying to run the trigger
-        """
-        trigger = Trigger("Trigger", {})
-        with mock.patch("kalliope.core.Utils.get_dynamic_class_instantiation") as mock_get_class_instantiation:
-            TriggerLauncher.get_trigger(trigger=trigger,
-                                        callback=None)
-
-            mock_get_class_instantiation.assert_called_once_with(package_name="trigger",
-                                                                 module_name=trigger.name,
-                                                                 parameters=trigger.parameters)
-            mock_get_class_instantiation.reset_mock()
-
-    ####
-    # Synapse Launcher
-    def test_start_synapse(self):
-        """
-        Test the Synapse launcher trying to start synapse
-        """
-        # Init
-        neuron1 = Neuron(name='neurone1', parameters={'var1': 'val1'})
-        neuron2 = Neuron(name='neurone2', parameters={'var2': 'val2'})
-        neuron3 = Neuron(name='neurone3', parameters={'var3': 'val3'})
-        neuron4 = Neuron(name='neurone4', parameters={'var4': 'val4'})
-
-        signal1 = Order(sentence="this is the sentence")
-        signal2 = Order(sentence="this is the second sentence")
-        signal3 = Order(sentence="that is part of the third sentence")
-
-        synapse1 = Synapse(name="Synapse1", neurons=[neuron1, neuron2], signals=[signal1])
-        synapse2 = Synapse(name="Synapse2", neurons=[neuron3, neuron4], signals=[signal2])
-        synapse3 = Synapse(name="Synapse3", neurons=[neuron2, neuron4], signals=[signal3])
-
-        all_synapse_list = [synapse1,
-                            synapse2,
-                            synapse3]
-
-        br = Brain(synapses=all_synapse_list)
-
-        sl = SettingLoader()
-        r = Resources(neuron_folder="/var/tmp/test/resources")
-        sl.settings.resources = r
-        with mock.patch("kalliope.core.Utils.get_dynamic_class_instantiation") as mock_get_class_instantiation:
-            # Success
-            SynapseLauncher.start_synapse("Synapse1", brain=br)
-
-            calls = [mock.call(package_name="neurons",
-                               module_name=neuron1.name,
-                               parameters=neuron1.parameters,
-                               resources_dir='/var/tmp/test/resources'),
-                     mock.call(package_name="neurons",
-                               module_name=neuron2.name,
-                               parameters=neuron2.parameters,
-                               resources_dir='/var/tmp/test/resources')]
-            mock_get_class_instantiation.assert_has_calls(calls=calls)
-            mock_get_class_instantiation.reset_mock()
-
-            # Fail
-            with self.assertRaises(SynapseNameNotFound):
-                SynapseLauncher.start_synapse("Synapse4", brain=br)
-
-    def test_run_synapse(self):
-        """
-        Test to run a Synapse
-        """
-        neuron1 = Neuron(name='neurone1', parameters={'var1': 'val1'})
-        neuron2 = Neuron(name='neurone2', parameters={'var2': 'val2'})
-        signal1 = Order(sentence="this is the sentence")
-        synapse1 = Synapse(name="Synapse1", neurons=[neuron1, neuron2], signals=[signal1])
-        synapse_empty = Synapse(name="Synapse_empty", neurons=[], signals=[signal1])
-        sl = SettingLoader()
-        resources = Resources(neuron_folder='/var/tmp/test/resources')
-        sl.settings.resources = resources
-        with mock.patch("kalliope.core.Utils.get_dynamic_class_instantiation") as mock_get_class_instantiation:
-            SynapseLauncher._run_synapse(synapse=synapse1)
-
-            calls = [mock.call(package_name="neurons",
-                               module_name=neuron1.name,
-                               parameters=neuron1.parameters,
-                               resources_dir="/var/tmp/test/resources"),
-                     mock.call(package_name="neurons",
-                               module_name=neuron2.name,
-                               parameters=neuron2.parameters,
-                               resources_dir="/var/tmp/test/resources")]
-            mock_get_class_instantiation.assert_has_calls(calls=calls)
-            mock_get_class_instantiation.reset_mock()
-
-            # Do not any Neurons
-            SynapseLauncher._run_synapse(synapse=synapse_empty)
-            mock_get_class_instantiation.assert_not_called()
-            mock_get_class_instantiation.reset_mock()
-
-    ####
-    # Neurons Launcher
-    def test_start_neuron(self):
-        """
-        Test the Neuron Launcher trying to start a Neuron
-        """
-        neuron = Neuron(name='neurone1', parameters={'var1': 'val1'})
-        sl = SettingLoader()
-        resources = Resources(neuron_folder='/var/tmp/test/resources')
-        sl.settings.resources = resources
-        with mock.patch("kalliope.core.Utils.get_dynamic_class_instantiation") as mock_get_class_instantiation:
-            NeuronLauncher.start_neuron(neuron=neuron)
-
-            mock_get_class_instantiation.assert_called_once_with(package_name="neurons",
-                                                                 module_name=neuron.name,
-                                                                 parameters=neuron.parameters,
-                                                                 resources_dir=sl.settings.resources.neuron_folder)
-            mock_get_class_instantiation.reset_mock()
-
-

+ 358 - 0
Tests/test_lifo_buffer.py

@@ -0,0 +1,358 @@
+import os
+import unittest
+
+import mock
+
+from kalliope.core import LIFOBuffer
+from kalliope.core.ConfigurationManager import BrainLoader
+from kalliope.core.LIFOBuffer import Serialize, SynapseListAddedToLIFO
+
+from kalliope.core.Models import Singleton
+from kalliope.core.Models.MatchedSynapse import MatchedSynapse
+
+
+class TestLIFOBuffer(unittest.TestCase):
+
+    def setUp(self):
+        # be sure the brain haven't been instantiated before
+        Singleton._instances = dict()
+
+        if "/Tests" in os.getcwd():
+            self.brain_to_test = os.getcwd() + os.sep + "brains/lifo_buffer_test_brain.yml"
+        else:
+            self.brain_to_test = os.getcwd() + os.sep + "Tests/brains/lifo_buffer_test_brain.yml"
+
+        BrainLoader(file_path=self.brain_to_test)
+        # create a new lifo buffer
+        self.lifo_buffer = LIFOBuffer()
+        self.lifo_buffer.clean()
+
+    def test_execute(self):
+        """
+        In this test the brain contains a neurotransmitter
+        """
+        # --------------------------------------
+        # Test 1. The user answers correctly to all neurotransmitter
+        # --------------------------------------
+
+        # we suppose that the first synapse has matched the first synapse
+        synapse = BrainLoader().brain.get_synapse_by_name("synapse1")
+        order = "enter in synapse 1"
+        matched_synapse = MatchedSynapse(matched_synapse=synapse,
+                                         user_order=order,
+                                         matched_order=order)
+        list_matched_synapse = list()
+        list_matched_synapse.append(matched_synapse)
+        self.lifo_buffer.add_synapse_list_to_lifo(list_matched_synapse)
+        self.lifo_buffer.api_response.user_order = order
+
+        with mock.patch("kalliope.core.TTS.TTSModule.generate_and_play"):
+
+            response = self.lifo_buffer.execute(is_api_call=True)
+
+            expected_result = {
+                'status': 'waiting_for_answer',
+                'matched_synapses': [
+                    {
+                        'matched_order': 'enter in synapse 1',
+                        'neuron_module_list':
+                            [
+                                {
+                                    'neuron_name': 'Say',
+                                    'generated_message': 'question in synapse 1'
+                                }
+                            ],
+                        'synapse_name': 'synapse1'
+                    }
+                ],
+                'user_order': 'enter in synapse 1'
+            }
+
+            self.assertEqual(response, expected_result)
+
+            # give an answer
+            answer = "answer synapse1"
+            response = self.lifo_buffer.execute(answer=answer,
+                                                is_api_call=True)
+            expected_result = {
+                'status': 'waiting_for_answer',
+                'matched_synapses': [
+                    {
+                        'matched_order': 'enter in synapse 1',
+                        'neuron_module_list': [
+                            {
+                                'neuron_name': 'Say',
+                                 'generated_message': 'question in synapse 1'
+                            },
+                            {
+                                'neuron_name': 'Neurotransmitter',
+                                'generated_message': None
+                            }
+                        ],
+                        'synapse_name': 'synapse1'
+                    },
+                    {
+                        'matched_order': 'answer synapse1',
+                        'neuron_module_list': [
+                            {
+                                'neuron_name': 'Say',
+                                'generated_message': 'enter synapse 2'
+                            }
+                        ],
+                    'synapse_name': 'synapse2'
+                    }
+                ],
+                'user_order': None
+            }
+            self.assertEqual(response, expected_result)
+
+            # give the last answer
+            answer = "synapse5"
+            response = self.lifo_buffer.execute(answer=answer,
+                                                is_api_call=True)
+            expected_result = {
+                'status': 'complete',
+                'matched_synapses': [
+                    {
+                        'matched_order': 'answer synapse1',
+                        'neuron_module_list': [
+                            {
+                                'neuron_name': 'Say',
+                                'generated_message': 'enter synapse 2'
+                            },
+                            {
+                                'neuron_name': 'Neurotransmitter',
+                                'generated_message': None
+                            }
+                        ],
+                        'synapse_name': 'synapse2'
+                    },
+                    {
+                        'matched_order': 'synapse5',
+                        'neuron_module_list': [
+                            {
+                                'neuron_name': 'Say',
+                                'generated_message': 'execution of synapse 5'
+                            }
+                        ],
+                        'synapse_name': 'synapse5'
+                    },
+                    {
+                        'matched_order': 'enter in synapse 1',
+                        'neuron_module_list':[
+                            {
+                                'neuron_name': 'Say',
+                                'generated_message': 'question in synapse 1'
+                            },
+                            {
+                                'neuron_name': 'Neurotransmitter',
+                                'generated_message': None
+                            },
+                            {
+                                'neuron_name': 'Say',
+                                'generated_message': 'last neuron in synapse 1'
+                            }
+                        ],
+                        'synapse_name': 'synapse1'
+                    }
+                ],
+                'user_order': None
+            }
+
+            self.assertEqual(response, expected_result)
+
+        # --------------------------------------
+        # Test 2. The user doesn't answered correctly to the first neurotransmitter
+        # --------------------------------------
+
+        # we suppose that the first synapse has matched the first synapse
+        synapse = BrainLoader().brain.get_synapse_by_name("synapse1")
+        order = "enter in synapse 1"
+        matched_synapse = MatchedSynapse(matched_synapse=synapse,
+                                         user_order=order,
+                                         matched_order=order)
+        list_matched_synapse = list()
+        list_matched_synapse.append(matched_synapse)
+        self.lifo_buffer.add_synapse_list_to_lifo(list_matched_synapse)
+        self.lifo_buffer.api_response.user_order = order
+
+        with mock.patch("kalliope.core.TTS.TTSModule.generate_and_play"):
+            # fist call to enter in the neurotransmitter
+            self.lifo_buffer.execute(is_api_call=True)
+
+            wrong_answer = "wrong answer"
+            response = self.lifo_buffer.execute(answer=wrong_answer, is_api_call=True)
+
+            expected_result = {
+                'status': 'complete',
+                'matched_synapses': [
+                    {
+                        'matched_order': 'enter in synapse 1',
+                        'neuron_module_list': [
+                            {
+                                'neuron_name': 'Say',
+                                'generated_message': 'question in synapse 1'
+                            },
+                            {
+                                'neuron_name': 'Neurotransmitter',
+                                'generated_message': None
+                            },
+                            {
+                                'neuron_name': 'Say',
+                                'generated_message': 'last neuron in synapse 1'
+                            }
+                        ],
+                        'synapse_name': 'synapse1'
+                    },
+                    {
+                        'matched_order': None,
+                        'neuron_module_list': [
+                            {
+                                'neuron_name': 'Say',
+                                'generated_message': 'not understood'
+                            }
+                        ],
+                        'synapse_name': 'synapse4'
+                    }
+                ],
+                'user_order': None
+            }
+
+            self.assertEqual(response, expected_result)
+
+        # --------------------------------------
+        # Test 3. No synapse matched, we still execute the list
+        # --------------------------------------
+        list_matched_synapse = list()
+        self.lifo_buffer.add_synapse_list_to_lifo(list_matched_synapse)
+        self.lifo_buffer.api_response.user_order = "this is an order"
+
+        with mock.patch("kalliope.core.TTS.TTSModule.generate_and_play"):
+            # fist call to enter in the neurotransmitter
+            response = self.lifo_buffer.execute(is_api_call=True)
+
+            expected_result = {
+                'status': None,
+                'matched_synapses': [],
+                'user_order': 'this is an order'
+            }
+
+            self.assertEqual(response, expected_result)
+
+    def test_add_synapse_list_to_lifo(self):
+        """
+        Testing to add a synapse to the lifo
+        """
+        synapse = BrainLoader().brain.get_synapse_by_name("synapse1")
+        order = "enter in synapse 1"
+        matched_synapse = MatchedSynapse(matched_synapse=synapse,
+                                         user_order=order,
+                                         matched_order=order)
+        list_matched_synapse = list()
+        list_matched_synapse.append(matched_synapse)
+        self.lifo_buffer.add_synapse_list_to_lifo(list_matched_synapse)
+
+        self.assertEqual(self.lifo_buffer.lifo_list, [list_matched_synapse])
+
+    def test_clean(self):
+        """
+        Test the Cleaning of the matched synapses list
+        """
+        synapse = BrainLoader().brain.get_synapse_by_name("synapse1")
+        order = "enter in synapse 1"
+        matched_synapse = MatchedSynapse(matched_synapse=synapse,
+                                         user_order=order,
+                                         matched_order=order)
+        list_matched_synapse = list()
+        list_matched_synapse.append(matched_synapse)
+        self.lifo_buffer.add_synapse_list_to_lifo(list_matched_synapse)
+
+        self.lifo_buffer.clean()
+        self.assertEqual(0, len(self.lifo_buffer.lifo_list))
+
+    def test_return_serialized_api_response(self):
+        """
+        Test the serialization
+        """
+        self.lifo_buffer.clean()
+        self.lifo_buffer.execute(is_api_call=True)
+        expected_result = {'status': None, 'matched_synapses': [], 'user_order': None}
+        response = self.lifo_buffer._return_serialized_api_response()
+        self.assertEqual(expected_result, response)
+
+    def test_process_synapse_list(self):
+        """
+        Testing the neuron list from a synapse
+        """
+        synapse = BrainLoader().brain.get_synapse_by_name("synapse1")
+        order = "enter in synapse 1"
+        matched_synapse = MatchedSynapse(matched_synapse=synapse,
+                                         user_order=order,
+                                         matched_order=order)
+        list_matched_synapse = list()
+        list_matched_synapse.append(matched_synapse)
+
+        with mock.patch("kalliope.core.LIFOBuffer._process_neuron_list"):
+            self.lifo_buffer._process_synapse_list(list_matched_synapse)
+            expected_response = {
+                'status': None,
+                'matched_synapses': [
+                    {
+                        'matched_order': 'enter in synapse 1',
+                        'neuron_module_list': [],
+                        'synapse_name': 'synapse1'
+                    }
+                ],
+                'user_order': None
+            }
+            self.assertEqual(expected_response, self.lifo_buffer.api_response.serialize())
+            self.assertEqual(0, len(self.lifo_buffer.lifo_list))
+
+    def test_process_neuron_list(self):
+        # Test with a neuron that doesn't wait for an answer
+        synapse = BrainLoader().brain.get_synapse_by_name("synapse5")
+        order = "synapse5"
+        matched_synapse = MatchedSynapse(matched_synapse=synapse,
+                                         user_order=order,
+                                         matched_order=order)
+
+        with mock.patch("kalliope.core.TTS.TTSModule.generate_and_play"):
+            self.lifo_buffer.set_api_call(True)
+            self.lifo_buffer._process_neuron_list(matched_synapse=matched_synapse)
+            self.assertEqual("complete", self.lifo_buffer.api_response.status)
+
+        # test with neuron that wait for an answer
+        self.lifo_buffer.clean()
+        synapse = BrainLoader().brain.get_synapse_by_name("synapse6")
+        order = "synapse6"
+        matched_synapse = MatchedSynapse(matched_synapse=synapse,
+                                         user_order=order,
+                                         matched_order=order)
+
+        self.lifo_buffer.set_api_call(True)
+        with mock.patch("kalliope.core.TTS.TTSModule.generate_and_play"):
+            with self.assertRaises(Serialize):
+                self.lifo_buffer._process_neuron_list(matched_synapse=matched_synapse)
+
+        # test with a neuron that want to add a synapse list to the LIFO
+        self.lifo_buffer.clean()
+        synapse = BrainLoader().brain.get_synapse_by_name("synapse6")
+        order = "synapse6"
+        matched_synapse = MatchedSynapse(matched_synapse=synapse,
+                                         user_order=order,
+                                         matched_order=order)
+
+        self.lifo_buffer.set_api_call(True)
+        self.lifo_buffer.set_answer("synapse 6 answer")
+        with mock.patch("kalliope.core.TTS.TTSModule.generate_and_play"):
+            with self.assertRaises(SynapseListAddedToLIFO):
+                self.lifo_buffer._process_neuron_list(matched_synapse=matched_synapse)
+
+
+if __name__ == '__main__':
+    unittest.main()
+
+    # suite = unittest.TestSuite()
+    # suite.addTest(TestLIFOBuffer("test_process_neuron_list"))
+    # runner = unittest.TextTestRunner()
+    # runner.run(suite)

+ 484 - 0
Tests/test_models.py

@@ -0,0 +1,484 @@
+import unittest
+
+import mock
+from kalliope.core.Models.Tts import Tts
+
+from kalliope.core.Models.Trigger import Trigger
+
+from kalliope.core.Models.Stt import Stt
+
+from kalliope.core.Models.RestAPI import RestAPI
+
+from kalliope.core.Models.Dna import Dna
+
+from kalliope.core import LIFOBuffer
+from kalliope.core.Models.Settings import Settings
+
+from kalliope.core.Models import Neuron, Order, Synapse, Brain, Event, Resources
+
+from kalliope.core.Models.APIResponse import APIResponse
+from kalliope.core.Models.MatchedSynapse import MatchedSynapse
+
+
+class TestModels(unittest.TestCase):
+
+    def setUp(self):
+        # Init
+        neuron1 = Neuron(name='neurone1', parameters={'var1': 'val1'})
+        neuron2 = Neuron(name='neurone2', parameters={'var2': 'val2'})
+        neuron3 = Neuron(name='neurone3', parameters={'var3': 'val3'})
+        neuron4 = Neuron(name='neurone4', parameters={'var4': 'val4'})
+
+        signal1 = Order(sentence="this is the sentence")
+        signal2 = Order(sentence="this is the second sentence")
+        signal3 = Order(sentence="that is part of the third sentence")
+
+        self.synapse1 = Synapse(name="Synapse1", neurons=[neuron1, neuron2], signals=[signal1])
+        self.synapse2 = Synapse(name="Synapse2", neurons=[neuron3, neuron4], signals=[signal2])
+        self.synapse3 = Synapse(name="Synapse3", neurons=[neuron2, neuron4], signals=[signal3])
+
+        self.all_synapse_list1 = [self.synapse1,
+                                  self.synapse2,
+                                  self.synapse3]
+
+        self.all_synapse_list2 = [self.synapse2,
+                                  self.synapse3]
+
+        self.brain_test1 = Brain(synapses=self.all_synapse_list1)
+        self.brain_test2 = Brain(synapses=self.all_synapse_list2)
+        # this brain is the same as the first one
+        self.brain_test3 = Brain(synapses=self.all_synapse_list1)
+
+        self.settings_test = Settings(default_synapse="Synapse3")
+
+        # clean the LiFO
+        LIFOBuffer.lifo_list = list()
+
+    def test_APIResponse(self):
+        user_order = "user order"
+        self.matched_synapse = MatchedSynapse(matched_synapse=self.synapse1, matched_order=user_order)
+
+        api_response = APIResponse()
+        api_response.user_order = user_order
+        api_response.list_processed_matched_synapse = [self.matched_synapse]
+
+        expected_result_serialize = {
+            'status': None,
+            'matched_synapses':
+                [
+                    {
+                        'matched_order': 'user order',
+                        'neuron_module_list': [],
+                        'synapse_name': 'Synapse1'
+                    }
+                ],
+                'user_order': 'user order'
+        }
+
+        self.assertEqual(expected_result_serialize, api_response.serialize())
+
+        expected_result_str = "{'status': None, 'matched_synapses': [{'matched_order': 'user order', " \
+                              "'neuron_module_list': [], 'synapse_name': 'Synapse1'}], 'user_order': 'user order'}"
+
+        self.assertEqual(expected_result_str, api_response.__str__())
+
+    def test_Brain(self):
+        # test get synapse by name
+        expect_result = self.synapse1
+        synapse_name = "Synapse1"
+        self.assertEqual(self.brain_test1.get_synapse_by_name(synapse_name), expect_result)
+
+        # test equals
+        self.assertTrue(self.brain_test1.__eq__(self.brain_test3))
+
+        # test not equals
+        self.assertFalse(self.brain_test1.__eq__(self.brain_test2))
+
+    def test_Dna(self):
+        # create DNA object
+        dna1 = Dna(name="dna1", module_type="neuron", author="kalliope",
+                   kalliope_supported_version="0.4.4", tags="test")
+
+        dna2 = Dna(name="dna2", module_type="neuron", author="community",
+                   kalliope_supported_version="0.4.2", tags="other")
+
+        # this dna is exactly the same as the first one
+        dna3 = Dna(name="dna1", module_type="neuron", author="kalliope",
+                   kalliope_supported_version="0.4.4", tags="test")
+
+        expected_result_serialize = {
+            'kalliope_supported_version': '0.4.4',
+            'tags': 'test',
+            'type': 'neuron',
+            'name': 'dna1',
+            'author': 'kalliope'
+        }
+        expected_result_str = "{'kalliope_supported_version': '0.4.4', 'tags': 'test', 'type':" \
+                              " 'neuron', 'name': 'dna1', 'author': 'kalliope'}"
+
+        self.assertEqual(expected_result_serialize, dna1.serialize())
+        self.assertEqual(expected_result_str, dna1.__str__())
+
+        self.assertTrue(dna1.__eq__(dna3))
+        self.assertFalse(dna1.__eq__(dna2))
+
+    def test_Event(self):
+        event1 = Event(year=2017, month=12, day=31, week=53, day_of_week=2,
+                       hour=8, minute=30, second=0)
+
+        event2 = Event(year=2018, month=11, day=30, week=25, day_of_week=4,
+                       hour=9, minute=40, second=0)
+
+        # same as the event1
+        event3 = Event(year=2017, month=12, day=31, week=53, day_of_week=2,
+                       hour=8, minute=30, second=0)
+
+        expected_result_serialize = {
+            'event': {
+                'week': 53,
+                'second': 0,
+                'minute': 30,
+                'hour': 8,
+                'year': 2017,
+                'day': 31,
+                'day_of_week': 2,
+                'month': 12
+            }
+        }
+        expected_result_str = "{'event': {'week': 53, 'second': 0, 'minute': 30, 'hour': 8, " \
+                              "'year': 2017, 'day': 31, 'day_of_week': 2, 'month': 12}}"
+
+        self.assertEqual(expected_result_serialize, event1.serialize())
+        self.assertEqual(expected_result_str, event1.__str__())
+
+        self.assertTrue(event1.__eq__(event3))
+        self.assertFalse(event1.__eq__(event2))
+
+    def test_MatchedSynapse(self):
+        user_order = "user order"
+        matched_synapse1 = MatchedSynapse(matched_synapse=self.synapse1, matched_order=user_order)
+        matched_synapse2 = MatchedSynapse(matched_synapse=self.synapse2, matched_order=user_order)
+        matched_synapse3 = MatchedSynapse(matched_synapse=self.synapse1, matched_order=user_order)
+
+        expected_result_serialize = {
+            'matched_order': 'user order',
+            'neuron_module_list': [],
+            'synapse_name': 'Synapse1'
+        }
+        expected_result_str = "{'matched_order': 'user order', 'neuron_module_list': [], 'synapse_name': 'Synapse1'}"
+
+        self.assertEqual(expected_result_serialize, matched_synapse1.serialize())
+        self.assertEqual(expected_result_str, matched_synapse1.__str__())
+
+        self.assertTrue(matched_synapse1.__eq__(matched_synapse3))
+        self.assertFalse(matched_synapse1.__eq__(matched_synapse2))
+
+        # test neuron parameter loader is called
+        with mock.patch("kalliope.core.NeuronParameterLoader.get_parameters") as mock_get_parameters:
+
+            MatchedSynapse(matched_synapse=self.synapse1, matched_order=user_order, user_order=user_order)
+            mock_get_parameters.assert_called_once_with(synapse_order=user_order,
+                                                        user_order=user_order)
+            mock_get_parameters.reset_mock()
+
+    def test_Neuron(self):
+
+        neuron1 = Neuron(name="test", parameters={"key1": "val1", "key2": "val2"})
+        neuron2 = Neuron(name="test", parameters={"key3": "val3", "key4": "val4"})
+        neuron3 = Neuron(name="test", parameters={"key1": "val1", "key2": "val2"})
+
+        expected_result_serialize = {'name': 'test', 'parameters': {'key2': 'val2', 'key1': 'val1'}}
+        expected_result_str = "{'name': 'test', 'parameters': {'key2': 'val2', 'key1': 'val1'}}"
+
+        self.assertEqual(expected_result_serialize, neuron1.serialize())
+        self.assertEqual(expected_result_str, neuron1.__str__())
+
+        self.assertTrue(neuron1.__eq__(neuron3))
+        self.assertFalse(neuron1.__eq__(neuron2))
+
+        # test password
+        neuron_name = "test"
+        neuron_parameters = {
+            "password": "my secret",
+            "parameter": "test"
+        }
+
+        neuron = Neuron()
+        neuron.name = neuron_name
+        neuron.parameters = neuron_parameters
+
+        expected_result = "{'name': 'test', 'parameters': {'password': '*****', 'parameter': 'test'}}"
+
+        self.assertEqual(neuron.__str__(), expected_result)
+
+        neuron_name = "test"
+        neuron_parameters = {
+            "password_parameter": "my secret",
+            "parameter": "test"
+        }
+
+        neuron = Neuron()
+        neuron.name = neuron_name
+        neuron.parameters = neuron_parameters
+
+        expected_result = "{'name': 'test', 'parameters': {'parameter': 'test', 'password_parameter': '*****'}}"
+
+        self.assertEqual(neuron.__str__(), expected_result)
+
+    def test_Order(self):
+        order1 = Order(sentence="this is an order")
+        order2 = Order(sentence="this is an other order")
+        order3 = Order(sentence="this is an order")
+
+        expected_result_serialize = {'order': 'this is an order'}
+        expected_result_str = "{'order': 'this is an order'}"
+
+        self.assertEqual(expected_result_serialize, order1.serialize())
+        self.assertEqual(expected_result_str, order1.__str__())
+
+        self.assertTrue(order1.__eq__(order3))
+        self.assertFalse(order1.__eq__(order2))
+
+    def test_Resources(self):
+        resource1 = Resources(neuron_folder="/path/neuron", stt_folder="/path/stt",
+                              tts_folder="/path/tts", trigger_folder="/path/trigger")
+
+        resource2 = Resources(neuron_folder="/other_path/neuron", stt_folder="/other_path/stt",
+                              tts_folder="/other_path/tts", trigger_folder="/other_path/trigger")
+
+        resource3 = Resources(neuron_folder="/path/neuron", stt_folder="/path/stt",
+                              tts_folder="/path/tts", trigger_folder="/path/trigger")
+
+        expected_result_serialize = {
+            'tts_folder': '/path/tts',
+            'neuron_folder': '/path/neuron',
+            'stt_folder': '/path/stt',
+            'trigger_folder': '/path/trigger'
+        }
+        expected_result_str = "{'tts_folder': '/path/tts', 'neuron_folder': '/path/neuron', " \
+                              "'stt_folder': '/path/stt', 'trigger_folder': '/path/trigger'}"
+
+        self.assertEqual(expected_result_serialize, resource1.serialize())
+        self.assertEqual(expected_result_str, resource1.__str__())
+
+        self.assertTrue(resource1.__eq__(resource3))
+        self.assertFalse(resource1.__eq__(resource2))
+
+    def test_RestAPI(self):
+
+        rest_api1 = RestAPI(password_protected=True, login="admin", password="password", active=True,
+                            port=5000, allowed_cors_origin="*")
+
+        rest_api2 = RestAPI(password_protected=False, active=False,
+                            port=5000, allowed_cors_origin=None)
+
+        rest_api3 = RestAPI(password_protected=True, login="admin", password="password", active=True,
+                            port=5000, allowed_cors_origin="*")
+
+        expected_result_serialize = {
+            'password_protected': True,
+            'port': 5000,
+            'active': True,
+            'allowed_cors_origin': '*',
+            'password': 'password',
+            'login': 'admin'
+        }
+        expected_result_str = "{'password_protected': True, 'port': 5000, 'active': True, 'allowed_cors_origin': '*', " \
+                              "'password': 'password', 'login': 'admin'}"
+
+        self.assertEqual(expected_result_serialize, rest_api1.serialize())
+        self.assertEqual(expected_result_str, rest_api1.__str__())
+
+        self.assertTrue(rest_api1.__eq__(rest_api3))
+        self.assertFalse(rest_api1.__eq__(rest_api2))
+
+    def test_Settings(self):
+        with mock.patch('platform.machine', return_value='pumpkins'):
+            rest_api1 = RestAPI(password_protected=True, login="admin", password="password", active=True,
+                                port=5000, allowed_cors_origin="*")
+
+            setting1 = Settings(default_tts_name="pico2wav",
+                                default_stt_name="google",
+                                default_trigger_name="swoyboy",
+                                ttss=["ttts"],
+                                stts=["stts"],
+                                random_wake_up_answers=["yes"],
+                                random_wake_up_sounds=None,
+                                play_on_ready_notification=False,
+                                on_ready_answers=None,
+                                on_ready_sounds=None,
+                                triggers=["snowboy"],
+                                rest_api=rest_api1,
+                                cache_path="/tmp/kalliope",
+                                default_synapse="default_synapse",
+                                resources=None,
+                                variables={"key1": "val1"})
+
+            setting2 = Settings(default_tts_name="accapela",
+                                default_stt_name="bing",
+                                default_trigger_name="swoyboy",
+                                ttss=["ttts"],
+                                stts=["stts"],
+                                random_wake_up_answers=["no"],
+                                random_wake_up_sounds=None,
+                                play_on_ready_notification=False,
+                                on_ready_answers=None,
+                                on_ready_sounds=None,
+                                triggers=["snowboy"],
+                                rest_api=rest_api1,
+                                cache_path="/tmp/kalliope_tmp",
+                                default_synapse="my_default_synapse",
+                                resources=None,
+                                variables={"key1": "val1"})
+
+            setting3 = Settings(default_tts_name="pico2wav",
+                                default_stt_name="google",
+                                default_trigger_name="swoyboy",
+                                ttss=["ttts"],
+                                stts=["stts"],
+                                random_wake_up_answers=["yes"],
+                                random_wake_up_sounds=None,
+                                play_on_ready_notification=False,
+                                on_ready_answers=None,
+                                on_ready_sounds=None,
+                                triggers=["snowboy"],
+                                rest_api=rest_api1,
+                                cache_path="/tmp/kalliope",
+                                default_synapse="default_synapse",
+                                resources=None,
+                                variables={"key1": "val1"})
+
+            expected_result_serialize = {
+                'default_synapse': 'default_synapse',
+                'default_tts_name': 'pico2wav',
+                'rest_api':
+                    {
+                        'password_protected': True,
+                        'port': 5000,
+                        'active': True,
+                        'allowed_cors_origin': '*',
+                        'password': 'password',
+                        'login': 'admin'
+                    },
+                'play_on_ready_notification': False,
+                'default_stt_name': 'google',
+                'kalliope_version': '0.4.4b',
+                'random_wake_up_sounds': None,
+                'on_ready_answers': None,
+                'default_trigger_name': 'swoyboy',
+                'cache_path': '/tmp/kalliope',
+                'stts': ['stts'],
+                'machine': 'pumpkins',
+                'random_wake_up_answers': ['yes'],
+                'on_ready_sounds': None,
+                'ttss': ['ttts'],
+                'variables': {'key1': 'val1'},
+                'resources': None,
+                'triggers': ['snowboy']
+            }
+
+            expected_result_str = "{'default_synapse': 'default_synapse', 'default_tts_name': 'pico2wav', 'rest_api': " \
+                                  "{'password_protected': True, 'port': 5000, 'active': True, 'allowed_cors_origin': " \
+                                  "'*', 'password': 'password', 'login': 'admin'}, 'play_on_ready_notification': " \
+                                  "False, 'default_stt_name': 'google', 'kalliope_version': '0.4.4b', " \
+                                  "'random_wake_up_sounds': None, 'on_ready_answers': None, 'default_trigger_name': " \
+                                  "'swoyboy', 'cache_path': '/tmp/kalliope', 'stts': ['stts'], 'machine': 'pumpkins', " \
+                                  "'random_wake_up_answers': ['yes'], 'on_ready_sounds': None, 'ttss': ['ttts'], " \
+                                  "'variables': {'key1': 'val1'}, 'resources': None, 'triggers': ['snowboy']}"
+
+            self.assertEqual(expected_result_serialize, setting1.serialize())
+            self.assertEqual(expected_result_str, setting1.__str__())
+
+            self.assertTrue(setting1.__eq__(setting3))
+            self.assertFalse(setting1.__eq__(setting2))
+
+    def test_Stt(self):
+        stt1 = Stt(name="stt1", parameters={"key1": "val1"})
+        stt2 = Stt(name="stt2", parameters={"key2": "val2"})
+        stt3 = Stt(name="stt1", parameters={"key1": "val1"})
+
+        expected_result_serialize = {'name': 'stt1', 'parameters': {'key1': 'val1'}}
+        expected_result_str = "{'name': 'stt1', 'parameters': {'key1': 'val1'}}"
+
+        self.assertEqual(expected_result_serialize, stt1.serialize())
+        self.assertEqual(expected_result_str, stt1.__str__())
+
+        self.assertTrue(stt1.__eq__(stt3))
+        self.assertFalse(stt1.__eq__(stt2))
+
+    def test_Synapse(self):
+        neuron1 = Neuron(name='neurone1', parameters={'var1': 'val1'})
+        neuron2 = Neuron(name='neurone2', parameters={'var2': 'val2'})
+        neuron3 = Neuron(name='neurone3', parameters={'var3': 'val3'})
+        neuron4 = Neuron(name='neurone4', parameters={'var4': 'val4'})
+
+        signal1 = Order(sentence="this is the sentence")
+        signal2 = Order(sentence="this is the second sentence")
+
+        synapse1 = Synapse(name="Synapse1", neurons=[neuron1, neuron2], signals=[signal1])
+        synapse2 = Synapse(name="Synapse2", neurons=[neuron3, neuron4], signals=[signal2])
+        synapse3 = Synapse(name="Synapse1", neurons=[neuron1, neuron2], signals=[signal1])
+
+        expected_result_serialize = {
+            'signals': [
+                {
+                    'order': 'this is the sentence'
+                }
+            ],
+            'neurons': [
+                {
+                    'name': 'neurone1',
+                     'parameters': {
+                         'var1': 'val1'
+                     }
+                },
+                {
+                    'name': 'neurone2',
+                    'parameters':
+                        {
+                            'var2': 'val2'
+                        }
+                }
+            ],
+            'name': 'Synapse1'
+        }
+
+        expected_result_str = "{'signals': [{'order': 'this is the sentence'}], 'neurons': [{'name': 'neurone1', " \
+                              "'parameters': {'var1': 'val1'}}, {'name': 'neurone2', 'parameters': {'var2': " \
+                              "'val2'}}], 'name': 'Synapse1'}"
+
+        self.assertEqual(expected_result_serialize, synapse1.serialize())
+        self.assertEqual(expected_result_str, synapse1.__str__())
+
+        self.assertTrue(synapse1.__eq__(synapse3))
+        self.assertFalse(synapse1.__eq__(synapse2))
+
+    def test_Trigger(self):
+        trigger1 = Trigger(name="trigger1", parameters={"key1": "val1"})
+        trigger2 = Trigger(name="trigger2", parameters={"key2": "val2"})
+        trigger3 = Trigger(name="trigger1", parameters={"key1": "val1"})
+
+        expected_result_serialize = {'name': 'trigger1', 'parameters': {'key1': 'val1'}}
+        expected_result_str = "{'name': 'trigger1', 'parameters': {'key1': 'val1'}}"
+
+        self.assertEqual(expected_result_serialize, trigger1.serialize())
+        self.assertEqual(expected_result_str, trigger1.__str__())
+
+        self.assertTrue(trigger1.__eq__(trigger3))
+        self.assertFalse(trigger1.__eq__(trigger2))
+
+    def test_Tts(self):
+        tts1 = Tts(name="tts1", parameters={"key1": "val1"})
+        tts2 = Tts(name="tts2", parameters={"key2": "val2"})
+        tts3 = Tts(name="tts1", parameters={"key1": "val1"})
+
+        expected_result_serialize = {'name': 'tts1', 'parameters': {'key1': 'val1'}}
+        expected_result_str = "{'name': 'tts1', 'parameters': {'key1': 'val1'}}"
+
+        self.assertEqual(expected_result_serialize, tts1.serialize())
+        self.assertEqual(expected_result_str, tts1.__str__())
+
+        self.assertTrue(tts1.__eq__(tts3))
+        self.assertFalse(tts1.__eq__(tts2))
+
+

+ 90 - 0
Tests/test_neuron_launcher.py

@@ -0,0 +1,90 @@
+import unittest
+import mock
+
+from kalliope.core.Models.Resources import Resources
+from kalliope.core.NeuronLauncher import NeuronLauncher
+from kalliope.core.ConfigurationManager import SettingLoader
+
+from kalliope.core.Models.Neuron import Neuron
+
+
+class TestNeuronLauncher(unittest.TestCase):
+    """
+    Class to test Launchers Classes (TriggerLauncher, SynapseLauncher, NeuronLauncher) and methods
+    """
+
+    def setUp(self):
+        pass
+
+    ####
+    # Neurons Launcher
+    def test_launch_neuron(self):
+        """
+        Test the Neuron Launcher trying to start a Neuron
+        """
+        neuron = Neuron(name='neurone1', parameters={'var1': 'val1'})
+        sl = SettingLoader()
+        resources = Resources(neuron_folder='/var/tmp/test/resources')
+        sl.settings.resources = resources
+        with mock.patch("kalliope.core.Utils.get_dynamic_class_instantiation") as mock_get_class_instantiation:
+            NeuronLauncher.launch_neuron(neuron=neuron)
+
+            mock_get_class_instantiation.assert_called_once_with(package_name="neurons",
+                                                                 module_name=neuron.name,
+                                                                 parameters=neuron.parameters,
+                                                                 resources_dir=sl.settings.resources.neuron_folder)
+            mock_get_class_instantiation.reset_mock()
+
+    def test_start_neuron(self):
+        """
+        Testing params association and starting a Neuron
+        """
+
+        with mock.patch("kalliope.core.NeuronLauncher.launch_neuron") as mock_launch_neuron_method:
+            # Assert to the neuron is launched
+            neuron1 = Neuron(name='neurone1', parameters={'var1': 'val1'})
+            params = {
+                'param1':'parval1'
+            }
+            NeuronLauncher.start_neuron(neuron=neuron1,
+                                        parameters_dict=params)
+            mock_launch_neuron_method.assert_called_with(neuron1)
+            mock_launch_neuron_method.reset_mock()
+
+            # Assert the params are well passed to the neuron
+            neuron2 = Neuron(name='neurone2', parameters={'var2': 'val2', 'args': ['arg1', 'arg2']})
+            params = {
+                'arg1':'argval1',
+                'arg2':'argval2'
+            }
+            NeuronLauncher.start_neuron(neuron=neuron2,
+                                        parameters_dict=params)
+            neuron2_params = Neuron(name='neurone2',
+                                    parameters={'var2': 'val2',
+                                                'args': ['arg1', 'arg2'],
+                                                'arg1':'argval1',
+                                                'arg2':'argval2'}
+                                    )
+            mock_launch_neuron_method.assert_called_with(neuron2_params)
+            mock_launch_neuron_method.reset_mock()
+
+            # Assert the Neuron is not started when missing args
+            neuron3 = Neuron(name='neurone3', parameters={'var3': 'val3', 'args': ['arg3', 'arg4']})
+            params = {
+                'arg1': 'argval1',
+                'arg2': 'argval2'
+            }
+            NeuronLauncher.start_neuron(neuron=neuron3,
+                                        parameters_dict=params)
+            mock_launch_neuron_method.assert_not_called()
+            mock_launch_neuron_method.reset_mock()
+
+            # Assert no neuron is launched when waiting for args and none are given
+            neuron4 = Neuron(name='neurone4', parameters={'var4': 'val4', 'args': ['arg5', 'arg6']})
+            params = {}
+            NeuronLauncher.start_neuron(neuron=neuron4,
+                                        parameters_dict=params)
+            mock_launch_neuron_method.assert_not_called()
+            mock_launch_neuron_method.reset_mock()
+
+

+ 0 - 40
Tests/test_neuron_model.py

@@ -1,40 +0,0 @@
-import os
-import unittest
-
-from kalliope.core.Models import Neuron
-
-
-class TestNeuronModule(unittest.TestCase):
-
-    def test_password_parameter(self):
-        neuron_name = "test"
-        neuron_parameters = {
-            "password": "my secret",
-            "parameter": "test"
-        }
-
-        neuron = Neuron()
-        neuron.name = neuron_name
-        neuron.parameters = neuron_parameters
-
-        expected_result = "Neuron: name: test, parameters: {'password': '*****', 'parameter': 'test'}"
-
-        self.assertEqual(neuron.__str__(), expected_result)
-
-    def test_password_in_parameter(self):
-        neuron_name = "test"
-        neuron_parameters = {
-            "password_parameter": "my secret",
-            "parameter": "test"
-        }
-
-        neuron = Neuron()
-        neuron.name = neuron_name
-        neuron.parameters = neuron_parameters
-
-        expected_result = "Neuron: name: test, parameters: {'parameter': 'test', 'password_parameter': '*****'}"
-
-        self.assertEqual(neuron.__str__(), expected_result)
-
-if __name__ == '__main__':
-    unittest.main()

+ 11 - 56
Tests/test_neuron_module.py

@@ -3,10 +3,6 @@ import unittest
 import mock
 import mock
 
 
 from kalliope.core.NeuronModule import NeuronModule, TemplateFileNotFoundException
 from kalliope.core.NeuronModule import NeuronModule, TemplateFileNotFoundException
-from kalliope.core.Models.Neuron import Neuron
-from kalliope.core.Models.Synapse import Synapse
-from kalliope.core.Models.Brain import Brain
-from kalliope.core.Models.Order import Order
 
 
 
 
 class TestNeuronModule(unittest.TestCase):
 class TestNeuronModule(unittest.TestCase):
@@ -114,61 +110,20 @@ class TestNeuronModule(unittest.TestCase):
         expected_result = "hello, this is a {{ test }}"
         expected_result = "hello, this is a {{ test }}"
         self.assertEqual(NeuronModule._get_content_of_file(self.file_template), expected_result)
         self.assertEqual(NeuronModule._get_content_of_file(self.file_template), expected_result)
 
 
-    def test_run_synapse_by_name_with_order(self):
+    def test_serialize(self):
         """
         """
-        Test to start a synapse with a specific given order
-        Scenarii :
-            - Neuron has been found and launched
-            - Neuron has not been found
+        Test the serialisation of the neuron module
         """
         """
+        neuron_module = NeuronModule()
+        neuron_module.neuron_name = "kalliope"
+        neuron_module.tts_message = "I am french"
 
 
-        # Init
-        neuron1 = Neuron(name='neurone1', parameters={'var1': 'val1'})
-        neuron2 = Neuron(name='neurone2', parameters={'var2': 'val2'})
-        neuron3 = Neuron(name='neurone3', parameters={'var3': 'val3'})
-        neuron4 = Neuron(name='neurone4', parameters={'var4': 'val4'})
-
-        signal1 = Order(sentence="the sentence")
-        signal2 = Order(sentence="the second sentence")
-        signal3 = Order(sentence="part of the third sentence")
-
-        synapse1 = Synapse(name="Synapse1", neurons=[neuron1, neuron2], signals=[signal1])
-        synapse2 = Synapse(name="Synapse2", neurons=[neuron3, neuron4], signals=[signal2])
-        synapse3 = Synapse(name="Synapse3", neurons=[neuron2, neuron4], signals=[signal3])
-
-        all_synapse_list = [synapse1,
-                            synapse2,
-                            synapse3]
-
-        br = Brain(synapses=all_synapse_list)
-
-        order = "This is the order"
-        synapse_name = "Synapse2"
-        answer = "This is the {{ answer }}"
-        expected_parameter = {"answer": "order"}
-
-        with mock.patch("kalliope.core.NeuronLauncher.start_neuron_list") as mock_NeuronLauncher_start:
-            neuron_mod = NeuronModule()
-            neuron_mod.brain = br
-
-            # Success, run synapse 2
-            launched_synapse = neuron_mod.run_synapse_by_name_with_order(order=order,
-                                                                         synapse_name=synapse_name,
-                                                                         order_template=answer)
-            self.assertEqual(synapse2, launched_synapse)
-
-            mock_NeuronLauncher_start.assert_called_once_with(neuron_list=[neuron3, neuron4],
-                                                              parameters_dict=expected_parameter)
-            mock_NeuronLauncher_start.reset_mock()
-
-            # Fail
-            synapse_name = "Synapse5"
-            self.assertIsNone(neuron_mod.run_synapse_by_name_with_order(order=order,
-                                                                        synapse_name=synapse_name,
-                                                                        order_template=answer))
-
-            mock_NeuronLauncher_start.assert_not_called()
-            mock_NeuronLauncher_start.reset_mock()
+        expected_result = {
+            'neuron_name': "kalliope",
+            'generated_message': "I am french"
+        }
+
+        self.assertEqual(expected_result, neuron_module.serialize())
 
 
 
 
 
 

+ 8 - 1
Tests/test_order_analyser.py

@@ -5,6 +5,7 @@ from kalliope.core.Models import Brain
 from kalliope.core.Models import Neuron
 from kalliope.core.Models import Neuron
 from kalliope.core.Models import Order
 from kalliope.core.Models import Order
 from kalliope.core.Models import Synapse
 from kalliope.core.Models import Synapse
+from kalliope.core.Models.MatchedSynapse import MatchedSynapse
 from kalliope.core.OrderAnalyser import OrderAnalyser
 from kalliope.core.OrderAnalyser import OrderAnalyser
 
 
 
 
@@ -38,9 +39,15 @@ class TestOrderAnalyser(unittest.TestCase):
 
 
         # TEST1: should return synapse1
         # TEST1: should return synapse1
         spoken_order = "this is the sentence"
         spoken_order = "this is the sentence"
+
+        # Create the matched synapse
+        matched_synapse_1 = MatchedSynapse(matched_synapse=synapse1,
+                                           matched_order=spoken_order,
+                                           user_order=spoken_order)
+
         matched_synapses = OrderAnalyser.get_matching_synapse(order=spoken_order, brain=br)
         matched_synapses = OrderAnalyser.get_matching_synapse(order=spoken_order, brain=br)
         self.assertEqual(len(matched_synapses), 1)
         self.assertEqual(len(matched_synapses), 1)
-        self.assertTrue(any(synapse1 in matched_synapse for matched_synapse in matched_synapses))
+        self.assertTrue(matched_synapse_1 in matched_synapses)
 
 
         # TEST2: should return synapse1 and 2
         # TEST2: should return synapse1 and 2
         spoken_order = "this is the second sentence"
         spoken_order = "this is the second sentence"

+ 68 - 80
Tests/test_rest_api.py

@@ -5,6 +5,7 @@ import unittest
 from flask import Flask
 from flask import Flask
 from flask_testing import LiveServerTestCase
 from flask_testing import LiveServerTestCase
 
 
+from kalliope.core import LIFOBuffer
 from kalliope.core.Models import Singleton
 from kalliope.core.Models import Singleton
 from kalliope._version import version_str
 from kalliope._version import version_str
 from kalliope.core.ConfigurationManager import BrainLoader
 from kalliope.core.ConfigurationManager import BrainLoader
@@ -16,6 +17,8 @@ class TestRestAPI(LiveServerTestCase):
 
 
     def tearDown(self):
     def tearDown(self):
         Singleton._instances = {}
         Singleton._instances = {}
+        # clean the lifo
+        LIFOBuffer.lifo_list = list()
 
 
     def create_app(self):
     def create_app(self):
         """
         """
@@ -128,8 +131,6 @@ class TestRestAPI(LiveServerTestCase):
         # a lot of char ti process
         # a lot of char ti process
         self.maxDiff = None
         self.maxDiff = None
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
-        # print response.get_data()
-        # print json.dumps(expected_content)
         self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(response.get_data())))
         self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(response.get_data())))
 
 
     def test_get_one_synapse(self):
     def test_get_one_synapse(self):
@@ -175,26 +176,14 @@ class TestRestAPI(LiveServerTestCase):
         url = self.get_server_url() + "/synapses/start/id/test"
         url = self.get_server_url() + "/synapses/start/id/test"
         result = self.client.post(url)
         result = self.client.post(url)
 
 
-        expected_content = {
-            "synapses": {
-                "name": "test",
-                "neurons": [
-                    {
-                        "name": "say",
-                        "parameters": {
-                            "message": [
-                                "test message"
-                            ]
-                        }
-                    }
-                ],
-                "signals": [
-                    {
-                        "order": "test_order"
-                    }
-                ]
-            }
-        }
+        expected_content = {'status': 'complete',
+                            'matched_synapses':
+                                [{'matched_order': None,
+                                  'neuron_module_list':
+                                      [{'generated_message': 'test message', 'neuron_name': 'Say'}],
+                                  'synapse_name': 'test'}],
+                            'user_order': None
+                            }
         self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data())))
         self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data())))
         self.assertEqual(result.status_code, 201)
         self.assertEqual(result.status_code, 201)
 
 
@@ -217,28 +206,22 @@ class TestRestAPI(LiveServerTestCase):
         data = {"order": "test_order"}
         data = {"order": "test_order"}
         result = self.client.post(url, headers=headers, data=json.dumps(data))
         result = self.client.post(url, headers=headers, data=json.dumps(data))
 
 
-        expected_content = {
-            "synapses": [
-                {
-                    "name": "test",
-                    "neurons": [
-                        {
-                            "name": "say",
-                            "parameters": {
-                                "message": [
-                                    "test message"
-                                ]
+        expected_content = {'status': 'complete',
+                            'matched_synapses':
+                                [
+                                    {
+                                        'matched_order': "test_order",
+                                        'neuron_module_list':
+                                            [
+                                                {
+                                                    'generated_message': 'test message', 'neuron_name': 'Say'
+                                                }
+                                            ],
+                                  'synapse_name': 'test'
+                                    }
+                                ],
+                            'user_order': "test_order"
                             }
                             }
-                        }
-                    ],
-                    "signals": [
-                        {
-                            "order": "test_order"
-                        }
-                    ]
-                }
-            ]
-        }
         self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data())))
         self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data())))
         self.assertEqual(result.status_code, 201)
         self.assertEqual(result.status_code, 201)
 
 
@@ -250,46 +233,51 @@ class TestRestAPI(LiveServerTestCase):
                                   headers=headers,
                                   headers=headers,
                                   data=json.dumps(data))
                                   data=json.dumps(data))
 
 
-        expected_content = {'error': {'error': "The given order doesn't match any synapses"}}
+        expected_content = {'status': None, 'matched_synapses': [], 'user_order': u'non existing order'}
 
 
         self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data())))
         self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data())))
-        self.assertEqual(result.status_code, 400)
+        self.assertEqual(result.status_code, 201)
 
 
-    # TODO this doesn't work on travis but works locally with python -m unittest discover
-    # def test_post_synapse_by_audio(self):
-    #     url = self.get_server_url() + "/synapses/start/audio"
-    #     with open(os.path.join(self.audio_file), 'rb') as fp:
-    #         file = FileStorage(fp)
-    #         data = {
-    #             'file': file
-    #         }
-    #         result = self.client.post(url, data=data, content_type='multipart/form-data')
-    #
-    #         expected_content = {
-    #             "synapses": [
-    #                 {
-    #                     "name": "test2",
-    #                     "neurons": [
-    #                         {
-    #                             "name": "say",
-    #                             "parameters": {
-    #                                 "message": [
-    #                                     "test message"
-    #                                 ]
-    #                             }
-    #                         }
-    #                     ],
-    #                     "signals": [
-    #                         {
-    #                             "order": "bonjour"
-    #                         }
-    #                     ]
-    #                 }
-    #             ]
-    #         }
-    #
-    #         self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data())))
-    #         self.assertEqual(result.status_code, 201)
+        # TODO this doesn't work on travis but works locally with python -m unittest discover
+        # def test_post_synapse_by_audio(self):
+        #     url = self.get_server_url() + "/synapses/start/audio"
+        #     with open(os.path.join(self.audio_file), 'rb') as fp:
+        #         file = FileStorage(fp)
+        #         data = {
+        #             'file': file
+        #         }
+        #         result = self.client.post(url, data=data, content_type='multipart/form-data')
+        #
+        #         expected_content = {
+        #             "synapses": [
+        #                 {
+        #                     "name": "test2",
+        #                     "neurons": [
+        #                         {
+        #                             "name": "say",
+        #                             "parameters": {
+        #                                 "message": [
+        #                                     "test message"
+        #                                 ]
+        #                             }
+        #                         }
+        #                     ],
+        #                     "signals": [
+        #                         {
+        #                             "order": "bonjour"
+        #                         }
+        #                     ]
+        #                 }
+        #             ]
+        #         }
+        #
+        #         self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data())))
+        #         self.assertEqual(result.status_code, 201)
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
     unittest.main()
     unittest.main()
+
+    # suite = unittest.TestSuite()
+    # suite.addTest(TestRestAPI("test_post_synapse_by_order_not_found"))
+    # runner = unittest.TextTestRunner()
+    # runner.run(suite)

+ 81 - 36
Tests/test_synapse_launcher.py

@@ -2,7 +2,9 @@ import unittest
 
 
 import mock
 import mock
 
 
+from kalliope.core import LIFOBuffer
 from kalliope.core.Models import Brain
 from kalliope.core.Models import Brain
+from kalliope.core.Models.MatchedSynapse import MatchedSynapse
 from kalliope.core.Models.Settings import Settings
 from kalliope.core.Models.Settings import Settings
 from kalliope.core.SynapseLauncher import SynapseLauncher, SynapseNameNotFound
 from kalliope.core.SynapseLauncher import SynapseLauncher, SynapseNameNotFound
 
 
@@ -31,50 +33,93 @@ class TestSynapseLauncher(unittest.TestCase):
         self.synapse2 = Synapse(name="Synapse2", neurons=[neuron3, neuron4], signals=[signal2])
         self.synapse2 = Synapse(name="Synapse2", neurons=[neuron3, neuron4], signals=[signal2])
         self.synapse3 = Synapse(name="Synapse3", neurons=[neuron2, neuron4], signals=[signal3])
         self.synapse3 = Synapse(name="Synapse3", neurons=[neuron2, neuron4], signals=[signal3])
 
 
-        all_synapse_list = [self.synapse1,
-                            self.synapse2,
-                            self.synapse3]
+        self.all_synapse_list = [self.synapse1,
+                                 self.synapse2,
+                                 self.synapse3]
 
 
-        self.brain_test = Brain(synapses=all_synapse_list)
+        self.brain_test = Brain(synapses=self.all_synapse_list)
         self.settings_test = Settings(default_synapse="Synapse3")
         self.settings_test = Settings(default_synapse="Synapse3")
 
 
-    def test_run_matching_synapse_or_default(self):
+        # clean the LiFO
+        LIFOBuffer.lifo_list = list()
 
 
+    def test_start_synapse_by_name(self):
+        # existing synapse in the brain
+        with mock.patch("kalliope.core.LIFOBuffer.execute"):
+            should_be_created_matched_synapse = MatchedSynapse(matched_synapse=self.synapse1)
+            SynapseLauncher.start_synapse_by_name("Synapse1", brain=self.brain_test)
+            # we expect that the lifo has been loaded with the synapse to run
+            expected_result = [[should_be_created_matched_synapse]]
+            self.assertEqual(expected_result, LIFOBuffer.lifo_list)
+
+        # non existing synapse in the brain
+        with self.assertRaises(SynapseNameNotFound):
+            SynapseLauncher.start_synapse_by_name("not_existing", brain=self.brain_test)
+
+    def test_run_matching_synapse_from_order(self):
+        # ------------------
         # test_match_synapse1
         # test_match_synapse1
-        with mock.patch("kalliope.core.NeuronLauncher.start_neuron_list"):
+        # ------------------
+        with mock.patch("kalliope.core.LIFOBuffer.execute"):
             order_to_match = "this is the sentence"
             order_to_match = "this is the sentence"
-            expected_result = [self.synapse1]
 
 
-            self.assertEqual(expected_result,
-                             SynapseLauncher.run_matching_synapse_or_default(order_to_match,
-                                                                             brain=self.brain_test,
-                                                                             settings=self.settings_test))
+            should_be_created_matched_synapse = MatchedSynapse(matched_synapse=self.synapse1,
+                                                               user_order=order_to_match,
+                                                               matched_order="this is the sentence")
+            expected_result = [[should_be_created_matched_synapse]]
+            SynapseLauncher.run_matching_synapse_from_order(order_to_match,
+                                                            brain=self.brain_test,
+                                                            settings=self.settings_test)
 
 
+            self.assertEqual(expected_result, LIFOBuffer.lifo_list)
+
+        # -------------------------
         # test_match_synapse1_and_2
         # test_match_synapse1_and_2
-        with mock.patch("kalliope.core.NeuronLauncher.start_neuron_list"):
+        # -------------------------
+        # clean LIFO
+        LIFOBuffer.lifo_list = list()
+        with mock.patch("kalliope.core.LIFOBuffer.execute"):
             order_to_match = "this is the second sentence"
             order_to_match = "this is the second sentence"
-            expected_result = [self.synapse1, self.synapse2]
-
-            self.assertEqual(expected_result,
-                             SynapseLauncher.run_matching_synapse_or_default(order_to_match,
-                                                                             brain=self.brain_test,
-                                                                             settings=self.settings_test))
-
+            should_be_created_matched_synapse1 = MatchedSynapse(matched_synapse=self.synapse1,
+                                                                user_order=order_to_match,
+                                                                matched_order="this is the sentence")
+            should_be_created_matched_synapse2 = MatchedSynapse(matched_synapse=self.synapse2,
+                                                                user_order=order_to_match,
+                                                                matched_order="this is the second sentence")
+
+            expected_result = [[should_be_created_matched_synapse1, should_be_created_matched_synapse2]]
+            SynapseLauncher.run_matching_synapse_from_order(order_to_match,
+                                                            brain=self.brain_test,
+                                                            settings=self.settings_test)
+            self.assertEqual(expected_result, LIFOBuffer.lifo_list)
+
+        # -------------------------
         # test_match_default_synapse
         # test_match_default_synapse
-        with mock.patch("kalliope.core.NeuronLauncher.start_neuron"):
-            order_to_match = "this is an invalid order"
-            expected_result = [self.synapse3]
-
-            self.assertEqual(expected_result,
-                             SynapseLauncher.run_matching_synapse_or_default(order_to_match,
-                                                                             brain=self.brain_test,
-                                                                             settings=self.settings_test))
-
-    def test_start_synapse(self):
-        with mock.patch("kalliope.core.NeuronLauncher.start_neuron"):
-            expected_result = self.synapse1
-            self.assertEqual(expected_result,
-                             SynapseLauncher.start_synapse("Synapse1", brain=self.brain_test))
-
-        with self.assertRaises(SynapseNameNotFound):
-            SynapseLauncher.start_synapse(name="no_do_exist", brain=self.brain_test)
+        # -------------------------
+        # clean LIFO
+        LIFOBuffer.lifo_list = list()
+        with mock.patch("kalliope.core.LIFOBuffer.execute"):
+            order_to_match = "not existing sentence"
+            should_be_created_matched_synapse = MatchedSynapse(matched_synapse=self.synapse3,
+                                                               user_order=order_to_match,
+                                                               matched_order=None)
+
+            expected_result = [[should_be_created_matched_synapse]]
+            SynapseLauncher.run_matching_synapse_from_order(order_to_match,
+                                                            brain=self.brain_test,
+                                                            settings=self.settings_test)
+            self.assertEqual(expected_result, LIFOBuffer.lifo_list)
+
+        # -------------------------
+        # test_no_match_and_no_default_synapse
+        # -------------------------
+        # clean LIFO
+        LIFOBuffer.lifo_list = list()
+        with mock.patch("kalliope.core.LIFOBuffer.execute"):
+            order_to_match = "not existing sentence"
+            new_settings = Settings()
+            expected_result = [[]]
+            SynapseLauncher.run_matching_synapse_from_order(order_to_match,
+                                                            brain=self.brain_test,
+                                                            settings=new_settings)
+            self.assertEqual(expected_result, LIFOBuffer.lifo_list)

+ 31 - 0
Tests/test_trigger_launcher.py

@@ -0,0 +1,31 @@
+import unittest
+import mock
+
+from kalliope.core.TriggerLauncher import TriggerLauncher
+
+from kalliope.core.Models.Trigger import Trigger
+
+
+class TestTriggerLauncher(unittest.TestCase):
+    """
+    Class to test Launchers Classes (TriggerLauncher, SynapseLauncher, NeuronLauncher) and methods
+    """
+
+    def setUp(self):
+        pass
+
+    ####
+    # Trigger Launcher
+    def test_get_trigger(self):
+        """
+        Test the Trigger Launcher trying to run the trigger
+        """
+        trigger = Trigger("Trigger", {})
+        with mock.patch("kalliope.core.Utils.get_dynamic_class_instantiation") as mock_get_class_instantiation:
+            TriggerLauncher.get_trigger(trigger=trigger,
+                                        callback=None)
+
+            mock_get_class_instantiation.assert_called_once_with(package_name="trigger",
+                                                                 module_name=trigger.name,
+                                                                 parameters=trigger.parameters)
+            mock_get_class_instantiation.reset_mock()

+ 5 - 4
kalliope/__init__.py

@@ -120,13 +120,14 @@ def main():
 
 
         # user set a synapse to start
         # user set a synapse to start
         if args.run_synapse is not None:
         if args.run_synapse is not None:
-            SynapseLauncher.start_synapse(args.run_synapse,
-                                          brain=brain)
+            SynapseLauncher.start_synapse_by_name(args.run_synapse,
+                                                  brain=brain)
 
 
         if args.run_order is not None:
         if args.run_order is not None:
-            SynapseLauncher.run_matching_synapse_or_default(args.run_order,
+            SynapseLauncher.run_matching_synapse_from_order(args.run_order,
                                                             brain=brain,
                                                             brain=brain,
-                                                            settings=settings)
+                                                            settings=settings,
+                                                            is_api_call=False)
 
 
         if (args.run_synapse is None) and (args.run_order is None):
         if (args.run_synapse is None) and (args.run_order is None):
             # first, load events in event manager
             # first, load events in event manager

+ 0 - 8
kalliope/core/ConfigurationManager/BrainLoader.py

@@ -87,7 +87,6 @@ class BrainLoader(object):
         for synapses_dict in dict_brain:
         for synapses_dict in dict_brain:
             if "includes" not in synapses_dict:     # we don't need to check includes as it's not a synapse
             if "includes" not in synapses_dict:     # we don't need to check includes as it's not a synapse
                 if ConfigurationChecker().check_synape_dict(synapses_dict):
                 if ConfigurationChecker().check_synape_dict(synapses_dict):
-                    # print "synapses_dict ok"
                     name = synapses_dict["name"]
                     name = synapses_dict["name"]
                     neurons = self._get_neurons(synapses_dict["neurons"], self.settings)
                     neurons = self._get_neurons(synapses_dict["neurons"], self.settings)
                     signals = self._get_signals(synapses_dict["signals"])
                     signals = self._get_signals(synapses_dict["signals"])
@@ -127,7 +126,6 @@ class BrainLoader(object):
         for neuron_dict in neurons_dict:
         for neuron_dict in neurons_dict:
             if isinstance(neuron_dict, dict):
             if isinstance(neuron_dict, dict):
                 if ConfigurationChecker().check_neuron_dict(neuron_dict):
                 if ConfigurationChecker().check_neuron_dict(neuron_dict):
-                    # print "Neurons dict ok"
                     for neuron_name in neuron_dict:
                     for neuron_name in neuron_dict:
 
 
                         name = neuron_name
                         name = neuron_name
@@ -164,11 +162,9 @@ class BrainLoader(object):
         .. seealso:: Event, Order
         .. seealso:: Event, Order
         .. warnings:: Class method and Private
         .. warnings:: Class method and Private
         """
         """
-        # print signals_dict
         signals = list()
         signals = list()
         for signal_dict in signals_dict:
         for signal_dict in signals_dict:
             if ConfigurationChecker().check_signal_dict(signal_dict):
             if ConfigurationChecker().check_signal_dict(signal_dict):
-                # print "Signals dict ok"
                 event_or_order = cls._get_event_or_order_from_dict(signal_dict)
                 event_or_order = cls._get_event_or_order_from_dict(signal_dict)
                 signals.append(event_or_order)
                 signals.append(event_or_order)
 
 
@@ -192,7 +188,6 @@ class BrainLoader(object):
         .. warnings:: Static method and Private
         .. warnings:: Static method and Private
         """
         """
         if 'event' in signal_or_event_dict:
         if 'event' in signal_or_event_dict:
-            # print "is event"
             event = signal_or_event_dict["event"]
             event = signal_or_event_dict["event"]
             if ConfigurationChecker.check_event_dict(event):
             if ConfigurationChecker.check_event_dict(event):
                 return cls._get_event_object(event)
                 return cls._get_event_object(event)
@@ -257,18 +252,15 @@ class BrainLoader(object):
         """
         """
 
 
         if isinstance(parameter, dict):
         if isinstance(parameter, dict):
-            # print "parameter is dict %s" % str(parameter)
             for key, value in parameter.iteritems():
             for key, value in parameter.iteritems():
                 parameter[key] = cls._replace_global_variables(value, settings=settings)
                 parameter[key] = cls._replace_global_variables(value, settings=settings)
             return parameter
             return parameter
         if isinstance(parameter, list):
         if isinstance(parameter, list):
-            # print "parameter is list %s" % str(parameter)
             new_parameter_list = list()
             new_parameter_list = list()
             for el in parameter:
             for el in parameter:
                 new_parameter_list.append(cls._replace_global_variables(el, settings=settings))
                 new_parameter_list.append(cls._replace_global_variables(el, settings=settings))
             return new_parameter_list
             return new_parameter_list
         if isinstance(parameter, str) or isinstance(parameter, unicode) or isinstance(parameter, int):
         if isinstance(parameter, str) or isinstance(parameter, unicode) or isinstance(parameter, int):
-            # print "parameter is string %s" % parameter
             if Utils.is_containing_bracket(parameter):
             if Utils.is_containing_bracket(parameter):
                 return cls._get_global_variable(sentence=parameter, settings=settings)
                 return cls._get_global_variable(sentence=parameter, settings=settings)
             return parameter
             return parameter

+ 0 - 4
kalliope/core/ConfigurationManager/SettingLoader.py

@@ -244,7 +244,6 @@ class SettingLoader(object):
         stts = list()
         stts = list()
         for speechs_to_text_el in speechs_to_text_list:
         for speechs_to_text_el in speechs_to_text_list:
             if isinstance(speechs_to_text_el, dict):
             if isinstance(speechs_to_text_el, dict):
-                # print "Neurons dict ok"
                 for stt_name in speechs_to_text_el:
                 for stt_name in speechs_to_text_el:
                     name = stt_name
                     name = stt_name
                     parameters = speechs_to_text_el[name]
                     parameters = speechs_to_text_el[name]
@@ -284,7 +283,6 @@ class SettingLoader(object):
         ttss = list()
         ttss = list()
         for text_to_speech_el in text_to_speech_list:
         for text_to_speech_el in text_to_speech_list:
             if isinstance(text_to_speech_el, dict):
             if isinstance(text_to_speech_el, dict):
-                # print "Neurons dict ok"
                 for tts_name in text_to_speech_el:
                 for tts_name in text_to_speech_el:
                     name = tts_name
                     name = tts_name
                     parameters = text_to_speech_el[name]
                     parameters = text_to_speech_el[name]
@@ -323,7 +321,6 @@ class SettingLoader(object):
         triggers = list()
         triggers = list()
         for trigger_el in triggers_list:
         for trigger_el in triggers_list:
             if isinstance(trigger_el, dict):
             if isinstance(trigger_el, dict):
-                # print "Neurons dict ok"
                 for trigger_name in trigger_el:
                 for trigger_name in trigger_el:
                     name = trigger_name
                     name = trigger_name
                     parameters = trigger_el[name]
                     parameters = trigger_el[name]
@@ -458,7 +455,6 @@ class SettingLoader(object):
                      allowed_cors_origin = rest_api["allowed_cors_origin"]
                      allowed_cors_origin = rest_api["allowed_cors_origin"]
 
 
             except KeyError, e:
             except KeyError, e:
-                # print e
                 raise SettingNotFound("%s settings not found" % e)
                 raise SettingNotFound("%s settings not found" % e)
 
 
             # config ok, we can return the rest api object
             # config ok, we can return the rest api object

+ 1 - 1
kalliope/core/EventManager.py

@@ -46,4 +46,4 @@ class EventManager(object):
         # get a brain
         # get a brain
         brain_loader = BrainLoader()
         brain_loader = BrainLoader()
         brain = brain_loader.brain
         brain = brain_loader.brain
-        SynapseLauncher.start_synapse(synapse_name, brain=brain)
+        SynapseLauncher.start_synapse_by_name(synapse_name, brain=brain)

+ 193 - 0
kalliope/core/LIFOBuffer.py

@@ -0,0 +1,193 @@
+import logging
+
+from kalliope.core.NeuronLauncher import NeuronLauncher
+from kalliope.core.Models import Singleton
+from kalliope.core.Models.APIResponse import APIResponse
+
+logging.basicConfig()
+logger = logging.getLogger("kalliope")
+
+
+class Serialize(Exception):
+    """
+    When raised, the LIFO class return the current API response to the caller
+    """
+    pass
+
+
+class SynapseListAddedToLIFO(Exception):
+    """
+    When raised, a synapse list to process has been added to the LIFO list. 
+    The LIFO must start over and process the last synapse list added
+    """
+    pass
+
+
+class LIFOBuffer(object):
+    """
+    This class is a LIFO list of synapse to process where the last synapse list to enter will be the first synapse
+    list to be processed.
+    This design is needed in order to use Kalliope from the API. 
+    Because we want to return an information when a Neuron is still processing and waiting for an answer from the user
+    like with the Neurotransmitter neuron.
+    
+    """
+    __metaclass__ = Singleton
+
+    api_response = APIResponse()
+    lifo_list = list()
+    logger.debug("[LIFOBuffer] LIFO buffer created")
+    answer = None
+    is_api_call = False
+
+    @classmethod
+    def set_answer(cls, value):
+        cls.answer = value
+
+    @classmethod
+    def set_api_call(cls, value):
+        cls.is_api_call = value
+
+    @classmethod
+    def add_synapse_list_to_lifo(cls, matched_synapse_list):
+        """
+        Add a synapse list to process to the lifo
+        :param matched_synapse_list: List of Matched Synapse
+        :return: 
+        """
+        logger.debug("[LIFOBuffer] Add a new synapse list to process to the LIFO")
+        cls.lifo_list.append(matched_synapse_list)
+
+    @classmethod
+    def clean(cls):
+        """
+        Clean the LIFO by creating a new list
+        """
+        cls.lifo_list = list()
+        cls.api_response = APIResponse()
+
+    @classmethod
+    def _return_serialized_api_response(cls):
+        """
+        Serialize Exception has been raised by the execute process somewhere, return the serialized API response
+        to the caller. Clean up the APIResponse object for the next call
+        :return: 
+        """
+        # we prepare a json response
+        returned_api_response = cls.api_response.serialize()
+        # we clean up the API response object for the next call
+        cls.api_response = APIResponse()
+        return returned_api_response
+
+    @classmethod
+    def execute(cls, answer=None, is_api_call=False):
+        """
+        Process the LIFO list.
+        
+        The LIFO list contains multiple list of matched synapses.        
+        For each list of matched synapse we process synapses inside        
+        For each synapses we process neurons.        
+        If a neuron add a Synapse list to the lifo, this synapse list is processed before executing the first list 
+        in which we were in.
+        
+        :param answer: String answer to give the the last neuron which whas waiting for an answer
+        :param is_api_call: Boolean passed to all neuron in order to let them know if the current call comes from API
+        :return: serialized APIResponse object
+        """
+        # store the answer if present
+        cls.answer = answer
+        cls.is_api_call = is_api_call
+
+        try:
+            # we keep looping over the LIFO til we have synapse list to process in it
+            while cls.lifo_list:
+                logger.debug("[LIFOBuffer] number of synapse list to process: %s" % len(cls.lifo_list))
+                try:
+                    # get the last list of matched synapse in the LIFO
+                    last_synapse_fifo_list = cls.lifo_list[-1]
+                    cls._process_synapse_list(last_synapse_fifo_list)
+                except SynapseListAddedToLIFO:
+                    continue
+                # remove the synapse list from the LIFO
+                cls.lifo_list.remove(last_synapse_fifo_list)
+            raise Serialize
+
+        except Serialize:
+            return cls._return_serialized_api_response()
+
+    @classmethod
+    def _process_synapse_list(cls, synapse_list):
+        """
+        Process a list of matched synapse.
+        Execute each neuron list for each synapse.
+        Add info in the API response object after each processed synapse
+        Remove the synapse from the synapse_list when it has been fully executed
+        :param synapse_list: List of MatchedSynapse
+        """
+        # we keep processing til we have synapse in the FIFO to process
+        while synapse_list:
+            # get the first matched synapse in the list
+            matched_synapse = synapse_list[0]
+            # add the synapse to the API response so the user will get the status if the synapse was not already
+            # in the response
+            if matched_synapse not in cls.api_response.list_processed_matched_synapse:
+                cls.api_response.list_processed_matched_synapse.append(matched_synapse)
+
+            cls._process_neuron_list(matched_synapse=matched_synapse)
+
+            # The synapse has been processed we can remove it from the list.
+            synapse_list.remove(matched_synapse)
+
+    @classmethod
+    def _process_neuron_list(cls, matched_synapse):
+        """
+        Process the neuron list of the matched_synapse
+        Execute the Neuron
+        Executing a Neuron creates a NeuronModule object. This one can have 3 status:
+        - waiting for an answer: The neuron wait for an answer from the caller. The api response object is returned.
+                                 The neuron is not removed from the matched synapse to be executed again
+        - want to execute a synapse: The neuron add a list of synapse to execute to the lifo. 
+                                     The LIFO restart over to process it.The neuron is removed from the matched synapse
+        - complete: The neuron has been executed and its not waiting for an answer and doesn't want to start a synapse
+                    The neuron is removed from the matched synapse
+        :param matched_synapse: MatchedSynapse object to process
+        """
+
+        logger.debug("[LIFOBuffer] number of neuron to process: %s" % len(matched_synapse.neuron_fifo_list))
+        # while we have synapse to process in the list of synapse
+        while matched_synapse.neuron_fifo_list:
+            # get the first neuron in the FIFO neuron list
+            neuron = matched_synapse.neuron_fifo_list[0]
+            # from here, we are back into the last neuron we were processing.
+            if cls.answer is not None:  # we give the answer if exist to the first neuron
+                neuron.parameters["answer"] = cls.answer
+                # the next neuron should not get this answer
+                cls.answer = None
+            # todo fix this when we have a full client/server call. The client would be the voice or api call
+            neuron.parameters["is_api_call"] = cls.is_api_call
+            logger.debug("[LIFOBuffer] process_neuron_list: is_api_call: %s" % cls.is_api_call)
+            # execute the neuron
+            instantiated_neuron = NeuronLauncher.start_neuron(neuron=neuron,
+                                                              parameters_dict=matched_synapse.parameters)
+
+            # the status of an execution is "complete" if no neuron are waiting for an answer
+            cls.api_response.status = "complete"
+            if instantiated_neuron.is_waiting_for_answer:  # the neuron is waiting for an answer
+                logger.debug("[LIFOBuffer] Wait for answer mode")
+                cls.api_response.status = "waiting_for_answer"
+                raise Serialize
+            else:
+                logger.debug("[LIFOBuffer] complete mode")
+                # we add the instantiated neuron to the neuron_module_list.
+                # This one contains info about generated text
+                matched_synapse.neuron_module_list.append(instantiated_neuron)
+                # the neuron is fully processed we can remove it from the list
+                matched_synapse.neuron_fifo_list.remove(neuron)
+
+            if instantiated_neuron.pending_synapse:  # the last executed neuron want to run a synapse
+                logger.debug("[LIFOBuffer] Last executed neuron want to run a synapse. Restart the LIFO")
+                # add the synapse to the lifo (inside a list as expected by the lifo)
+                cls.add_synapse_list_to_lifo([instantiated_neuron.pending_synapse])
+                # we have added a list of synapse to the LIFO ! this one must start over.
+                # break all while loop until the execution is back to the LIFO loop
+                raise SynapseListAddedToLIFO

+ 4 - 1
kalliope/core/MainController.py

@@ -196,7 +196,10 @@ class MainController:
         Start the order analyser with the caught order to process
         Start the order analyser with the caught order to process
         """
         """
         logger.debug("order in analysing_order_thread %s" % self.order_to_process)
         logger.debug("order in analysing_order_thread %s" % self.order_to_process)
-        SynapseLauncher.run_matching_synapse_or_default(self.order_to_process, self.brain, self.settings)
+        SynapseLauncher.run_matching_synapse_from_order(self.order_to_process,
+                                                        self.brain,
+                                                        self.settings,
+                                                        is_api_call=False)
 
 
         # return to the state "unpausing_trigger"
         # return to the state "unpausing_trigger"
         self.unpause_trigger()
         self.unpause_trigger()

+ 23 - 0
kalliope/core/Models/APIResponse.py

@@ -0,0 +1,23 @@
+
+
+class APIResponse(object):
+
+    def __init__(self):
+        self.user_order = None
+        self.list_processed_matched_synapse = list()
+        self.status = None
+
+    def __str__(self):
+        return str(self.serialize())
+
+    def serialize(self):
+        """
+        This method allows to serialize in a proper way this object
+        :return: A dict of name and parameters
+        :rtype: Dict
+        """
+        return {
+            'user_order': self.user_order,
+            'matched_synapses': [e.serialize() for e in self.list_processed_matched_synapse],
+            'status': self.status
+        }

+ 1 - 5
kalliope/core/Models/Dna.py

@@ -25,11 +25,7 @@ class Dna(object):
         }
         }
 
 
     def __str__(self):
     def __str__(self):
-        return "Dna: name: %s, " \
-               "type: %s, " \
-               "author: %s, " \
-               "kalliope_supported_version: %s, " \
-               "tags: %s" % (self.name, self.module_type, self.author, self.kalliope_supported_version, self.tags)
+        return str(self.serialize())
 
 
     def __eq__(self, other):
     def __eq__(self, other):
         """
         """

+ 1 - 3
kalliope/core/Models/Event.py

@@ -17,9 +17,7 @@ class Event(object):
         self.second = second
         self.second = second
 
 
     def __str__(self):
     def __str__(self):
-        return "%s:  year: %s, month: %s, day: %s, week: %s, day_of_week: %s, hour: %s, minute: %s, second: %s" \
-               % (self.__class__.__name__, self.year, self.month, self.day, self.week,
-                  self.day_of_week, self.hour, self.minute, self.second)
+        return str(self.serialize())
 
 
     def serialize(self):
     def serialize(self):
         """
         """

+ 55 - 0
kalliope/core/Models/MatchedSynapse.py

@@ -0,0 +1,55 @@
+import copy
+
+from kalliope.core.NeuronParameterLoader import NeuronParameterLoader
+
+
+class MatchedSynapse(object):
+    """
+    This class represent a synapse that has matched an order send by an User.
+    """
+
+    def __init__(self, matched_synapse=None, matched_order=None, user_order=None):
+        """
+        :param matched_synapse: The synapse that has matched in the brain.
+        :param matched_order: The order from the synapse that have matched.
+        :param user_order: The order said by the user.
+        """
+
+        # create a copy of the synapse. the received synapse come from the brain.
+        self.synapse = matched_synapse
+        # create a fifo list that contains all neurons to process.
+        # Create a copy to be sure when we remove a neuron from this list it will not be removed from the synapse's
+        # neuron list
+        self.neuron_fifo_list = copy.deepcopy(self.synapse.neurons)
+        self.matched_order = matched_order
+        self.parameters = dict()
+        if matched_order is not None:
+            self.parameters = NeuronParameterLoader.get_parameters(synapse_order=self.matched_order,
+                                                                   user_order=user_order)
+
+        # list of Neuron Module
+        self.neuron_module_list = list()
+
+    def __str__(self):
+        return str(self.serialize())
+
+    def serialize(self):
+        """
+        This method allows to serialize in a proper way this object
+
+        :return: A dict of name and parameters
+        :rtype: Dict
+        """
+        return {
+            'synapse_name': self.synapse.name,
+            'matched_order': self.matched_order,
+            'neuron_module_list': [e.serialize() for e in self.neuron_module_list]
+        }
+
+    def __eq__(self, other):
+        """
+        This is used to compare 2 objects
+        :param other:
+        :return:
+        """
+        return self.__dict__ == other.__dict__

+ 8 - 4
kalliope/core/Models/Neuron.py

@@ -27,16 +27,20 @@ class Neuron(object):
         the output of this parameter will be masked in order to not appears in clean in the console
         the output of this parameter will be masked in order to not appears in clean in the console
         :return: string description of the neuron
         :return: string description of the neuron
         """
         """
-        returned_string = str()
-        returned_string += "Neuron: name: %s" % self.name
+        returned_dict = {
+            'name': self.name,
+            'parameters': self.parameters
+        }
+
         cleaned_parameters = dict()
         cleaned_parameters = dict()
         for key, value in self.parameters.iteritems():
         for key, value in self.parameters.iteritems():
             if "password" in key:
             if "password" in key:
                 cleaned_parameters[key] = "*****"
                 cleaned_parameters[key] = "*****"
             else:
             else:
                 cleaned_parameters[key] = value
                 cleaned_parameters[key] = value
-        returned_string += ", parameters: %s" % cleaned_parameters
-        return returned_string
+        returned_dict["parameters"] = cleaned_parameters
+
+        return str(returned_dict)
 
 
     def __eq__(self, other):
     def __eq__(self, other):
         """
         """

+ 1 - 1
kalliope/core/Models/Order.py

@@ -9,7 +9,7 @@ class Order(object):
         self.sentence = sentence
         self.sentence = sentence
 
 
     def __str__(self):
     def __str__(self):
-        return "%s: Sentence: %s" % (self.__class__.__name__, self.sentence)
+        return str(self.serialize())
 
 
     def serialize(self):
     def serialize(self):
         """
         """

+ 1 - 5
kalliope/core/Models/Resources.py

@@ -11,11 +11,7 @@ class Resources(object):
         self.trigger_folder = trigger_folder
         self.trigger_folder = trigger_folder
 
 
     def __str__(self):
     def __str__(self):
-        return "%s: neuron_folder: %s, stt_folder: %s, tts_folder: %s, trigger_folder: %s" % (self.__class__.__name__,
-                                                                                              self.neuron_folder,
-                                                                                              self.stt_folder,
-                                                                                              self.tts_folder,
-                                                                                              self.trigger_folder)
+        return str(self.serialize())
 
 
     def serialize(self):
     def serialize(self):
         """
         """

+ 24 - 9
kalliope/core/Models/RestAPI.py

@@ -3,7 +3,12 @@ class RestAPI(object):
     This Class is representing the rest API with all its configuration.
     This Class is representing the rest API with all its configuration.
     """
     """
 
 
-    def __init__(self, password_protected=None, login=None, password=None, active=None, port=None, allowed_cors_origin=None):
+    def __init__(self,
+                 password_protected=None,
+                 login=None, password=None,
+                 active=None,
+                 port=None,
+                 allowed_cors_origin=None):
         """
         """
         :param password_protected: If true, the rest api will ask for an authentication
         :param password_protected: If true, the rest api will ask for an authentication
         :param login: login used if auth is activated
         :param login: login used if auth is activated
@@ -19,14 +24,24 @@ class RestAPI(object):
         self.allowed_cors_origin = allowed_cors_origin
         self.allowed_cors_origin = allowed_cors_origin
 
 
     def __str__(self):
     def __str__(self):
-        return "%s: RestAPI: password_protected: %s, login: %s, " \
-              "password: %s, active: %s, port: %s, allow_cors_request: %s" % (self.__class__.__name__,
-                                                       self.password_protected,
-                                                       self.login,
-                                                       self.password,
-                                                       self.active,
-                                                       self.port,
-                                                       self.allowed_cors_origin)
+        return str(self.serialize())
+
+    def serialize(self):
+        """
+        This method allows to serialize in a proper way this object
+
+        :return: A dict of order
+        :rtype: Dict
+        """
+
+        return {
+            'password_protected': self.password_protected,
+            'login': self.login,
+            'password': self.password,
+            'active': self.active,
+            'port': self.port,
+            'allowed_cors_origin': self.allowed_cors_origin
+        }
 
 
     def __eq__(self, other):
     def __eq__(self, other):
         """
         """

+ 33 - 3
kalliope/core/Models/Settings.py

@@ -24,9 +24,7 @@ class Settings(object):
                  cache_path=None,
                  cache_path=None,
                  default_synapse=None,
                  default_synapse=None,
                  resources=None,
                  resources=None,
-                 variables= None, # dict()
-                 machine=None,
-                 kalliope_version=None):
+                 variables=None):
 
 
         self.default_tts_name = default_tts_name
         self.default_tts_name = default_tts_name
         self.default_stt_name = default_stt_name
         self.default_stt_name = default_stt_name
@@ -47,6 +45,38 @@ class Settings(object):
         self.machine = platform.machine()   # can be x86_64 or armv7l
         self.machine = platform.machine()   # can be x86_64 or armv7l
         self.kalliope_version = current_kalliope_version
         self.kalliope_version = current_kalliope_version
 
 
+    def serialize(self):
+        """
+        This method allows to serialize in a proper way this object
+
+        :return: A dict of order
+        :rtype: Dict
+        """
+
+        return {
+            'default_tts_name': self.default_tts_name,
+            'default_stt_name': self.default_stt_name,
+            'default_trigger_name': self.default_trigger_name,
+            'ttss': self.ttss,
+            'stts': self.stts,
+            'random_wake_up_answers': self.random_wake_up_answers,
+            'random_wake_up_sounds': self.random_wake_up_sounds,
+            'play_on_ready_notification': self.play_on_ready_notification,
+            'on_ready_answers': self.on_ready_answers,
+            'on_ready_sounds': self.on_ready_sounds,
+            'triggers': self.triggers,
+            'rest_api': self.rest_api.serialize(),
+            'cache_path': self.cache_path,
+            'default_synapse': self.default_synapse,
+            'resources': self.resources,
+            'variables': self.variables,
+            'machine': self.machine,
+            'kalliope_version': self.kalliope_version
+        }
+
+    def __str__(self):
+        return str(self.serialize())
+
     def __eq__(self, other):
     def __eq__(self, other):
         """
         """
         This is used to compare 2 objects
         This is used to compare 2 objects

+ 7 - 1
kalliope/core/Models/Stt.py

@@ -10,7 +10,13 @@ class Stt(object):
         self.parameters = parameters
         self.parameters = parameters
 
 
     def __str__(self):
     def __str__(self):
-        return "Stt name: %s, parameters: %s" % (str(self.name), str(self.parameters))
+        return str(self.serialize())
+
+    def serialize(self):
+        return {
+            'name': self.name,
+            'parameters': self.parameters
+        }
 
 
     def __eq__(self, other):
     def __eq__(self, other):
         """
         """

+ 1 - 8
kalliope/core/Models/Synapse.py

@@ -25,14 +25,7 @@ class Synapse(object):
         }
         }
 
 
     def __str__(self):
     def __str__(self):
-        return_val = "Synapse name: %s" % self.name
-        return_val += "\nneurons:"
-        for el in self.neurons:
-            return_val += str(el)
-        return_val += "\nsignals:"
-        for el in self.signals:
-            return_val += str(el)
-        return return_val
+        return str(self.serialize())
 
 
     def __eq__(self, other):
     def __eq__(self, other):
         """
         """

+ 7 - 1
kalliope/core/Models/Trigger.py

@@ -10,7 +10,13 @@ class Trigger(object):
         self.parameters = parameters
         self.parameters = parameters
 
 
     def __str__(self):
     def __str__(self):
-        return "Trigger name: %s, parameters: %s" % (str(self.name), str(self.parameters))
+        return str(self.serialize())
+
+    def serialize(self):
+        return {
+            'name': self.name,
+            'parameters': self.parameters
+        }
 
 
     def __eq__(self, other):
     def __eq__(self, other):
         """
         """

+ 7 - 1
kalliope/core/Models/Tts.py

@@ -10,7 +10,13 @@ class Tts(object):
         self.parameters = parameters
         self.parameters = parameters
 
 
     def __str__(self):
     def __str__(self):
-        return "Tts name: %s, parameters: %s" % (str(self.name), str(self.parameters))
+        return str(self.serialize())
+
+    def serialize(self):
+        return {
+            'name': self.name,
+            'parameters': self.parameters
+        }
 
 
     def __eq__(self, other):
     def __eq__(self, other):
         """
         """

+ 28 - 32
kalliope/core/NeuronLauncher.py

@@ -13,7 +13,7 @@ class NeuronLauncher:
         pass
         pass
 
 
     @classmethod
     @classmethod
-    def start_neuron(cls, neuron):
+    def launch_neuron(cls, neuron):
         """
         """
         Start a neuron plugin
         Start a neuron plugin
         :param neuron: neuron object
         :param neuron: neuron object
@@ -33,46 +33,42 @@ class NeuronLauncher:
                                                      resources_dir=neuron_folder)
                                                      resources_dir=neuron_folder)
 
 
     @classmethod
     @classmethod
-    def start_neuron_list(cls, neuron_list, parameters_dict=None):
+    def start_neuron(cls, neuron, parameters_dict=None):
         """
         """
         Execute each neuron from the received neuron_list.
         Execute each neuron from the received neuron_list.
         Replace parameter if exist in the received dict of parameters_dict
         Replace parameter if exist in the received dict of parameters_dict
-        :param neuron_list: list of Neuron object to run
+        :param neuron: Neuron object to run
         :param parameters_dict: dict of parameter to load in each neuron if expecting a parameter
         :param parameters_dict: dict of parameter to load in each neuron if expecting a parameter
         :return: List of the instantiated neurons (no errors detected)
         :return: List of the instantiated neurons (no errors detected)
         """
         """
-
-        instantiated_neuron = list()
-
-        for neuron in neuron_list:
-            problem_in_neuron_found = False
-            if isinstance(neuron.parameters, dict):
-                # print neuron.parameters
-                if "args" in neuron.parameters:
-                    logger.debug("The neuron waits for parameter")
-                    # check that the user added parameters to his order
-                    if parameters_dict is None:
-                        # we don't raise an error and break the program but we don't run the neuron
-                        problem_in_neuron_found = True
-                        Utils.print_danger("Error: The neuron %s is waiting for argument. "
-                                           "Argument found in bracket in the given order" % neuron.name)
-                    else:
-                        # we add wanted arguments the existing neuron parameter dict
-                        for arg in neuron.parameters["args"]:
-                            if arg in parameters_dict:
-                                logger.debug("Parameter %s added to the current parameter "
-                                             "of the neuron: %s" % (arg, neuron.name))
-                                neuron.parameters[arg] = parameters_dict[arg]
-                            else:
-                                # we don't raise an error and break the program but
-                                # we don't run the neuron
-                                problem_in_neuron_found = True
-                                Utils.print_danger("Error: Argument \"%s\" not found in the"
-                                                   " order" % arg)
+        instantiated_neuron = None
+        problem_in_neuron_found = False
+        if isinstance(neuron.parameters, dict):
+            if "args" in neuron.parameters:
+                logger.debug("The neuron waits for parameter")
+                # check that the user added parameters to his order
+                if parameters_dict is None:
+                    # we don't raise an error and break the program but we don't run the neuron
+                    problem_in_neuron_found = True
+                    Utils.print_danger("Error: The neuron %s is waiting for argument. "
+                                       "Argument found in bracket in the given order" % neuron.name)
+                else:
+                    # we add wanted arguments the existing neuron parameter dict
+                    for arg in neuron.parameters["args"]:
+                        if arg in parameters_dict:
+                            logger.debug("Parameter %s added to the current parameter "
+                                         "of the neuron: %s" % (arg, neuron.name))
+                            neuron.parameters[arg] = parameters_dict[arg]
+                        else:
+                            # we don't raise an error and break the program but
+                            # we don't run the neuron
+                            problem_in_neuron_found = True
+                            Utils.print_danger("Error: Argument \"%s\" not found in the"
+                                               " order" % arg)
 
 
             # if no error detected, we run the neuron
             # if no error detected, we run the neuron
             if not problem_in_neuron_found:
             if not problem_in_neuron_found:
-                instantiated_neuron.append(cls.start_neuron(neuron))
+                instantiated_neuron = cls.launch_neuron(neuron)
             else:
             else:
                 Utils.print_danger("A problem has been found in the Synapse.")
                 Utils.print_danger("A problem has been found in the Synapse.")
 
 

+ 40 - 36
kalliope/core/NeuronModule.py

@@ -8,6 +8,7 @@ from jinja2 import Template
 from kalliope.core import OrderListener
 from kalliope.core import OrderListener
 from kalliope.core.ConfigurationManager import SettingLoader, BrainLoader
 from kalliope.core.ConfigurationManager import SettingLoader, BrainLoader
 from kalliope.core.Models import Order
 from kalliope.core.Models import Order
+from kalliope.core.Models.MatchedSynapse import MatchedSynapse
 from kalliope.core.NeuronLauncher import NeuronLauncher
 from kalliope.core.NeuronLauncher import NeuronLauncher
 from kalliope.core.NeuronParameterLoader import NeuronParameterLoader
 from kalliope.core.NeuronParameterLoader import NeuronParameterLoader
 from kalliope.core.OrderAnalyser import OrderAnalyser
 from kalliope.core.OrderAnalyser import OrderAnalyser
@@ -89,6 +90,31 @@ class NeuronModule(object):
         self.say_template = kwargs.get('say_template', None)
         self.say_template = kwargs.get('say_template', None)
         # check if there is a template file associate to the output message
         # check if there is a template file associate to the output message
         self.file_template = kwargs.get('file_template', None)
         self.file_template = kwargs.get('file_template', None)
+        # keep the generated message
+        self.tts_message = None
+        # if the current call is api one
+        self.is_api_call = kwargs.get('is_api_call', False)
+        # boolean to know id the synapse is waiting for an answer
+        self.is_waiting_for_answer = False
+        # the synapse name to add the the buffer
+        self.pending_synapse = None
+
+    def __str__(self):
+        retuned_string = ""
+        retuned_string += self.tts_message
+        return retuned_string
+
+    def serialize(self):
+        """
+        This method allows to serialize in a proper way this object
+
+        :return: A dict of name and parameters
+        :rtype: Dict
+        """
+        return {
+            'neuron_name': self.neuron_name,
+            'generated_message': self.tts_message
+        }
 
 
     def say(self, message):
     def say(self, message):
         """
         """
@@ -119,6 +145,8 @@ class NeuronModule(object):
 
 
         if tts_message is not None:
         if tts_message is not None:
             logger.debug("tts_message to say: %s" % tts_message)
             logger.debug("tts_message to say: %s" % tts_message)
+            self.tts_message = tts_message
+            Utils.print_success(tts_message)
 
 
             # create a tts object from the tts the user want to use
             # create a tts object from the tts the user want to use
             tts_object = next((x for x in self.settings.ttss if x.name == self.tts), None)
             tts_object = next((x for x in self.settings.ttss if x.name == self.tts), None)
@@ -186,48 +214,24 @@ class NeuronModule(object):
 
 
         return returned_message
         return returned_message
 
 
-    def run_synapse_by_name(self, name):
-        SynapseLauncher.start_synapse(name=name, brain=self.brain)
+    def run_synapse_by_name(self, synapse_name, user_order=None, synapse_order=None):
+        """
+        call the lifo for adding a synapse to execute in the list of synapse list to process
+        :param synapse_name: The name of the synapse to run
+        :param user_order: The user order
+        :param synapse_order: The synapse order
+        """
+        synapse = BrainLoader().get_brain().get_synapse_by_name(synapse_name)
+        matched_synapse = MatchedSynapse(matched_synapse=synapse,
+                                         matched_order=synapse_order,
+                                         user_order=user_order)
+        self.pending_synapse = matched_synapse
 
 
     @staticmethod
     @staticmethod
     def is_order_matching(order_said, order_match):
     def is_order_matching(order_said, order_match):
         return OrderAnalyser().spelt_order_match_brain_order_via_table(order_to_analyse=order_match,
         return OrderAnalyser().spelt_order_match_brain_order_via_table(order_to_analyse=order_match,
                                                                        user_said=order_said)
                                                                        user_said=order_said)
 
 
-    def run_synapse_by_name_with_order(self, order, synapse_name, order_template):
-        """
-        Run a synapse using its name, and giving an order so it can retrieve its params.
-        Useful for neurotransmitters.
-        :param order: the order to match
-        :param synapse_name: the name of the synapse
-        :param order_template: order_template coming from the neurotransmitter
-        :return: True if a synapse as been found and started using its params
-        """
-        synapse_to_run = self.brain.get_synapse_by_name(synapse_name=synapse_name)
-        if synapse_to_run:
-            # Make a list with the synapse
-            logger.debug("[run_synapse_by_name_with_order]-> a synapse has been found  %s" % synapse_to_run.name)
-            list_to_run = list()
-            list_to_run.append(synapse_to_run)
-
-            # load parameters from the answer
-            parameters = None
-            for signal in synapse_to_run.signals:
-                if isinstance(signal, Order):
-                    parameters = NeuronParameterLoader.get_parameters(synapse_order=order_template,
-                                                                      user_order=order)
-                    if parameters is not None:
-                        logger.debug("[NeuronModule]-> parameter load from user answer: %s" % parameters)
-                        break
-
-            # start the neuron list
-            NeuronLauncher.start_neuron_list(neuron_list=synapse_to_run.neurons, parameters_dict=parameters)
-
-        else:
-            logger.debug("[NeuronModule]-> run_synapse_by_name_with_order, the synapse has not been found : %s"
-                         % synapse_name)
-        return synapse_to_run
-
     @staticmethod
     @staticmethod
     def _get_content_of_file(real_file_template_path):
     def _get_content_of_file(real_file_template_path):
         """
         """

+ 11 - 1
kalliope/core/OrderAnalyser.py

@@ -2,6 +2,7 @@
 import collections
 import collections
 from collections import Counter
 from collections import Counter
 
 
+from kalliope.core.Models.MatchedSynapse import MatchedSynapse
 from kalliope.core.Utils.Utils import Utils
 from kalliope.core.Utils.Utils import Utils
 from kalliope.core.ConfigurationManager import SettingLoader
 from kalliope.core.ConfigurationManager import SettingLoader
 from kalliope.core.Models import Order
 from kalliope.core.Models import Order
@@ -53,7 +54,16 @@ class OrderAnalyser:
                         logger.debug("Order found! Run synapse name: %s" % synapse.name)
                         logger.debug("Order found! Run synapse name: %s" % synapse.name)
                         Utils.print_success("Order matched in the brain. Running synapse \"%s\"" % synapse.name)
                         Utils.print_success("Order matched in the brain. Running synapse \"%s\"" % synapse.name)
                         list_match_synapse.append(synapse_order_tuple(synapse=synapse, order=signal.sentence))
                         list_match_synapse.append(synapse_order_tuple(synapse=synapse, order=signal.sentence))
-        return list_match_synapse
+
+        # create a list of MatchedSynapse from the tuple list
+        list_synapse_to_process = list()
+        for tuple_el in list_match_synapse:
+            new_matching_synapse = MatchedSynapse(matched_synapse=tuple_el.synapse,
+                                                  matched_order=tuple_el.order,
+                                                  user_order=order)
+            list_synapse_to_process.append(new_matching_synapse)
+
+        return list_synapse_to_process
 
 
     @classmethod
     @classmethod
     def spelt_order_match_brain_order_via_table(cls, order_to_analyse, user_said):
     def spelt_order_match_brain_order_via_table(cls, order_to_analyse, user_said):

+ 32 - 27
kalliope/core/RestAPI/FlaskAPI.py

@@ -4,9 +4,11 @@ import threading
 
 
 import time
 import time
 
 
+from kalliope.core.LIFOBuffer import LIFOBuffer
+from kalliope.core.Models.MatchedSynapse import MatchedSynapse
 from kalliope.core.Utils.FileManager import FileManager
 from kalliope.core.Utils.FileManager import FileManager
 
 
-from kalliope.core.ConfigurationManager import SettingLoader
+from kalliope.core.ConfigurationManager import SettingLoader, BrainLoader
 from kalliope.core.OrderListener import OrderListener
 from kalliope.core.OrderListener import OrderListener
 from werkzeug.utils import secure_filename
 from werkzeug.utils import secure_filename
 
 
@@ -45,8 +47,8 @@ class FlaskAPI(threading.Thread):
         sl = SettingLoader()
         sl = SettingLoader()
         self.settings = sl.settings
         self.settings = sl.settings
 
 
-        # list of launched synapse by the Order Analyser when using the /synapses/start/audio URL
-        self.launched_synapses = None
+        # api_response sent by the Order Analyser when using the /synapses/start/audio URL
+        self.api_response = None
         # boolean used to notify the main process that we get the list of returned synapse
         # boolean used to notify the main process that we get the list of returned synapse
         self.order_analyser_return = False
         self.order_analyser_return = False
 
 
@@ -136,18 +138,25 @@ class FlaskAPI(threading.Thread):
         :param synapse_name:
         :param synapse_name:
         :return:
         :return:
         """
         """
-        synapse_target = self._get_synapse_by_name(synapse_name)
+        # get a synapse object from the name
+        synapse_target = BrainLoader().get_brain().get_synapse_by_name(synapse_name=synapse_name)
 
 
         if synapse_target is None:
         if synapse_target is None:
             data = {
             data = {
                 "synapse name not found": "%s" % synapse_name
                 "synapse name not found": "%s" % synapse_name
             }
             }
             return jsonify(error=data), 404
             return jsonify(error=data), 404
-
-        # run the synapse
-        SynapseLauncher.start_synapse(synapse_name, brain=self.brain)
-        data = jsonify(synapses=synapse_target.serialize())
-        return data, 201
+        else:
+            # generate a MatchedSynapse from the synapse
+            matched_synapse = MatchedSynapse(matched_synapse=synapse_target)
+            # get the current LIFO buffer
+            lifo_buffer = LIFOBuffer()
+            # this is a new call we clean up the LIFO
+            lifo_buffer.clean()
+            lifo_buffer.add_synapse_list_to_lifo([matched_synapse])
+            response = lifo_buffer.execute(is_api_call=True)
+            data = jsonify(response)
+            return data, 201
 
 
     @requires_auth
     @requires_auth
     def run_synapse_by_order(self):
     def run_synapse_by_order(self):
@@ -169,20 +178,13 @@ class FlaskAPI(threading.Thread):
             # get the order
             # get the order
             order_to_run = order["order"]
             order_to_run = order["order"]
 
 
-            launched_synapses = SynapseLauncher.run_matching_synapse_or_default(order_to_run,
-                                                                                self.brain,
-                                                                                self.settings)
-
-            if launched_synapses:
-                # if the list is not empty, we have launched one or more synapses
-                data = jsonify(synapses=[e.serialize() for e in launched_synapses])
-                return data, 201
-            else:
-                data = {
-                    "error": "The given order doesn't match any synapses"
-                }
-                return jsonify(error=data), 400
+            api_response = SynapseLauncher.run_matching_synapse_from_order(order_to_run,
+                                                                           self.brain,
+                                                                           self.settings,
+                                                                           is_api_call=True)
 
 
+            data = jsonify(api_response)
+            return data, 201
         else:
         else:
             data = {
             data = {
                 "error": "order cannot be null"
                 "error": "order cannot be null"
@@ -226,9 +228,9 @@ class FlaskAPI(threading.Thread):
             while not self.order_analyser_return:
             while not self.order_analyser_return:
                 time.sleep(0.1)
                 time.sleep(0.1)
             self.order_analyser_return = False
             self.order_analyser_return = False
-            if self.launched_synapses is not None and self.launched_synapses:
-                data = jsonify(synapses=[e.serialize() for e in self.launched_synapses])
-                self.launched_synapses = None
+            if self.api_response is not None and self.api_response:
+                data = jsonify(self.api_response)
+                self.api_response = None
                 return data, 201
                 return data, 201
             else:
             else:
                 data = {
                 data = {
@@ -256,8 +258,11 @@ class FlaskAPI(threading.Thread):
         :return:
         :return:
         """
         """
         logger.debug("order to process %s" % order)
         logger.debug("order to process %s" % order)
-        list_launched_synapse = SynapseLauncher.run_matching_synapse_or_default(order, self.brain, self.settings)
-        self.launched_synapses = list_launched_synapse
+        api_response = SynapseLauncher.run_matching_synapse_from_order(order,
+                                                                       self.brain,
+                                                                       self.settings,
+                                                                       is_api_call=True)
+        self.api_response = api_response
 
 
         # this boolean will notify the main process that the order have been processed
         # this boolean will notify the main process that the order have been processed
         self.order_analyser_return = True
         self.order_analyser_return = True

+ 1 - 1
kalliope/core/ShellGui.py

@@ -193,5 +193,5 @@ class ShellGui:
             self.show_main_menu()
             self.show_main_menu()
         if code == self.d.OK:
         if code == self.d.OK:
             logger.debug("Run synapse from GUI: %s" % tag)
             logger.debug("Run synapse from GUI: %s" % tag)
-            SynapseLauncher.start_synapse(tag, brain=self.brain)
+            SynapseLauncher.start_synapse_by_name(tag, brain=self.brain)
             self.show_synapses_test_menu()
             self.show_synapses_test_menu()

+ 50 - 56
kalliope/core/SynapseLauncher.py

@@ -1,7 +1,9 @@
 import logging
 import logging
 
 
+from kalliope.core.ConfigurationManager import BrainLoader
+from kalliope.core.LIFOBuffer import LIFOBuffer
+from kalliope.core.Models.MatchedSynapse import MatchedSynapse
 from kalliope.core.NeuronLauncher import NeuronLauncher
 from kalliope.core.NeuronLauncher import NeuronLauncher
-from kalliope.core.NeuronParameterLoader import NeuronParameterLoader
 from kalliope.core.OrderAnalyser import OrderAnalyser
 from kalliope.core.OrderAnalyser import OrderAnalyser
 
 
 
 
@@ -20,75 +22,67 @@ class SynapseNameNotFound(Exception):
 
 
 class SynapseLauncher(object):
 class SynapseLauncher(object):
 
 
-    def __init__(self):
-        pass
-
     @classmethod
     @classmethod
-    def start_synapse(cls, name, brain=None):
+    def start_synapse_by_name(cls, name, brain=None):
         """
         """
         Start a synapse by it's name
         Start a synapse by it's name
         :param name: Name (Unique ID) of the synapse to launch
         :param name: Name (Unique ID) of the synapse to launch
         :param brain: Brain instance
         :param brain: Brain instance
         """
         """
-
+        logger.debug("[SynapseLauncher] start_synapse_by_name called with synapse name: %s " % name)
         # check if we have found and launched the synapse
         # check if we have found and launched the synapse
         synapse = brain.get_synapse_by_name(synapse_name=name)
         synapse = brain.get_synapse_by_name(synapse_name=name)
 
 
         if not synapse:
         if not synapse:
             raise SynapseNameNotFound("The synapse name \"%s\" does not exist in the brain file" % name)
             raise SynapseNameNotFound("The synapse name \"%s\" does not exist in the brain file" % name)
         else:
         else:
-            cls._run_synapse(synapse=synapse)
-            return synapse
+            # get our singleton LIFO
+            lifo_buffer = LIFOBuffer()
+            list_synapse_to_process = list()
+            new_matching_synapse = MatchedSynapse(matched_synapse=synapse,
+                                                  matched_order=None,
+                                                  user_order=None)
+            list_synapse_to_process.append(new_matching_synapse)
+            lifo_buffer.add_synapse_list_to_lifo(list_synapse_to_process)
+            return lifo_buffer.execute(is_api_call=True)
 
 
     @classmethod
     @classmethod
-    def _run_synapse(cls, synapse):
-        """
-        Start all neurons in the synapse
-        :param synapse: Synapse for which we run neurons
-        :return:
+    def run_matching_synapse_from_order(cls, order_to_process, brain, settings, is_api_call=False):
         """
         """
-        for neuron in synapse.neurons:
-            NeuronLauncher.start_neuron(neuron)
-        return True
-
-    @classmethod
-    def run_matching_synapse_or_default(cls, order_to_process, brain, settings):
+        
+        :param order_to_process: the spoken order sent by the user
+        :param brain: Brain object
+        :param settings: Settings object
+        :param is_api_call: if True, the current call come from the API. This info must be known by launched Neuron
+        :return: list of matched synapse
         """
         """
-        This method will run all synapse that match the given order "order_to_process"
-        :param order_to_process: The text order to process in the order analyser
-        :param brain: Brain instance
-        :param settings: Settings instance
-        :return: Return a list of launched synapse
-        """
-        no_synapse_match = False
-        # create a list of launched synapse to return
-        launched_synapses = list()
-        if order_to_process is not None:  # maybe we have received a null audio from STT engine
-            launched_synapses_tuple = OrderAnalyser.get_matching_synapse(order=order_to_process, brain=brain)
-
-            # oa contains the list Named tuple of synapse to run with the associated order that has matched
-            # for each synapse, get neurons, et for each neuron, get parameters
-            if not launched_synapses_tuple:
-                no_synapse_match = True
-            else:
-                # the order match one or more synapses
-                for tuple_el in launched_synapses_tuple:
-                    launched_synapses.append(tuple_el.synapse)
-                    logger.debug("[SynapseLauncher] Get parameter for %s " % tuple_el.synapse.name)
-                    parameters = NeuronParameterLoader.get_parameters(synapse_order=tuple_el.order,
-                                                                      user_order=order_to_process)
-                    # start the neuron list
-                    NeuronLauncher.start_neuron_list(neuron_list=tuple_el.synapse.neurons,
-                                                     parameters_dict=parameters)
-        else:
-            no_synapse_match = True
-
-        if no_synapse_match:  # then run the default synapse
-            if settings.default_synapse is not None:
-                logger.debug("[SynapseLauncher] No matching Synapse-> running default synapse ")
-                synapses = SynapseLauncher.start_synapse(name=settings.default_synapse,
-                                                         brain=brain)
-                launched_synapses.append(synapses)
 
 
-        # return the launched synapse list
-        return launched_synapses
+        # get our singleton LIFO
+        lifo_buffer = LIFOBuffer()
+
+        # if the LIFO is not empty, so, the current order is passed to the current processing synapse as an answer
+        if len(lifo_buffer.lifo_list) > 0:
+            # the LIFO is not empty, this is an answer to a previous call
+            return lifo_buffer.execute(answer=order_to_process, is_api_call=is_api_call)
+
+        else:  # the LIFO is empty, this is a new call
+            # get a list of matched synapse from the order
+            list_synapse_to_process = OrderAnalyser.get_matching_synapse(order=order_to_process, brain=brain)
+
+            if not list_synapse_to_process:  # the order analyser returned us an empty list
+                # add the default synapse if exist into the lifo
+                if settings.default_synapse:
+                    logger.debug("[SynapseLauncher] No matching Synapse-> running default synapse ")
+                    # get the default synapse
+                    default_synapse = brain.get_synapse_by_name(settings.default_synapse)
+                    new_matching_synapse = MatchedSynapse(matched_synapse=default_synapse,
+                                                          matched_order=None,
+                                                          user_order=order_to_process)
+                    list_synapse_to_process.append(new_matching_synapse)
+                else:
+                    logger.debug("[SynapseLauncher] No matching Synapse and no default synapse ")
+
+            lifo_buffer.add_synapse_list_to_lifo(list_synapse_to_process)
+            lifo_buffer.api_response.user_order = order_to_process
+
+            return lifo_buffer.execute(is_api_call=is_api_call)

+ 0 - 27
kalliope/core/TTS/TTSLauncher.py

@@ -1,27 +0,0 @@
-import logging
-
-from kalliope.core import Utils
-
-logging.basicConfig()
-logger = logging.getLogger("kalliope")
-
-
-class TTSLauncher(object):
-    def __init__(self):
-        pass
-
-    @classmethod
-    def get_tts(cls, tts):
-        """
-        Return an instance of a TTS module from the name of this module
-        :param tts: TTS model
-        :type tts: Tts
-        :return: TTS module instance
-
-        .. seealso::  TTS
-        .. warnings:: Class Method and Public
-        """
-        logger.debug("get TTS module \"%s\" with parameters %s" % (tts.name, tts.parameters))
-        return Utils.get_dynamic_class_instantiation(package_name="tts",
-                                                     module_name=tts.name,
-                                                     parameters=tts.parameters)

+ 1 - 0
kalliope/core/TTS/__init__.py

@@ -0,0 +1 @@
+from TTSModule import TTSModule

+ 2 - 1
kalliope/core/Utils/Utils.py

@@ -87,7 +87,8 @@ class Utils(object):
         :return:
         :return:
         """
         """
         import json
         import json
-        pipe_print(json.dumps(to_print, indent=2))
+        line = json.dumps(to_print, indent=2)
+        return line.encode('utf-8')
 
 
     ##################
     ##################
     #
     #

+ 3 - 3
kalliope/core/__init__.py

@@ -6,6 +6,6 @@ from kalliope.core.Utils import FileManager
 from kalliope.core.ResourcesManager import ResourcesManager
 from kalliope.core.ResourcesManager import ResourcesManager
 from kalliope.core.NeuronLauncher import NeuronLauncher
 from kalliope.core.NeuronLauncher import NeuronLauncher
 from kalliope.core.SynapseLauncher import SynapseLauncher
 from kalliope.core.SynapseLauncher import SynapseLauncher
-
-
-
+from kalliope.core.LIFOBuffer import LIFOBuffer
+from kalliope.core.NeuronParameterLoader import NeuronParameterLoader
+from kalliope.core.NeuronModule import NeuronModule

+ 14 - 5
kalliope/neurons/neurotransmitter/neurotransmitter.py

@@ -14,6 +14,8 @@ class Neurotransmitter(NeuronModule):
         self.from_answer_link = kwargs.get('from_answer_link', None)
         self.from_answer_link = kwargs.get('from_answer_link', None)
         self.default = kwargs.get('default', None)
         self.default = kwargs.get('default', None)
         self.direct_link = kwargs.get('direct_link', None)
         self.direct_link = kwargs.get('direct_link', None)
+        self.is_api_call = kwargs.get('is_api_call', False)
+        self.answer = kwargs.get('answer', None)
 
 
         # do some check
         # do some check
         if self._is_parameters_ok():
         if self._is_parameters_ok():
@@ -21,8 +23,14 @@ class Neurotransmitter(NeuronModule):
                 logger.debug("Neurotransmitter directly call to the synapse name: %s" % self.direct_link)
                 logger.debug("Neurotransmitter directly call to the synapse name: %s" % self.direct_link)
                 self.run_synapse_by_name(self.direct_link)
                 self.run_synapse_by_name(self.direct_link)
             else:
             else:
-                # the user is using a from_answer_link, we call the stt to get an audio
-                self.get_audio_from_stt(callback=self.callback)
+                if self.is_api_call:
+                    if self.answer is not None:
+                        self.callback(self.answer)
+                    else:
+                        self.is_waiting_for_answer = True
+                else:
+                    # the user is using a from_answer_link, we call the stt to get an audio
+                    self.get_audio_from_stt(callback=self.callback)
 
 
     def callback(self, audio):
     def callback(self, audio):
         """
         """
@@ -41,9 +49,10 @@ class Neurotransmitter(NeuronModule):
                 for answer in el["answers"]:
                 for answer in el["answers"]:
                     if self.is_order_matching(audio, answer):
                     if self.is_order_matching(audio, answer):
                         logger.debug("Neurotransmitter: match answer: %s" % answer)
                         logger.debug("Neurotransmitter: match answer: %s" % answer)
-                        found = self.run_synapse_by_name_with_order(order=audio,
-                                                                    synapse_name=el["synapse"],
-                                                                    order_template=answer)
+                        self.run_synapse_by_name(synapse_name=el["synapse"],
+                                                 user_order=audio,
+                                                 synapse_order=answer)
+                        found = True
                         break
                         break
             if not found:  # the answer do not correspond to any answer. We run the default synapse
             if not found:  # the answer do not correspond to any answer. We run the default synapse
                 self.run_synapse_by_name(self.default)
                 self.run_synapse_by_name(self.default)

+ 23 - 29
kalliope/neurons/neurotransmitter/tests/test_neurotransmitter.py

@@ -2,7 +2,7 @@ import unittest
 
 
 from mock import mock
 from mock import mock
 
 
-from kalliope.core.NeuronModule import NeuronModule, MissingParameterException, InvalidParameterException
+from kalliope.core.NeuronModule import MissingParameterException, InvalidParameterException
 from kalliope.neurons.neurotransmitter import Neurotransmitter
 from kalliope.neurons.neurotransmitter import Neurotransmitter
 
 
 
 
@@ -31,23 +31,23 @@ class TestNeurotransmitter(unittest.TestCase):
         """
         """
         Testing the Parameters checking
         Testing the Parameters checking
         """
         """
-        def run_test_InvalidParameterException(parameters_to_test):
+        def run_test_invalid_parameter_exception(parameters_to_test):
             with self.assertRaises(InvalidParameterException):
             with self.assertRaises(InvalidParameterException):
                 Neurotransmitter(**parameters_to_test)
                 Neurotransmitter(**parameters_to_test)
 
 
-        def run_test_MissingParameterException(parameters_to_test):
+        def run_test_missing_parameter_exception(parameters_to_test):
             with self.assertRaises(MissingParameterException):
             with self.assertRaises(MissingParameterException):
                 Neurotransmitter(**parameters_to_test)
                 Neurotransmitter(**parameters_to_test)
 
 
         # empty
         # empty
         parameters = dict()
         parameters = dict()
-        run_test_MissingParameterException(parameters)
+        run_test_missing_parameter_exception(parameters)
 
 
         # missing direct_link and from_answer_link
         # missing direct_link and from_answer_link
         parameters = {
         parameters = {
             "default": self.default
             "default": self.default
         }
         }
-        run_test_MissingParameterException(parameters)
+        run_test_missing_parameter_exception(parameters)
 
 
         # missing direct_link and from_answer_link
         # missing direct_link and from_answer_link
         parameters = {
         parameters = {
@@ -55,14 +55,14 @@ class TestNeurotransmitter(unittest.TestCase):
             "from_answer_link": self.from_answer_link,
             "from_answer_link": self.from_answer_link,
             "direct_link": self.direct_link
             "direct_link": self.direct_link
         }
         }
-        run_test_InvalidParameterException(parameters)
+        run_test_invalid_parameter_exception(parameters)
 
 
         # missing default
         # missing default
         parameters = {
         parameters = {
             "from_answer_link": self.from_answer_link,
             "from_answer_link": self.from_answer_link,
             "direct_link": self.direct_link
             "direct_link": self.direct_link
         }
         }
-        run_test_InvalidParameterException(parameters)
+        run_test_invalid_parameter_exception(parameters)
 
 
         # Missing answer in from_answer_link
         # Missing answer in from_answer_link
         self.from_answer_link = [
         self.from_answer_link = [
@@ -75,7 +75,7 @@ class TestNeurotransmitter(unittest.TestCase):
             "default": self.default,
             "default": self.default,
             "from_answer_link": self.from_answer_link
             "from_answer_link": self.from_answer_link
         }
         }
-        run_test_MissingParameterException(parameters)
+        run_test_missing_parameter_exception(parameters)
 
 
         # Missing synapse in from_answer_link
         # Missing synapse in from_answer_link
         self.from_answer_link = [
         self.from_answer_link = [
@@ -88,7 +88,7 @@ class TestNeurotransmitter(unittest.TestCase):
             "default": self.default,
             "default": self.default,
             "from_answer_link": self.from_answer_link
             "from_answer_link": self.from_answer_link
         }
         }
-        run_test_MissingParameterException(parameters)
+        run_test_missing_parameter_exception(parameters)
 
 
     def testCallback(self):
     def testCallback(self):
         """
         """
@@ -98,57 +98,51 @@ class TestNeurotransmitter(unittest.TestCase):
             "default": self.default,
             "default": self.default,
             "from_answer_link": self.from_answer_link
             "from_answer_link": self.from_answer_link
         }
         }
-        with mock.patch.object(NeuronModule, 'get_audio_from_stt', create=True) as mock_get_audio_from_stt:
-            with mock.patch.object(NeuronModule, 'run_synapse_by_name', create=True) as mock_run_synapse_by_name:
+        with mock.patch("kalliope.core.NeuronModule.get_audio_from_stt") as mock_get_audio_from_stt:
+            with mock.patch("kalliope.core.NeuronModule.run_synapse_by_name") as mock_run_synapse_by_name:
                 # testing running the default when no order matching
                 # testing running the default when no order matching
                 nt = Neurotransmitter(**parameters)
                 nt = Neurotransmitter(**parameters)
                 mock_get_audio_from_stt.assert_called_once()
                 mock_get_audio_from_stt.assert_called_once()
                 mock_get_audio_from_stt.reset_mock()
                 mock_get_audio_from_stt.reset_mock()
+
                 # testing running the default when audio None
                 # testing running the default when audio None
                 audio_text = None
                 audio_text = None
                 nt.callback(audio=audio_text)
                 nt.callback(audio=audio_text)
                 mock_run_synapse_by_name.assert_called_once_with(self.default)
                 mock_run_synapse_by_name.assert_called_once_with(self.default)
                 mock_run_synapse_by_name.reset_mock()
                 mock_run_synapse_by_name.reset_mock()
+
                 # testing running the default when no order matching
                 # testing running the default when no order matching
                 audio_text = "try test audio "
                 audio_text = "try test audio "
                 nt.callback(audio=audio_text)
                 nt.callback(audio=audio_text)
                 mock_run_synapse_by_name.assert_called_once_with(self.default)
                 mock_run_synapse_by_name.assert_called_once_with(self.default)
                 mock_run_synapse_by_name.reset_mock()
                 mock_run_synapse_by_name.reset_mock()
 
 
-                with mock.patch.object(NeuronModule,
-                                       'run_synapse_by_name_with_order',
-                                       create=True) as mock_run_synapse_by_name_with_order:
-
-                    audio_text="answer one"
-                    nt.callback(audio=audio_text)
-                    mock_run_synapse_by_name_with_order.assert_called_once_with(order=audio_text,
-                                                                                synapse_name="synapse2",
-                                                                                order_template="answer one")
+                # Testing calling the right synapse
+                audio_text = "answer one"
+                nt.callback(audio=audio_text)
+                mock_run_synapse_by_name.assert_called_once_with(synapse_name="synapse2",
+                                                                 user_order=audio_text,
+                                                                 synapse_order="answer one")
 
 
     def testInit(self):
     def testInit(self):
         """
         """
         Testing the init method of the neurontransmitter.
         Testing the init method of the neurontransmitter.
         """
         """
 
 
-        with mock.patch.object(NeuronModule, 'run_synapse_by_name', create=True) as mock_run_synapse_by_name:
+        with mock.patch("kalliope.core.NeuronModule.run_synapse_by_name") as mock_run_synapse_by_name:
             # Test direct link
             # Test direct link
             parameters = {
             parameters = {
                 "default": self.default,
                 "default": self.default,
                 "direct_link": self.direct_link
                 "direct_link": self.direct_link
             }
             }
-            nt = Neurotransmitter(**parameters)
+            Neurotransmitter(**parameters)
             mock_run_synapse_by_name.assert_called_once_with(self.direct_link)
             mock_run_synapse_by_name.assert_called_once_with(self.direct_link)
 
 
-        with mock.patch.object(NeuronModule, 'get_audio_from_stt', create=True) as mock_get_audio_from_stt:
+        with mock.patch("kalliope.core.NeuronModule.get_audio_from_stt") as mock_get_audio_from_stt:
             # Test get_audio_from_stt
             # Test get_audio_from_stt
             parameters = {
             parameters = {
                 "default": self.default,
                 "default": self.default,
                 "from_answer_link": self.from_answer_link,
                 "from_answer_link": self.from_answer_link,
             }
             }
-            nt = Neurotransmitter(**parameters)
+            Neurotransmitter(**parameters)
             mock_get_audio_from_stt.assert_called_once()
             mock_get_audio_from_stt.assert_called_once()
-
-
-
-
-