Utils.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. import logging
  2. import os
  3. import inspect
  4. import imp
  5. import re
  6. logging.basicConfig()
  7. logger = logging.getLogger("kalliope")
  8. def pipe_print(line):
  9. print(line.encode('utf-8'))
  10. class ModuleNotFoundError(Exception):
  11. """
  12. The module can not been found
  13. .. notes: Check the case: must be in lower case.
  14. """
  15. pass
  16. class Utils(object):
  17. color_list = dict(
  18. PURPLE='\033[95m',
  19. BLUE='\033[94m',
  20. GREEN='\033[92m',
  21. YELLOW='\033[93m',
  22. RED='\033[91m',
  23. ENDLINE='\033[0m',
  24. BOLD='\033[1m',
  25. UNDERLINE='\033[4m'
  26. )
  27. ##################
  28. #
  29. # Shell properly displayed
  30. #
  31. #########
  32. @classmethod
  33. def print_info(cls, text_to_print):
  34. pipe_print(cls.color_list["BLUE"] + text_to_print + cls.color_list["ENDLINE"])
  35. @classmethod
  36. def print_success(cls, text_to_print):
  37. pipe_print(cls.color_list["GREEN"] + text_to_print + cls.color_list["ENDLINE"])
  38. @classmethod
  39. def print_warning(cls, text_to_print):
  40. pipe_print(cls.color_list["YELLOW"] + text_to_print + cls.color_list["ENDLINE"])
  41. @classmethod
  42. def print_danger(cls, text_to_print):
  43. pipe_print(cls.color_list["RED"] + text_to_print + cls.color_list["ENDLINE"])
  44. @classmethod
  45. def print_header(cls, text_to_print):
  46. pipe_print(cls.color_list["HEADER"] + text_to_print + cls.color_list["ENDLINE"])
  47. @classmethod
  48. def print_header(cls, text_to_print):
  49. pipe_print(cls.color_list["PURPLE"] + text_to_print + cls.color_list["ENDLINE"])
  50. @classmethod
  51. def print_bold(cls, text_to_print):
  52. pipe_print(cls.color_list["BOLD"] + text_to_print + cls.color_list["ENDLINE"])
  53. @classmethod
  54. def print_underline(cls, text_to_print):
  55. pipe_print(cls.color_list["UNDERLINE"] + text_to_print + cls.color_list["ENDLINE"])
  56. @staticmethod
  57. def print_yaml_nicely(to_print):
  58. """
  59. Used for debug
  60. :param to_print: Dict to print nicely
  61. :return:
  62. """
  63. import json
  64. pipe_print(json.dumps(to_print, indent=2))
  65. ##################
  66. #
  67. # Dynamic loading
  68. #
  69. #########
  70. @classmethod
  71. def get_dynamic_class_instantiation(cls, package_name, module_name, parameters=None, resources_dir=None):
  72. """
  73. Load a python class dynamically
  74. from my_package.my_module import my_class
  75. mod = __import__('my_package.my_module', fromlist=['my_class'])
  76. klass = getattr(mod, 'my_class')
  77. :param package_name: name of the package where we will find the module to load (neurons, tts, stt, trigger)
  78. :param module_name: name of the module from the package_name to load. This one is capitalized. Eg: Snowboy
  79. :param parameters: dict parameters to send as argument to the module
  80. :param resources_dir: the resource directory to check for external resources
  81. :return:
  82. """
  83. logger.debug("Run plugin %s with parameter %s" % (module_name, parameters))
  84. package_path = "kalliope." + package_name + "." + module_name.lower() + "." + module_name.lower()
  85. if resources_dir is not None:
  86. neuron_resource_path = resources_dir + os.sep + module_name.lower() \
  87. + os.sep + module_name.lower() + ".py"
  88. if os.path.exists(neuron_resource_path):
  89. imp.load_source(module_name.capitalize(), neuron_resource_path)
  90. package_path = module_name.capitalize()
  91. logger.debug("[Utils]-> get_dynamic_class_instantiation : loading path : %s, as package %s" % (
  92. neuron_resource_path, package_path))
  93. mod = __import__(package_path, fromlist=[module_name.capitalize()])
  94. try:
  95. klass = getattr(mod, module_name.capitalize())
  96. except AttributeError:
  97. logger.debug("Error: No module named %s " % module_name.capitalize())
  98. raise ModuleNotFoundError("The module %s does not exist in package %s" % (module_name.capitalize(), package_name))
  99. if klass is not None:
  100. # run the plugin
  101. if not parameters:
  102. return klass()
  103. elif isinstance(parameters, dict):
  104. return klass(**parameters)
  105. else:
  106. return klass(parameters)
  107. return None
  108. ##################
  109. #
  110. # Paths management
  111. #
  112. #########
  113. @staticmethod
  114. def get_current_file_parent_parent_path(current_script_path):
  115. parent_parent_path = os.path.normpath(current_script_path + os.sep + os.pardir + os.sep + os.pardir)
  116. return parent_parent_path
  117. @staticmethod
  118. def get_current_file_parent_path(current_script_path):
  119. parent_path = os.path.normpath(current_script_path + os.sep + os.pardir)
  120. return parent_path
  121. @classmethod
  122. def get_real_file_path(cls, file_path_to_test):
  123. """
  124. Try to return a full path from a given <file_path_to_test>
  125. If the path is an absolute on, we return it directly.
  126. If the path is relative, we try to get the full path in this order:
  127. - from the current directory where kalliope has been called + the file_path_to_test.
  128. Eg: /home/me/Documents/kalliope_config
  129. - from /etc/kalliope + file_path_to_test
  130. - from the default file passed as <file_name> at the root of the project
  131. :param file_path_to_test file path to test
  132. :type file_path_to_test: str
  133. :return: absolute path to the file file_path_to_test or None if is doen't exist
  134. """
  135. if not os.path.isabs(file_path_to_test):
  136. current_script_path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
  137. path_order = {
  138. 1: os.getcwd() + os.sep + file_path_to_test,
  139. 2: "/etc/kalliope" + os.sep + file_path_to_test,
  140. # In this case 'get_current_file_parent_parent_path' is corresponding to kalliope root path
  141. # from /an/unknown/path/kalliope/kalliope/core/Utils to /an/unknown/path/kalliope/kalliope
  142. 3: cls.get_current_file_parent_parent_path(current_script_path) + os.sep + file_path_to_test
  143. }
  144. for key in sorted(path_order):
  145. new_file_path_to_test = path_order[key]
  146. logger.debug("Try to load file from %s: %s" % (key, new_file_path_to_test))
  147. if os.path.isfile(new_file_path_to_test):
  148. logger.debug("File found in %s" % new_file_path_to_test)
  149. return new_file_path_to_test
  150. else:
  151. if os.path.isfile(file_path_to_test):
  152. return file_path_to_test
  153. else:
  154. return None
  155. @staticmethod
  156. def query_yes_no(question, default="yes"):
  157. """Ask a yes/no question via raw_input() and return their answer.
  158. "question" is a string that is presented to the user.
  159. "default" is the presumed answer if the user just hits <Enter>.
  160. It must be "yes" (the default), "no" or None (meaning
  161. an answer is required of the user).
  162. The "answer" return value is True for "yes" or False for "no".
  163. """
  164. valid = {"yes": True, "y": True, "ye": True,
  165. "no": False, "n": False}
  166. if default is None:
  167. prompt = " [y/n] "
  168. elif default == "yes":
  169. prompt = " [Y/n] "
  170. elif default == "no":
  171. prompt = " [y/N] "
  172. else:
  173. raise ValueError("invalid default answer: '%s'" % default)
  174. while True:
  175. Utils.print_warning(question + prompt)
  176. choice = raw_input().lower()
  177. if default is not None and choice == '':
  178. return valid[default]
  179. elif choice in valid:
  180. return valid[choice]
  181. else:
  182. Utils.print_warning("Please respond with 'yes' or 'no' or 'y' or 'n').\n")
  183. ##################
  184. #
  185. # Brackets management
  186. #
  187. #########
  188. @staticmethod
  189. def is_containing_bracket(sentence):
  190. """
  191. Return True if the text in <sentence> contains brackets
  192. :param sentence:
  193. :return:
  194. """
  195. # print "sentence to test %s" % sentence
  196. pattern = r"{{|}}"
  197. # prog = re.compile(pattern)
  198. check_bool = re.search(pattern, str(sentence))
  199. if check_bool is not None:
  200. return True
  201. return False
  202. @staticmethod
  203. def find_all_matching_brackets(sentence):
  204. """
  205. Find all the bracket matches from a given sentence
  206. :param sentence: the sentence to check
  207. :return: the list with all the matches
  208. """
  209. pattern = r"((?:{{\s*)[\w\.]+(?:\s*}}))"
  210. # find everything like {{ word }}
  211. return re.findall(pattern, str(sentence))
  212. @staticmethod
  213. def remove_spaces_in_brackets(sentence):
  214. """
  215. If has brackets it removes spaces in brackets
  216. :param sentence: the sentence to work on
  217. :return: the sentence without any spaces in brackets
  218. """
  219. pattern = '\s+(?=[^\{\{\}\}]*\}\})'
  220. # Remove white spaces (if any) between the variable and the double brace then split
  221. return re.sub(pattern, '', str(sentence))
  222. ##################
  223. #
  224. # Lists management
  225. #
  226. #########
  227. @staticmethod
  228. def get_next_value_list(list_to_check):
  229. ite = list_to_check.__iter__()
  230. next(ite, None)
  231. return next(ite, None)