Browse Source

Merge pull request #31 from kalliope-project/singleton_brain_settings

Singleton brain settings configchecker
Monf 8 years ago
parent
commit
4f54bc44d8

+ 32 - 25
core/ConfigurationManager/BrainLoader.py

@@ -34,31 +34,38 @@ class BrainLoader(object):
         :return: Brain object
         :return: Brain object
         :rtype: Brain
         :rtype: Brain
         """
         """
-        # get the brain with dict
-        dict_brain = cls.get_yaml_config(file_path)
-        # create a new brain
-        brain = Brain()
-        brain.brain_yaml = dict_brain
-        # create list of Synapse
-        synapses = list()
-        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 ConfigurationChecker().check_synape_dict(synapses_dict):
-                    # print "synapses_dict ok"
-                    name = synapses_dict["name"]
-                    neurons = cls._get_neurons(synapses_dict["neurons"])
-                    signals = cls._get_signals(synapses_dict["signals"])
-                    new_synapse = Synapse(name=name, neurons=neurons, signals=signals)
-                    synapses.append(new_synapse)
-        brain.synapses = synapses
-        if file_path is None:
-            brain.brain_file = cls._get_root_brain_path()
-        else:
-            brain.brain_file = file_path
-        # check that no synapse have the same name than another
-        if ConfigurationChecker().check_synapes(synapses):
-            return brain
-        return None
+
+        # Instantiate a brain
+        brain = Brain.Instance()
+        logger.debug("Is brain already loaded ? %r" % brain.is_loaded)
+        if brain.is_loaded is False:
+            # get the brain with dict
+            dict_brain = cls.get_yaml_config(file_path)
+
+            brain.brain_yaml = dict_brain
+            # create list of Synapse
+            synapses = list()
+            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 ConfigurationChecker().check_synape_dict(synapses_dict):
+                        # print "synapses_dict ok"
+                        name = synapses_dict["name"]
+                        neurons = cls._get_neurons(synapses_dict["neurons"])
+                        signals = cls._get_signals(synapses_dict["signals"])
+                        new_synapse = Synapse(name=name, neurons=neurons, signals=signals)
+                        synapses.append(new_synapse)
+            brain.synapses = synapses
+            if file_path is None:
+                brain.brain_file = cls._get_root_brain_path()
+            else:
+                brain.brain_file = file_path
+            # check that no synapse have the same name than another
+            if not ConfigurationChecker().check_synapes(synapses):
+                brain = None
+
+            # The Brain Singleton is loaded
+            brain.is_loaded = True
+        return brain
 
 
     @staticmethod
     @staticmethod
     def _get_neurons(neurons_dict):
     def _get_neurons(neurons_dict):

+ 22 - 1
core/ConfigurationManager/ConfigurationChecker.py

@@ -1,5 +1,7 @@
 import re
 import re
 
 
+from core.Utils import Utils, ModuleNotFoundError
+
 
 
 class InvalidSynapeName(Exception):
 class InvalidSynapeName(Exception):
     pass
     pass
@@ -67,7 +69,26 @@ class ConfigurationChecker:
 
 
     @staticmethod
     @staticmethod
     def check_neuron_dict(neuron_dict):
     def check_neuron_dict(neuron_dict):
-        # TODO check that the Neuron plugin exist
+        """
+        Check received neuron dict is valid:
+        - neuron exist
+        :param neuron_dict:
+        :return:
+        """
+        def check_neuron_exist(neuron_name):
+            package_name = "neurons"
+            mod = __import__(package_name, fromlist=[neuron_name])
+            try:
+                getattr(mod, neuron_name)
+            except AttributeError:
+                raise ModuleNotFoundError("The module %s does not exist in package %s" % (neuron_name, package_name))
+            return True
+
+        if isinstance(neuron_dict, dict):
+            for neuron_name in neuron_dict:
+                check_neuron_exist(neuron_name)
+        else:
+            check_neuron_exist(neuron_dict)
         return True
         return True
 
 
     @staticmethod
     @staticmethod

+ 35 - 24
core/ConfigurationManager/SettingLoader.py

@@ -1,7 +1,8 @@
-from YAMLLoader import YAMLLoader
 import logging
 import logging
 
 
+from YAMLLoader import YAMLLoader
 from core.FileManager import FileManager
 from core.FileManager import FileManager
+from core.Models import Singleton
 from core.Models.RestAPI import RestAPI
 from core.Models.RestAPI import RestAPI
 from core.Models.Settings import Settings
 from core.Models.Settings import Settings
 from core.Models.Stt import Stt
 from core.Models.Stt import Stt
@@ -43,29 +44,39 @@ class SettingLoader(object):
         Return a Settings object from settings.yml file
         Return a Settings object from settings.yml file
         :return:
         :return:
         """
         """
-        settings = cls.get_yaml_config(file_path)
-        default_stt_name = cls._get_default_speech_to_text(settings)
-        default_tts_name = cls._get_default_text_to_speech(settings)
-        default_trigger_name = cls._get_default_trigger(settings)
-        stts = cls._get_stts(settings)
-        ttss = cls._get_ttss(settings)
-        triggers = cls._get_triggers(settings)
-        random_wake_up_answers = cls._get_random_wake_up_answers(settings)
-        random_wake_up_sounds = cls._get_random_wake_up_sounds(settings)
-        rest_api = cls._get_rest_api(settings)
-        cache_path = cls._get_cache_path(settings)
-
-        # create a setting object
-        setting_object = Settings(default_stt_name=default_stt_name,
-                                  default_tts_name=default_tts_name,
-                                  default_trigger_name=default_trigger_name,
-                                  stts=stts,
-                                  ttss=ttss,
-                                  triggers=triggers,
-                                  random_wake_up_answers=random_wake_up_answers,
-                                  random_wake_up_sounds=random_wake_up_sounds,
-                                  rest_api=rest_api,
-                                  cache_path=cache_path)
+
+        # create a new setting
+        setting_object = Settings.Instance()
+        logger.debug("Is Settings already loaded ? %r" % setting_object.is_loaded)
+        if setting_object.is_loaded is False:
+
+            # Get the setting parameters
+            settings = cls.get_yaml_config(file_path)
+            default_stt_name = cls._get_default_speech_to_text(settings)
+            default_tts_name = cls._get_default_text_to_speech(settings)
+            default_trigger_name = cls._get_default_trigger(settings)
+            stts = cls._get_stts(settings)
+            ttss = cls._get_ttss(settings)
+            triggers = cls._get_triggers(settings)
+            random_wake_up_answers = cls._get_random_wake_up_answers(settings)
+            random_wake_up_sounds = cls._get_random_wake_up_sounds(settings)
+            rest_api = cls._get_rest_api(settings)
+            cache_path = cls._get_cache_path(settings)
+
+            # Load the setting singleton with the parameters
+            setting_object.default_tts_name=default_tts_name
+            setting_object.default_stt_name=default_stt_name
+            setting_object.default_trigger_name=default_trigger_name
+            setting_object.stts=stts
+            setting_object.ttss=ttss
+            setting_object.triggers=triggers
+            setting_object.random_wake_up_answers=random_wake_up_answers
+            setting_object.random_wake_up_sounds=random_wake_up_sounds
+            setting_object.rest_api=rest_api
+            setting_object.cache_path=cache_path
+            # The Settings Singleton is loaded
+            setting_object.is_loaded = True
+
         return setting_object
         return setting_object
 
 
     @staticmethod
     @staticmethod

+ 2 - 1
core/ConfigurationManager/__init__.py

@@ -1,2 +1,3 @@
 from YAMLLoader import YAMLLoader
 from YAMLLoader import YAMLLoader
-from .SettingLoader import SettingLoader
+from SettingLoader import SettingLoader
+from BrainLoader import BrainLoader

+ 6 - 1
core/Models/Brain.py

@@ -1,6 +1,11 @@
+from core.Models import Singleton
+
+
+@Singleton
+class Brain:
 
 
-class Brain(object):
     def __init__(self, synapses=None, brain_file=None, brain_yaml=None):
     def __init__(self, synapses=None, brain_file=None, brain_yaml=None):
         self.synapses = synapses
         self.synapses = synapses
         self.brain_file = brain_file
         self.brain_file = brain_file
         self.brain_yaml = brain_yaml
         self.brain_yaml = brain_yaml
+        self.is_loaded = False

+ 15 - 3
core/Models/Settings.py

@@ -1,9 +1,20 @@
+from core.Models import Singleton
 
 
 
 
+@Singleton
 class Settings(object):
 class Settings(object):
-    def __init__(self, default_tts_name=None, default_stt_name=None,
-                 default_trigger_name=None, ttss=None, stts=None,
-                 random_wake_up_answers=None, random_wake_up_sounds=None, triggers=None, rest_api=None, cache_path=None):
+    def __init__(self,
+                 default_tts_name=None,
+                 default_stt_name=None,
+                 default_trigger_name=None,
+                 ttss=None,
+                 stts=None,
+                 random_wake_up_answers=None,
+                 random_wake_up_sounds=None,
+                 triggers=None,
+                 rest_api=None,
+                 cache_path=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
         self.default_trigger_name = default_trigger_name
         self.default_trigger_name = default_trigger_name
@@ -14,3 +25,4 @@ class Settings(object):
         self.triggers = triggers
         self.triggers = triggers
         self.rest_api = rest_api
         self.rest_api = rest_api
         self.cache_path = cache_path
         self.cache_path = cache_path
+        self.is_loaded = False

+ 38 - 0
core/Models/Singleton.py

@@ -0,0 +1,38 @@
+class Singleton:
+    """
+    A non-thread-safe helper class to ease implementing singletons.
+    This should be used as a decorator -- not a metaclass -- to the
+    class that should be a singleton.
+
+    The decorated class can define one `__init__` function that
+    takes only the `self` argument. Other than that, there are
+    no restrictions that apply to the decorated class.
+
+    To get the singleton instance, use the `Instance` method. Trying
+    to use `__call__` will result in a `TypeError` being raised.
+
+    Limitations: The decorated class cannot be inherited from.
+
+    """
+
+    def __init__(self, decorated):
+        self._decorated = decorated
+
+    def Instance(self):
+        """
+        Returns the singleton instance. Upon its first call, it creates a
+        new instance of the decorated class and calls its `__init__` method.
+        On all subsequent calls, the already created instance is returned.
+
+        """
+        try:
+            return self._instance
+        except AttributeError:
+            self._instance = self._decorated()
+            return self._instance
+
+    def __call__(self):
+        raise TypeError('Singletons must be accessed through `Instance()`.')
+
+    def __instancecheck__(self, inst):
+        return isinstance(inst, self._decorated)

+ 3 - 1
core/Models/__init__.py

@@ -1,5 +1,7 @@
+from Singleton import Singleton
 from Event import Event
 from Event import Event
 from Brain import Brain
 from Brain import Brain
 from Order import Order
 from Order import Order
 from Synapse import Synapse
 from Synapse import Synapse
-from Neuron import Neuron
+from Neuron import Neuron
+

+ 6 - 5
core/NeuronModule.py

@@ -9,7 +9,7 @@ from jinja2 import Template
 from core import OrderListener
 from core import OrderListener
 from core.SynapseLauncher import SynapseLauncher
 from core.SynapseLauncher import SynapseLauncher
 from core.Utils import Utils
 from core.Utils import Utils
-from core.ConfigurationManager import SettingLoader
+from core.ConfigurationManager import SettingLoader, BrainLoader
 
 
 logging.basicConfig()
 logging.basicConfig()
 logger = logging.getLogger("kalliope")
 logger = logging.getLogger("kalliope")
@@ -55,6 +55,7 @@ class NeuronModule(object):
         logger.debug("NeuronModule called from class %s with parameters: %s" % (child_name, str(kwargs)))
         logger.debug("NeuronModule called from class %s with parameters: %s" % (child_name, str(kwargs)))
 
 
         self.settings = SettingLoader.get_settings()
         self.settings = SettingLoader.get_settings()
+        self.brain = BrainLoader.get_brain()
 
 
         # check if the user has overrider the TTS
         # check if the user has overrider the TTS
         tts = kwargs.get('tts', None)
         tts = kwargs.get('tts', None)
@@ -156,6 +157,9 @@ class NeuronModule(object):
         # else:
         # else:
         #     raise NoTemplateException("You must specify a say_template or a file_template")
         #     raise NoTemplateException("You must specify a say_template or a file_template")
 
 
+    def run_synapse_ny_name(self, name):
+        SynapseLauncher.start_synapse(name=name, brain=self.brain)
+
     @staticmethod
     @staticmethod
     def _get_content_of_file(real_file_template_path):
     def _get_content_of_file(real_file_template_path):
         with open(real_file_template_path, 'r') as content_file:
         with open(real_file_template_path, 'r') as content_file:
@@ -179,7 +183,4 @@ class NeuronModule(object):
         oa = OrderListener(callback=callback)
         oa = OrderListener(callback=callback)
         oa.start()
         oa.start()
 
 
-    @staticmethod
-    def run_synapse_ny_name(name):
-        # TODO find a way to get the current brain file. NeuronModule doesn't have any ref about it
-        SynapseLauncher.start_synapse(name=name)
+

+ 1 - 0
core/__init__.py

@@ -3,3 +3,4 @@ from core.OrderListener import OrderListener
 from core.ShellGui import ShellGui
 from core.ShellGui import ShellGui
 from core.FileManager import FileManager
 from core.FileManager import FileManager
 from core.Utils import Utils
 from core.Utils import Utils
+

+ 1 - 2
install/files/python_requirements.txt

@@ -1,7 +1,6 @@
 SpeechRecognition==3.4.6
 SpeechRecognition==3.4.6
 pyaudio==0.2.9
 pyaudio==0.2.9
 ansible==2.1.1.0
 ansible==2.1.1.0
-pygame
 python2-pythondialog==3.4.0
 python2-pythondialog==3.4.0
 jinja==1.2
 jinja==1.2
 python-crontab==2.1.1
 python-crontab==2.1.1
@@ -14,4 +13,4 @@ pyowm==2.5.0
 python-twitter==3.1
 python-twitter==3.1
 flask==0.11.1
 flask==0.11.1
 Flask-Restful==0.3.5
 Flask-Restful==0.3.5
-wikipedia==1.4.0
+wikipedia==1.4.0

+ 16 - 15
test.py

@@ -1,14 +1,8 @@
 # coding: utf8
 # coding: utf8
 import logging
 import logging
 
 
-from flask import Flask
-
-from core import OrderAnalyser
-from core import Utils
-from core.ConfigurationManager import SettingLoader
 from core.ConfigurationManager.BrainLoader import BrainLoader
 from core.ConfigurationManager.BrainLoader import BrainLoader
-from core.Players import Mplayer
-from core.RestAPI.FlaskAPI import FlaskAPI
+from core.ConfigurationManager.SettingLoader import SettingLoader
 
 
 logging.basicConfig()
 logging.basicConfig()
 logger = logging.getLogger("kalliope")
 logger = logging.getLogger("kalliope")
@@ -16,17 +10,24 @@ logger.setLevel(logging.DEBUG)
 
 
 
 
 brain = BrainLoader.get_brain()
 brain = BrainLoader.get_brain()
-#
-# order = "bonjour"
-# oa = OrderAnalyser(order=order, brain=brain)
-# oa.start()
-
 
 
+brain2 = BrainLoader.get_brain()
+brain3 = BrainLoader.get_brain()
+brain4 = BrainLoader.get_brain()
 
 
-app = Flask(__name__)
-flask_api = FlaskAPI(app, port=5000, brain=brain)
-flask_api.start()
 
 
+print brain is brain2
+print brain is brain3
+print brain is brain4
+print brain4 is brain2
 
 
+set = SettingLoader.get_settings()
+set2 = SettingLoader.get_settings()
+set3 = SettingLoader.get_settings()
+set4 = SettingLoader.get_settings()
 
 
+print set is set2
+print set is set3
+print set is set4
+print set3 is set2