Add files via upload

This commit is contained in:
blueShard-dev 2020-06-28 11:15:51 +00:00 committed by GitHub
parent b8e3072563
commit bc65ff575d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 6762 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -0,0 +1,143 @@
#!/usr/bin/python3
__author__ = "blueShard"
__license__ = "GPL-3.0"
__version__ = "0.1.0"
try:
from .utils import aion_data_path, aion_path
except ImportError:
from utils import aion_data_path, aion_path
def speech_output(speech_output: str) -> None:
"""
plays a output of an artificial voice from the given words
:param speech_output: str
the words to be said
syntax: <speech output words>
example: "This is an test"
:return: None
:since: 0.1.0
"""
try:
from .config import Aion
except ImportError:
from config import Aion
from os import system
try:
tts_engine = Aion().get_tts_engine()
except IndexError:
Aion().reset()
tts_engine = Aion().get_tts_engine()
if tts_engine == "espeak":
system("espeak -v" + Aion().get_language().split("_")[0] + " " + str(speech_output) + " stdout | aplay")
print("Sayed '" + str(speech_output) + "'")
elif tts_engine == "pico2wave":
system('pico2wave --lang=' + Aion().get_language().split("_")[0] + '-' + Aion().get_language().split("_")[1] + ' --wave=/tmp/aion.wav "' + str(speech_output) + "." + '"; aplay /tmp/aion.wav; rm /tmp/aion.wav')
print("Sayed '" + str(speech_output) + "'")
def start(sudo: bool = False) -> None:
"""
starts aion
:param sudo: bool
says if 'aion' should run as sudo (True) or not (False)
syntax: <sudo>
example: False
:return: None
:since: 0.1.0
"""
from os import system
if sudo is True:
system("sudo python3 " + aion_path + "/main.py")
else:
system("python3 " + aion_path + "/main.py")
class ExecuteAionFile:
"""
base class for execution '.aion' files
:since: 0.1.0
"""
def __init__(self, fname: str) -> None:
"""
makes the file available for all functions in this class and calls the '_main()' function
:param fname: str
path of the file
syntax: <filename>
example: "/home/pi/test.aion"
:return: None
:since: 0.1.0
"""
self.fname = fname
self._main()
def _main(self) -> None:
"""
checks which type of an 'aion' file is the given file
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import init_no_file_type
from .utils import remove_space
except ImportError:
from _error_codes import init_no_file_type
from utils import remove_space
for line in open(self.fname, "r"):
if line.isspace():
continue
elif line.startswith("#"):
line = remove_space(line, "")
if line.startswith("#type:"):
line = line.replace("#type:", "")
if line.strip() == "skill":
self._skill()
elif "plugin" in line.strip():
self._plugin()
else:
raise IndexError("Errno: " + init_no_file_type + " - Couldn't find file type in " + self.fname)
def _plugin(self) -> None:
"""
execute the given file as plugin type
:return: None
:since: 0.1.0
"""
try:
from .plugin import execute_aion_file_type_plugin
except ImportError:
from plugin import execute_aion_file_type_plugin
execute_aion_file_type_plugin(self.fname)
def _skill(self) -> None:
"""
execute the given file as skill type
:return: None
:since: 0.1.0
"""
try:
from .skill import execute_aion_file_type_skill
except ImportError:
from skill import execute_aion_file_type_skill
execute_aion_file_type_skill(self.fname)

View File

@ -0,0 +1,120 @@
# __init__.py (01)
init_no_file_type = "01792"
# _error_codes.py (07)
# _errors.py (04)
# acph.py (57)
acph_activate_phrase_exist = "57042"
# config.py (40)
config_no_hotword_file_file = "40863"
config_no_supported_listening_mode = "40518"
config_no_supported_listening_source = "40801"
config_no_supported_time_format = "40014"
config_no_supported_tts_engine = "40744"
config_name_config_is_used_as_root_name = "40026"
config_character_must_be_in_alphabet = "40955"
config_root_tag_cannot_be_removed = "40471"
config_root_tag_cannot_be_updated = "40849"
# language.py (68)
language_lng_file_doesnt_exist = "16898"
language_entry_already_exist = "66873"
language_lng_file_already_exist = "68481"
# logging.py (87)
# save.py (83)
save_save_not_found = "83160"
save_save_name_already_exist = "83923"
# plugin.py (36)
plugin_aion_plugin_file_not_found = "36134"
plugin_to_much_aion_files = "36278"
plugin_couldnt_find_key = "36896"
plugin_couldnt_find_plugin_type = "36132"
plugin_illegal_run_after_pseudonym = "36987"
plugin_run_after_pseudonym_already_exist = "36059"
plugin_illegal_run_before_pseudonym = "36165"
plugin_run_before_pseudonym_already_exist = "36919"
plugin_file_doesnt_exist_in_setup_dir = "36713"
plugin_directory_doesnt_exist_in_setup_dir = "36426"
plugin_run_after_additional_directories_already_exist = "36550"
plugin_run_before_additional_directories_already_exist = "36635"
plugin_python3_module_not_found = "36277"
plugin_couldnt_find_plugin_dot_aion = "36184"
plugin_author_must_be_str = "36534"
plugin_plugin_name_must_be_str = "36370"
plugin_main_file_must_be_str = "36938"
plugin_main_file_not_found = "36430"
plugin_main_file_name_must_be_plugin_name = "36276"
plugin_skill_must_be_dict = "36261"
plugin_plugin_methods_must_be_dict = "36358"
plugin_version_must_be_str = "36184"
plugin_additional_directories_must_be_list_or_tuple = "36512"
plugin_couldnt_find_additional_directories_directory = "36606"
plugin_description_must_be_str = "36716"
plugin_language_locales_must_be_list_or_tuple = "36351"
plugin_language_dict_must_be_dict = "36297"
plugin_language_dict_character_must_be_in_alphabet = "36756"
plugin_license_must_be_str = "36333"
plugin_required_python3_package_must_be_list_or_tuple = "36054"
# skill.py (25)
skill_author_must_be_str = "25662"
skill_language_locales_must_be_list_or_tuple = "25351"
skill_skill_name_must_be_str = "25432"
skill_main_file_must_be_str = "25586"
skill_main_file_not_found = "25439"
skill_main_file_name_must_be_skill_name = "25737"
skill_version_must_be_str = "25133"
skill_additional_directories_must_be_list_or_tuple = "25902"
skill_couldnt_find_additional_directories_directory = "25271"
skill_description_must_be_str = "25367"
skill_language_dict_must_be_dict = "25487"
skill_language_dict_character_must_be_in_alphabet = "25540"
skill_license_must_be_str = "25248"
skill_required_python3_package_must_be_list_or_tuple = "25780"
skill_activate_phrases_must_be_dict = "25161"
skill_activate_phrases_character_must_be_in_alphabet = "25559"
skill_package_couldnt_find_directory = "25816"
skill_package_couldnt_find_aion_file = "25505"
skill_package_expected_one_aion_file = "25253"
skill_couldnt_find_key = "25319"
skill_skill_already_exist = "25045"
skill_file_doesnt_exist = "25174"
skill_directory_doesnt_exist = "25974"
skill_directory_already_exist = "25819"
skill_couldnt_install_python3_package = "25082"
skill_couldnt_find_skill_dot_aion = "25184"
# usb.py (99)
# utils.py (92)
utils_unexpected_error = "92700"
utils_fname_doesnt_exist = "92029"
utils_couldnt_find_parent = "92613"
utils_dict_index_out_of_range = "92743"
# variable.py (20)
variable_get_value_variable_file_variable_doesnt_exist = "92481"
variable_get_value_user_variables_variable_doesnt_exist = "92255"
variable_remove_variable_variable_doesnt_exist = "92010"
variable_set_value_variable_doesnt_exist = "92603"

View File

@ -0,0 +1,158 @@
#!/usr/bin/python3
try:
from .config import Aion as _Aion
from .utils import aion_data_path as _aion_data_path
except ImportError:
from config import Aion as _Aion
from utils import aion_data_path as _aion_data_path
def _acph_file() -> str:
"""
gets the activate phrase file for the current language
:return: None
:since: 0.1.0
"""
from colorama import Fore
from os.path import isfile
if isfile(acph_directory + "/" + language + ".acph") is False:
print(Fore.RED + "didn't found acph file in your language. Using the default acph file (en_US)" + Fore.RESET)
return acph_directory + "/en_US.acph"
else:
return acph_directory + "/" + language + ".acph"
language = _Aion().get_language()
acph_directory = _aion_data_path + "/language"
acph_file = _acph_file()
supported_languages = ["de_DE", "en_US"]
def add_acph(language_locale: str, skill: str, acph_dict: dict = {}) -> None:
"""
adds an new entry(s) to from argument 'language_locale' given language
:param language_locale: str
language locale from the language to which the entry(s) is/are to be added
syntax: <language locale>
example: "de_DE"
:param skill: str
skill name to which the acph belongs
syntax: "<skill name>"
example: "test_skill"
:param acph_dict: dict, optional
defines a word or a sentence from which a method is called
syntax: {<activate phrase>: <method that should get called after the activate phrase was said>}
example: {"start test": "MyTestMethod"}
NOTE: in key 'activate_phrase' you can use the '__and__' statement. This checks if the words before and after '__and__' are in the sentence that the user has spoken in
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import acph_activate_phrase_exist
from .utils import BaseXMLWriter
except ImportError:
from _error_codes import acph_activate_phrase_exist
from utils import BaseXMLWriter
acph_writer = BaseXMLWriter(acph_directory + "/" + language_locale + ".acph")
for acph, method in acph_dict:
if exist_acph(language_locale, acph):
raise IndexError("Errno: " + acph_activate_phrase_exist + " - The activate phrase " + acph + " already exist")
acph_writer.add("<root>", acph, skill=skill, method=method)
acph_writer.write()
def create_acph_file(language_locale: str, skill_acph_dict_dict: dict = {}) -> None:
"""
creates a new '.acph' file for given language locale with given skill_acph_dict_dict
:param language_locale: str
language locale of language from which the new file is to be created
syntax: <language_locale>
example: "en_US"
:param skill_acph_dict_dict: dict, optional
skill name you want to add specific entries
syntax: {<skill name>: {<activate phrase>: <method that should get called after the activate phrase was said>}}
example: {"test_skill": {"start test": "MyTestMethod"}}
NOTE: in key 'activate_phrase' you can use the '__and__' statement. This checks if the words before and after '__and__' are in the sentence that the user has spoken in
:return: None
:since: 0.1.0
"""
try:
from .utils import BaseXMLBuilder
except ImportError:
from utils import BaseXMLBuilder
acph_builder = BaseXMLBuilder(language_locale)
for skill, acph_dict in skill_acph_dict_dict.items():
for acph, method in acph_dict.items():
acph_builder.create_root_element(acph, skill=skill, method=method)
acph_builder.write(acph_directory + "/" + language_locale + ".acph")
def delete_acph(language_locale: str, acph_list: list = []) -> None:
"""
deletes entries from '<language_locale>.acph'
:param language_locale: str
language locale from (file) which the activate phases is being deleted
syntax: <language locale>
example: "en_US"
:param acph_list: list, optional
name of the activate phases you want to remove
syntax: [<activate phase name>]
example: ["test_acph"]
:return: None
:since: 0.1.0
"""
try:
from .utils import BaseXMLWriter
except ImportError:
from utils import BaseXMLWriter
acph_writer = BaseXMLWriter(acph_directory + "/" + language_locale + ".acph")
for item in acph_list:
acph_writer.remove("<root>", str(item))
acph_writer.write()
def exist_acph(language_locale: str, acph: str) -> bool:
"""
checks if a entry exist
:param language_locale: str
language locale from (file) which the activate phrase should be search
syntax: <language locale>
example: "en_US"
:param acph: str
activate phrase you want to check if exists
syntax: <acph name>
example: "start test"
:return: bool
returns True if acph exist / False if not
syntax: <boolean>
example: False
:since: 0.1.0
"""
try:
from .utils import BaseXMLReader
except ImportError:
from utils import BaseXMLReader
acph = acph.replace(" ", "_")
acph_reader = BaseXMLReader(acph_directory + "/" + language_locale + ".acph")
for item in acph_reader.get_infos(["<root>"]).items().index(0):
if acph in item["childs"]:
return True
else:
return False

View File

@ -0,0 +1,490 @@
#!/usr/bin/python3
try:
from .utils import aion_data_path as _aion_data_path, BaseXMLReader as _BaseXMLReader, BaseXMLWriter as _BaseXMLWriter
except ImportError:
from utils import aion_data_path as _aion_data_path, BaseXMLReader as _BaseXMLReader, BaseXMLWriter as _BaseXMLWriter
config_file = _aion_data_path + "/config.xml"
class Aion:
"""
get infos about all aion internal configs (and change them)
:since: 0.1.0
"""
def __init__(self) -> None:
"""
set all class values
:return: None
:since: 0.1.0
"""
self.all_listening_modes = ["auto", "manual"]
self.all_stt_engines = ["google", "pocketsphinx"]
self.all_time_formats = ["12", "24"]
self.all_tts_engines = ["pico2wave", "espeak"]
self.supported_languages = ["de_DE", "en_US"]
self._aion_cfg_reader = _BaseXMLReader(config_file)
self._aion_cfg_writer = _BaseXMLWriter(config_file)
def get_hotword_file(self) -> str:
"""
get set hotword file path
:return: str
returns path of the hotword file
syntax: <hotword file path>
example: "/usr/local/aion-<aion_version>/etc/Aion.pmdl"
:since: 0.1.0
"""
from glob import glob
for value_list in self._aion_cfg_reader.get_infos(["hotword_file"]).values():
for config in value_list:
if config["parent"]["tag"] == "aion":
return glob(config["text"])[0]
def get_language(self) -> str:
"""
get set language locale
:return: str
returns language locale
syntax: <language locale>
example: "en_US"
:since: 0.1.0
"""
for value_list in self._aion_cfg_reader.get_infos(["language"]).values():
for config in value_list:
if config["parent"]["tag"] == "aion":
return config["text"]
def get_listening_mode(self) -> str:
"""
get set listening mode
:return: str
returns listening mode
syntax: <listening mode>
example: "auto"
:since: 0.1.0
"""
for value_list in self._aion_cfg_reader.get_infos(["listening_mode"]).values():
for config in value_list:
if config["parent"]["tag"] == "aion":
return config["text"]
def get_pid_manipulation_number(self) -> int:
"""
get set pid manipulation number
:return: int
returns the pid manipulation number
syntax: <pid manipulation number>
example: 4
:since: 0.1.0
"""
for value_list in self._aion_cfg_reader.get_infos(["pid_manipulation_number"]).values():
for config in value_list:
if config["parent"]["tag"] == "aion":
return int(config["text"])
def get_stt_engine(self) -> str:
"""
get set speech-to-text engine
:return: str
returns speech-to-text engine
syntax: <speech-to-text engine>
example: "google"
:since: 0.1.0
"""
for value_list in self._aion_cfg_reader.get_infos(["listening_source"]).values():
for config in value_list:
if config["parent"]["tag"] == "aion":
return config["text"]
def get_time_format(self) -> int:
"""
get set time format
:return: str
returns time format
syntax: <time format>
example: 24
:since: 0.1.0
"""
for value_list in self._aion_cfg_reader.get_infos(["time_format"]).values():
for config in value_list:
if config["parent"]["tag"] == "aion":
return int(config["text"])
def get_tts_engine(self) -> str:
"""
get set text-to-speech engine
:return: str
returns text-to-speech engine
syntax: <text-to-speech engine>
example: "espeak"
:since: 0.1.0
"""
for value_list in self._aion_cfg_reader.get_infos(["tts_engine"]).values():
for config in value_list:
if config["parent"]["tag"] == "aion":
return config["text"]
@staticmethod
def reset() -> None:
"""
resets the aion config values
:return: None
:since: 0.1.0
"""
from locale import getdefaultlocale
_BaseXMLWriter(config_file).remove("config", "aion")
aion_cfg_writer = _BaseXMLWriter(config_file)
aion_cfg_writer.add("config", "aion")
aion_cfg_writer.add("aion", "hotword_file", text="/usr/local/aion-*/etc/Aion.pmdl")
aion_cfg_writer.add("aion", "language", text=str(getdefaultlocale()[0]))
aion_cfg_writer.add("aion", "listening_mode", text="auto")
aion_cfg_writer.add("aion", "pid_manipulation_number", text="4")
aion_cfg_writer.add("aion", "stt_engine", text="pocketsphinx")
aion_cfg_writer.add("aion", "time_format", text="12")
aion_cfg_writer.add("aion", "tts_engine", text="espeak")
aion_cfg_writer.write()
def set_hotword_file(self, hotword_file: str) -> None:
"""
sets the hotword file
:param hotword_file: str
location from the new hotword file
syntax: <hotword_file>
example: "/usr/local/aion-*/etc/Aion.pmdl"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import config_no_hotword_file_file
except ImportError:
from _error_codes import config_no_hotword_file_file
from os.path import isfile
if isfile(hotword_file):
self._aion_cfg_writer.update("aion", "hotword_file", text=str(hotword_file))
self._aion_cfg_writer.write()
else:
raise FileNotFoundError("Errno: " + config_no_hotword_file_file + " - Couldn't find file '" + hotword_file + "'")
def set_language(self, language: str) -> None:
"""
sets the language locale
:param language: str
new language locale
syntax: <language locale>
example: "en_US"
:return: None
:since: 0.1.0
"""
from colorama import Fore
if language in self.supported_languages:
self._aion_cfg_writer.update("aion", "language", text=str(language))
self._aion_cfg_writer.write()
else:
print(Fore.RED + "'" + language + "' isn't an official supported language for speech output (type 'aion.Config.supported_languages' to see all supported languages).\n"
"The complete speech output is now in English. You have to create your own '.lng' file to support your language.\n" +
str(self.supported_languages) + " are the supported languages" + Fore.RESET)
self._aion_cfg_writer.update("aion", "language", text=str(language))
self._aion_cfg_writer.write()
def set_listening_mode(self, listening_mode: str) -> None:
"""
sets the listening mode
:param listening_mode: str
new listening mode
syntax: <listening mode>
example: "auto"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import config_no_supported_listening_mode
except ImportError:
from _error_codes import config_no_supported_listening_mode
if listening_mode in self.all_listening_modes:
self._aion_cfg_writer.update("aion", "listening_mode", text=str(listening_mode))
self._aion_cfg_writer.write()
else:
raise ValueError("Errno: " + config_no_supported_listening_mode + " - " + str(listening_mode) + " isn't a supported listening mode. Please choose from these: " + str(self.all_listening_modes))
def set_pid_manipulation_number(self, pid_manipulation_number: int) -> None:
"""
sets the pid manipulation number
:param pid_manipulation_number: int
new pid manipulation number
syntax: <pid manipulation number>
example: 4
:return: None
:since: 0.1.0
"""
self._aion_cfg_writer.update("aion", "listening_mode", text=str(pid_manipulation_number))
self._aion_cfg_writer.write()
def set_stt_engine(self, stt_engine: str) -> None:
"""
sets the speech-to-text engine
:param stt_engine: str
new speech-to-text engine
syntax: <speech-to-text engine>
example: "pocketsphinx"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import config_no_supported_listening_source
except ImportError:
from _error_codes import config_no_supported_listening_source
if stt_engine in self.all_stt_engines:
self._aion_cfg_writer.update("aion", "stt_engine", text=str(stt_engine))
self._aion_cfg_writer.write()
else:
raise ValueError("Errno: " + config_no_supported_listening_source + " - " + str(stt_engine) + " isn't a supported listening source. Please choose from these: " + str(self.all_stt_engines))
def set_time_format(self, time_format: str) -> None:
"""
sets the time format
:param time_format: str
new time format
syntax: <time format>
example: "24"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import config_no_supported_time_format
except ImportError:
from _error_codes import config_no_supported_time_format
if str(time_format) in self.all_time_formats:
self._aion_cfg_writer.update("aion", "time_format", text=str(time_format))
self._aion_cfg_writer.write()
else:
raise ValueError("Error: " + config_no_supported_time_format + " - " + str(time_format) + " isn't a supported time format. Please choose from these: " + str(self.all_time_formats))
def set_tts_engine(self, tts_engine: str) -> None:
"""
sets the text-to-speech engine
:param tts_engine: str
new text-to-speech engine
syntax: <text-to-speech engine>
example: "espeak"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import config_no_supported_tts_engine
except ImportError:
from _error_codes import config_no_supported_tts_engine
if tts_engine in self.all_tts_engines:
self._aion_cfg_writer.update("aion", "tts_engine", text=str(tts_engine))
self._aion_cfg_writer.write()
else:
raise ValueError("Errno: " + config_no_supported_tts_engine + " - " +str(tts_engine) + " isn't a supported tts engine. Please choose from these: " + str(self.all_tts_engines))
def add_entry(name: str, text: str = None, attrib: dict = {}, parent_name: str = "config", parent_attrib: dict = {}) -> None:
"""
adds an entry from the config file
:param name: str
name of the new entry
syntax: <name>
example: "test_entry"
:param text: str, optional
text of the new entry
syntax: <text>
example: "Test"
:param attrib: dict, optional
attributes of the new entry
syntax: {<attribute name>: <attribute value>}
example: {"test_attrib", "test"}
:param parent_name: str, optional
name of the parent entry to which the entry is added
syntax: <parent name>
example: "test_parent"
:param parent_attrib: dict, optional
attributes of the parent entry
syntax: {<parent attribute name>: <parent attribute value>}
example: {"version": "1.0.0"}
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import config_name_config_is_used_as_root_name, config_character_must_be_in_alphabet
except ImportError:
from _error_codes import config_name_config_is_used_as_root_name, config_character_must_be_in_alphabet
cfg_writer = _BaseXMLWriter(config_file)
if name == "config":
raise NameError("Errno: " + config_name_config_is_used_as_root_name + " - Name 'config' is already used as root name")
for char in name:
if char not in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_":
raise IndexError("Errno: " + config_character_must_be_in_alphabet + " - " + char + " in " + name + " must be in 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_'")
cfg_writer.add(parent_name, name, text, attrib, parent_attrib=parent_attrib)
cfg_writer.write()
def delete_entry(name: str, parent_name: str = "config", parent_attrib: dict = {}) -> None:
"""
deletes an entry from the config file
:param name: str
name of the entry to be deleted
syntax: <name>
example: "test_entry"
:param parent_name: str, optional
name of the parent entry of the entry to be deleted
syntax: <parent name>
example: "test_parent"
:param parent_attrib: dict, optional
attributes of the parent entry from the entry to be searched
syntax: {<attribute name>: <attribute value>}
example: {"test_attrib", "test"}
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import config_root_tag_cannot_be_removed
except ImportError:
from _error_codes import config_root_tag_cannot_be_removed
cfg_writer = _BaseXMLWriter(config_file)
if name == "config":
raise NameError("Errno: " + config_root_tag_cannot_be_removed + " - The root tag cannot be removed")
cfg_writer.remove(parent_name, name, parent_attrib)
cfg_writer.write()
def get_entry(name: str, parent_name: str = None, parent_attrib: dict = None) -> dict:
"""
get infos about an entry
:param name: str
name of the entry to be searched
syntax: <name>
example: "test_entry"
:param parent_name: str, optional
name of the parent entry of the entry to be deleted
syntax: <parent name>
example: "test_parent"
:param parent_attrib: dict, optional
attributes of the parent entry
syntax: {<attribute name>: <attribute value>}
example: {"test_attrib", "test"}
:return: dict
returns the infos about the given entry
syntax: {"text": <text of entry>, "attrib": <attributes of entry>}
e.g.: {"text": "entry text", "attrib": {"version": "1.0.0"}}
:since: 0.1.0
"""
cfg_reader = _BaseXMLReader(config_file)
return_dict = {}
if parent_name:
for value_list in cfg_reader.get_infos([name]).values():
for entry in value_list:
if entry["parent"] == parent_name:
if parent_attrib:
if entry["attrib"] == parent_attrib:
return_dict["text"] = entry["text"]
return_dict["attrib"] = entry["attrib"]
break
else:
return_dict["text"] = entry["text"]
return_dict["attrib"] = entry["attrib"]
break
else:
return_dict["text"] = cfg_reader.get_infos([name]).items().index(0)["text"]
return_dict["attrib"] = cfg_reader.get_infos([name]).items().index(0)["attrib"]
return return_dict
def update_entry(name: str, text: str = None, attrib: dict = {}, parent_name: str = "config", **extra: str) -> None:
"""
updates an entry
:param name: str
name of the entry to be updated
syntax: <name>
example: "test_entry"
:param text: str, optional
new text of the entry to be updated
syntax: <text>
example: "new test text"
:param attrib: dict, optional
new attributes of the entry to be updated
syntax: {<attribute name>: <attribute value>}
example: {"new_test_attrib", "new_test"}
:param parent_name: str, optional
parent entry of the entry to be updated
syntax: <parent name>
example: "test_parent"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import config_root_tag_cannot_be_updated
except ImportError:
from _error_codes import config_root_tag_cannot_be_updated
cfg_writer = _BaseXMLWriter(config_file)
if name == "config":
raise NameError("Errno: " + config_root_tag_cannot_be_updated + " - Can't update root name")
if extra:
cfg_writer.update(parent_name, name, text, {**attrib, **extra})
else:
cfg_writer.update(parent_name, name, text, attrib)

View File

@ -0,0 +1,231 @@
#!/usr/bin/python3
try:
from .config import Aion as _Aion
from .utils import aion_data_path as _aion_data_path
except ImportError:
from config import Aion as _Aion
from utils import aion_data_path as _aion_data_path
def _language_file() -> str:
"""
gets the language file for the current language
:return: str
return the language file for the current language
syntax: "<language file>"
example: "en_US"
:since: 0.1.0
"""
from colorama import Fore
from os.path import isfile
if isfile(language_directory + "/" + language + ".lng") is False:
print(Fore.RED + "didn't found language file in your language. Using the default language file (en_US)" + Fore.RESET)
return language_directory + "/en_US.lng"
else:
return language_directory + "/" + language + ".lng"
language = _Aion().get_language()
language_directory = _aion_data_path + "/language"
language_file = _language_file()
supported_languages = ["de_DE", "en_US"]
def add_entry(language_locale: str, skill: str, entry_dict: dict = {}) -> None:
"""
adds an new entry(s) to from argument 'language_locale' given language
:param language_locale: str
language locale from the language to which the entry(s) is/are to be added
syntax: <language locale>
example: "de_DE"
:param skill: str
skill name to which the entry belongs
syntax: "<skill name>"
example: "test_skill"
:param entry_dict: dict, optional
all texts for execution of a function
syntax: {<entry name>: <text of your entry>}
example: {"test_entry": "Test function was executed correctly"}
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import language_lng_file_doesnt_exist, language_entry_already_exist
except ImportError:
from _error_codes import language_lng_file_doesnt_exist, language_entry_already_exist
from os.path import isfile
lng_file = language_directory + "/" + language_locale + ".lng"
if isfile(lng_file) is False:
raise FileNotFoundError("Errno: " + language_lng_file_doesnt_exist + " - The file " + lng_file + " doesn't exist")
try:
from .utils import BaseXMLWriter
except ImportError:
from utils import BaseXMLWriter
lng_adder = BaseXMLWriter(lng_file)
for entry, text in entry_dict.items():
if exist_entry(language_locale, skill, entry) is True:
raise IndexError("Errno: " + language_entry_already_exist + " - The entry " + entry + " already exist")
lng_adder.add("<root>", skill + "." + str(entry), text=str(text))
lng_adder.write()
def create_lng_file(language_locale: str, extra_dict: dict = {}, **extra: dict) -> None:
"""
creates a new '.lng' file for given language locale with given entry_dict
:param language_locale: str
language locale of language from which the new file is to be created
syntax: <language_locale>
example: en_US
:param extra_dict: dict, optional
skill name you want to add specific entries
syntax: {<name of the skill you want to add entries>: {{<name of the entry>: <text of the entry>}}
example: {"test_skill": {"test_entry": "This is the text for the test text entry"}}
:param extra: kwargs, optional
skill name you want to add specific entries
syntax: <name of the skill you want to add entries>={<name of the entry>: <text of the entry>}
example: test_skill={"test_success": "The test was executed successfully", "text_error": "The test wasn't executed successfully"}
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import language_lng_file_already_exist
from .utils import BaseXMLBuilder
except ImportError:
from _error_codes import language_lng_file_already_exist
from utils import BaseXMLBuilder
from os.path import isfile
if isfile(language_directory + "/" + language_locale + ".lng"):
raise FileExistsError("Errno: " + language_lng_file_already_exist + " - The language file " + language_locale + ".lng already exist in directory " + language_directory)
lng_file = BaseXMLBuilder(language_locale)
for skill, entry_dict in extra_dict.items():
for entry_name, entry_text in entry_dict.items():
lng_file.create_root_element(language_locale, str(skill) + "." + str(entry_name), text=str(entry_text))
for skill, entry_dict in extra.items():
for entry_name, entry_text in entry_dict.items():
lng_file.create_root_element(language_locale, str(skill) + "." + str(entry_name), text=str(entry_text))
lng_file.write(language_directory + "/" + language_locale + ".lng")
def delete_entry(language_locale: str, skill: str, entry_list: list = []) -> None:
"""
deletes entries from '<language_locale>.lng'
:param language_locale: str
language locale from (file) which the entry is being deleted
syntax: <language locale>
example: "en_US"
:param skill : str
name of the skill from which the entries should be deleted
syntax: <skill name>
example: "test"
:param entry_list: list, optional
name of the entries you want to remove
syntax: [<entry name>]
example: ["test_entry"]
:return: None
:since: 0.1.0
"""
try:
from .utils import BaseXMLWriter
except ImportError:
from utils import BaseXMLWriter
lng_writer = BaseXMLWriter(language_directory + "/" + language_locale + ".lng")
for item in entry_list:
lng_writer.remove("<root>", str(skill) + "." + str(item))
lng_writer.write()
def exist_entry(language_locale: str, skill: str, entry: str) -> bool:
"""
checks if a entry exist
:param language_locale: str
language locale from (file) which the entry should be search
syntax: <language locale>
example: "en_US"
:param skill: str
skill name from the entry
syntax: <skill name>
example: "test"
:param entry: str
entry name of skill (entry)
syntax: <entry name>
example: "test_entry"
:return: bool
returns True if entry exist / False if not
syntax: <boolean>
example: False
:since: 0.1.0
"""
try:
from .utils import BaseXMLReader
except ImportError:
from utils import BaseXMLReader
entry = entry.replace(" ", "_")
lng_reader = BaseXMLReader(language_directory + "/" + language_locale + ".lng")
for item in lng_reader.get_infos(["<root>"]).items().index(0):
if skill + "." + entry in item["childs"]:
return True
else:
return False
def start(skill: str, entry: str, format: dict = {}) -> str:
"""
returns entry from given arguments
:param skill: str
name of the skill from the entry you want to call
syntax: <skill name>
example: "test_skill"
:param entry: str
name of the entry you want to call
syntax: <entry>
example: "test_func_entry"
:param format: dict
dictionary to format the string in the '.lng' file
syntax: <format>
example: {"test", "newtest"}: "This is a test" -> "This is a newtest"
:return: str
returns the (from 'format' formatted) string from the in '/etc/aion_data/config.xml' setted language locale '.lng' file
syntax: <return string>
example: "This is a test"
:since: 0.1.0
"""
from ast import literal_eval
from random import choice
try:
from .utils import BaseXMLReader
except ImportError:
from utils import BaseXMLReader
lng_reader = BaseXMLReader(language_file)
for item in lng_reader.get_infos([skill + "." + entry]).values().index(0):
try:
if item["text"].startswith("[") and item["text"].endswith("]"):
return str(choice(literal_eval(item["text"]))).format(**format)
else:
return str(item["text"]).format(**format)
except SyntaxError:
return str(item["text"]).format(**format)

View File

@ -0,0 +1,775 @@
#!/usr/bin/python3
from time import time as _time
class LogAll:
"""
'LogConsole' and 'LogFile' classes in one class
:since: 0.1.0
"""
def __init__(self, log_fname: str, critical_fname: str = None, debug_fname: str = None, error_fname: str = None, info_fname: str = None, warning_fname: str = None,
console_log_format: str = "[{runtime}] - {filename}(line: {lineno}) - {levelname}: {message}",
file_log_format: str = "[{year}-{month}-{day} {hour}:{minute}:{second}] - {filename}(line: {lineno}) - {levelname}: {message}") -> None:
"""
:param log_fname: str
filename of the file to which all logging messages should be saved
syntax: <filename>
example: "/home/pi/test.log"
:param critical_fname: str, optional
filename of the file to which critical logging messages should be saved
syntax: <filename>
example: "/home/pi/test_critical.log"
:param debug_fname: str, optional
filename of the file to which debug logging messages should be saved
syntax: <filename>
example: "/home/pi/test_debug.log"
:param error_fname: str, optional
filename of the file to which error logging messages should be saved
syntax: <filename>
example: "/home/pi/test_error.log"
:param info_fname: str, optional
filename of the file to which info logging messages should be saved
syntax: <filename>
example: "/home/pi/test_info.log"
:param warning_fname: str, optional
filename of the file to which warning logging messages should be saved
syntax: <fname>
example: "/home/pi/test_warning.log"
:param console_log_format: str, optional
format of the console output
syntax: <format>
example: [{runtime}] - {filename}(line: {lineno}) - {levelname}: {message}
NOTE: in 'format' you can use the following curly bracktes:
year gives the year back
month gives the month back
day gives the day back
hour gives the hour back
minute gives the minute back
second gives the second back
microsecond gives the microsecond back
runtime gives the back since the logger has started
levelname gives the levelname back
filename gives the name of the file from which the logger is called back
lineno gives the line number back from which the levelname function was called
function gives the function back from which the levelname function was called
message gives the in levelname function given message back
:param file_log_format: str, optional
format of the output that should be write to file
syntax: <format>
example: [{runtime}] - {filename}(line: {lineno}) - {levelname}: {message}
NOTE: in 'format' you can use the following curly bracktes:
year gives the year back
month gives the month back
day gives the day back
hour gives the hour back
minute gives the minute back
second gives the second back
microsecond gives the microsecond back
runtime gives the back since the logger has started
levelname gives the levelname back
filename gives the name of the file from which the logger is called back
lineno gives the line number back from which the levelname function was called
function gives the function back from which the levelname function was called
message gives the in levelname function given message back
:return: None
:since: 0.1.0
"""
from datetime import datetime
from inspect import getframeinfo, stack
caller_infos = getframeinfo(stack()[1][0])
self.log_fname = log_fname
self.critical_fname = critical_fname
self.debug_fname = debug_fname
self.error_fname = error_fname
self.info_fname = info_fname
self.warning_fname = warning_fname
self._date = datetime.now()
self._filename = caller_infos.filename
self._console_log_format = console_log_format
self._file_log_format = file_log_format
self._function = caller_infos.function
self._lineno = caller_infos.lineno
self._start_time = _time()
def _format(self, levelname: str, message: str, lineno: int = None) -> dict:
"""
returns a dict with custom entries
:param levelname: str
name of the level
syntax: <levelname>
example: "INFO"
:param message: str
message in the dict
syntax: <message>
example: "Test message"
:param lineno: int
line number in the dict
syntax: <line number>
example: 34
:return: dict
syntax: {"year": <year>,
"month": <month>,
"day": <day>,
"hour": <hour>,
"minute": <minute>,
"second": <second>,
"microsecond": <microsecond>,
"runtime": <runtime>,
"levelname": <level name>,
"filename": <filename>,
"lineno": <line number>,
"function": <function>,
"message": <message>}
example: {"year": 2000,
"month": 1,
"day": 1,
"hour": 00,
"minute": 00,
"second": 00,
"microsecond": 00000,
"runtime": "01:23:45",
"levelname": "INFO",
"filename": "abc.py",
"lineno": 123,
"function": "test_function",
"message": "This is a test message"}
:since: 0.1.0
"""
if lineno:
return {"year": self._date.year, "month": self._date.month, "day": self._date.day, "hour": self._date.hour, "minute": self._date.minute, "second": self._date.second, "microsecond": self._date.microsecond,
"runtime": self._runtime(), "levelname": levelname, "filename": self._filename, "lineno": lineno, "function": self._function, "message": message}
else:
return {"year": self._date.year, "month": self._date.month, "day": self._date.day, "hour": self._date.hour, "minute": self._date.minute, "second": self._date.second, "microsecond": self._date.microsecond,
"runtime": self._runtime(), "levelname": levelname, "filename": self._filename, "lineno": self._lineno, "function": self._function, "message": message}
def _runtime(self) -> str:
"""
returns the runtime
:return: str
returns the runtime
syntax: <hour>:<minute>:<day>
example: "01:23:45"
:since: 0.1.0
"""
second = int(_time() - self._start_time)
minute = 0
hour = 0
while (second / 60) >= 1:
minute += 1
second -= 60
while (minute / 60) >= 1:
hour += 1
minute -= 60
if len(str(second)) == 1:
second = "0" + str(second)
if len(str(minute)) == 1:
minute = "0" + str(minute)
if len(str(hour)) == 1:
hour = "0" + str(hour)
return str(str(hour) + ":" + str(minute) + ":" + str(second))
def critical(self, msg: str, lineno: int = None) -> None:
"""
prints and write given format with 'critical' levelname and in 'msg' given message
:param msg: str
message you want to print and write
syntax: <message>
example: "critical message"
:param lineno: int, optional
custom 'lineno' (line number) entry
syntax: <lineno>
example: 5
:return: None
:since: 0.1.0
"""
LogFile(self.log_fname, format=self._file_log_format).critical(msg, self._format("CRITICAL", msg, lineno=lineno))
if self.critical_fname is not None:
LogFile(self.critical_fname, format=self._file_log_format).critical(msg, self._format("CRITICAL", msg, lineno=lineno))
LogConsole(self._console_log_format).critical(msg, self._format("CRITICAL", msg, lineno=lineno))
def debug(self, msg: str, lineno: int = None) -> None:
"""
prints and write given format with 'debug' levelname and in 'msg' given message
:param msg: str
message you want to print and write
syntax: <message>
example: "debug message"
:param lineno: int, optional
custom 'lineno' (line number) entry
syntax: <lineno>
example: 5
:return: None
:since: 0.1.0
"""
LogFile(self.log_fname, format=self._file_log_format).debug(msg, self._format("DEBUG", msg, lineno=lineno))
if self.debug_fname is not None:
LogFile(self.debug_fname, format=self._file_log_format).debug(msg, self._format("DEBUG", msg, lineno=lineno))
LogConsole(self._console_log_format).debug(msg, self._format("DEBUG", msg, lineno=lineno))
def error(self, msg: str, lineno=None) -> None:
"""
prints and write given format with 'error' levelname and in 'msg' given message
:param msg: str
message you want to print and write
syntax: <message>
example: "error message"
:param lineno: int, optional
custom 'lineno' (line number) entry
syntax: <lineno>
example: 5
:return: None
:since: 0.1.0
"""
LogFile(self.log_fname, format=self._file_log_format).error(msg, self._format("ERROR", msg, lineno=lineno))
if self.error_fname is not None:
LogFile(self.error_fname, format=self._file_log_format).error(msg, self._format("ERROR", msg, lineno=lineno))
LogConsole(self._console_log_format).error(msg, self._format("ERROR", msg, lineno=lineno))
def info(self, msg: str, lineno=None) -> None:
"""
prints and write given format with 'info' levelname and in 'msg' given message
:param msg: str
message you want to print and write
syntax: <message>
example: "info message"
:param lineno: int, optional
custom 'lineno' (line number) entry
syntax: <lineno>
example: 5
:return: None
:since: 0.1.0
"""
LogFile(self.log_fname, format=self._file_log_format).info(msg, self._format("INFO", msg, lineno=lineno))
if self.info_fname is not None:
LogFile(self.log_fname, format=self._file_log_format).info(msg, self._format("INFO", msg, lineno=lineno))
LogConsole(self._console_log_format).info(msg, self._format("INFO", msg, lineno=lineno))
def warning(self, msg: str, lineno=None) -> None:
"""
prints and write given format with 'warning' levelname and in 'msg' given message
:param msg: str
message you want to print and write
syntax: <message>
example: "warning message"
:param lineno: int, optional
custom 'lineno' (line number) entry
syntax: <lineno>
example: 5
:return: None
:since: 0.1.0
"""
LogFile(self.log_fname, format=self._file_log_format).warning(msg, self._format("WARNING", msg, lineno=lineno))
if self.warning_fname is not None:
LogFile(self.warning_fname, format=self._file_log_format).warning(msg, self._format("WARNING", msg, lineno=lineno))
LogConsole(self._console_log_format).warning(msg, self._format("WARNING", msg, lineno=lineno))
class LogConsole:
"""
a simple logger for consoles
:since: 0.1.0
"""
def __init__(self, format: str = "[{runtime}] - {filename}(line: {lineno}) - {levelname}: {message}") -> None:
"""
:param format: str, optional
format of the console output
syntax: <format>
example: [{runtime}] - {filename}(line: {lineno}) - {levelname}: {message}
NOTE: in 'format' you can use the following curly bracktes:
year gives the year back
month gives the month back
day gives the day back
hour gives the hour back
minute gives the minute back
second gives the second back
microsecond gives the microsecond back
runtime gives the back since the logger has started
levelname gives the levelname back
filename gives the name of the file from which the logger is called back
lineno gives the line number back from which the levelname function was called
function gives the function back from which the levelname function was called
message gives the in levelname function given message back
:return: None
:since: 0.1.0
"""
from datetime import datetime
from inspect import getframeinfo, stack
self.format = format
self._caller_infos = getframeinfo(stack()[1][0])
self._date = datetime.now()
self._start_time = _time()
def _format(self, levelname: str, message: str) -> dict:
"""
returns a dict with custom entries
:param levelname: str
name of the level
syntax: <levelname>
example: "INFO"
:param message: str
message in the dict
syntax: <message>
example: "Test message"
:return: dict
syntax: {"year": <year>,
"month": <month>,
"day": <day>,
"hour": <hour>,
"minute": <minute>,
"second": <second>,
"microsecond": <microsecond>,
"runtime": <runtime>,
"levelname": <level name>,
"filename": <filename>,
"lineno": <line number>,
"function": <function>,
"message": <message>}
example: {"year": 2000,
"month": 1,
"day": 1,
"hour": 00,
"minute": 00,
"second": 00,
"microsecond": 00000,
"runtime": "01:23:45",
"levelname": "INFO",
"filename": "abc.py",
"lineno": 123,
"function": "test_function",
"message": "This is a test message"}
:since: 0.1.0
"""
return {"year": self._date.year, "month": self._date.month, "day": self._date.day, "hour": self._date.hour, "minute": self._date.minute, "second": self._date.second, "microsecond": self._date.microsecond,
"runtime": self._runtime(), "levelname": levelname, "filename": self._caller_infos.filename, "lineno": self._caller_infos.lineno, "function": self._caller_infos.function, "message": message}
def _runtime(self) -> str:
"""
returns the runtime
:return: str
returns the runtime
syntax: <hour>:<minute>:<day>
example: "01:23:45"
:since: 0.1.0
"""
second = int(_time() - self._start_time)
minute = 0
hour = 0
while (second / 60) >= 1:
minute += 1
second -= 60
while (minute / 60) >= 1:
hour += 1
minute -= 60
if len(str(second)) == 1:
second = "0" + str(second)
if len(str(minute)) == 1:
minute = "0" + str(minute)
if len(str(hour)) == 1:
hour = "0" + str(hour)
return str(str(hour) + ":" + str(minute) + ":" + str(second))
def critical(self, msg: str, _format_values: dict = None) -> None:
"""
prints given format with 'critical' levelname and in 'msg' given message
:param msg: str
message you want to print out
syntax: <message>
example: "critical message"
:param _format_values: dict, optional
dictionary with own format values
syntax: {<key>: <value>}
example: {"mytext": "This is my text"}
NOTE: if you use '_format_values' the in function '_format' given format values won't used
:return: None
:since: 0.1.0
"""
if _format_values is None:
print(self.format.format(**self._format(levelname="CRITICAL", message=msg)))
else:
print(self.format.format(**_format_values))
def debug(self, msg: str, _format_values: dict = None) -> None:
"""
prints given format with 'debug' levelname and in 'msg' given message
:param msg: str
message you want to print out
syntax: <message>
example: "debug message"
:param _format_values: dict, optional
dictionary with own format values
syntax: {<key>: <value>}
example: {"mytext": "This is my text"}
NOTE: if you use '_format_values' the in function '_format' given format values won't used
:return: None
:since: 0.1.0
"""
if _format_values is None:
print(self.format.format(**self._format(levelname="DEBUG", message=msg)))
else:
print(self.format.format(**_format_values))
def error(self, msg: str, _format_values: dict = None) -> None:
"""
prints given format with 'error' levelname and in 'msg' given message
:param msg: str
message you want to print out
syntax: <message>
example: "error message"
:param _format_values: dict, optional
dictionary with own format values
syntax: {<key>: <value>}
example: {"mytext": "This is my text"}
NOTE: if you use '_format_values' the in function '_format' given format values won't used
:return: None
:since: 0.1.0
"""
if _format_values is None:
print(self.format.format(**self._format(levelname="ERROR", message=msg)))
else:
print(self.format.format(**_format_values))
def info(self, msg: str, _format_values: dict = None) -> None:
"""
prints given format with 'info' levelname and in 'msg' given message
:param msg: str
message you want to print out
syntax: <message>
example: "info message"
:param _format_values: dict, optional
dictionary with own format values
syntax: {<key>: <value>}
example: {"mytext": "This is my text"}
NOTE: if you use '_format_values' the in function '_format' given format values won't used
:return: None
:since: 0.1.0
"""
if _format_values is None:
print(self.format.format(**self._format(levelname="INFO", message=msg)))
else:
print(self.format.format(**_format_values))
def warning(self, msg: str, _format_values: dict = None) -> None:
"""
prints given format with 'warning' levelname and in 'msg' given message
:param msg: str
message you want to print out
syntax: <message>
example: "warning message"
:param _format_values: dict, optional
dictionary with own format values
syntax: {<key>: <value>}
example: {"mytext": "This is my text"}
NOTE: if you use '_format_values' the in function '_format' given format values won't used
:return: None
:since: 0.1.0
"""
if _format_values is None:
print(self.format.format(**self._format(levelname="WARNING", message=msg)))
else:
print(self.format.format(**_format_values))
class LogFile:
"""
a simple logger for files
:since: 0.1.0
"""
def __init__(self, log_fname: str, mode: str = "a", format: str = "[{year}-{month}-{day} {hour}:{minute}:{second}] - {filename}(line: {lineno}) - {levelname}: {message}") -> None:
"""
:param log_fname: str
filename of the file to which the logging messages should be saved
syntax: <fname>
example: "/home/pi/test.log"
:param mode: str, optional
mode to write on file
syntax: <mode>
example: "a"
:param format: str, optional
format of the output that should be write to file
syntax: <format>
example: [{runtime}] - {filename}(line: {lineno}) - {levelname}: {message}
NOTE: in 'format' you can use the following curly bracktes:
year gives the year back
month gives the month back
day gives the day back
hour gives the hour back
minute gives the minute back
second gives the second back
microsecond gives the microsecond back
runtime gives the back since the logger has started
levelname gives the levelname back
filename gives the name of the file from which the logger is called back
lineno gives the line number back from which the levelname function was called
function gives the function back from which the levelname function was called
message gives the in levelname function given message back
:return: None
:since: 0.1.0
"""
from datetime import datetime
from inspect import getframeinfo, stack
self.format = format
self.log_fname = log_fname
self.mode = mode
self._caller_infos = getframeinfo(stack()[1][0])
self._date = datetime.now()
self._start_time = _time()
def _format(self, levelname: str, message: str) -> dict:
"""
returns a dict with custom entries
:param levelname: str
name of the level
syntax: <levelname>
example: "INFO"
:param message: str
message in the dict
syntax: <message>
example: "Test message"
:return: dict
syntax: {"year": <year>,
"month": <month>,
"day": <day>,
"hour": <hour>,
"minute": <minute>,
"second": <second>,
"microsecond": <microsecond>,
"runtime": <runtime>,
"levelname": <level name>,
"filename": <filename>,
"lineno": <line number>,
"function": <function>,
"message": <message>}
example: {"year": 2000,
"month": 1,
"day": 1,
"hour": 00,
"minute": 00,
"second": 00,
"microsecond": 00000,
"runtime": "01:23:45",
"levelname": "INFO",
"filename": "abc.py",
"lineno": 123,
"function": "test_function",
"message": "This is a test message"}
:since: 0.1.0
"""
return {"year": self._date.year, "month": self._date.month, "day": self._date.day, "hour": self._date.hour, "minute": self._date.minute, "second": self._date.second, "microsecond": self._date.microsecond,
"runtime": self._runtime(), "levelname": levelname, "filename": self._caller_infos.filename, "lineno": self._caller_infos.lineno, "function": self._caller_infos.function, "message": message}
def _runtime(self) -> str:
"""
returns the runtime
:return: str
returns the runtime
syntax: <hour>:<minute>:<day>
example: "01:23:45"
:since: 0.1.0
"""
second = int(_time() - self._start_time)
minute = 0
hour = 0
while (second / 60) >= 1:
minute += 1
second -= 60
while (minute / 60) >= 1:
hour += 1
minute -= 60
if len(str(second)) == 1:
second = "0" + str(second)
if len(str(minute)) == 1:
minute = "0" + str(minute)
if len(str(hour)) == 1:
hour = "0" + str(hour)
return str(str(hour) + ":" + str(minute) + ":" + str(second))
def _write(self, msg: str) -> None:
"""
writes the given message to the log file
:param msg: str
message that should be write to the file
syntax: <message>
example: "Test message"
:return: None
:since: 0.1.0
"""
with open(self.log_fname, self.mode) as file:
file.write(msg + "\n")
file.close()
def critical(self, msg: str, _format_values: dict = None) -> None:
"""
writes given format with 'critical' levelname and in 'msg' given message to file
:param msg: str
message you want to write to file
syntax: <message>
example: "critical message"
:param _format_values: dict, optional
dictionary with own format values
syntax: {<key>: <value>}
example: {"mytext": "This is my text"}
NOTE: if you use '_format_values' the in function '_format' given format values won't used
:return: None
:since: 0.1.0
"""
if _format_values is None:
self._write(self.format.format(**self._format(levelname="CRITICAL", message=msg)))
else:
self._write(self.format.format(**_format_values))
def debug(self, msg: str, _format_values: dict = None) -> None:
"""
writes given format with 'debug' levelname and in 'msg' given message to file
:param msg: str
message you want to write to file
syntax: <message>
example: "debug message"
:param _format_values: dict, optional
dictionary with own format values
syntax: {<key>: <value>}
example: {"mytext": "This is my text"}
NOTE: if you use '_format_values' the in function '_format' given format values won't used
:return: None
:since: 0.1.0
"""
if _format_values is None:
self._write(self.format.format(**self._format(levelname="DEBUG", message=msg)))
else:
self._write(self.format.format(**_format_values))
def error(self, msg: str, _format_values: dict = None) -> None:
"""
writes given format with 'debug' levelname and in 'msg' given message to file
:param msg: str
message you want to write to file
syntax: <message>
example: "debug message"
:param _format_values: dict, optional
dictionary with own format values
syntax: {<key>: <value>}
example: {"mytext": "This is my text"}
NOTE: if you use '_format_values' the in function '_format' given format values won't used
:return: None
:since: 0.1.0
"""
if _format_values is None:
self._write(self.format.format(**self._format(levelname="ERROR", message=msg)))
else:
self._write(self.format.format(**_format_values))
def info(self, msg: str, _format_values: dict = None) -> None:
"""
writes given format with 'info' levelname and in 'msg' given message to file
:param msg: str
message you want to write to file
syntax: <message>
example: "info message"
:param _format_values: dict, optional
dictionary with own format values
syntax: {<key>: <value>}
example: {"mytext": "This is my text"}
NOTE: if you use '_format_values' the in function '_format' given format values won't used
:return: None
:since: 0.1.0
"""
if _format_values is None:
self._write(self.format.format(**self._format(levelname="INFO", message=msg)))
else:
self._write(self.format.format(**_format_values))
def warning(self, msg: str, _format_values: dict = None) -> None:
"""
writes given format with 'warning' levelname and in 'msg' given message to file
:param msg: str
message you want to write to file
syntax: <message>
example: "warning message"
:param _format_values: dict, optional
dictionary with own format values
syntax: {<key>: <value>}
example: {"mytext": "This is my text"}
NOTE: if you use '_format_values' the in function '_format' given format values won't used
:return: None
:since: 0.1.0
"""
if _format_values is None:
self._write(self.format.format(**self._format(levelname="WARNING", message=msg)))
else:
self._write(self.format.format(**_format_values))

View File

@ -0,0 +1,910 @@
#!/usr/bin/python3
try:
from .utils import aion_data_path as _aion_data_path, BaseXMLReader as _BaseXMLReader
except ImportError:
from utils import aion_data_path as _aion_data_path, BaseXMLReader as _BaseXMLReader
RUN_AFTER = "run_after"
RUN_BEFORE = "run_after"
run_after_path = _aion_data_path + "/plugins/run_after"
run_before_path = _aion_data_path + "/plugins/run_before"
run_after_file = _aion_data_path + "/plugins/run_after/run_after.xml"
run_before_file = _aion_data_path + "/plugins/run_before/run_before.xml"
class RunAfter:
"""
base class to create custom 'run_after' plugins
:since: 0.1.0
"""
def __init__(self, activate_phrase: str, speech_input: str) -> None:
"""
makes the variables available for all class functions
:param activate_phrase: str
activate phrase from which this class was called
syntax: <activate phrase>
example: "start plugin test"
:param speech_input: str
input that the user has spoken in
syntax: <speech input>
example: "start plugin test"
:return: None
:since: 0.1.0
"""
self.activate_phrase = activate_phrase
self.speech_input = speech_input
def main(self) -> None:
"""
gets called if the class get called from the 'run_after_plugin' plugin of the 'Skill' class
:return: None
:since: 0.1.0
"""
pass
class RunBefore:
"""
base class to create custom 'run_before' plugins
:since: 0.1.0
"""
def __init__(self, activate_phrase: str, speech_input: str) -> None:
"""
makes the variables available for all class functions
:param activate_phrase: str
activate phrase from which this class was called
syntax: <activate phrase>
example: "start plugin test"
:param speech_input: str
input that the user has spoken in
syntax: <speech input>
example: "start plugin test"
:return: None
:since: 0.1.0
"""
self.activate_phrase = activate_phrase
self.speech_input = speech_input
def main(self) -> None:
"""
gets called if the class get called from the 'run_before_plugin' function of the 'Skill' class
:return: None
:since: 0.1.0
"""
pass
def create_run_after_plugin_file(author: str,
plugin_name: str,
main_file: str,
skill: str,
plugin_methods: dict,
version: str,
additional_directories: list = [],
description: str = "",
language_locales: list = [],
language_dict: dict = {},
license: str = "",
required_python3_packages: list = []) -> None:
"""
creates a file from which a 'run_after' plugin can be installed
:param author: str
name of the author from the plugin
syntax: <author name>
example: "blueShard"
:param main_file: str
file name of file where all plugin methods are defined
syntax: <file name>
example: "test.py"
NOTE: the file must be in the same directory as the file from which 'create_run_after_plugin_file' is being executed
:param plugin_name: str
root name of the plugin you create
syntax: <plugin name>
example: "text_plugin"
:param skill: str
name of the skill you want to add the 'run_before' plugin
syntax: <skill name>
example: "Play"
NOTE: be case-sensitive!
:param plugin_methods: dict
dictionary of plugin pseudonym with plugin method you want to add to given 'skill'
syntax: {"<plugin pseudonym>": <plugin methods>}
example: ["test_plugin_run_test_2": "TestPlugin"]
NOTE: be case-sensitive!
NOTE2: the plugins pseudonyms are only pseudonyms for the given methods
NOTE3: you can't remove individual plugins via the 'aion' command line command
:param version: str
version (number) of your plugin
syntax: <version>
example: "1.0.0"
:param additional_directories: list, optional
list of additional directories your main file needs for execution
syntax: [<additional directories>]
example: ["test_directory"]
NOTE: the directories must be in the same directory as the file from which 'create_run_after_plugin_file' is being executed
:param description: str, optional
description of your plugin
syntax: <description>
example: "A simple plugin to test the method 'create_run_after_plugin_file'"
:param language_locales: list
list of language locales for which the 'language_dict' should be stored
syntax: [<language locale>]
example: ["en_US"]
:param language_dict: dict, optional
dictionary of messages which are saved in (from argument 'language_locales' given) '.lng' files
syntax: {<entry>, <text>}
example: {"test_entry": "The test was successful"}
NOTE: the method name should be included in the entry for legibility
NOTE2: for more infos about language ('.lng') files, see file 'language.py'
:param license: str, optional
license of the plugin
syntax: <license>
example: "MPL-2.0"
:param required_python3_packages: list, optional
list of python3 packages your plugin needs for correct execution
syntax: [<python3 package>]
example: ["aionlib"]
:return: None
:since: 0.1.0
"""
_create_befater_plugin_file("run_after",
author,
plugin_name,
main_file,
skill,
plugin_methods,
version,
additional_directories,
description,
language_locales,
language_dict,
license,
required_python3_packages)
def create_run_before_plugin_file(author: str,
plugin_name: str,
main_file: str,
skill: str,
plugin_methods: dict,
version: str,
additional_directories: list = [],
description: str = "",
language_locales: list = [],
language_dict: dict = {},
license: str = "",
required_python3_packages: list = []) -> None:
"""
creates a file from which a 'run_before' plugin can be installed
:param author: str
name of the author from the plugin
syntax: <author name>
example: "blueShard"
:param main_file: str
file name of file where all plugin methods are defined
syntax: <file name>
example: "test.py"
NOTE: the file must be in the same directory as the file from which 'create_run_before_plugin_file' is being executed
:param plugin_name: str
root name of the plugins you create
syntax: <plugin name>
example: "text_plugin"
:param skill: str
name of the skill you want to add the 'run_before' plugin
syntax: <skill name>
example: "Play"
NOTE: be case-sensitive!
:param plugin_methods: dict
dictionary of plugin pseudonym with plugin method you want to add to given 'skill'
syntax: {"<plugin pseudonyms>": <plugin methods>}
example: ["test_plugin_run_test_2": "TestPlugin"]
NOTE: be case-sensitive!
NOTE2: the plugins pseudonyms are only pseudonyms for the given methods
NOTE3: you can't remove individual plugins via the 'aion' command line command
:param plugin_name: str
name of the plugin you create
syntax: <plugin name>
example: "text_plugin"
:param version: str
version (number) of your plugin
syntax: <version>
example: "1.0.0"
:param additional_directories: list, optional
list of additional directories your main file needs for execution
syntax: [<additional directories>]
example: ["test_directory"]
NOTE: the directories must be in the same directory as the file from which 'create_run_before_plugin_file' is being executed
:param description: str, optional
description of your plugin
syntax: <description>
example: "A simple plugin to test the method 'create_run_after_plugin_file'"
:param language_locales: list
list of language locales for which the 'language_dict' should be stored
syntax: [<language locale>]
example: ["en_US"]
:param language_dict: dict, optional
dictionary of messages which are saved in (from argument 'language_locales' given) '.lng' files
syntax: {<entry>, <text>}
example: {"test_entry": "The test was successful"}
NOTE: the method name should be included in the entry for legibility
NOTE2: for more infos about language ('.lng') files, see file 'language.py'
:param license: str, optional
license of the plugin
syntax: <license>
example: "MPL-2.0"
:param required_python3_packages: list, optional
list of python3 packages your plugin needs for correct execution
syntax: [<python3 package>]
example: ["aionlib"]
:return: None
:since: 0.1.0
"""
_create_befater_plugin_file("run_before",
author,
plugin_name,
main_file,
skill,
plugin_methods,
version,
additional_directories,
description,
language_locales,
language_dict,
license,
required_python3_packages)
def create_plugin_package(dir_name: str) -> None:
"""
creates a stand alone file ('.plugin') from given directory
:param dir_name: str
directory name of the directory from which you want to create a '.plugin' file
syntax: <directory name>
example: "/home/pi/test/"
:return: None
:note: 'plugin.aion' file must be in the given directory (see 'create_run_after_plugin_file' / 'create_run_before_plugin_file' to create a 'plugin.aion' file)
:since: 0.1.0
"""
try:
from ._error_codes import plugin_aion_plugin_file_not_found, plugin_to_much_aion_files
except ImportError:
from _error_codes import plugin_aion_plugin_file_not_found, plugin_to_much_aion_files
from os import listdir, mkdir, rename
from os.path import isdir
from random import sample
from shutil import make_archive, rmtree
if isdir(dir_name) is False:
raise NotADirectoryError("couldn't find the directory '" + dir_name + "'")
name = ""
file_num = 0
for file in listdir(dir_name):
if file.endswith(".aion"):
file_num += 1
name = "".join(file.split(".aion")[0])
if file_num == 0:
raise FileNotFoundError("Errno: " + plugin_aion_plugin_file_not_found + " - Couldn't find .aion file in " + dir_name + ". To create one use the 'create_plugin_file' function in aionlib.skill")
elif file_num > 1:
raise FileExistsError("Errno: " + plugin_to_much_aion_files + " - Expected one .aion file in " + dir_name + ", got " + str(file_num))
plugin_dir_name = "plugin_" + name + "".join([str(num) for num in sample(range(1, 10), 5)])
mkdir(plugin_dir_name)
make_archive(name + ".plugin", "zip", plugin_dir_name)
rename(plugin_dir_name + ".plugin.zip", plugin_dir_name + ".plugin")
rmtree(plugin_dir_name)
def execute_aion_file_type_plugin(fname: str) -> None:
"""
installs custom plugin from '<file name>.aion'
:param fname: str
file name of the '.aion' file
syntax: <file name>
example: "/home/pi/plugin.aion"
:return: None
:since: 0.1.0
"""
try:
from ._errors import plugin_couldnt_find_key, plugin_couldnt_find_plugin_type, plugin_illegal_run_after_pseudonym, plugin_run_after_pseudonym_already_exist,\
plugin_illegal_run_before_pseudonym, plugin_run_before_pseudonym_already_exist, plugin_file_doesnt_exist_in_setup_dir, plugin_directory_doesnt_exist_in_setup_dir,\
plugin_run_after_additional_directories_already_exist, plugin_run_before_additional_directories_already_exist, plugin_python3_module_not_found
from .acph import add_acph
from .language import add_entry, language_directory
from .utils import remove_space, BaseXMLReader, BaseXMLWriter
except ImportError:
from _error_codes import plugin_couldnt_find_key, plugin_couldnt_find_plugin_type, plugin_illegal_run_after_pseudonym, plugin_run_after_pseudonym_already_exist,\
plugin_illegal_run_before_pseudonym, plugin_run_before_pseudonym_already_exist, plugin_file_doesnt_exist_in_setup_dir, plugin_directory_doesnt_exist_in_setup_dir,\
plugin_run_after_additional_directories_already_exist, plugin_run_before_additional_directories_already_exist, plugin_python3_module_not_found
from acph import add_acph
from language import add_entry, language_directory
from utils import remove_space, BaseXMLReader, BaseXMLWriter
from ast import literal_eval
from importlib import import_module
from os import listdir, path
from shutil import copy, copytree
from subprocess import call
setup_dict = {}
setup_dir = path.dirname(path.abspath(fname))
plugin_type = ""
is_skill = True
for line in open(fname, "r"):
if line.startswith("#"):
no_space_line = remove_space(line, "")
if no_space_line == "#type:run_after_plugin":
plugin_type = RUN_AFTER
elif no_space_line == "#type:run_before_plugin":
plugin_type = RUN_BEFORE
continue
setup_dict[line.split("=")[0].strip()] = line.split("=")[1].strip()
try:
author = setup_dict["author"]
main_file = setup_dict["main_file"]
plugin_name = setup_dict["plugin_name"]
skill = setup_dict["skill"]
plugin_methods = literal_eval(setup_dict["plugin_methods"])
version = setup_dict["version"]
additional_directories = literal_eval(setup_dict["additional_directories"])
description = setup_dict["description"]
language_locales = literal_eval(setup_dict["language_locales"])
language_dict = literal_eval(setup_dict["language_dict"])
license = setup_dict["license"]
required_python3_packages = literal_eval(setup_dict["required_python3_packages"])
except KeyError as error:
raise KeyError("Errno: " + plugin_couldnt_find_key + " - Couldn't find key " + str(error) + " in " + fname)
if plugin_type != RUN_AFTER or plugin_type != RUN_BEFORE:
raise NameError("Errno: " + plugin_couldnt_find_plugin_type + " - Couldn't find plugin type ('RUN_AFTER' or 'RUN_BEFORE') in " + fname)
# ----- #
if plugin_type == RUN_AFTER:
for pseudonym in plugin_methods:
if pseudonym == "run_after":
raise NameError("Errno: " + plugin_illegal_run_after_pseudonym + " - Illegal name '" + pseudonym + "' in " + str(plugin_methods))
try:
if pseudonym in get_all_run_after_plugins()[skill]:
raise NameError("Errno: " + plugin_run_before_pseudonym_already_exist + " - The plugin pseudonym " + plugin_name + " already exist")
except KeyError:
is_skill = False
pass
elif plugin_type == RUN_BEFORE:
for pseudonym in plugin_methods:
if pseudonym == "run_before":
raise NameError("Errno: " + plugin_illegal_run_before_pseudonym + " - Illegal name '" + pseudonym + "' in " + str(plugin_methods))
try:
if pseudonym in get_all_run_before_plugins()[skill]:
raise NameError("Errno: " + plugin_run_after_pseudonym_already_exist + " - The plugin pseudonym " + plugin_name + " already exist")
except KeyError:
is_skill = False
pass
if path.isfile(setup_dir + "/" + main_file) is False:
raise FileNotFoundError("Errno: " + plugin_file_doesnt_exist_in_setup_dir + " - The file " + main_file + " doesn't exist in setup dir (" + setup_dir + ")")
for directory in additional_directories:
if path.isdir(setup_dir + "/" + directory) is False:
raise NotADirectoryError("Errno: " + plugin_directory_doesnt_exist_in_setup_dir + " - The directory " + directory + " doesn't exist in setup dir (" + setup_dir + ")")
if plugin_type == RUN_AFTER:
if directory in listdir(run_after_path):
raise IsADirectoryError("Errno: " + plugin_run_after_additional_directories_already_exist + " - The directory " + directory + " already exist in " + run_after_path)
elif plugin_type == RUN_BEFORE:
if directory in listdir(run_before_path):
raise IsADirectoryError("Errno: " + plugin_run_before_additional_directories_already_exist + " - The directory " + directory + " already exist in " + run_before_path)
# ----- #
for package in required_python3_packages:
call("pip3 install " + package, shell=True)
try:
import_module(package)
except ModuleNotFoundError:
raise ModuleNotFoundError("Errno: " + plugin_python3_module_not_found + " - Couldn't install the required python3 package '" + package + "'")
dat_writer = None
if plugin_type == RUN_AFTER:
copy(main_file, run_after_path + "/" + main_file)
for directory in additional_directories:
copytree(directory, run_after_path + "/" + directory)
for language in language_locales:
add_entry(language, plugin_name, language_dict)
dat_writer = BaseXMLWriter(run_after_file)
if is_skill is False:
dat_writer.add("run_after", skill, type="skill")
dat_writer.write()
elif plugin_type == RUN_BEFORE:
copy(main_file, run_after_path + "/" + main_file)
for directory in additional_directories:
copytree(directory, run_after_path + "/" + directory)
for language in language_locales:
add_entry(language, plugin_name, language_dict)
dat_writer = BaseXMLWriter(run_before_file)
if is_skill is False:
dat_writer.add("run_before", skill, type="skill")
dat_writer.write()
for pseudonym, method in plugin_methods.values():
dat_writer.add(skill, str(pseudonym), parent_attrib={"type": "skill"}, method=method, root_plugin=plugin_name)
dat_writer.add(str(pseudonym), "additional_directories", str(additional_directories))
dat_writer.add(str(pseudonym), "author", str(author))
dat_writer.add(str(pseudonym), "description", str(description))
dat_writer.add(str(pseudonym), "language_dict", str(language_dict))
dat_writer.add(str(pseudonym), "language_locales", str(language_locales))
dat_writer.add(str(pseudonym), "license", str(license))
dat_writer.add(str(pseudonym), "main_file", str(main_file))
dat_writer.add(str(pseudonym), "required_python3_packages", str(required_python3_packages))
dat_writer.add(str(pseudonym), "version", str(version))
dat_writer.write()
def execute_plugin_file(fname: str) -> None:
"""
executes a '<name>.plugin' file for installing custom plugins
:param fname: str
file name of the '.plugin' file
syntax: <fname>
example: "/home/pi/test.plugin"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import plugin_couldnt_find_plugin_dot_aion
except ImportError:
from _error_codes import plugin_couldnt_find_plugin_dot_aion
from glob import glob
from os.path import isfile
from zipfile import ZipFile
with ZipFile(fname, "r") as zipfile:
zipfile.extractall("/tmp")
zipfile.close()
if isfile(glob("/tmp/plugin_*/plugin.aion")[0]) is False:
raise FileNotFoundError("Errno: " + plugin_couldnt_find_plugin_dot_aion + "couldn't find 'plugin.aion' in " + fname)
else:
execute_aion_file_type_plugin(glob("/tmp/plugin_*/plugin.aion")[0])
def get_all_run_after_plugins() -> dict:
"""
get all installed 'run_after' plugins + infos
:return: dict
returns dict of all plugins + infos
:since: 0.1.0
"""
try:
from .utils import is_dict_in_dict
except ImportError:
from utils import is_dict_in_dict
run_after = {}
for value in _BaseXMLReader(run_after_file).get_infos("<all>").values():
for child in value:
attrib = child["attrib"]
parent_tag = child["parent"]["tag"]
parent_attrib = child["parent"]["attrib"]
if is_dict_in_dict({"type": "skill"}, parent_attrib):
try:
run_after[parent_tag][child["tag"]] = {"method": attrib["method"], "root_plugin": attrib["root_plugin"]}
except KeyError:
run_after[parent_tag] = {}
else:
for skill in run_after.values():
for plugin in skill:
if plugin == parent_tag:
run_after[skill][plugin][child["tag"]] = child["text"]
break
return run_after
def get_all_run_before_plugins() -> dict:
"""
get all installed 'run_before' plugins + infos
:return: dict
returns dict of all plugins + infos
:since: 0.1.0
"""
try:
from .utils import is_dict_in_dict
except ImportError:
from utils import is_dict_in_dict
run_before = {}
for value in _BaseXMLReader(run_before_file).get_infos("<all>").values():
for child in value:
attrib = child["attrib"]
parent_tag = child["parent"]["tag"]
parent_attrib = child["parent"]["attrib"]
if is_dict_in_dict({"type": "skill"}, parent_attrib):
try:
run_before[parent_tag][child["tag"]] = {"method": attrib["method"], "root_plugin": attrib["root_plugin"]}
except KeyError:
run_before[parent_tag] = {}
else:
for skill in run_before.values():
for plugin in skill:
if plugin == parent_tag:
run_before[skill][plugin][child["tag"]] = child["text"]
break
return run_before
def get_run_after_plugin_infos(plugin_name: str) -> dict:
"""
returns infos about an given 'run_after' plugin
:param plugin_name: str
the name of the 'run_after' plugin
syntax: <plugin name>
example: "test_plugin"
:return: dict
returns a dictionary with infos of the 'run_after' plugin
syntax: {"author": <author>,
"main_file": <main file>,
"plugin_root_name": <plugin root name>
"plugin_name": <plugin name>,
"plugin_method": <plugin method>
"version": <version>,
"additional_directories": [<additional directories>],
"description": <description>,
"language_locales": [<language locales>],
"language_dict": {<entry>: <text>}
"license": <license>,
"required_python3_packages": [<python3 packages>]}
example: {"author": "blueShard",
"main_file": "test.py",
"plugin_root_name:": "test_plugin"
"plugin_name": "test_plugin_run_after",
"plugin_method": "test_plugin_method"
"version": "1.0.0",
"additional_directories": ["test_directory"],
"description": "A simple plugin to test the method 'get_run_after_plugin_infos",
"language_locales": ["en_US"],
"language_dict": {"test_method": "The test was successful"},
"license": "MPL-2.0",
"required_python3_packages": ["aionlib"]}
:since: 0.1.0
"""
for skill in get_all_run_after_plugins().values():
for plugin, infos in skill.values():
if plugin == plugin_name:
return infos
def get_run_before_plugin_infos(plugin_name: str) -> dict:
"""
returns infos about an given 'run_before' plugin
:param plugin_name: str
the name of the 'run_after' plugin
syntax: <plugin name>
example: "test_plugin"
:return: dict
returns a dictionary with infos of the 'run_after' plugin
syntax: {"author": <author>,
"main_file": <main file>,
"plugin_root_name": <plugin root name>
"plugin_name": <plugin name>,
"plugin_method": <plugin method>
"version": <version>,
"additional_directories": [<additional directories>],
"description": <description>,
"language_locales": [<language locales>],
"language_dict": {<entry>: <text>}
"license": <license>,
"required_python3_packages": [<python3 packages>]}
example: {"author": "blueShard",
"main_file": "test.py",
"plugin_root_name:": "test_plugin"
"plugin_name": "test_plugin_run_before",
"plugin_method": "test_plugin_method"
"version": "1.0.0",
"additional_directories": ["test_directory"],
"description": "A simple plugin to test the method 'get_run_before_plugin_infos",
"language_locales": ["en_US"],
"language_dict": {"test_method": "The test was successful"},
"license": "MPL-2.0",
"required_python3_packages": ["aionlib"]}
:since: 0.1.0
"""
for skill in get_all_run_before_plugins().values():
for plugin, infos in skill.values():
if plugin == plugin_name:
return infos
def remove_plugin(plugin_name: str, plugin_type: (RUN_AFTER, RUN_BEFORE)) -> None:
"""
removes given plugin
:param plugin_name: str
name of the plugin you want to remove
syntax: <plugin name>
example: "test"
:param plugin_type: (RUN_AFTER, RUN_BEFORE)
type of the plugin
syntax: <plugin type>
example: RUN_AFTER
:since: 0.1.0
"""
try:
from .language import language_directory, delete_entry
from .utils import BaseXMLReader, BaseXMLWriter
except ImportError:
from language import language_directory, delete_entry
from utils import BaseXMLReader, BaseXMLWriter
from ast import literal_eval
from os import remove as remove
from shutil import rmtree
if plugin_type == RUN_AFTER:
plugin_infos = get_run_after_plugin_infos(plugin_name)
remove(run_after_path + "/" + plugin_infos["main_file"])
for dir in plugin_infos["additional_directories"]:
rmtree(run_after_path + "/" + dir)
for language in plugin_infos["language_locales"]:
delete_entry(language, plugin_name, entry_list=[key.replace(" ", "_") for key in literal_eval(plugin_infos["language_dict"])])
remove_xml = BaseXMLWriter(run_after_file)
remove_xml.remove(plugin_infos["method"], plugin_name)
remove_xml.write()
def _create_befater_plugin_file(type: (RUN_AFTER, RUN_BEFORE),
author: str,
plugin_name: str,
main_file: str,
skill: str,
plugin_methods: dict,
version: str,
additional_directories: list = [],
description: str = "",
language_locales: list = [],
language_dict: dict = {},
license: str = "",
required_python3_packages: list = []) -> None:
"""
creates a file from which a plugin can be installed
:param type: (RUN_AFTER, RUN_BEFORE)
type of the plugin
syntax: <plugin type>
example: RUN_AFTER
:param author: str
name of the author from the plugin
syntax: <author name>
example: "blueShard"
:param main_file: str
file name of file where all plugin methods are defined
syntax: <file name>
example: "test.py"
NOTE: the file must be in the same directory as the file from which 'create_run_after_plugin_file' is being executed
:param plugin_name: str
root name of the plugin you create
syntax: <plugin name>
example: "text_plugin"
:param skill: str
name of the skill you want to add the 'run_before' plugin
syntax: <skill name>
example: "Play"
NOTE: be case-sensitive!
:param plugin_methods: dict
dictionary of plugin pseudonym with plugin method you want to add to given 'skill'
syntax: {"<plugin pseudonym>": <plugin methods>}
example: ["test_plugin_run_test_2": "TestPlugin"]
NOTE: be case-sensitive!
NOTE2: the plugins pseudonyms are only pseudonyms for the given methods
NOTE3: you can't remove individual plugins via the 'aion' command line command
:param version: str
version (number) of your plugin
syntax: <version>
example: "1.0.0"
:param additional_directories: list, optional
list of additional directories your main file needs for execution
syntax: [<additional directories>]
example: ["test_directory"]
NOTE: the directories must be in the same directory as the file from which 'create_run_after_plugin_file' is being executed
:param description: str, optional
description of your plugin
syntax: <description>
example: "A simple plugin to test the method 'create_run_after_plugin_file'"
:param language_locales: list
list of language locales for which the 'language_dict' should be stored
syntax: [<language locale>]
example: ["en_US"]
:param language_dict: dict, optional
dictionary of messages which are saved in (from argument 'language_locales' given) '.lng' files
syntax: {<entry>, <text>}
example: {"test_entry": "The test was successful"}
NOTE: the method name should be included in the entry for legibility
NOTE2: for more infos about language ('.lng') files, see file 'language.py'
:param license: str, optional
license of the plugin
syntax: <license>
example: "MPL-2.0"
:param required_python3_packages: list, optional
list of python3 packages your plugin needs for correct execution
syntax: [<python3 package>]
example: ["aionlib"]
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import plugin_author_must_be_str, plugin_plugin_name_must_be_str, plugin_main_file_must_be_str, plugin_main_file_not_found, plugin_main_file_name_must_be_plugin_name,\
plugin_skill_must_be_dict, plugin_plugin_methods_must_be_dict, plugin_version_must_be_str, plugin_additional_directories_must_be_list_or_tuple,\
plugin_couldnt_find_additional_directories_directory, plugin_description_must_be_str, plugin_language_locales_must_be_list_or_tuple, plugin_language_dict_must_be_dict,\
plugin_language_dict_character_must_be_in_alphabet, plugin_license_must_be_str, plugin_required_python3_package_must_be_list_or_tuple
except ImportError:
from _error_codes import plugin_author_must_be_str, plugin_plugin_name_must_be_str, plugin_main_file_must_be_str, plugin_main_file_not_found, plugin_main_file_name_must_be_plugin_name,\
plugin_skill_must_be_dict, plugin_plugin_methods_must_be_dict, plugin_version_must_be_str, plugin_additional_directories_must_be_list_or_tuple,\
plugin_couldnt_find_additional_directories_directory, plugin_description_must_be_str, plugin_language_locales_must_be_list_or_tuple, plugin_language_dict_must_be_dict,\
plugin_language_dict_character_must_be_in_alphabet, plugin_license_must_be_str, plugin_required_python3_package_must_be_list_or_tuple
from os import getcwd, listdir
write_dict = {}
if isinstance(author, str) is False:
raise TypeError("Errno: " + plugin_author_must_be_str + " - Argument 'author' must be str, got " + type(author).__name__)
write_dict["author"] = author
if isinstance(plugin_name, str) is False:
raise TypeError("Errno: " + plugin_plugin_name_must_be_str + " - Argument 'plugin_name' must be str, got " + type(plugin_name).__name__)
write_dict["plugin_name"] = plugin_name
if isinstance(main_file, str) is False:
raise TypeError("Errno: " + plugin_main_file_must_be_str + " - argument 'main_file' must be str, got " + type(author).__name__)
if main_file not in listdir(getcwd()):
raise FileNotFoundError("Errno: " + plugin_main_file_not_found + " - Couldn't find the file " + main_file + " in current directory")
if main_file[:-3] == plugin_name is False:
raise NameError("Errno: " + plugin_main_file_name_must_be_plugin_name + " - The file name from " + main_file + " must be same as the argument 'plugin_name' (" + plugin_name + ")")
write_dict["main_file"] = main_file
if isinstance(skill, str) is False:
raise TypeError("Errno: " + plugin_skill_must_be_dict + " - Argument 'skill' must be dict, got " + type(plugin_methods).__name__)
write_dict["skill"] = skill
if isinstance(plugin_methods, dict) is False:
raise TypeError("Errno: " + plugin_plugin_methods_must_be_dict + " - Argument 'plugin_methods' must be dict, got " + type(plugin_methods).__name__)
write_dict["plugin_methods"] = plugin_methods
if isinstance(version, str) is False:
raise TypeError("Errno: " + plugin_version_must_be_str + " - Argument 'version' must be str, got " + type(version).__name__)
write_dict["version"] = version
# ----- #
if isinstance(additional_directories, (list, tuple)) is False:
raise TypeError("Errno: " + plugin_additional_directories_must_be_list_or_tuple + " - Argument 'additional_directories' must be list or tuple, got " + type(additional_directories).__name__)
for directory in additional_directories:
if directory not in listdir(getcwd()):
raise NotADirectoryError("Errno: " + plugin_couldnt_find_additional_directories_directory + " - Couldn't find the directory " + directory + " in current directory")
write_dict["additional_directories"] = additional_directories
if isinstance(description, str) is False:
raise TypeError("Errno: " + plugin_description_must_be_str+ " - Argument 'description' must be str, got " + type(description).__name__)
write_dict["description"] = description
if isinstance(language_locales, (list, tuple)) is False:
raise TypeError("Errno: " + plugin_language_locales_must_be_list_or_tuple + " - Argument 'language_locales' must be list or tuple, got " + type(language_locales).__name__)
write_dict["language_locales"] = language_locales
if isinstance(language_dict, dict) is False:
raise TypeError("Errno: " + plugin_language_locales_must_be_list_or_tuple + " - Argument 'language_dict' must be dict, got " + type(language_dict).__name__)
for key in language_dict.keys():
tmp_string = ""
for char in key:
if char == " ":
char = "_"
if char.lower() not in "abcdefghijklmnopqrstuvwxyz_":
raise ValueError("Errno: " + plugin_language_dict_character_must_be_in_alphabet + " - Letter " + str(char) + " in " + str(key) + " must be in 'ABCDEFGHIJLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz_'")
tmp_string = tmp_string + char
language_dict[tmp_string] = language_dict.pop(key)
write_dict["language_dict"] = language_dict
if isinstance(license, str) is False:
raise TypeError("Errno: " + plugin_license_must_be_str + " - Argument 'license' must be str, got " + type(license).__name__)
write_dict["license"] = license
if isinstance(required_python3_packages, (list, tuple)) is False:
raise TypeError("Errno: " + plugin_required_python3_package_must_be_list_or_tuple + " - Argument 'required_python3_packages' must be list or tuple, got " + type(required_python3_packages).__name__)
write_dict["required_python3_packages"] = required_python3_packages
# ----- #
with open("plugin.aion", "w") as file:
file.write("#type: " + type.lower() + "_plugin\n")
for key, value in write_dict.items():
file.write(key + " = " + str(value) + "\n")
file.close()
def _run_befater_plugin(type: (RUN_AFTER, RUN_BEFORE), fname: str, plugin_name: str, activate_phrase: str, speech_input: str) -> None:
"""
runs a plugin
:param type: (RUN_AFTER, RUN_BEFORE)
type of the plugin
syntax: <plugin type>
example: RUN_AFTER
:param fname: str
file path of the plugin file
syntax: <filename>
example: "/home/pi/test.py"
:param plugin_name: str
name of the plugin
syntax: <plugin name>
example: "TestPlugin"
:param activate_phrase: str
activate phrase, which calls the skill class to which the plugin belongs
syntax: <activate phrase>
example: "Start test plugin"
:param speech_input: str
speech input, which calls the skill class to which the plugin belongs
syntax: <speech input>
example: "Start test plugin"
:return: None
:since: 0.1.0
"""
from sys import path
path.insert(1, _aion_data_path + "/" + type.lower())
exec("__import__('" + fname + "')." + plugin_name + "(" + activate_phrase + ", " + speech_input + ").main()")

View File

@ -0,0 +1,91 @@
#!/usr/bin/python3
try:
from .utils import aion_data_path as _aion_data_path
except ImportError:
from utils import aion_data_path as _aion_data_path
save_path = _aion_data_path + "/saves"
def load_save(name: str, current_save_name: str = None) -> None:
"""
loads a saved aion_data
:param name: str
name of the new aion_data save
syntax: "<name>"
example: "test save"
:param current_save_name: str, optional
if not None, the current aion_data get saved under this name
syntax: "<current save name>"
example: "test save2"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import save_save_not_found
except ImportError:
from _error_codes import save_save_not_found
from os import listdir
from shutil import copytree, rmtree
if name not in listdir(save_path):
raise NotADirectoryError("Errno: " + save_save_not_found + " - Couldn't find the save '" + name + "'")
else:
if current_save_name:
save(current_save_name)
rmtree(_aion_data_path)
copytree(save_path + "/" + name, _aion_data_path)
def save(name: str) -> None:
"""
saves the current aion_data directory
:param name: str
name of the save
syntax: "<name>"
example: "test save"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import save_save_name_already_exist
from .utils import BaseXMLWriter
except ImportError:
from _error_codes import save_save_name_already_exist
from utils import BaseXMLWriter
from os import listdir
from shutil import copytree
if name in listdir(save_path):
raise NameError("Errno: " + save_save_name_already_exist + " - The save name '" + name + "' already exists")
else:
copytree(_aion_data_path, save_path + "/" + name)
def saves() -> list:
"""
get all aion_data saves
:return: list
returns a list of the names of the aion_data saves
syntax: [<saves>]
example: ["test save", "test save2"]
:since: 0.1.0
"""
from os import listdir
return_list = []
for file in listdir(save_path):
return_list.append(file)
return return_list

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -0,0 +1,228 @@
#!/usr/bin/python3
from shell_utils import *
import sys
sys.path.insert(0, "..")
help = """
Usage:
aion [command]
Commands:
start starts aion
run runs aion
install <skill / plugin> installs a skill or plugin
uninstall <skill / plugin> uninstalls a skill or plugin
remove <skill / plugin> removes a skill or plugin
update <skill / plugin> updates a skill or plugin
version <skill / plugin> version of a skill or plugin
save <name> saves the current aion_data directory (with a name)
load <version> [name] loads a saved aion_data directory (add optional name to save the current aion_data directory with this name)
saves shows all saved aion_data directory
pid shows the pid from the running aion process
kill kills aion
stop stops aion
pack <custom skill / plugin directory> packs the given directory with a custom skill or plugin into one standalone file for installation
"""
def main():
from argparse import ArgumentParser, RawTextHelpFormatter
import os
parser = ArgumentParser(description="Command line support for the 'aion' project", formatter_class=RawTextHelpFormatter, add_help=False)
parser.add_argument("command", nargs="+")
args = parser.parse_args()
try:
command = args.command[0].strip()
if os.path.isfile(command):
import __init__
__init__.ExecuteAionFile(command)
elif command == "help" or command == "-help" or command == "--help":
print(help)
elif command == "start" or command == "run":
os.system("python3 " + atils.aion_path + "/main.py")
elif command == "install":
errno = "77227"
arglen_check(args.command, 2)
package = args.command[1]
if package == "aion":
must_be_sudo()
Install.aion()
print("Installed aion")
elif package == "respeaker":
must_be_sudo()
Install.respeaker(yesno("Install in compatibility mode? (installs older kernel version)? (y/n): "))
print("Installed respeaker")
elif os.path.exists(package):
if package.strip() == "skill.aion":
Install.skill_from_aion_file(package)
elif package.strip() == "plugin.aion":
Install.plugin_from_aion_file(package)
elif package.endswith(".skill"):
Install.skill_from_skill_file(package)
elif package.endswith(".plugin"):
Install.plugin_from_plugin_file(package)
else:
AionShellError(package + " is an unknowing skill / plugin. Type 'aion help' for help", errno)
else:
AionShellError(package + " is an unknowing skill / plugin. Type 'aion help' for help", errno)
elif args.command in ["kill", "stop"]: # kist
arglen_check(args.command, 1)
is_aion_running(command)
import variable
import signal
avar = variable.Variable()
os.kill(int(avar.get_value("AION_PID")), signal.SIGKILL)
elif command == "load":
arglen_check(args.command, 2, 3)
import save as asave
if len(args.command) == 3:
asave.load_save(str(args.command[1]), str(args.command[2]))
else:
asave.load_save(str(args.command[1]))
elif command == "pack":
no_skill_plugin_file_errno = "27177"
no_dir_errno = "27178"
arglen_check(args.command, 2)
dir = args.command[1]
if os.path.isdir(dir):
if os.path.isfile(dir + "/skill.aion"):
Pack.skill(dir)
elif os.path.isfile(dir + "/plugin.aion"):
Pack.plugin(dir)
else:
AionShellError("couldn't find 'skill.aion' or 'plugin.aion' in " + dir + ". See 'create_skill_file' function in 'aionlib.skill' to create a 'skill.aion' file"
"or 'create_plugin_file' function in 'aionlib.plugin' to create a 'plugin.aion' file", no_skill_plugin_file_errno)
else:
AionShellError("couldn't find directory " + dir, no_dir_errno)
elif command == "pid":
arglen_check(args.command, 1)
is_aion_running(command)
import variable
avar = variable.Variable()
print(avar.get_value("AION_PID"))
elif command == "save":
arglen_check(args.command, 2)
import save as asave
asave.save(args.command[1])
elif command == "saves":
arglen_check(args.command, 1)
import save as asave
print(" ".join(asave.saves()))
elif command in ["remove", "uninstall"]: # UnRem
errno = "07340"
arglen_check(args.command, 2)
package = args.command[1]
if command == "uninstall":
name = "Uninstall"
else:
name = "Remove"
question = yesno(name + " " + package + "? (y/n): ")
if package == "aion":
if question is True:
question = yesno("Should your personal data ('/etc/aion_data/': custom skills / plugins, version saves, language files, ...) deleted as well? (y/n): ")
UnRem.aion(question)
print(name + "ed aion")
print("You should reboot now to complete the " + name.lower() + " process")
elif package == "aionlib":
if question is True:
UnRem.aionlib()
print(name + "ed aionlib")
elif package == "respeaker":
if question is True:
UnRem.respeaker()
print(name + "ed respeaker")
else:
package_type = which_package(package, "Type in the number of your package type: ")
if package_type == -1:
AionShellError("couldn't find skill / plugin " + package, errno)
elif package_type == 0:
UnRem.skill(package)
elif package_type == 1:
UnRem.run_after_plugin(package)
elif package_type == 2:
UnRem.run_before_plugin(package)
elif command in ["run", "start"]:
arglen_check(args.command, 1)
import start
from os import geteuid
if geteuid() == 0:
start(True)
elif geteuid() == 1000:
start(False)
elif command == "update":
errno = "43503"
arglen_check(args.command, 2)
package = args.command[1]
if package == "aion":
Update.aion()
elif package == "aionlib":
Update.aionlib()
else:
package_type = which_package(package, "Type in the number of your package type: ")
if package_type == -1:
AionShellError("couldn't find skill / plugin " + package, errno)
elif package_type == 0:
Update.skill(package)
elif package_type == 1:
Update.run_after_plugin(package)
elif package_type == 2:
Update.run_before_plugin(package)
elif command == "variable":
arglen_check(args.command, 2)
command_variable = args.command[1]
import variable
avar = variable.Variable()
print(avar.get_value(command_variable))
elif command == "version":
errno = "56297"
arglen_check(args.command, 2)
package = args.command[1]
if package == "aion":
Version.aion()
elif package == "aionlib":
Version.aionlib()
else:
package_type = which_package(package, "Type in the number of your package type: ")
if package_type == -1:
AionShellError("couldn't find skill / plugin " + package, errno)
elif package_type == 0:
Version.skill(package)
elif package_type == 1:
Version.run_after_plugin(package)
elif package_type == 2:
Version.run_before_plugin(package)
else:
errno = "12345"
AionShellError(" ".join(args.command) + " isn't a command. Type 'aion help' to get help", errno)
except KeyboardInterrupt:
exit(-1)

View File

@ -0,0 +1,612 @@
#!/usr/bin/python3
import sys
from glob import glob
sys.path.insert(1, glob("/usr/local/aion-*/aion_core/")[0])
import utils as atils
class AionShellError:
"""
base class for errors while using the 'aion' shell command (for the exact identification of the error)
"""
def __init__(self, errormsg: str, errno: str = "00000") -> None:
"""
the error 'function'
:param errormsg: str
message that should be printed out
syntax: <error message>
example: "An example error occured"
:param errno: str
error number
syntax: <error number>
example: "11112"
:return: None
:since: 0.1.0
"""
from colorama import Fore
print(Fore.RED + "AionShellError: [Errno " + str(errno) + "]: " + str(errormsg) + Fore.RESET)
def arglen_check(arg_list: list, arg_len: int, max_arg_len: int = None) -> None:
"""
checks if the length of a list is equal to a given length
:param arg_list: list
list you want to check if the length is equal to the given length
syntax: [<list content>]
example: ["example1", "example2"]
:param arg_len: int
length you want to check
syntax: <length>
example: 2
:param max_arg_len: int
if not None, it checks if the arg list length is between 'arg_len' and 'max_arg_len
syntax: <max length>
example: 4
:return: None
:since: 0.1.0
"""
if max_arg_len is None:
max_arg_len = arg_len
if len(arg_list) < arg_len or len(arg_list) > max_arg_len:
from colorama import Fore
if arg_len == max_arg_len:
if arg_len == 1:
print(Fore.RED + "Expected 1 argument, got " + str(len(arg_list)) + " (" + ", ".join(arg_list) + "). Type 'aion help' for help" + Fore.RESET)
else:
print(Fore.RED + "Expected " + str(arg_len) + " arguments, got " + str(len(arg_list)) + " (" + ", ".join(arg_list) + "). Type 'aion help' for help" + Fore.RESET)
else:
print(Fore.RED + "Expected " + str(arg_len) + " to " + str(max_arg_len) + " arguments, got " + str(len(arg_list)) + " (" + ", ".join(arg_list) + "). Type 'aion help' for help" + Fore.RESET)
exit(-1)
def which_package(package: str, input_sentence: str) -> int:
"""
if a user want to uninstall (or something else) a skill or plugin and there are more than one plugin / skill with this name, this function get called
:param package: str
name of the package
syntax: <package name>
example: "test_package
:param input_sentence: str
sentence the user should be asked for input
syntax: <input sentence>
example: "Type in the number of your package type: "
:return: int
returns the type of the package (0 = skill; 1 = run after plugin; 2 = run before plugin)
syntax: <package type>
example: 2
:since: 0.1.0
"""
from plugin import get_all_run_after_plugins, get_all_run_before_plugins
from skill import get_all_skills
in_package = []
if package in get_all_skills():
in_package.append("Skill: " + str(len(in_package)))
else:
for plugin in get_all_run_after_plugins().values():
if package in plugin:
in_package.append("Run after plugin: " + str(len(in_package)))
for plugin in get_all_run_before_plugins().values():
if package in plugin:
in_package.append("Run before plugin: " + str(len(in_package)))
if len(in_package) == 0:
return -1
elif len(in_package) == 1:
choose = 0
else:
for pa in in_package:
print(pa)
print("Found package '" + str(package) + "' multiple times")
while True:
input_choose = input(input_sentence)
if str(input_choose) not in [str(l) for l in range(len(in_package))]:
print("Your number must be in " + ", ".join([str(l) for l in range(len(in_package))]))
else:
choose = input_choose
break
if in_package[choose].startswith("Skill"):
return 0
elif in_package[choose].startswith("Run after"):
return 1
elif in_package[choose].startswith("Run before"):
return 2
def is_aion_running(command: str) -> None:
"""
checks if aion is running
:param command: str
command that the user has typed in
syntax: <command>
example: "pid"
:return: None
:since: 0.1.0
"""
import variable
from ast import literal_eval
from colorama import Fore
if literal_eval(variable.Variable().get_value(variable.IS_AION_RUNNING)) is False:
print(Fore.RED + command + " can only used if aion is running. Type 'aion run' or 'aion start' to start aion" + Fore.RESET)
exit(-1)
def must_be_sudo() -> None:
"""
checks if the user is root and if not it prints an warning message
:return: None
:since: 0.1.0
"""
from colorama import Fore
if atils.is_root() is False:
print(Fore.RED + "to execute the command, aion must be run as sudo" + Fore.RESET)
exit(-1)
def yesno(question: str) -> bool:
"""
asks a yes no question
:param question: str
question you want to ask
syntax: <question>
example: "Execute test command? (y/n): "
:return: bool
returns if the user entered y / yes (True) or n / no (False)
syntax: <boolean>
example: True
:since: 0.1.0
"""
while True:
yn = input(question)
if yn.lower().strip() == "y" or yn.lower().strip() == "yes":
return True
elif yn.lower().strip() == "n" or yn.lower().strip() == "no":
return False
else:
print("Please choose 'y' or 'n'")
class Install:
"""
base class for installation
"""
@staticmethod
def aion() -> None:
"""
installs aion
:return: None
:since: 0.1.0
"""
must_be_sudo()
from os import system
from shutil import rmtree
system("git clone https://github.com/blueShard/aion_project /tmp/aion_project")
system("bash /tmp/aion_project/install.sh")
rmtree("/tmp/aion_project", ignore_errors=True)
@staticmethod
def plugin_from_aion_file(fname: str) -> None:
"""
installs a plugin from a 'plugin.aion' file
:param fname: str
path of the file
syntax: <filename>
example: "/home/pi/test_plugin/plugin.aion"
:return: None
:since: 0.1.0
"""
must_be_sudo()
from plugin import execute_aion_file_type_plugin
execute_aion_file_type_plugin(fname)
@staticmethod
def plugin_from_plugin_file(fname: str) -> None:
"""
installs a plugin from a '.plugin' package
:param fname: str
path of the file
syntax: <filename>
example: "/home/pi/test_plugin/test.plugin"
:return: None
:since: 0.1.0
"""
must_be_sudo()
from plugin import execute_plugin_file
execute_plugin_file(fname)
@staticmethod
def skill_from_aion_file(fname: str) -> None:
"""
installs a skill from a 'skill.aion' file
:param fname: str
path of the file
syntax: <filename>
example: "/home/pi/test_skill/skill.aion"
:return: None
:since: 0.1.0
"""
must_be_sudo()
from skill import execute_aion_file_type_skill
execute_aion_file_type_skill(fname)
@staticmethod
def skill_from_skill_file(fname: str) -> None:
"""
installs a skill from a '.skill' package
:param fname: str
path of the file
syntax: <filename>
example: "/home/pi/test_skill/test.skill"
:return: None
:since: 0.1.0
"""
must_be_sudo()
from skill import execute_skill_file
execute_skill_file(fname)
@staticmethod
def respeaker(compatibility_mode: bool = False) -> None:
"""
installs respeaker
:param compatibility_mode:
installs an old kernel version which is definitely compatible with respeaker
(the current version may contain patches etc. which make respeaker not work properly anymore and to which the developers of respeaker have to adapt the software first)
syntax: <boolean>
example: False
:return: None
:since: 0.1.0
"""
must_be_sudo()
from os import system
from shutil import copy, rmtree
system("git clone https://github.com/respeaker/seeed-voicecard.git /tmp/seeed-voicecard")
copy("/tmp/seeed-voicecard/uninstall.sh", atils.aion_path + "/etc/respeaker_uninstall.sh")
if compatibility_mode:
system("cd /tmp/seeed-voicecard/; ./install.sh --compat-kernel")
else:
system("cd /tmp/seeed-voicecard/; ./install.sh")
system("amixer cset numid=3 2")
rmtree("/tmp/seeed-voicecard", ignore_errors=True)
class Pack:
"""
base class for packing plugin or skill directories to '.plugin' or '.skill' packages
"""
@staticmethod
def skill(directory: str) -> None:
"""
creates a skill package from given directory
:param directory: str
path of the directory
syntax: <filename>
example: "/home/pi/test_skill.skill"
:return: None
:since: 0.1.0
"""
from skill import create_skill_package
create_skill_package(directory)
@staticmethod
def plugin(directory: str) -> None:
"""
creates a plugin package from given directory
:param directory: str
path of the directory
syntax: <filename>
example: "/home/pi/test_plugin.plugin"
:return: None
:since: 0.1.0
"""
from plugin import create_plugin_package
create_plugin_package(directory)
class UnRem: # this class name combine the word uninstall and remove
@staticmethod
def aion(personal_data: bool = False) -> None:
"""
deletes aion
:param personal_data: bool
checks if all personal data should be deleted as well
syntax: <boolean>
example: True
:return: None
:since: 0.1.0
"""
must_be_sudo()
from glob import glob
from os import system
if personal_data is True:
system("bash " + glob("/usr/local/aion-*/etc/uninstall.sh")[0] + " --all")
else:
system("bash " + glob("/usr/local/aion-*/etc/uninstall.sh")[0])
@staticmethod
def aionlib() -> None:
"""
uninstalls aionlib
:return: None
:since: 0.1.0
"""
must_be_sudo()
from os import system
system("yes | pip3 uninstall aionlib")
@staticmethod
def run_after_plugin(name: str) -> None:
"""
uninstalls a run after plugin
:param name: str
name of the run after plugin
syntax: <run after plugin>
example: "test_run_after_plugin"
:return: None
:since: 0.1.0
"""
must_be_sudo()
from plugin import RUN_AFTER, remove_plugin
remove_plugin(name, RUN_AFTER)
@staticmethod
def run_before_plugin(name: str) -> None:
"""
uninstalls a run before plugin
:param name: str
name of the run before plugin
syntax: <run before plugin>
example: "test_run_before_plugin"
:return: None
:since: 0.1.0
"""
must_be_sudo()
from plugin import RUN_BEFORE, remove_plugin
remove_plugin(name, RUN_BEFORE)
@staticmethod
def skill(name: str) -> None:
"""
uninstalls a skill
:param name: str
name of the skill
syntax: <skill>
example: "test_skill"
:return: None
:since: 0.1.0
"""
must_be_sudo()
from skill import remove_skill
remove_skill(name)
@staticmethod
def respeaker() -> None:
"""
uninstalls respeaker (if installed)
:return: None
:since: 0.1.0
"""
must_be_sudo()
from os import path, system
if path.isfile(atils.aion_path + "/etc/respeaker_uninstall.sh") is False:
raise FileNotFoundError("can't find file '" + atils.aion_path + "/etc/respeaker_uninstall.sh' to uninstall respeaker")
else:
system("bash " + atils.aion_path + "/etc/respeaker_uninstall.sh")
class Update:
@staticmethod
def aion() -> None:
"""
updates aion
:return: None
:since: 0.1.0
"""
from colorama import Fore
print(Fore.RED + "The update command for aion isn't created yet" + Fore.RESET)
@staticmethod
def aionlib() -> None:
"""
updates aionlib
:return: None
:since: 0.1.0
"""
must_be_sudo()
from os import system
system("yes | pip3 install --upgrade aionlib")
@staticmethod
def run_after_plugin(name: str) -> None:
"""
updates a run after plugin
:param name: str
name of the plugin
syntax: <plugin name>
example: "test_run_after_plugin"
:return: None
:since: 0.1.0
"""
from colorama import Fore
print(Fore.RED + "The update command for 'run_after_plugin' isn't created yet")
@staticmethod
def run_before_plugin(name: str) -> None:
"""
updates a run before plugin
:param name: str
name of the run before plugin
syntax: <plugin name>
example: "test_run_before_plugin"
:return: None
:since: 0.1.0
"""
from colorama import Fore
print(Fore.RED + "The update command for 'run_before_plugin' isn't created yet")
@staticmethod
def skill(name: str) -> None:
"""
updates a skill
:param name: str
name if the skill
syntax: <skill name>
example: "test_skill"
:return: None
:since: 0.1.0
"""
from colorama import Fore
print(Fore.RED + "The update command for 'skill' isn't created yet")
class Version:
@staticmethod
def aion() -> None:
"""
prints the version of 'aion'
:return: None
:since: 0.1.0
"""
from glob import glob
print("".join(glob("/usr/local/aion-*").remove("/usr/local/aion-")))
@staticmethod
def aionlib() -> None:
"""
prints the version of aionlib (if installed)
:return: None
:since: 0.1.0
"""
try:
from aionlib import __version__ as aionlib_version
print(aionlib_version)
except ImportError:
print("'aionlib' isn't installed. To install aionlib, type 'sudo pip3 install aionlib'")
@staticmethod
def run_after_plugin(name: str) -> None:
"""
prints the version of a run after plugin
:param name: str
name of the plugin
syntax: <plugin name>
example: "test_run_after_plugin"
:return: None
:since: 0.1.0
"""
from plugin import get_run_after_plugin_infos
for key, item in get_run_after_plugin_infos(name):
if key == "version":
print(item)
break
@staticmethod
def run_before_plugin(name: str) -> None:
"""
prints the version of a run before plugin
:param name: str
name of the plugin
syntax: <plugin name>
example: "test_run_before_plugin"
:return: None
:since: 0.1.0
"""
from plugin import get_run_before_plugin_infos
for key, item in get_run_before_plugin_infos(name):
if key == "version":
print(item)
break
@staticmethod
def skill(name: str) -> None:
"""
prints the version of a skill
:param name: str
name of the skill
syntax: <plugin name>
example: "test_skill"
:return: None
:since: 0.1.0
"""
from skill import get_skill_infos
for key, item in get_skill_infos(name):
if key == "version":
print(item)
break

View File

@ -0,0 +1,585 @@
#!/usr/bin/python3
try:
from .utils import aion_data_path as _aion_data_path
except ImportError:
from utils import aion_data_path as _aion_data_path
skills_path = _aion_data_path + "/skills"
skills_file = skills_path + "/skills.xml"
class Skill:
"""
base class for use custom skills
:since: 0.1.0
"""
def __init__(self, activate_phrase: str, speech_input: str, run_after_plugins: dict, run_before_plugins: dict) -> None:
"""
:param activate_phrase: str
activate phrase that called this class
syntax: "<activate phrase>"
example: "test"
:param speech_input: str
complete spoken words
syntax: "<speech input>"
example: "Start the test"
:param run_after_plugins: dict
all run after plugins
:param run_before_plugins: dict
all run before plugins
:return: None
:since: 0.1.0
"""
self.activate_phrase = activate_phrase
self.speech_input = speech_input
try:
self.run_after_plugins = run_after_plugins[self.__class__.__name__]
except KeyError:
self.run_after_plugins = {}
try:
self.run_before_plugins = run_before_plugins[self.__class__.__name__]
except KeyError:
self.run_before_plugins = {}
def main(self) -> None:
"""
gets called if user says the defined activate_phrase
:return: None
:since: 0.1.0
"""
pass
def run_after(self) -> None:
"""
gets called after the 'main' function was executed
:return: None
:since: 0.1.0
"""
pass
def run_before(self) -> None:
"""
gets called before the 'main' function was executed
:return: None
:since: 0.1.0
"""
pass
def start_run_after_plugin(self, plugin_name: str) -> None:
"""
calls a 'run_after' plugin (all plugins are in at the root of 'run_after_plugins' dict)
:param plugin_name: str
name of the plugin that should called (all plugins are in at the root of 'run_after_plugins' dict)
syntax: "<plugin name>"
example: "ExampleClass
:return: None
:since: 0.1.0
"""
try:
from .plugin import _run_befater_plugin, RUN_AFTER
except ImportError:
from plugin import _run_befater_plugin, RUN_AFTER
if plugin_name in self.run_after_plugins:
_run_befater_plugin(RUN_AFTER, plugin_name, self.run_after_plugins[plugin_name]["method"], self.activate_phrase, self.speech_input)
def start_run_before_plugin(self, plugin_name: str) -> None:
"""
calls a 'run_before' plugin (all plugins are in at the root of 'run_before_plugins' dict)
:param plugin_name: str
name of the plugin that should called (all plugins are in at the root of 'run_before_plugins' dict)
syntax: "<plugin name>"
example: "ExampleClass"
:return: None
:since: 0.1.0
"""
try:
from .plugin import _run_befater_plugin, RUN_BEFORE
except ImportError:
from plugin import _run_befater_plugin, RUN_BEFORE
if plugin_name in self.run_before_plugins:
_run_befater_plugin(RUN_BEFORE, plugin_name, self.run_before_plugins[plugin_name]["method"], self.activate_phrase, self.speech_input)
def speech_output(self, speech_output: str) -> None:
"""
plays a output of an artificial voice from the given words
:param speech_output: str
the words to be said
syntax: "<speech output words>"
example: "This is an test"
:return: None
:since: 0.1.0
"""
try:
from . import speech_output as _speech_output
except ImportError:
from .__init__ import speech_output as _speech_output
_speech_output(speech_output)
def create_skill_file(activate_phrases: dict,
author: str,
language_locales: list,
skill_name: str,
main_file: str,
version: str,
additional_directories: list = [],
description: str = "",
language_dict: dict = {},
license: str = "",
required_python3_packages: list = []) -> None:
"""
creates a file from which a skill can be installed
:param activate_phrases: dict
defines a word or a sentence from which a method is called
syntax: {<activate phrase>: <method that should get called after the activate phrase was said>}
example: {"start test": "MyTestMethod"}
NOTE: in key 'activate_phrase' you can use the '__and__' statement. This checks if the words before and after '__and__' are in the sentence that the user has spoken in
:param author: str
name of the author from the skill
syntax: <author name>
example: "blueShard"
:param language_locales: list
list of language locales for which the skill is available
syntax: [<language locale>]
example: ["en_US"]
:param main_file: str
file name of file where all methods for the activate_phrases are defined
syntax: <file name>
example: "test.py"
NOTE: the file must be in the same directory as the file from which 'create_skill_file' is being executed
:param skill_name: str
name of the skill you create
syntax: <skill name>
example: "text_skill"
:param version: str
version (number) of your skill
syntax: <version>
example: "1.0.0"
:param additional_directories: list, optional
list of additional directories your main file needs for execution
syntax: [<additional directories>]
example: ["test_directory"]
NOTE: the directories must be in the same directory as the file from which 'create_skill_file' is being executed
:param description: str, optional
description of your skill
syntax: <description>
example: "A simple skill to test the method 'create_skill_file'"
:param language_dict: dict, optional
dictionary of messages which are saved in (from argument 'language_locales' given) '.lng' files
syntax: {<entry>, <text>}
example: {"test_entry": "The test was successful"}
NOTE: the method name should be included in the entry for legibility
NOTE2: for more infos about language ('.lng') files, see file 'language.py'
:param license: str, optional
license of the skill
syntax: <license>
example: "MPL-2.0"
:param required_python3_packages: list, optional
list of python3 packages your package needs for correct execution
syntax: [<python3 package>]
example: ["aionlib"]
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import skill_author_must_be_str, skill_language_locales_must_be_list_or_tuple, skill_skill_name_must_be_str, skill_main_file_must_be_str, skill_main_file_not_found,\
skill_main_file_name_must_be_skill_name, skill_version_must_be_str, skill_additional_directories_must_be_list_or_tuple, skill_couldnt_find_additional_directories_directory,\
skill_description_must_be_str, skill_language_dict_must_be_dict, skill_language_dict_character_must_be_in_alphabet, skill_license_must_be_str,\
skill_required_python3_package_must_be_list_or_tuple, skill_activate_phrases_must_be_dict, skill_activate_phrases_character_must_be_in_alphabet
except ImportError:
from _error_codes import skill_author_must_be_str, skill_language_locales_must_be_list_or_tuple, skill_skill_name_must_be_str, skill_main_file_must_be_str, skill_main_file_not_found,\
skill_main_file_name_must_be_skill_name, skill_version_must_be_str, skill_additional_directories_must_be_list_or_tuple, skill_couldnt_find_additional_directories_directory,\
skill_description_must_be_str, skill_language_dict_must_be_dict, skill_language_dict_character_must_be_in_alphabet, skill_license_must_be_str,\
skill_required_python3_package_must_be_list_or_tuple, skill_activate_phrases_must_be_dict, skill_activate_phrases_character_must_be_in_alphabet
from os import getcwd, listdir
write_dict = {}
if isinstance(author, str) is False:
raise TypeError("Errno: " + skill_author_must_be_str + " - Argument 'author' must be str, got " + type(author).__name__)
write_dict["author"] = author
if isinstance(language_locales, (list, tuple)) is False:
raise TypeError("Errno: " + skill_language_locales_must_be_list_or_tuple + " - Argument 'language_locales' must be list or tuple, got " + type(language_locales).__name__)
write_dict["language_locales"] = language_locales
if isinstance(skill_name, str) is False:
raise TypeError("Errno: " + skill_skill_name_must_be_str + " - Argument 'skill_name' must be str, got " + type(skill_name).__name__)
write_dict["skill_name"] = skill_name
if isinstance(main_file, str) is False:
raise TypeError("Errno: " + skill_main_file_must_be_str + " - Argument 'main_file' must be str, got " + type(author).__name__)
if main_file not in listdir(getcwd()):
raise FileNotFoundError("Errno: " + skill_main_file_not_found + " - Couldn't find the file " + main_file + " in current directory")
if main_file[:-3] == skill_name is False:
raise NameError("Errno: " + skill_main_file_name_must_be_skill_name + " - The file name from " + main_file + " must be same as the argument 'name' (" + skill_name + ")")
write_dict["main_file"] = main_file
if isinstance(version, str) is False:
raise TypeError("Errno: " + skill_version_must_be_str + " - Argument 'version' must be str, got " + type(version).__name__)
write_dict["version"] = version
# ----- #
if isinstance(additional_directories, (list, tuple)) is False:
raise TypeError("Errno: " + skill_additional_directories_must_be_list_or_tuple + " - Argument 'additional_directories' must be list or tuple, got " + type(additional_directories).__name__)
for directory in additional_directories:
if directory not in listdir(getcwd()):
raise NotADirectoryError("Errno: " + skill_couldnt_find_additional_directories_directory + " - Couldn't find the directory " + directory + " in current directory")
write_dict["additional_directories"] = additional_directories
if isinstance(description, str) is False:
raise TypeError("Errno: " + skill_description_must_be_str + " - Argument 'description' must be str, got " + type(description).__name__)
write_dict["description"] = description
if isinstance(language_dict, dict) is False:
raise TypeError("Errno: " + skill_language_dict_must_be_dict + " - Argument 'language_success' must be dict, got " + type(language_dict).__name__)
for key in language_dict.keys():
tmp_string = ""
for char in key:
if char == " ":
char = "_"
if char.lower() not in "abcdefghijklmnopqrstuvwxyz_":
raise ValueError("Errno: " + skill_language_dict_character_must_be_in_alphabet + " - Setter " + str(char) + " in " + str(key) + " must be in 'ABCDEFGHIJLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz_'")
tmp_string = tmp_string + char
language_dict[tmp_string] = language_dict.pop(key)
write_dict["language_dict"] = language_dict
if isinstance(license, str) is False:
raise TypeError("Errno: " + skill_license_must_be_str + " - Argument 'license' must be str, got " + type(license).__name__)
write_dict["license"] = license
if isinstance(required_python3_packages, (list, tuple)) is False:
raise TypeError("Errno: " + skill_required_python3_package_must_be_list_or_tuple + " - Argument 'required_python3_packages' must be list or tuple, got " + type(required_python3_packages).__name__)
write_dict["required_python3_packages"] = required_python3_packages
# ----- #
if isinstance(activate_phrases, dict) is False:
raise TypeError("Errno: " + skill_activate_phrases_must_be_dict + " - Argument 'activate_phrases' must be dict, got " + type(activate_phrases).__name__)
for item in activate_phrases:
tmp_string = ""
for char in item:
if char == " ":
char = "_"
if char.lower() not in "abcdefghijklmnopqrstuvwxyz-_":
raise ValueError("Errno: " + skill_activate_phrases_character_must_be_in_alphabet + " - Letter " + str(char) + " in " + str(item) + " must be in 'ABCDEFGHIJLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz-_'")
tmp_string = tmp_string + char
activate_phrases[tmp_string] = activate_phrases.pop(item)
write_dict["activate_phrases"] = activate_phrases
# ----- #
with open("skill.aion", "w") as file:
file.write("#type: skill\n")
for key, value in write_dict.items():
file.write(key + " = " + str(value) + "\n")
file.close()
def create_skill_package(dir_name: str) -> None:
"""
creates a stand alone file ('.skill') from given directory
:param dir_name: str
directory name of the directory from which you want to create a '.skill' file
syntax: <directory name>
example: "/home/pi/test/"
:return: None
:note: 'skill.aion' file must be in the given directory (see 'create_skill_file' to create a 'skill.aion' file)
:since: 0.1.0
"""
try:
from ._error_codes import skill_package_couldnt_find_directory, skill_package_couldnt_find_aion_file, skill_package_expected_one_aion_file
except ImportError:
from _error_codes import skill_package_couldnt_find_directory, skill_package_couldnt_find_aion_file, skill_package_expected_one_aion_file
from os import listdir, mkdir, rename
from os.path import isdir
from random import sample
from shutil import make_archive, rmtree
if isdir(dir_name) is False:
raise NotADirectoryError("Errno: " + skill_package_couldnt_find_directory + " - Couldn't find the directory '" + dir_name + "'")
name = ""
file_num = 0
for file in listdir(dir_name):
if file.endswith(".aion"):
file_num += 1
name = "".join(file.split(".aion")[0])
if file_num == 0:
raise FileNotFoundError("Errno: " + skill_package_couldnt_find_aion_file + " - Couldn't find .aion file in " + dir_name + ". To create one use the 'create_skill_file' function in aionlib.skill")
elif file_num > 1:
raise FileExistsError("Errno: " + skill_package_expected_one_aion_file + " - Expected one .aion file in " + dir_name + ", got " + str(file_num))
skill_dir_name = "skill_" + name + "".join([str(num) for num in sample(range(1, 10), 5)])
mkdir(skill_dir_name)
make_archive(name + ".skill", "zip", skill_dir_name)
rename(skill_dir_name + ".skill.zip", skill_dir_name + ".skill")
rmtree(skill_dir_name)
def execute_aion_file_type_skill(fname: str) -> None:
"""
installs custom skill from '<file name>.aion'
:param fname: str
file name of the '.aion' file
syntax: <file name>
example: "/home/pi/skill.aion"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import skill_couldnt_find_key, skill_skill_already_exist, skill_file_doesnt_exist, skill_directory_doesnt_exist, skill_directory_already_exist, \
skill_couldnt_install_python3_package
from .acph import add_acph
from .language import add_entry, language_directory
from .utils import BaseXMLReader, BaseXMLWriter
except ImportError:
from acph import add_acph
from language import add_entry, language_directory
from utils import BaseXMLReader, BaseXMLWriter
from _error_codes import skill_couldnt_find_key, skill_skill_already_exist, skill_file_doesnt_exist, skill_directory_doesnt_exist, skill_directory_already_exist, \
skill_couldnt_install_python3_package
from ast import literal_eval
from importlib import import_module
from os import listdir, path
from shutil import copy, copytree
from subprocess import call
setup_dict = {}
setup_dir = path.dirname(path.abspath(fname))
for line in open(fname, "r"):
if line.startswith("#"):
continue
setup_dict[line.split("=")[0].strip()] = line.split("=")[1].strip()
try:
activate_phrases = literal_eval(setup_dict["activate_phrases"])
author = setup_dict["author"]
language_locales = literal_eval(setup_dict["language_locales"])
main_file = setup_dict["main_file"]
skill_name = setup_dict["skill_name"]
version = setup_dict["version"]
additional_directories = literal_eval(setup_dict["additional_directories"])
description = setup_dict["description"]
language_dict = literal_eval(setup_dict["language_dict"])
license = setup_dict["license"]
required_python3_packages = literal_eval(setup_dict["required_python3_packages"])
except KeyError as error:
raise KeyError("Errno: " + skill_couldnt_find_key + " - Couldn't find key " + str(error) + " in " + fname)
# ----- #
if skill_name in get_all_skills():
raise NameError("Errno: " + skill_skill_already_exist + " - The skill " + skill_name + " already exist")
if path.isfile(setup_dir + "/" + main_file) is False:
raise FileNotFoundError("Errno: " + skill_file_doesnt_exist + " - The file " + main_file + " doesn't exist in setup dir (" + setup_dir + ")")
for directory in additional_directories:
if path.isdir(setup_dir + "/" + directory) is False:
raise NotADirectoryError("Errno: " + skill_directory_doesnt_exist + " - The directory " + directory + " doesn't exist in setup dir (" + setup_dir + ")")
if directory in listdir(skills_path):
raise IsADirectoryError("Errno: " + skill_directory_already_exist + " - The directory " + directory + " already exist in " + skills_path)
# ----- #
for package in required_python3_packages:
call("pip3 install " + package, shell=True)
try:
import_module(package)
except ModuleNotFoundError:
raise ModuleNotFoundError("Errno: " + skill_couldnt_install_python3_package + " - Couldn't install the required python3 package '" + package + "'")
copy(main_file, skills_path + "/" + main_file)
for directory in additional_directories:
copytree(directory, skills_path + "/" + directory)
for language in language_locales:
add_acph(language, skill_name, activate_phrases)
add_entry(language, skill_name, language_dict)
dat_writer = BaseXMLWriter(skills_file)
dat_writer.add("<root>", str(skill_name), author=str(author))
dat_writer.add(str(skill_name), "activate_phrases", str(activate_phrases))
dat_writer.add(str(skill_name), "additional_directories", str(additional_directories))
dat_writer.add(str(skill_name), "description", str(description))
dat_writer.add(str(skill_name), "language_dict", str(language_dict))
dat_writer.add(str(skill_name), "language_locales", str(language_locales))
dat_writer.add(str(skill_name), "license", str(license))
dat_writer.add(str(skill_name), "main_file", str(main_file))
dat_writer.add(str(skill_name), "required_python3_packages", str(required_python3_packages))
dat_writer.add(str(skill_name), "version", str(version))
dat_writer.write()
def execute_skill_file(fname: str) -> None:
"""
executes a '<name>.skill' file for installing custom skills
:param fname: str
file name of the '.skill' file
syntax: <fname>
example: "/home/pi/test.skill"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import skill_couldnt_find_skill_dot_aion
except ImportError:
from _error_codes import skill_couldnt_find_skill_dot_aion
from glob import glob
from os.path import isfile
from zipfile import ZipFile
with ZipFile(fname, "r") as zipfile:
zipfile.extractall("/tmp")
zipfile.close()
if isfile(glob("/tmp/skill_*/skill.aion")[0]) is False:
raise FileNotFoundError("Errno: " + skill_couldnt_find_skill_dot_aion + " - ouldn't find 'skill.aion' in " + fname)
else:
execute_aion_file_type_skill(glob("/tmp/skill_*/skill.aion")[0])
def get_all_skills() -> list:
"""
returns all installed skills
:return: list
returns list of all installed skills
syntax: [<skill>]
example: ["skills"]
:since: 0.1.0
"""
try:
from .utils import BaseXMLReader
except ImportError:
from utils import BaseXMLReader
return BaseXMLReader(skills_file).get_infos("<root>").items().index(0)[0]["childs"]
def get_skill_infos(skill_name: str) -> dict:
"""
returns infos about an given skill
:param skill_name: str
name of the skill you want to get infos about
syntax: <skill name>
example: "test_skill"
:return: dict
returns a dictionary with infos of the skill
syntax: {"activate_phrases": {<activate phrases>},
"author": <author>,
"language_locales": [<language locales>],
"main_file": <main file>,
"skill_name": <skill name>,
"version": <version>,
"additional_directories": [<additional directories>],
"description": <description>,
"language_dict": {<entry>: <text>}
"license": <license>,
"required_python3_packages": [<python3 packages>]}
example: {"activate_phrases": {"start test": "test_method_start"}},
"author": "blueShard",
"language_locales": ["en_US"],
"main_file": "test.py",
"skill_name": "text_skill",
"version": "1.0.0",
"additional_directories": ["test_directory"],
"description": "A simple skill to test the function 'get_skill_infos",
"language_dict": {"test_func": "The test was successful"},
"license": "MPL-2.0",
"required_python3_packages": ["aionlib"]}
:since: 0.1.0
"""
try:
from .utils import BaseXMLReader
except ImportError:
from utils import BaseXMLReader
from ast import literal_eval
skill_reader = BaseXMLReader(skills_file)
return_dict = {"skill_name": skill_name}
for value_list in skill_reader.get_infos("<all>").values():
for skill in value_list:
try:
if skill["parent"]["tag"] == skill_name:
try:
return_dict[skill["tag"]] = literal_eval(skill["text"])
except (EOFError, SyntaxError, ValueError):
return_dict[skill["tag"]] = skill["text"]
except KeyError:
pass
return return_dict
def remove_skill(skill_name: str) -> None:
"""
removes given skill
:param skill_name: str
name of the skill you want to remove
syntax: <skill name>
example: "test"
:return: None
:since: 0.1.0
"""
try:
from .acph import delete_acph
from .language import language_directory, delete_entry
from .utils import BaseXMLReader, BaseXMLWriter
except ImportError:
from acph import delete_acph
from language import language_directory, delete_entry
from utils import BaseXMLReader, BaseXMLWriter
from os import remove as os_remove
from shutil import rmtree
skill_infos = get_skill_infos(skill_name)
os_remove(skills_path + "/" + skill_infos["main_file"])
for dir in skill_infos["additional_directories"]:
rmtree(skills_path + "/" + dir)
for language in skill_infos["language_locales"]:
delete_acph(language, [acph_dict["activate_phrase"] for acph_dict in skill_infos["activate_phrases"]])
delete_entry(language, skill_name, entry_list=[key.replace(" ", "_") for key in skill_infos["language_dict"]])
remove_xml = BaseXMLWriter(skills_file)
remove_xml.remove("<root>", skill_name)
remove_xml.write()

View File

@ -0,0 +1,102 @@
#!/usr/bin/python3
import pyudev, psutil
from os import system
class USB:
def __init__(self) -> None:
"""
:return: None
:since: 0.1.0
"""
pass
class _DeviceInfos:
"""
base class for usb infos
:since: 0.1.0
"""
def __init__(self, action: str) -> None:
"""
:param action: str
name of the action
syntax: <action name>
example: "add"
:return: None
:since: 0.1.0
"""
self.action = action
self.add = False
self.remove = False
if self.action == "add":
self.add = True
self.remove = False
elif action == "remove":
self.remove = True
self.add = False
def __iter__(self):
return self
@staticmethod
def mount() -> None:
"""
mounts a usb device
:return: None
:since: 0.1.0
"""
pass
def listen(self) -> _DeviceInfos:
"""
listen permanent to usb ports for actions etc.
:return: None
:since: 0.1.0
"""
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by(subsystem="usb")
removable = [device for device in context.list_devices(subsystem='block', DEVTYPE='disk') if device.attributes.asstring('removable') == "1"]
for device in removable:
partitions = [device.device_node for device in context.list_devices(subsystem='block', DEVTYPE='partition', parent=device)]
print("All removable partitions: {}".format(", ".join(partitions)))
print("Mounted removable partitions:")
for p in psutil.disk_partitions():
if p.device in partitions:
print(" {}: {}".format(p.device, p.mountpoint))
for device in iter(monitor.poll, None):
if device.action == "add":
yield self._DeviceInfos("add")
elif device.action == "remove":
yield self._DeviceInfos("remove")
print([device.device_node for device in context.list_devices(subsystem='block', DEVTYPE='partition')])
@staticmethod
def umount() -> None:
"""
unmount usb device
:return: None
:since: 0.1.0
"""
system("sudo umount /mnt/usbstick")
if __name__ == '__main__':
print([device.device_node for device in pyudev.Context().list_devices(subsystem='block', DEVTYPE='partition')])
for action in USB().listen():
pass

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,200 @@
#!/usr/bin/python3
_aion_variable_file = "/tmp/aion39ewefv90erfte25"
_default_variables = {"IS_AION_RUNNING": False}
IS_AION_RUNNING = "IS_AION_RUNNING"
class Variable:
"""
base class for aion variables
:since: 0.1.0
"""
def __init__(self) -> None:
"""
set all class variables
:return: None
:since: 0.1.0
"""
from os.path import isfile as _isfile
self._user_variables = {}
if _isfile(_aion_variable_file):
self._aion_open_variable_file = open(_aion_variable_file, "w+")
else:
self._aion_open_variable_file = None
def add_variable(self, variable_name: str, value: str) -> None:
"""
adds a variable
:param variable_name: str
name of the variable you want to add
syntax: <variable name>
example: "test_variable"
:param value: str
value of the variable
syntax: <value>
example: "test_value"
:return: None
:since: 0.1.0
"""
if self._aion_open_variable_file is not None:
file = open(_aion_variable_file, "a")
file.write(variable_name + "=" + value)
self._aion_open_variable_file = open(_aion_variable_file, "w+")
self._user_variables[variable_name] = value
def close(self) -> None:
"""
remove the file with the saved variables
:return: None
:since: 0.1.0
"""
from os import remove
if self._aion_open_variable_file is not None:
remove(_aion_variable_file)
self._aion_open_variable_file = None
def get_value(self, variable_name: str) -> str:
"""
get the value of an variable
:param variable_name: str
name of the variable you want to get the value
syntax: <variable name>
example: "test_variable"
:return: str
return the value of the variable
syntax: <value>
example: <text_variable_value>
:since: 0.1.0
"""
try:
from ._error_codes import variable_get_value_variable_file_variable_doesnt_exist, variable_get_value_user_variables_variable_doesnt_exist
except ImportError:
from _error_codes import variable_get_value_variable_file_variable_doesnt_exist, variable_get_value_user_variables_variable_doesnt_exist
if self._aion_open_variable_file is not None:
for value in self._aion_open_variable_file:
if value.strip().startswith("#"):
continue
elif value.split("=")[0].strip() == variable_name:
return value.split("=")[1].strip()
raise KeyError("Errno: " + variable_get_value_variable_file_variable_doesnt_exist + " - The variable " + variable_name + " doesn't exists")
else:
try:
return str(_default_variables[variable_name])
except KeyError:
if variable_name in self._user_variables:
return self._user_variables[variable_name]
raise KeyError("Errno: " + variable_get_value_user_variables_variable_doesnt_exist + " - The variable " + variable_name + " doesn't exists")
def inititalize_variables(self, additional_variables: dict = {}) -> None:
"""
creates a new file for the variables to store
:param additional_variables: dict, optional
variables that should be added ('add_variable' could be used instead)
syntax: {"key": "value"}
example: {"test": "True"}
:return: None
:since: 0.1.0
"""
self._aion_open_variable_file = open(_aion_variable_file, "w+")
write_list = [variable + "=" + str(value) for variable, value in _default_variables.items()]
write_list = write_list + [str(additional_variable) + "=" + str(additional_value) for additional_variable, additional_value in additional_variables.items()]
write_list = write_list + [str(user_variable) + "=" + str(user_value) for user_variable, user_value in self._user_variables]
self._aion_open_variable_file.writelines(write_list)
self._aion_open_variable_file = open(_aion_variable_file, "w+")
def remove_variable(self, variable_name: str) -> None:
"""
removes a variable
:param variable_name: str
name of the variable
syntax: <variable name>
example: "test_variable"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import variable_remove_variable_variable_doesnt_exist
from .utils import remove_space, replace_line
except ImportError:
from _error_codes import variable_remove_variable_variable_doesnt_exist
from utils import remove_space, replace_line
found = False
if variable_name in self._user_variables:
del self._user_variables[variable_name]
found = True
if self._aion_open_variable_file is not None:
line_number = -1
for line in self._aion_open_variable_file:
line_number = line_number + 1
if remove_space(line, "").split("=")[0] == variable_name:
replace_line(_aion_variable_file, line_number, "")
self._aion_open_variable_file = open(_aion_variable_file, "w+")
return
if found is False:
raise KeyError("Errno: " + variable_remove_variable_variable_doesnt_exist + " - The variable " + variable_name + " doesn't exists")
def set_value(self, variable_name: str, value: str) -> None:
"""
set a new value to a variable
:param variable_name: str
name of the variable you want to change the value
syntax: "<variable name>"
example: "test_variable"
:param value: str
new value
syntax: "<new value>"
example: "new_test_value"
:return: None
:since: 0.1.0
"""
try:
from ._error_codes import variable_set_value_variable_doesnt_exist
from .utils import remove_space, replace_line
except ImportError:
from _error_codes import variable_set_value_variable_doesnt_exist
from utils import remove_space, replace_line
found = False
if variable_name in self._user_variables:
self._user_variables[variable_name] = value
found = True
if self._aion_open_variable_file is not None:
line_number = -1
for line in self._aion_open_variable_file:
line_number = line_number + 1
if remove_space(line, " ").split("=")[0] == variable_name:
replace_line(_aion_variable_file, line_number, variable_name + "=" + value)
self._aion_open_variable_file = open(_aion_variable_file, "w+")
return
if found is False:
raise KeyError("Errno: " + variable_set_value_variable_doesnt_exist + " - The variable " + variable_name + " doesn't exists")

View File

@ -0,0 +1,445 @@
from tkinter import *
from tkinter import scrolledtext
from tkinter import filedialog
from tkinter import messagebox
from tkinter.ttk import *
root = Tk()
menu = Menu(root)
root.config(menu=menu)
filemenu = Menu(menu, tearoff=FALSE)
helpmenu = Menu(menu, tearoff=FALSE)
ACC = Menu(menu, tearoff=FALSE)
active_window = ""
def info():
info = Tk()
info.title("Info")
info.resizable(width=0, height=0)
text = """Aion Command Creator
Version 1.0
Offizielles Programm zum erstellen von eigenen Befehlen für die Aion Platform"""
Label(info, text=text).pack()
info.mainloop()
def command_window():
def start_config_creator():
global root
global menu
global filemenu
global helpmenu
global ACC
root.destroy()
root = Tk()
menu = Menu(root)
root.config(menu=menu)
filemenu = Menu(menu, tearoff=FALSE)
helpmenu = Menu(menu, tearoff=FALSE)
ACC = Menu(menu, tearoff=FALSE)
config_window()
def anwser_extension():
global global_answer
global active_window
active_window = "answer_extension"
try:
for variable in global_command:
variable.destroy()
except:
pass
separator = Frame(height=2, relief=SUNKEN)
separator.pack(fill=X, padx=5, pady=5)
answer_extension_choose = Combobox(root, values=["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaggggggggggnjmrjrzhzaaaaaaaaaaaaa", "b"], width=100)
answer_extension_choose.pack()
answer_extension_choose.current(0)
free_space = Label(root)
free_space.pack()
answer = Text(root, width=80, height=5)
answer.pack()
global_answer = [separator, answer_extension_choose, free_space, answer]
def own_command():
global global_command
global active_window
active_window = "own_command"
try:
for variable in global_answer:
variable.destroy()
except:
pass
separator = Frame(height=2, relief=SUNKEN)
separator.pack(fill=X, padx=5, pady=5)
global_command = [separator]
def command_event(event):
global active_window
if command_choose.get() == "----------------------------":
new()
active_window = ""
elif command_choose.get() == "Antwort Erweiterung":
if active_window == "answer_extension":
pass
else:
anwser_extension()
elif command_choose.get() == "Eigener Befehl":
if active_window == "own_command":
pass
else:
own_command()
def new():
try:
for variable in global_answer:
variable.destroy()
except:
pass
try:
for variable in global_command:
variable.destroy()
except:
pass
command_choose.current(0)
root.title("ACC | Aion Command Creator | command Creator")
root.resizable(width=0, height=0)
menu.add_cascade(label="Datei", menu=filemenu)
filemenu.add_command(label="Neu", command=new)
filemenu.add_command(label="Öffnen...")
filemenu.add_command(label="Speichern")
filemenu.add_command(label="Speichern unter...")
filemenu.add_separator()
filemenu.add_command(label="Beenden", command=root.destroy)
menu.add_cascade(label="Hilfe", menu=helpmenu)
helpmenu.add_command(label="Hilfe anzeigen")
helpmenu.add_separator()
helpmenu.add_command(label="Info", command=info)
menu.add_cascade(label="ACC", menu=ACC)
ACC.add_command(label="Zum config Creator", command=start_config_creator)
Label(root, text="Was für eine Art soll dein Befehls sein?").pack()
command_choose = Combobox(root, values=["----------------------------", "Antwort Erweiterung", "Eigener Befehl"])
command_choose.pack()
command_choose.current(0)
command_choose.bind("<<ComboboxSelected>>", command_event)
root.mainloop()
def config_window():
def acc_file_search(file_name, search_element):
not_needed_informations = ["author=", "version=", "command_type="]
no_square_bracket = ["name=", "author=", "version=", "command_type="]
if "=" not in search_element:
search_element = search_element + "="
fileprint = open(file_name).read().splitlines()
acc_search_line = acc_search_file_element(file_name, search_element)
acc_file_search = fileprint[acc_search_line]
acc_file_line = []
if search_element in acc_file_search:
acc_file_search = acc_file_search.replace(search_element, "")
if "\n" in acc_file_search:
acc_file_search = acc_file_search.replace("\n", "")
acc_file_line.append(acc_file_search)
if "]" not in acc_file_search:
if search_element in no_square_bracket:
pass
elif search_element not in no_square_bracket:
acc_first_square_bracket_line = acc_search_file_element(file_name, search_element)
acc_second_square_bracket_line = acc_search_file_element(file_name, "]", acc_first_square_bracket_line)
while True:
bracket_lines = list(range(acc_first_square_bracket_line, acc_second_square_bracket_line + 1))
elements = []
for element_numbers in bracket_lines:
element_list = fileprint[element_numbers]
if search_element in element_list:
if not "=" in search_element:
search_element = search_element + "="
element_list = element_list.replace(search_element, "")
element_list = element_list.lstrip()
elements.append(element_list)
acc_file_line = elements
break
global acc_file
acc_file_temporary = []
for acc_file in acc_file_line:
acc_file = acc_file
if acc_file == "":
if search_element in not_needed_informations:
acc_file = ""
return acc_file
elif search_element not in not_needed_informations:
acc_file = ""
return acc_file
else:
acc_file = ""
return acc_file
if "[" in acc_file:
acc_file = acc_file.replace("[", "")
if "]" in acc_file:
acc_file = acc_file.replace("]", "")
if '"' in acc_file:
acc_file = acc_file.replace('"', "")
acc_file_temporary.append(acc_file)
if len(acc_file_temporary) > 1:
acc_file = (", ".join(acc_file_temporary))
else:
acc_file = ("".join(acc_file_temporary))
if ",," in acc_file:
acc_file = acc_file.replace(",,", ",")
return acc_file
def acc_search_file_element(file_name, search_element, from_line=0):
if "]" in search_element:
pass
if "[" in search_element:
pass
while True:
if search_element in open(file_name, "r").readlines()[from_line]:
break
else:
from_line = from_line + 1
return from_line
def start_command_creator():
global root
global menu
global filemenu
global helpmenu
global ACC
root.destroy()
root = Tk()
menu = Menu(root)
root.config(menu=menu)
filemenu = Menu(menu, tearoff=FALSE)
helpmenu = Menu(menu, tearoff=FALSE)
ACC = Menu(menu, tearoff=FALSE)
command_window()
def create_acc_config():
name = name_entry.get()
author = author_entry.get()
version = version_entry.get()
command_type = command_type_entry.get()
command_file = command_file_entry.get()
raw_command = raw_command_scrolledtext.get(1.0, END)
new_file = filedialog.asksaveasfile(mode="w", defaultextension=".cfg", filetypes=(("CFG Datei", "*.cfg"),))
global new_file_name
new_file_name = new_file.name
new_file.write(
'name=' + name + '\nauthor=' + author + '\nversion=' + version + '\ncommand_type=' + command_type + '\ncommand_file=["' + command_file + '"]\nraw_command=["' + raw_command + '"]')
def get_def():
get_def_list = []
numbers = []
def_print = open(open_command_file_name, "r").read().splitlines()
with open(open_command_file_name, "r") as get_def:
for line in get_def:
if "def " in line:
def_line = line
numbers.append(def_print[acc_search_file_element(open_command_file_name, def_line)])
for space in numbers:
non_space = space.lstrip()
get_def_list.append(non_space)
raw_command_scrolledtext.config(state=NORMAL)
for insert in get_def_list:
raw_command_scrolledtext.insert(1.0, insert + " = '',\n")
def new():
get_function.config(state=DISABLED)
name_entry.delete(0, END)
author_entry.delete(0, END)
version_entry.delete(0, END)
command_type_entry.delete(0, END)
command_file_entry.delete(0, END)
raw_command_scrolledtext.delete(1.0, END)
def open_acc_config():
open_file = filedialog.askopenfile(filetypes=(("CFG Datei", "*.cfg"), ("Alle Dateien", "*.*")))
global open_file_name
open_file_name = open_file.name
if ".cfg" not in open_file_name:
messagebox.showerror("Aion Command Creator", "Die Ausgewählte Datei ist keine config (*.cfg) Datei")
else:
open_file_read = open(open_file_name, "r").read()
if "name=" and "version=" and "command_type=" and "command_file=" and "raw_command=" in open_file_read:
raw_command_scrolledtext.config(state=NORMAL)
name_entry_insert = acc_file_search(open_file_name, "name")
author_entry_insert = acc_file_search(open_file_name, "author")
version_entry_insert = acc_file_search(open_file_name, "version")
command_type_entry_insert = acc_file_search(open_file_name, "command_type")
command_file_entry_insert = acc_file_search(open_file_name, "command_file")
raw_command_scrolledtext_insert = acc_file_search(open_file_name, "raw_command")
raw_command_scrolledtext_insert = raw_command_scrolledtext_insert.replace(",", "\n")
raw_command_scrolledtext_insert = raw_command_scrolledtext_insert.replace(" ", "")
name_entry.delete(0, END)
name_entry.insert(0, name_entry_insert)
author_entry.delete(0, END)
author_entry.insert(0, author_entry_insert)
version_entry.delete(0, END)
version_entry.insert(0, version_entry_insert)
command_type_entry.delete(0, END)
command_type_entry.insert(0, command_type_entry_insert)
command_file_entry.delete(0, END)
command_file_entry.insert(0, command_file_entry_insert)
raw_command_scrolledtext.delete(1.0, END)
raw_command_scrolledtext.insert(1.0, raw_command_scrolledtext_insert)
else:
print(open_file.name + " kann nicht gelesen werden")
def open_command_file():
import ntpath
open_file = filedialog.askopenfile(filetypes=(("PY Datei", "*.py"), ("Alle Dateien", "*.*")))
global open_command_file_name
open_command_file_name = open_file.name
if ".py" not in open_command_file_name:
messagebox.showerror("Aion Command Creator", "Die Ausgewählte Datei ist keine Python (*.py) Datei")
else:
command_file_entry.delete(0, END)
command_file_entry.insert(0, ntpath.basename(open_file.name))
raw_command_scrolledtext.config(state=NORMAL)
get_function.config(fg="green", state=NORMAL)
def save():
global file_name
try:
file_name = open_file_name
except:
try:
file_name = new_file_name
except:
create_acc_config()
return
name = name_entry.get()
author = author_entry.get()
version = version_entry.get()
command_type = command_type_entry.get()
command_file = command_file_entry.get()
raw_command = raw_command_scrolledtext.get("1.0", END)
file = open(file_name, "w")
file.write('name=' + name + '\nauthor=' + author + '\nversion=' + version + '\ncommand_type=' + command_type + '\ncommand_file=["' + command_file + '"]\nraw_command=["' + raw_command + '"]')
def show_help():
help = Tk()
help.title("Hilfe anzeigen")
help.resizable(width=0, height=0)
Label(help, text="Hilfe zum Aion Command Creator im Bereich 'config Creator'\n\n").pack()
Label(help, text="'Befehlspaket' = Paket, worin sich alle Dateien befinden").pack()
Label(help, text="'/' = oder").pack()
Label(help, text="Name: ").pack()
name = Text(help, height=2, width=100)
name.insert(1.0, "Legt den Namen für das Befehlspaket fest\n"
"Bsp: Tiergeräusche -> geräusche.py(Datei mit den Befehlsnamen) + geräusche.cfg(Konfigurations Datei)")
name.config(state=DISABLED)
name.pack()
Label(help, text="Autor").pack()
author = Text(help, height=2, width=100)
author.insert(1.0, "Legt den Namen vom Autor des Befehlspaket fest\n"
"Bsp: xXauthorXx / CaCtUsFiGhTeR")
author.config(state=DISABLED)
author.pack()
Label(help, text="Version").pack()
version = Text(help, height=2, width=100)
version.insert(1.0, "Legt die Version vom Befehlspaket fest\n"
"Bsp: v.1.1 / 1.3.7.4")
version.config(state=DISABLED)
version.pack()
Label(help, text="Befehls Typ").pack()
command_type = Text(help, height=2, width=100)
command_type.insert(1.0, "Legt den Befehlstyp des Befehlspaket fest\n"
"Bsp: Spiel / Antwort Erweiterung")
command_type.config(state=DISABLED)
command_type.pack()
Label(help, text="Befehlsdatei").pack()
command_file = Text(help, height=2, width=100)
command_file.insert(1.0, "Legt die Datei mit den Befehlen fest\n"
"Bsp: geräusche.py -> def kuh(): (enthält z.B. den Code zum abspielen von einem Kuh Geräusch)")
command_file.config(state=DISABLED)
command_file.pack()
Label(help, text="Befehl(e)").pack()
raw_command = Text(help, height=2, width=100)
raw_command.insert(1.0, "Legt den Namen der Funktion fest und mit welchen Spracheingaben diese aufgerufen wird\n"
"Bsp: def kuh(): = 'Mach Kuh Geräusche'")
raw_command.config(state=DISABLED)
raw_command.pack()
root.title("ACC | Aion Command Creator | config Creator")
root.resizable(width=0, height=0)
menu.add_cascade(label="Datei", menu=filemenu)
filemenu.add_command(label="Neu", command=new)
filemenu.add_command(label="Öffnen...", command=open_acc_config)
filemenu.add_command(label="Speichern", command=save)
filemenu.add_command(label="Speichern unter...", command=create_acc_config)
filemenu.add_separator()
filemenu.add_command(label="Beenden", command=root.destroy)
menu.add_cascade(label="Hilfe", menu=helpmenu)
helpmenu.add_command(label="Hilfe anzeigen", command=show_help)
helpmenu.add_separator()
helpmenu.add_command(label="Info", command=info)
menu.add_cascade(label="ACC", menu=ACC)
ACC.add_command(label="Zum command Creator", command=start_command_creator)
Label(root, text="* = Wird nicht unbedingt benötigt").pack()
Label(root, text="Name:", font="Times").pack()
name_entry = Entry(root, width=40)
name_entry.pack()
Label(root, text="Autor*:", font="Times").pack()
author_entry = Entry(root, width=40)
author_entry.pack()
Label(root, text="Version*: ", font="Times").pack()
version_entry = Entry(root, width=40)
version_entry.pack()
Label(root, text="Befehls Typ*:", font="Times").pack()
command_type_entry = Entry(root, width=40)
command_type_entry.pack()
Label(root, text="Befehls Datei:", font="Times").pack()
command_file_entry = Entry(root, width=55)
command_file_entry.pack()
Button(root, text="Wähle Datei aus", command=open_command_file).pack()
get_function = Button(root, text="Versuche alle Befehle aufzulisten", command=get_def)
get_function.config(state=DISABLED)
get_function.pack()
Label(root, text="Befehl(e):", font="Times").pack()
raw_command_scrolledtext = scrolledtext.ScrolledText(root, height=15, width=50)
raw_command_scrolledtext.config(state=DISABLED)
raw_command_scrolledtext.pack()
root.mainloop()
command_window()

View File

@ -0,0 +1,91 @@
#!/usr/bin/env python3
def acc_file_search(file_name, search_element):
import re
not_needed_informations = ["author=", "version=", "command_type="]
no_square_bracket = ["name=", "author=", "version=", "command_type="]
if "=" not in search_element:
search_element = search_element + "="
fileprint = open(file_name).read().splitlines()
acc_search_line = acc_search_file_element(file_name, search_element)
acc_file_search = fileprint[acc_search_line]
acc_file_line = []
if search_element in acc_file_search:
acc_file_search = acc_file_search.replace(search_element, "")
if "\n" in acc_file_search:
acc_file_search = acc_file_search.replace("\n", "")
acc_file_line.append(acc_file_search)
if "]" not in acc_file_search:
if search_element in no_square_bracket:
pass
elif search_element not in no_square_bracket:
acc_first_square_bracket_line = acc_search_file_element(file_name, search_element)
acc_second_square_bracket_line = acc_search_file_element(file_name, "]", acc_first_square_bracket_line)
while True:
bracket_lines = list(range(acc_first_square_bracket_line, acc_second_square_bracket_line + 1))
elements = []
for element_numbers in bracket_lines:
element_list = fileprint[element_numbers]
if search_element in element_list:
if not "=" in search_element:
search_element = search_element + "="
element_list = element_list.replace(search_element, "")
element_list = element_list.lstrip()
elements.append(element_list)
acc_file_line = elements
break
global acc_file
acc_file_temporary = []
for acc_file in acc_file_line:
acc_file = acc_file
if acc_file == "":
if search_element in not_needed_informations:
if "=" in search_element:
search_element = search_element.replace("=", "")
acc_file = ("There is no " + search_element)
return acc_file
elif search_element not in not_needed_informations:
if "=" in search_element:
search_element = search_element.replace("=", "")
pass
acc_file = ("There is no " + search_element + ", but it must be something indicated!")
return acc_file
else:
acc_file = "An error appears!"
return acc_file
if "[" in acc_file:
acc_file = acc_file.replace("[", "")
if "]" in acc_file:
acc_file = acc_file.replace("]", "")
if '"' in acc_file:
acc_file = acc_file.replace('"', "")
acc_file_temporary.append(acc_file)
if len(acc_file_temporary) > 1:
acc_file = (", ".join(acc_file_temporary))
else:
acc_file = ("".join(acc_file_temporary))
if ",," in acc_file:
acc_file = acc_file.replace(",,", ",")
if re.search("[a-zA-Z]", acc_file) == None:
if search_element in no_square_bracket:
if "=" in search_element:
search_element = search_element.replace("=", "")
print("There is no " + search_element + ", but it must be something indicated!")
return acc_file
def acc_search_file_element(file_name, search_element, from_line=0):
if "]" in search_element:
pass
if "[" in search_element:
pass
while True:
if search_element in open(file_name, "r").readlines()[from_line]:
break
else:
from_line = from_line + 1
return from_line
print(acc_file_search("example.cfg", "raw_command"))

View File

@ -0,0 +1,22 @@
from tkinter import *
root = Tk()
frame = Frame(root)
frame.pack()
bottomframe = Frame(root)
bottomframe.pack( side = BOTTOM )
redbutton = Button(frame, text="Red", fg="red")
redbutton.pack( side = LEFT)
greenbutton = Button(frame, text="green", fg="green")
greenbutton.pack( side = LEFT )
bluebutton = Button(frame, text="Blue", fg="blue")
bluebutton.pack( side = LEFT )
blackbutton = Button(bottomframe, text="Black", fg="black")
blackbutton.pack( side = BOTTOM)
root.mainloop()

View File

@ -0,0 +1,10 @@
name=a
author=
version=
command_type=
command_file=["g"]
raw_command=["defa():='a'
'b'
'c'
"]

Binary file not shown.

View File

@ -0,0 +1,27 @@
#!/bin/bash
if [ "$#" -gt "1" ]; then
echo "too many arguments were given"
elif [ "$#" -eq "1" ]; then
if [ "$1" == "--all" ]; then
yes | pip3 uninstall aionlib colorama pafy pocketsphinx psutil pyaudio pyudev snowboy SpeechRecognition Wikipedia-API youtube_dl
apt-get -y purge bison build-essential espeak ffmpeg flac libasound2-dev libatlas-base-dev libpulse-dev python3-pyaudio sox subversion swig vlc wget
apt-get -y autoremove
rm -r /usr/local/aion-*
rm -r /etc/aion_data
rm /usr/bin/aion
else
echo "unexpected argument were given"
exit 1
fi
else
yes | pip3 uninstall aionlib colorama pafy pocketsphinx psutil pyaudio pyudev snowboy SpeechRecognition Wikipedia-API youtube_dl
apt-get -y remove bison build-essential espeak ffmpeg flac libasound2-dev libatlas-base-dev libpulse-dev python3-pyaudio sox subversion swig vlc wget
rm -r /usr/local/aion-*
fi

11
aion_data/etc/install.sh Normal file
View File

@ -0,0 +1,11 @@
#!/bin/bash
if [ ! -d "/usr/local/aion-"]; then
apt-get install git
git --clone https://github.com/blueShard-dev/aion /tmp/aion_installation
bash /tmp/aion_installation/install.sh
rm -r /tmp/aion_installation
else
echo "Aion is already installed"
fi

View File

@ -0,0 +1,10 @@
<activate_phrases>
<erzähle__and__über skill="skills" method="Wikipedia"/>
<erzähl__and__über skill="skills" method="Wikipedia"/>
<ip-adresse skill="skills" method="IpAddress"/>
<prozessor_auslastung skill="skills" method="CpuUsage"/>
<spiele skill="skills" method="Play"/>
<spiel skill="skills" method="Play"/>
<uhr skill="skills" method="CurrentTime"/>
<zeit skill="skills" method="CurrenTime"/>
</activate_phrases>

View File

@ -0,0 +1,19 @@
<de_DE>
<skills.cpu_ram_usage>Der Prozessor wird zu {cpu_usage} und der RAM zu {ram_usage} prozent genutzt</skills.cpu_ram_usage>
<skills.cpu_usage>Der Prozessor wird zu {cpu_usage} genutzt</skills.cpu_usage>
<skills.current_time_full_am/>
<skills.current_time_full_pm/>
<skills.current_time_half_am/>
<skills.current_time_half_pm/>
<skills.current_time_past_am/>
<skills.current_time_past_pm/>
<skills.current_time_to_am/>
<skills.current_time_to_pm/>
<skills.current_time_full>Es ist {hour} Uhr</skills.current_time_full>
<skills.current_time_half>Es ist {hour} Uhr {minute}</skills.current_time_half>
<skills.current_time_etc>Es ist {hour} Uhr {minute}</skills.current_time_etc>
<skills.ip_address>Meine IP ist {ip_address}</skills.ip_address>
<skills.ram_usage>Der RAM wird zu {ram_usage} prozent genutzt</skills.ram_usage>
<skills.wikipedia>{article_text}</skills.wikipedia>
<skills.wikipedia_article_not_found>Der Artikel {article_text} existiert nicht</skills.wikipedia_article_not_found>
</de_DE>

View File

@ -0,0 +1,10 @@
<activate_phrases>
<cpu_usage skill="skills" method="CpuUsage"/>
<ip_address skill="skills" method="IpAddress"/>
<play skill="skills" method="Play"/>
<processor_usage skill="skills" method="CpuUsage"/>
<ram_usage skill="skills" method="RamUsage"/>
<tell__and__about skill="skills" method="Wikipedia"/>
<time skill="skills" method="CurrentTime"/>
<virtual_memory_usage skill="skills", method="RamUsage"/>
</activate_phrases>

View File

@ -0,0 +1,19 @@
<en_US>
<skills.cpu_ram_usage>The processor uses {cpu_usage} and the ram {ram_usage} percent</skills.cpu_ram_usage>
<skills.cpu_usage>The processor uses {cpu_usage} percent</skills.cpu_usage>
<skills.current_time_full_am>It's {hour} a.m.</skills.current_time_full_am>
<skills.current_time_full_pm>It's {hour} p.m.</skills.current_time_full_pm>
<skills.current_time_half_am>It's half past {hour} a.m.</skills.current_time_half_am>
<skills.current_time_half_pm>It's half past {hour} p.m.</skills.current_time_half_pm>
<skills.current_time_past_am>It's {minute} past {hour} a.m.</skills.current_time_past_am>
<skills.current_time_past_pm>It's {minute} past {hour} p.m.</skills.current_time_past_pm>
<skills.current_time_to_am>It's {minute} to {hour} a.m.</skills.current_time_to_am>
<skills.current_time_to_pm>It's {minute} to {hour} p.m.</skills.current_time_to_pm>
<skills.current_time_full>It's {hour} o'clock</skills.current_time_full>
<skills.current_time_half>It's half past {hour}</skills.current_time_half>
<skills.current_time_etc>It's {hour} {minute}</skills.current_time_etc>
<skills.ip_address>My IP is {ip_address}</skills.ip_address>
<skills.ram_usage>The ram uses {ram_usage} percent</skills.ram_usage>
<skills.wikipedia>{article_text}</skills.wikipedia>
<skills.wikipedia_article_not_found>The article {article_name} doesnt exist</skills.wikipedia_article_not_found>
</en_US>

View File

@ -0,0 +1,2 @@
<run_after>
</run_after>

View File

@ -0,0 +1,2 @@
<run_before>
</run_before>

235
aion_data/skills/skills.py Normal file
View File

@ -0,0 +1,235 @@
#!/usr/bin/python3
from glob import glob
from sys import path
path.insert(0, glob("/usr/local/aion-*/aion_core")[0])
from aion_core import config as aconf
from aion_core import language as alang
from aion_core.skill import Skill
class CpuRamUsage(Skill):
"""
skill class to get the cpu and ram usage
"""
def main(self):
from psutil import cpu_percent, virtual_memory
from statistics import mean
from time import sleep
testing_time = 10
print_process = False
cpu_list = []
ram_list = []
while True:
cpu = cpu_percent()
cpu_list.append(cpu)
ram = virtual_memory()[2]
ram_list.append(ram)
if print_process is True:
print("CPU: " + str(cpu) + "%")
print("RAM: " + str(ram) + "%")
sleep(1)
if 0.0 in cpu_list:
cpu_list.remove(0.0)
if len(cpu_list) == testing_time and len(ram_list) == testing_time:
cpu = mean(cpu_list)
ram = mean(ram_list)
break
elif len(cpu_list) == testing_time - 1 and len(ram_list) == testing_time:
cpu = cpu_percent()
cpu_list.append(cpu)
cpu = mean(cpu_list)
ram = mean(ram_list)
break
self.speech_output(alang.start("skills", "cpu_ram_usage", {"cpu_usage": round(cpu, 2), "ram_usage": round(ram, 2)}))
class CpuUsage(Skill):
"""
skill class to get the cpu usage
"""
def main(self):
from statistics import mean
from psutil import cpu_percent
from time import sleep
testing_time = 10
print_process = False
cpu_list = []
while True:
cpu = cpu_percent()
cpu_list.append(cpu)
if print_process is True:
print("CPU: " + str(cpu) + "%")
sleep(1)
if 0.0 in cpu_list:
cpu_list.remove(0.0)
if len(cpu_list) == testing_time:
cpu = (mean(cpu_list))
break
self.speech_output(alang.start("skills", "cpu_usage", {"cpu_usage": round(cpu, 2)}))
class CurrentTime(Skill):
"""
skill class to get the current time
"""
def main(self):
from datetime import datetime
current_time = datetime.now()
time_dict = {"hour": current_time.hour, "minute": current_time.minute, "second": current_time.second, "microsecond": current_time.microsecond}
if aconf.Aion().get_time_format() == "12":
if time_dict["minute"] == 0:
if time_dict["hour"] < 13:
self.speech_output(alang.start("skills", "current_time_full_am", time_dict))
else:
time_dict["hour"] = time_dict["hour"] - 12
self.speech_output(alang.start("skills", "current_time_full_pm", time_dict))
elif time_dict["minute"] == 30:
if time_dict["hour"] < 13:
self.speech_output(alang.start("skills", "current_time_half_am", time_dict))
else:
time_dict["hour"] = time_dict["hour"] - 12
self.speech_output(alang.start("skills", "current_time_half_pm", time_dict))
elif 0 < time_dict["minute"] < 30:
if time_dict["hour"] < 13:
self.speech_output(alang.start("skills", "current_time_past_am", time_dict))
else:
time_dict["hour"] = time_dict["hour"] - 12
self.speech_output(alang.start("skills", "current_time_past_pm", time_dict))
elif time_dict["minute"] > 30:
time_dict["minute"] = 60 - time_dict["minute"]
if time_dict["hour"] < 13:
self.speech_output(alang.start("skills", "current_time_to_am", time_dict))
else:
time_dict["hour"] = time_dict["hour"] - 12
self.speech_output(alang.start("skills", "current_time_to_pm", time_dict))
else:
self.speech_output(alang.start("skills", "current_time_etc", time_dict))
else:
if time_dict["minute"] == 0:
self.speech_output(alang.start("skills", "current_time_full", time_dict))
elif time_dict["minute"] == 30:
self.speech_output(alang.start("skills", "current_time_half", time_dict))
else:
self.speech_output(alang.start("skills", "current_time_etc", time_dict))
class IpAddress(Skill):
"""
skill class to get the ip address
"""
def main(self):
from socket import gethostname, gethostbyname
self.speech_output(alang.start("skills", "ip_address", {"ip_address": gethostbyname(gethostname() + ".local")}))
class Play(Skill):
"""
skill class to play a audio from youtube
"""
def main(self):
from aion_core.utils import get_full_directory_data, vlc
file_or_search_element = self.speech_input.lower().replace(self.activate_phrase.lower(), "")
for file in get_full_directory_data(file_or_search_element):
if file_or_search_element in file:
return vlc(file_or_search_element)
import urllib.parse, urllib.request
from pafy import new
from re import findall
search_query = urllib.parse.urlencode({"search_query": file_or_search_element})
for i in range(10): # sometimes the video url's cannot be found
try:
html_content = urllib.request.urlopen("https://www.youtube.com/results?" + search_query)
search_results = findall(r'href=\"\/watch\?v=(.{11})', html_content.read().decode())
vlc(new(str("https://www.youtube.com/watch?v=" + search_results[0])).getbestaudio().url)
break
# i do it this way, because vlc sometimes don't extract the 'only audio url' from the youtube url
except IndexError:
pass
def run_after(self):
for plugin in self.run_after_plugins:
self.start_run_after_plugin(plugin["name"])
class RamUsage(Skill):
"""
skill class to get ram usage
"""
def main(self):
from statistics import mean
from psutil import virtual_memory
from time import sleep
testing_time = 10
print_process = False
ram_list = []
while True:
ram = virtual_memory()[2]
ram_list.append(ram)
if print_process is True:
print("RAM: " + str(ram) + "%")
sleep(1)
if len(ram_list) == testing_time:
ram = mean(ram_list)
break
self.speech_output(alang.start("skills", "ram_usage", {"ram_usage": round(ram, 2)}))
class Shutdown(Skill):
"""
skill class to shutdown the system
"""
def main(self):
from os import system
system("sudo shutdown -h 0")
class Wikipedia(Skill):
"""
skill class to search an article on wikipedia
"""
def main(self):
from aion_core.utils import remove_brackets, remove_space, remove_string_sequence
from wikipediaapi import Wikipedia
splitted_acph = self.activate_phrase.split("__and__")
searched_article = remove_string_sequence(self.speech_input, splitted_acph[0], splitted_acph[-1])
wiki = Wikipedia(aconf.Aion().get_language().split("_")[0])
article = wiki.page(searched_article)
if article.exists():
article_text = remove_brackets(article.summary)
article_text = remove_space(article_text)
self.speech_output(alang.start("skills", "wikipedia", {"article_text": article_text}))
else:
self.speech_output(alang.start("skills", "wikipedia_article_not_found", {"article_name": searched_article}))

View File

@ -0,0 +1,10 @@
<skills>
<skills author="blueShard">
<additional_directories>None</additional_directories>
<description>The official skill library</description>
<license>MIT</license>
<main_file>skills.py</main_file>
<required_python3_packages>['psutil', 'statistics', 'Wikipedia-API']</required_python3_packages>
<version>1.0.0</version>
</skills>
</skills>