Explorar o código

[Feature] #203 Global variables

monf %!s(int64=8) %!d(string=hai) anos
pai
achega
ce2bfcb0a7

+ 4 - 0
Tests/settings/settings_test.yml

@@ -110,3 +110,7 @@ resource_directory:
   stt: "/tmp/kalliope/tests/kalliope_resources_dir/stt"
   tts: "/tmp/kalliope/tests/kalliope_resources_dir/tts"
   trigger: "/tmp/kalliope/tests/kalliope_resources_dir/trigger"
+
+# ---------------------------
+# Variables TODO
+# ---------------------------

+ 3 - 0
Tests/test_settings_loader.py

@@ -189,6 +189,9 @@ class TestSettingLoader(unittest.TestCase):
         sl = SettingLoader(file_path=self.settings_file_to_test)
         self.assertEquals(expected_resource, sl._get_resources(self.settings_dict))
 
+    def test_get_variables(self):
+        # TODO
+        pass
 
 if __name__ == '__main__':
     unittest.main()

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

@@ -112,6 +112,7 @@ class SettingLoader(object):
         cache_path = self._get_cache_path(settings)
         default_synapse = self._get_default_synapse(settings)
         resources = self._get_resources(settings)
+        variables = self._get_variables(settings)
 
         # Load the setting singleton with the parameters
         setting_object.default_tts_name = default_tts_name
@@ -129,6 +130,7 @@ class SettingLoader(object):
         setting_object.cache_path = cache_path
         setting_object.default_synapse = default_synapse
         setting_object.resources = resources
+        setting_object.variables = variables
 
         return setting_object
 
@@ -641,5 +643,27 @@ class SettingLoader(object):
 
         return on_ready_sounds
 
+    @staticmethod
+    def _get_variables(settings):
+        """
+        Return the dict of variables from the settings.
+        :param settings: The YAML settings file
+        :return: dict
+        """
+
+        variables = dict()
+        try:
+            variables_files_name = settings["var_files"]
+            # In case files are declared in settings.yml, make sure kalliope can access them.
+            for files in variables_files_name:
+                var = Utils.get_real_file_path(files)
+                if var is None:
+                    raise SettingInvalidException("Variables file %s not found" % files)
+                else:
+                    variables.update(YAMLLoader.get_config(var))
+            return variables
+        except KeyError:
+            # User does not provide this settings
+            return dict()
 
 

+ 2 - 0
kalliope/core/Models/Settings.py

@@ -24,6 +24,7 @@ class Settings(object):
                  cache_path=None,
                  default_synapse=None,
                  resources=None,
+                 variables= None, # dict()
                  machine=None,
                  kalliope_version=None):
 
@@ -42,6 +43,7 @@ class Settings(object):
         self.cache_path = cache_path
         self.default_synapse = default_synapse
         self.resources = resources
+        self.variables = variables
         self.machine = platform.machine()   # can be x86_64 or armv7l
         self.kalliope_version = current_kalliope_version
 

+ 31 - 33
kalliope/core/OrderAnalyser.py

@@ -65,7 +65,8 @@ class OrderAnalyser:
 
             # Start a neuron list with params
             self._start_list_neurons(list_neurons=tuple.synapse.neurons,
-                                     params=params)
+                                     params=params,
+                                     settings=self.settings)
             synapses_launched.append(tuple.synapse)
 
         # return the list of launched synapse
@@ -139,17 +140,37 @@ class OrderAnalyser:
         :return: the dict key/value
         """
         params = dict()
-        if cls._is_containing_bracket(string_order):
+        if Utils.is_containing_bracket(string_order):
             params = cls._associate_order_params_to_values(order_to_check, string_order)
             logger.debug("Parameters for order: %s" % params)
         return params
 
     @classmethod
-    def _start_list_neurons(cls, list_neurons, params):
+    def _start_list_neurons(cls, list_neurons, params, settings):
         # start neurons
         for neuron in list_neurons:
+            cls._replace_global_variables(neuron, settings)
             cls._start_neuron(neuron, params)
 
+    @staticmethod
+    def _replace_global_variables(neuron, settings):
+        """
+        Replace all the parameters with variables with the variable value.
+        :param neuron: the neuron
+        :param settings: the settings
+        """
+        for param in neuron.parameters:
+            if Utils.is_containing_bracket(neuron.parameters[param]):
+                sentence_no_spaces = Utils.remove_spaces_in_brackets(sentence=neuron.parameters[param])
+                list_of_bracket_params = Utils.find_all_matching_brackets(sentence=sentence_no_spaces)
+                for param_with_bracket in list_of_bracket_params:
+                    param_no_brackets = param_with_bracket.replace("{{", "").replace("}}", "")
+                    if param_no_brackets in settings.variables:
+                        logger.debug("Replacing variable %s with  %s" % (param_with_bracket,
+                                                                         settings.variables[param_no_brackets]))
+                        neuron.parameters[param] = sentence_no_spaces.replace(param_with_bracket,
+                                                                                    str(settings.variables[param_no_brackets]))
+
     @staticmethod
     def _start_neuron(neuron, params):
         """
@@ -190,8 +211,8 @@ class OrderAnalyser:
         else:
             Utils.print_danger("A problem has been found in the Synapse.")
 
-    @classmethod
-    def _associate_order_params_to_values(cls, order, order_to_check):
+    @staticmethod
+    def _associate_order_params_to_values(order, order_to_check):
         """
         Associate the variables from the order to the incoming user order
         :param order_to_check: the order to check incoming from the brain
@@ -203,9 +224,7 @@ class OrderAnalyser:
         logger.debug("[OrderAnalyser._associate_order_params_to_values] user order: %s, "
                      "order to check: %s" % (order, order_to_check))
 
-        pattern = '\s+(?=[^\{\{\}\}]*\}\})'
-        # Remove white spaces (if any) between the variable and the double brace then split
-        list_word_in_order = re.sub(pattern, '', order_to_check).split()
+        list_word_in_order = Utils.remove_spaces_in_brackets(order_to_check).split()
 
         # get the order, defined by the first words before {{
         # /!\ Could be empty if order starts with double brace
@@ -218,10 +237,10 @@ class OrderAnalyser:
         # make dict var:value
         dict_var = dict()
         for idx, ow in enumerate(list_word_in_order):
-            if cls._is_containing_bracket(ow):
+            if Utils.is_containing_bracket(ow):
                 # remove bracket and grab the next value / stop value
                 var_name = ow.replace("{{", "").replace("}}", "")
-                stop_value = cls._get_next_value_list(list_word_in_order[idx:])
+                stop_value = Utils._get_next_value_list(list_word_in_order[idx:])
                 if stop_value is None:
                     dict_var[var_name] = " ".join(truncate_list_word_said)
                     break
@@ -236,26 +255,6 @@ class OrderAnalyser:
             truncate_list_word_said = truncate_list_word_said[1:]
         return dict_var
 
-    @staticmethod
-    def _is_containing_bracket(sentence):
-        """
-        Return True if the text in <sentence> contains brackets
-        :param sentence:
-        :return:
-        """
-        # print "sentence to test %s" % sentence
-        pattern = r"{{|}}"
-        # prog = re.compile(pattern)
-        check_bool = re.search(pattern, sentence)
-        if check_bool is not None:
-            return True
-        return False
-
-    @staticmethod
-    def _get_next_value_list(list_to_check):
-        ite = list_to_check.__iter__()
-        next(ite, None)
-        return next(ite, None)
 
     @classmethod
     def spelt_order_match_brain_order_via_table(cls, order_to_analyse, user_said):
@@ -305,9 +304,8 @@ class OrderAnalyser:
         :param order: sentence to split
         :return: list of string without bracket
         """
-        pattern = r"((?:{{\s*)[\w\.]+(?:\s*}}))"
-        # find everything like {{ word }}
-        matches = re.findall(pattern, order)
+
+        matches = Utils.find_all_matching_brackets(order)
         for match in matches:
             order = order.replace(match, "")
         # then split

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

@@ -2,8 +2,7 @@ import logging
 import os
 import inspect
 import imp
-
-import sys
+import re
 
 logging.basicConfig()
 logger = logging.getLogger("kalliope")
@@ -217,3 +216,58 @@ class Utils(object):
                 return valid[choice]
             else:
                 Utils.print_warning("Please respond with 'yes' or 'no' or 'y' or 'n').\n")
+
+    ##################
+    #
+    # Brackets management
+    #
+    #########
+    @staticmethod
+    def is_containing_bracket(sentence):
+        """
+        Return True if the text in <sentence> contains brackets
+        :param sentence:
+        :return:
+        """
+        # print "sentence to test %s" % sentence
+        pattern = r"{{|}}"
+        # prog = re.compile(pattern)
+        check_bool = re.search(pattern, sentence)
+        if check_bool is not None:
+            return True
+        return False
+
+    @staticmethod
+    def find_all_matching_brackets(sentence):
+        """
+        Find all the bracket matches from a given sentence
+        :param sentence: the sentence to check
+        :return: the list with all the matches
+        """
+
+        pattern = r"((?:{{\s*)[\w\.]+(?:\s*}}))"
+        # find everything like {{ word }}
+        return re.findall(pattern, sentence)
+
+    @staticmethod
+    def remove_spaces_in_brackets(sentence):
+        """
+        If has brackets it removes spaces in brackets
+        :param sentence: the sentence to work on
+        :return: the sentence without any spaces in brackets
+        """
+
+        pattern = '\s+(?=[^\{\{\}\}]*\}\})'
+        # Remove white spaces (if any) between the variable and the double brace then split
+        return re.sub(pattern, '', sentence)
+
+    ##################
+    #
+    # Lists management
+    #
+    #########
+    @staticmethod
+    def _get_next_value_list(list_to_check):
+        ite = list_to_check.__iter__()
+        next(ite, None)
+        return next(ite, None)

+ 1 - 1
kalliope/neurons/sleep/sleep.py

@@ -6,7 +6,7 @@ from kalliope.core.NeuronModule import NeuronModule,  MissingParameterException
 class Sleep(NeuronModule):
     def __init__(self, **kwargs):
         super(Sleep, self).__init__(**kwargs)
-        self.seconds = kwargs.get('seconds', None)
+        self.seconds = float(kwargs.get('seconds', None))
 
         # check parameters
         if self._is_parameters_ok():

+ 2 - 2
kalliope/neurons/sleep/tests/test_sleep.py

@@ -7,7 +7,7 @@ from kalliope.neurons.sleep.sleep import Sleep
 class TestSleep(unittest.TestCase):
 
     def setUp(self):
-        self.second="second"
+        self.seconds = 10
         self.random="random"
 
     def testParameters(self):
@@ -19,7 +19,7 @@ class TestSleep(unittest.TestCase):
         parameters = dict()
         run_test(parameters)
 
-        # missing second
+        # missing seconds
         parameters = {
             "random": self.random
         }

+ 10 - 1
kalliope/settings.yml

@@ -126,7 +126,7 @@ on_ready_sounds:
 # Rest API
 # ---------------------------
 rest_api:
-  active: False
+  active: True
   port: 5000
   password_protected: True
   login: admin
@@ -153,3 +153,12 @@ default_synapse: "default-synapse"
 #  stt: "resources/stt"
 #  tts: "resources/tts"
 #  trigger: "resources/trigger"
+
+
+# ---------------------------
+# Global files variables
+# /!\ If a variable is defined in different files, the last file defines the value.
+# ---------------------------
+var_files:
+  - variables.yml
+  - variables2.yml