Utils.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. package_path = "kalliope." + package_name + "." + module_name.lower() + "." + module_name.lower()
  84. if resources_dir is not None:
  85. neuron_resource_path = resources_dir + os.sep + module_name.lower() \
  86. + os.sep + module_name.lower() + ".py"
  87. if os.path.exists(neuron_resource_path):
  88. imp.load_source(module_name.capitalize(), neuron_resource_path)
  89. package_path = module_name.capitalize()
  90. logger.debug("[Utils]-> get_dynamic_class_instantiation : loading path : %s, as package %s" % (
  91. neuron_resource_path, package_path))
  92. mod = __import__(package_path, fromlist=[module_name.capitalize()])
  93. try:
  94. klass = getattr(mod, module_name.capitalize())
  95. except AttributeError:
  96. logger.debug("Error: No module named %s " % module_name.capitalize())
  97. raise ModuleNotFoundError("The module %s does not exist in package %s" % (module_name.capitalize(), package_name))
  98. if klass is not None:
  99. # run the plugin
  100. if not parameters:
  101. return klass()
  102. elif isinstance(parameters, dict):
  103. return klass(**parameters)
  104. else:
  105. return klass(parameters)
  106. return None
  107. ##################
  108. #
  109. # Paths management
  110. #
  111. #########
  112. @staticmethod
  113. def get_current_file_parent_parent_path(current_script_path):
  114. parent_parent_path = os.path.normpath(current_script_path + os.sep + os.pardir + os.sep + os.pardir)
  115. return parent_parent_path
  116. @staticmethod
  117. def get_current_file_parent_path(current_script_path):
  118. parent_path = os.path.normpath(current_script_path + os.sep + os.pardir)
  119. return parent_path
  120. @classmethod
  121. def get_real_file_path(cls, file_path_to_test):
  122. """
  123. Try to return a full path from a given <file_path_to_test>
  124. If the path is an absolute on, we return it directly.
  125. If the path is relative, we try to get the full path in this order:
  126. - from the current directory where kalliope has been called + the file_path_to_test.
  127. Eg: /home/me/Documents/kalliope_config
  128. - from /etc/kalliope + file_path_to_test
  129. - from the default file passed as <file_name> at the root of the project
  130. :param file_path_to_test file path to test
  131. :type file_path_to_test: str
  132. :return: absolute path to the file file_path_to_test or None if is doen't exist
  133. """
  134. if not os.path.isabs(file_path_to_test):
  135. current_script_path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
  136. path_order = {
  137. 1: os.getcwd() + os.sep + file_path_to_test,
  138. 2: "/etc/kalliope" + os.sep + file_path_to_test,
  139. # In this case 'get_current_file_parent_parent_path' is corresponding to kalliope root path
  140. # from /an/unknown/path/kalliope/kalliope/core/Utils to /an/unknown/path/kalliope/kalliope
  141. 3: cls.get_current_file_parent_parent_path(current_script_path) + os.sep + file_path_to_test
  142. }
  143. for key in sorted(path_order):
  144. new_file_path_to_test = path_order[key]
  145. logger.debug("Try to load file from %s: %s" % (key, new_file_path_to_test))
  146. if os.path.isfile(new_file_path_to_test):
  147. logger.debug("File found in %s" % new_file_path_to_test)
  148. return new_file_path_to_test
  149. else:
  150. if os.path.isfile(file_path_to_test):
  151. return file_path_to_test
  152. else:
  153. return None
  154. @staticmethod
  155. def query_yes_no(question, default="yes"):
  156. """Ask a yes/no question via raw_input() and return their answer.
  157. "question" is a string that is presented to the user.
  158. "default" is the presumed answer if the user just hits <Enter>.
  159. It must be "yes" (the default), "no" or None (meaning
  160. an answer is required of the user).
  161. The "answer" return value is True for "yes" or False for "no".
  162. """
  163. valid = {"yes": True, "y": True, "ye": True,
  164. "no": False, "n": False}
  165. if default is None:
  166. prompt = " [y/n] "
  167. elif default == "yes":
  168. prompt = " [Y/n] "
  169. elif default == "no":
  170. prompt = " [y/N] "
  171. else:
  172. raise ValueError("invalid default answer: '%s'" % default)
  173. while True:
  174. Utils.print_warning(question + prompt)
  175. choice = raw_input().lower()
  176. if default is not None and choice == '':
  177. return valid[default]
  178. elif choice in valid:
  179. return valid[choice]
  180. else:
  181. Utils.print_warning("Please respond with 'yes' or 'no' or 'y' or 'n').\n")
  182. ##################
  183. #
  184. # Brackets management
  185. #
  186. #########
  187. @staticmethod
  188. def is_containing_bracket(sentence):
  189. """
  190. Return True if the text in <sentence> contains brackets
  191. :param sentence:
  192. :return:
  193. """
  194. # print "sentence to test %s" % sentence
  195. pattern = r"{{|}}"
  196. # prog = re.compile(pattern)
  197. if not isinstance(sentence, unicode):
  198. sentence = str(sentence)
  199. check_bool = re.search(pattern, sentence)
  200. if check_bool is not None:
  201. return True
  202. return False
  203. @staticmethod
  204. def find_all_matching_brackets(sentence):
  205. """
  206. Find all the bracket matches from a given sentence
  207. :param sentence: the sentence to check
  208. :return: the list with all the matches
  209. """
  210. pattern = r"((?:{{\s*)[\w\.]+(?:\s*}}))"
  211. # find everything like {{ word }}
  212. if not isinstance(sentence, unicode):
  213. sentence = str(sentence)
  214. return re.findall(pattern, sentence)
  215. @staticmethod
  216. def remove_spaces_in_brackets(sentence):
  217. """
  218. If has brackets it removes spaces in brackets
  219. :param sentence: the sentence to work on
  220. :return: the sentence without any spaces in brackets
  221. """
  222. pattern = '\s+(?=[^\{\{\}\}]*\}\})'
  223. # Remove white spaces (if any) between the variable and the double brace then split
  224. if not isinstance(sentence, unicode):
  225. sentence = str(sentence)
  226. return re.sub(pattern, '', sentence)
  227. ##################
  228. #
  229. # Lists management
  230. #
  231. #########
  232. @staticmethod
  233. def get_next_value_list(list_to_check):
  234. ite = list_to_check.__iter__()
  235. next(ite, None)
  236. return next(ite, None)