Utils.py 9.8 KB

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