Add files via upload

This commit is contained in:
blueShard-dev 2020-06-28 11:31:26 +00:00 committed by GitHub
parent 5ecf598a78
commit 8e6659e315
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 4051 additions and 0 deletions

34
README.md Normal file
View File

@ -0,0 +1,34 @@
**_aionlib_ - library support for [aion](https://github.com/blueShard-dev/aion)**
- [Introduction](#introduction)
- [Installation](#installation)
- [Todo](#todo)
- [License](#license)
# Introduction
**aionlib** is the official library support for the [aion](https://github.com/blueShard-dev/aion_project)
# Installation
To install **aionlib** with pip3, type:
```
sudo pip3 install aionlib
```
If you want to install **aionlib** from github, type:
```
sudo git clone https://github.com/blueShard-dev/aionlib
cd aionlib
sudo python3 setup.py install
```
# Todo
- [ ] tutorial for all classes / functions
# License
This project is licensed under the Mozilla Public Licence 2.0 (MPL-2.0) License - see the [LICENSE](License) file for more details

36
aionlib/__init__.py Normal file
View File

@ -0,0 +1,36 @@
#!/usr/bin/python3
__author__ = "blueShard"
__license__ = "GPL-3.0"
__version__ = "0.1.0"
from ._utils import start_check as _start_check
_start_check()
is_aion = _start_check.is_aion
is_linux = _start_check.is_linux
from ._utils import aion_data_path, aion_path
from . import config, language, logging, plugin, utils, variable
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
"""
if is_aion:
from ._utils import import_aion_internal_file
return import_aion_internal_file("__init__").speech_output(speech_output)
else:
from ._utils import no_aion
no_aion()

881
aionlib/_utils.py Normal file
View File

@ -0,0 +1,881 @@
#!/usr/bin/python3
from glob import glob as _glob
from xml.dom import minidom as _minidom
import xml.etree.ElementTree as _ET
aion_data_path = "/etc/aion_data"
aion_path = "".join(_glob("/usr/local/aion-*"))
def import_aion_internal_file(fname: str):
"""
imports an file from the aion core
:param fname: str
name of the file
syntax: <filename>
example: "version.py"
:return: a imported module from the aion core
:since: 0.1.0
"""
from . import is_aion
if is_aion:
from importlib import import_module
from sys import path
path.insert(0, aion_path + "/aion_core")
return import_module(fname)
else:
no_aion()
def no_aion() -> None:
"""
a function which get called from some 'aionlib' functions if aion is not installed but required
:return: None
:since: 0.1.0
"""
pass
def start_check() -> None:
"""
checks if system is linux and if aion is installed
:return: None
:since: 0.1.0
"""
from colorama import Fore
from os.path import isdir
from platform import system
if system().lower() != "linux":
print(Fore.RED + "It seems like you not using Linux (Raspbian on Raspberry Pi recommended). To use the whole library run this library on Linux (recommended Raspbian on Raspberry Pi)" + Fore.RESET)
start_check.is_linux = False
else:
start_check.is_linux = True
if isdir(aion_path) is False:
print(Fore.RED + "It seems like you haven't installed aion. To use the whole library install aion" + Fore.RESET)
start_check.is_aion = False
else:
start_check.is_aion = True
class BaseXMLBuilder:
"""
a class to simple build a '.xml' file
:since: 0.1.0
"""
def __init__(self, root_name: str = "root", **root_extra: str) -> None:
"""
:param root_name: str, optional
name of the root element of the xml file
syntax: <root name>
example: "root"
:param root_extra: kwargs, optional
attributes for the root element
syntax: <key>=<value>
example: author="blueShard"
:return: None
:since: 0.1.0
"""
self.root_name = root_name
self._element_list = [self.root_name]
self._root = _ET.Element(root_name, **root_extra)
def _prettify(self, string: str = None) -> str:
"""
prettifies the given string
:param string: str
string to prettify
syntax: <string>
example: "<root><test_element></test_element></root>"
:return: str
returns the_prettified string
syntax: <string>
example: "<root>
<test_element>
</test_element>
</root>"
:since: 0.1.0
"""
if string is None:
reparsed = _minidom.parseString(_ET.tostring(self._root, "utf-8"))
else:
reparsed = _minidom.parseString(bytes(string, "utf-8", errors="ignore"))
pre_output = reparsed.toprettyxml(indent=" ")
return "\n".join(pre_output.split("\n")[1:])
def create_root_element(self, name: str, text: str = None, attrib: dict = {}, **extra: str) -> None:
"""
creates a new entry as a sub element of the root element
:param name: str
name of the new element
syntax: <name>
example: "root_child"
:param text: str, optional
text of the new element
syntax: <text>
example: "This is a root element"
:param attrib: dict, optional
attributes for the new element
syntax: {<key>, <value>}
example: {"author": "blueShard"}
:param extra: kwargs, optional
attributes for the new element
syntax: <key>=<value>
example: author="blueShard"
:return: None
:since: 0.1.0
"""
if text:
element = _ET.Element(name, attrib, **extra).text = text
else:
element = _ET.Element(name, attrib, **extra)
self._root.append(element)
self._element_list.append(name)
def create_sub_element(self, parent_name: str, name: str, text: str = None, attrib: dict = {}, parent_attrib: dict = None, **extra: str) -> None:
"""
creates a sub element of an parent element
:param parent_name: str
name of the parent element to which the sub element should be added
syntax: <parent name>
example: "root_child"
:param name: str
name of the new sub element you want to add
syntax: <name>
example: "sub_child"
:param text: str, optional
text of the new sub element
syntax: <text>
example: "This is a sub element"
:param attrib: dict, optional
attributes for the new element
syntax: {<key>, <value>}
example: {"author": "blueShard"}
:param parent_attrib: dict, optional
attributes of the new sub element
syntax: {<key>: <value>}
example: {"language": "en_US"}
:param extra: kwargs, optional
attributes of the new sub element
syntax: <key>=<value>
example: language="en_US"
:return: None
:since: 0.1.0
"""
if parent_name in self._element_list:
for parent in self._root.iter(parent_name):
if parent_attrib:
if parent.attrib == parent_attrib:
if text:
_ET.SubElement(parent, name, attrib, **extra).text = text
else:
_ET.SubElement(parent, name, attrib, **extra)
self._element_list.append(name)
else:
if text:
_ET.SubElement(parent, name, attrib, **extra).text = text
else:
_ET.SubElement(parent, name, attrib, **extra)
self._element_list.append(name)
else:
raise IndexError("Couldn't find parent '" + parent_name + "'. The available parents are in this list: " + str(self._element_list))
def get_string(self, pretty_print: bool = True) -> str:
"""
get sting of the xml tree
:param pretty_print: bool, optional
sets True or False if the xml tree string should be pretty printed
syntax: <boolean>
example: True
:return: str
returns the string of the builded xml tree
syntax: <xml tree>
example: "<root>
<root_child author="blueShard">
<sub_child>This is a sub element</sub_child>
</root_child>
</root>"
:since: 0.1.0
"""
if pretty_print is True:
return self._prettify()
else:
return _ET.tostring(self._root, "utf-8").decode("ascii")
def write(self, fname: str, mode: str = "w", pretty_print: bool = True) -> None:
"""
writes the xml tree to a file
:param fname: str
filename of file you want to write
syntax: <filename>
example: "/home/pi/text.xml"
:param mode: str, optional
mode to write on file
syntax: <mode>
example: "w"
:param pretty_print: bool, optional
sets True or False if the xml tree string should be pretty printed
syntax: <boolean>
example: True
:return: None
:since: 0.1.0
"""
with open(fname, mode=mode) as file:
file.write(self.get_string(pretty_print))
file.close()
class BaseXMLReader:
"""
a class to simple reead '.xml' file
:since: 0.1.0
"""
def __init__(self, fname: str) -> None:
"""
makes the fname and auto_write available for all class methods and set all variables
:param fname: str
filename of the file you want to read
syntax: <filename>
example: "/home/pi/test.xml"
:return: None
:since: 0.1.0
"""
self.fname = fname
self._tree = _ET.parse(self.fname)
self._root = self._tree.getroot()
self.get_infos._root = self._root
def _prettify(self, string: str = None) -> str:
"""
prettifies the given string
:param string: str
string to prettify
syntax: <string>
example: "<root><test_element></test_element></root>"
:return: str
returns the_prettified string
syntax: <string>
example: "<root>
<test_element>
</test_element>
</root>"
:since: 0.1.0
"""
if string is None:
reparsed = _minidom.parseString(_ET.tostring(self._root, "utf-8"))
else:
reparsed = _minidom.parseString(bytes(string, "utf-8", errors="ignore"))
pre_output = reparsed.toprettyxml(indent=" ")
return "\n".join(pre_output.split("\n")[1:])
class get_infos(dict):
"""
a modified dict class with indexing items
:since: 0.1.0
"""
def __init__(self, elem_tags: (str, list) = []) -> dict:
"""
get infos about an element in the file
:param elem_tags: list
name of elements you want to get infos about
syntax: [<element tags>]
example: ["sub_child"]
:return: dict
returns a dict of names from the given elements with a list of dictionaries of found elements (complex description xD)
syntax: {<element>: [{"parent": {"tag": <parent tag>, "text": <text of the parent element>, "attrib": {<attributes of the parent element>}}, "childs": [<childs of the element>], "tag": <tag of the element>, "text": <text of the element>, "attrib": {<attributes of the element>}}]}
example: {"sub_child": [{"parent": {"tag": "root_child", "text": "", "attrib": {"author": "blueShard"}}, "childs": ["sub_child"], "tag": "sub_child", "text": "This is a sub element", "attrib": {}}]}
:since: 0.1.0
"""
if isinstance(elem_tags, str):
elem_tags = [elem_tags]
child_list = []
return_dict = {}
for elem in elem_tags:
if elem == "<all>":
continue
elif elem == "<root>":
return_dict[self._root.tag] = []
else:
return_dict[elem] = []
all_child_list = []
if "<all>" in elem_tags:
if self._root.tag in return_dict:
pass
else:
return_dict[self._root.tag] = []
return_dict[self._root.tag].append(
{"parent": {"tag": "", "text": "", "attrib": {}}, "childs": [child.tag for child in self._root], "tag": self._root.tag, "text": "", "attrib": self._root.attrib})
for root_child in self._root:
if root_child.tag in return_dict:
pass
else:
return_dict[root_child.tag] = []
return_dict[root_child.tag].append(
{"parent": {"tag": self._root.tag, "text": self._root.text, "attrib": self._root.attrib}, "childs": [sub_root_child.tag for sub_root_child in root_child],
"tag": root_child.tag, "text": root_child.text, "attrib": root_child.attrib})
all_child_list.append(root_child)
for parent in list(all_child_list):
for child in parent:
if child.tag in return_dict:
pass
else:
return_dict[child.tag] = []
return_dict[child.tag].append(
{"parent": {"tag": parent.tag, "text": parent.text, "attrib": parent.attrib}, "childs": [sub_child.tag for sub_child in child], "tag": child.tag, "text": child.text,
"attrib": child.attrib})
all_child_list.append(child)
if child in all_child_list:
all_child_list.remove(child)
else:
if self._root.tag in return_dict:
return_dict[self._root.tag].append({"parent": {}, "childs": [child.tag for child in self._root], "tag": self._root.tag, "text": "", "attrib": self._root.attrib})
for root_child in self._root:
if root_child.tag in return_dict:
return_dict[root_child.tag].append(
{"parent": {"tag": self._root.tag, "text": self._root.text, "attrib": self._root.attrib}, "childs": [sub_root_child.tag for sub_root_child in root_child],
"tag": root_child.tag, "text": root_child.text, "attrib": root_child.attrib})
else:
child_list.append(root_child)
for parent in list(child_list):
for child in parent:
if child.tag in return_dict:
return_dict[child.tag].append(
{"parent": {"tag": parent.tag, "text": parent.text, "attrib": parent.attrib}, "childs": [sub_child.tag for sub_child in child], "tag": child.tag, "text": child.text,
"attrib": child.attrib})
else:
child_list.append(child)
if child in child_list:
child_list.remove(child)
self._return_dict = return_dict
self.items._return_dict_keys = return_dict.keys()
self.items._return_dict_values = return_dict.values()
self.keys._return_dict_keys = return_dict.keys()
self.values._return_dict_values = return_dict.values()
super().__init__(self._return_dict)
def __iter__(self):
return iter(self._return_dict)
def __next__(self):
return self._return_dict
def __repr__(self):
return self._return_dict
def __str__(self):
return str(self._return_dict)
def index(self, index: int) -> dict:
"""
index a key-value pair in a dict
:param index: int
index of the key-value pair you want to get
syntax: <index>
example: 5
:return: dict
returns the key-value pair of the given index
syntax: {<key>: <value>}
example: {"test_key": "test_value"}
:since: 0.1.0
"""
i = 0
for key, value in self._return_dict.items():
if i == index:
return {key: value}
else:
i += 1
raise IndexError("dict index out of range")
class items:
"""
a modified items() function from dict with indexing items
:since: 0.1.0
"""
def __init__(self):
pass
def __getitem__(self, item):
return tuple(self._return_dict_items)[item]
def __iter__(self):
return iter(self._return_dict_items)
def __len__(self):
return len(self._return_dict_items)
def __next__(self):
return self._return_dict_items
def __repr__(self):
return self._return_dict_items
def __str__(self):
return str(self._return_dict_items)
def index(self, index: int):
"""
index a key-value pair in a dict
:param index: int
index of the key-value pair you want to get
syntax: <index>
example: 5
:return: the given index in the values
:since: 0.1.0
"""
return {list(self._return_dict_keys)[index]: list(self._return_dict_values)[index]}
class keys:
"""
a modified keys() function from dict with indexing items
:since: 0.1.0
"""
def __init__(self):
pass
def __iter__(self):
return iter(self._return_dict_keys)
def __len__(self):
return len(list(self._return_dict_keys))
def __next__(self):
return self._return_dict_keys
def __repr__(self):
return self._return_dict_keys
def __str__(self):
return str(self._return_dict_keys)
def index(self, index: int):
"""
index a key in a dict
:param index: int
index of the key you want to get
syntax: <index>
example: 5
:return: the given index in the keys
:since: 0.1.0
"""
return list(self._return_dict_keys)[index]
class values:
"""
a modified values() function from dict with indexing items
:since: 0.1.0
"""
def __init__(self):
pass
def __iter__(self):
return iter(self._return_dict_values)
def __len__(self):
return len(list(self._return_dict_values))
def __next__(self):
return self._return_dict_values
def __repr__(self):
return self._return_dict_values
def __str__(self):
return str(self._return_dict_values)
def index(self, index: int):
"""
index a value in a dict
:param index: int
index of the value you want to get
syntax: <index>
example: 5
:return: the given index in the values
:since: 0.1.0
"""
return list(self._return_dict_values)[index]
def get_string(self, pretty_print: bool = True) -> str:
"""
gets the string of the xml tree in the file
:param pretty_print: bool, optional
sets True or False if the xml tree string should be pretty printed
syntax: <boolean>
example: True
:return: str
returns the string of the xml tree
syntax: <xml tree>
example: "<root>
<root_child author="blueShard">
<sub_child>This is a sub element</sub_child>
</root_child>
</root>"
:since: 0.1.0
"""
string = _ET.tostring(self._root, "utf-8").decode("ascii")
if pretty_print is True:
if "\n" in string:
return string
else:
return self._prettify()
else:
if "\n" in string:
return "".join([line.strip() for line in _ET.tostring(self._root, "utf-8").decode("ascii").split("\n")])
else:
return string
class BaseXMLWriter:
"""
a class to simple change/write a '.xml' file
:since: 0.1.0
"""
def __init__(self, fname: str, auto_write: bool = False) -> None:
"""
:param fname: str
filename of the file you want to write to
syntax: <filename>
example: "/home/pi/test.xml"
:param auto_write: bool, optional
sets if after every change to the getted xml tree the changes should be write to the file
syntax: <boolean>
example: False
:return: None
:since: 0.1.0
"""
self.auto_write = auto_write
self.fname = fname
self._root = _ET.fromstring("".join([item.replace("\n", "").strip() for item in [line for line in open(self.fname, "r")]]))
def _prettify(self, string: str = None) -> str:
"""
prettifies the given string
:param string: str
string to prettify
syntax: <string>
example: "<root><test_element></test_element></root>"
:return: str
returns the_prettified string
syntax: <string>
example: "<root>
<test_element>
</test_element>
</root>"
:since: 0.1.0
"""
if string is None:
reparsed = _minidom.parseString(_ET.tostring(self._root, "utf-8"))
else:
reparsed = _minidom.parseString(string)
pre_output = reparsed.toprettyxml(indent=" ")
return "\n".join(pre_output.split("\n")[1:])
def add(self, parent_tag: str, elem_tag: str, text: str = None, attrib: dict = {}, parent_attrib: dict = None, **extra: str) -> None:
"""
adds an element to xml tree
:param parent_tag : str
name of the parent element
syntax: <parent name>
example: "root_child"
:param elem_tag : str
name of the element you want to add
syntax: <element name>
example: "second_sub_child"
:param text : str, optional
text of the element you want to add
syntax: <text>
example: "This is the second sub child"
:param attrib : dict
attributes for the new element
syntax: {<key>, <value>}
example: {"author": "blueShard"}
:param parent_attrib : dict, optional
attributes of the parent element
syntax: {<key>: <value>}
example: {"author": "blueShard"}
:param extra : kwargs, optional
attributes of the new element
syntax: <key>=<value>
example: language="de_DE"
:return: None
:since: 0.1.0
"""
if parent_tag == "<root>":
parent_tag = self._root.tag
if parent_tag == self._root.tag:
if parent_attrib:
if parent_attrib == self._root.attrib:
if text:
root_text_element = _ET.Element(elem_tag, attrib, **extra)
root_text_element.text = text
self._root.append(root_text_element)
else:
self._root.append(_ET.Element(elem_tag, attrib, **extra))
else:
if text:
root_text_element = _ET.Element(elem_tag, attrib, **extra)
root_text_element.text = text
self._root.append(root_text_element)
else:
self._root.append(_ET.Element(elem_tag, attrib, **extra))
else:
for parent in self._root.iter(parent_tag):
if parent_attrib:
if parent.attrib == parent_attrib:
if text:
_ET.SubElement(parent, elem_tag).text = text
else:
_ET.SubElement(parent, elem_tag, attrib, **extra)
else:
if text:
_ET.SubElement(parent, elem_tag).text = text
else:
_ET.SubElement(parent, elem_tag, attrib, **extra)
if self.auto_write is True:
self.write()
def get_string(self, pretty_print: bool = False) -> str:
"""
gets the string of the xml tree in the file
:param pretty_print: bool, optional
sets True or False if the xml tree string should be pretty printed
syntax: <boolean>
example: True
:return: str
returns the string of the xml tree
syntax: <xml tree>
example: "<root>
<root_child author="blueShard">
<sub_child>This is a sub element</sub_child>
<second_sub_child language="de_DE"/>
</root_child>
</root>"
:since: 0.1.0
"""
string = _ET.tostring(self._root, "utf-8").decode("ascii")
if pretty_print is True:
if "\n" in string:
return string
else:
return self._prettify()
else:
if "\n" in string:
return "".join([line.strip() for line in _ET.tostring(self._root, "utf-8").decode("ascii").split("\n")])
else:
return string
def remove(self, parent_tag: str, elem_tag: str, parent_attrib: dict = None) -> None:
"""
removes an element from the xml tree
:param parent_tag : str
name of the parent element
syntax: <parent name>
example: "root_child"
:param elem_tag : str
name of the element you want to remove
syntax: <element name>
example: "second_sub_child"
:param parent_attrib : dict, optional
attributes of the parent element
syntax: {<key>: <value>}
example: {"author": "blueShard"}
:return: None
:since: 0.1.0
"""
if parent_tag == "<root>":
parent_tag = self._root.tag
if parent_tag == self._root.tag:
for child in self._root:
if child.tag == elem_tag:
if parent_attrib:
if self._root.attrib == parent_attrib:
self._root.remove(child)
else:
self._root.remove(child)
for parent in self._root.iter(parent_tag):
for child in parent:
if child.tag == elem_tag:
if parent_attrib:
if parent.attrib == parent_attrib:
parent.remove(child)
else:
parent.remove(child)
if self.auto_write is True:
self.write()
def update(self, parent_tag: str, elem_tag: str, text: str = None, attrib: dict = {}, parent_attrib: dict = None, **extra: str) -> None:
"""
updates an element in the xml tree
:param parent_tag : str
name of the parent element
syntax: <parent name>
example: "root_child"
:param elem_tag : str
name of the element you want to update
syntax: <element name>
example: "second_sub_child"
:param text : str, optional
new text of the updated element
syntax: <text>
example: "New text of the second sub child"
:param attrib : dict
attributes for the new element
syntax: {<key>, <value>}
example: {"author": "blueShard"}
:param parent_attrib : dict, optional
attributes of the parent element
syntax: {<key>: <value>}
example: {"author": "blueShard"}
:param extra : kwargs, optional
new attributes of the updated element
syntax: <key>=<value>
example: language="de_DE"
:return: None
:since: 0.1.0
"""
if parent_tag == "<root>":
parent_tag = self._root.tag
if parent_tag == self._root.tag:
for child in self._root:
if child.tag == elem_tag:
if parent_attrib:
if self._root.attrib == parent_attrib:
if text:
child.text = str(text)
for key, value in attrib.items():
child.set(str(key), str(value))
for key, value in extra.items():
child.set(key, str(value))
else:
if text:
child.text = str(text)
for key, value in attrib.items():
child.set(str(key), str(value))
for key, value in extra.items():
child.set(key, str(value))
for parent in self._root.iter(parent_tag):
for child in parent:
if child.tag == elem_tag:
if parent_attrib:
if parent.attrib == parent_attrib:
if text:
child.text = str(text)
for key, value in attrib.items():
child.set(str(key), str(value))
for key, value in extra.items():
child.set(key, str(value))
else:
if text:
child.text = str(text)
for key, value in attrib.items():
child.set(str(key), str(value))
for key, value in extra.items():
child.set(key, str(value))
if self.auto_write is True:
self.write()
def write(self, mode: str = "w", pretty_print: bool = True) -> None:
"""
writes the xml tree to a file
:param mode : str, optional
mode to write on file
syntax: <mode>
example: "w"
:param pretty_print : bool, optional
sets True or False if the xml tree string should be pretty printed
syntax: <boolean>
example: True
:return: None
:since: 0.1.0
"""
with open(self.fname, mode=mode) as file:
if pretty_print is False:
file.write(_ET.tostring(self._root, "utf-8").decode("ascii"))
else:
file.write(self._prettify())
file.close()

125
aionlib/acph.py Normal file
View File

@ -0,0 +1,125 @@
#!/usr/bin/python3
def add_acph(fname: str, skill: str, acph_dict: dict = {}) -> None:
"""
adds an new entry(s) to from argument 'language_locale' given language
:param fname: str
name of the file where the activate phrases should be added
syntax: <file name>
example: "/home/pi/test.acph"
: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
:since: 0.1.0
"""
try:
from .utils import BaseXMLWriter
except ImportError:
from utils import BaseXMLWriter
acph_writer = BaseXMLWriter(fname)
for acph, method in acph_dict:
if exist_acph(fname, acph):
raise IndexError("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(language_locale + ".acph")
def delete_acph(fname: str, acph_list: list = []) -> None:
"""
deletes entries from '<language_locale>.acph'
:param fname: str
file from which the activate phases is being deleted
syntax: <language locale>
example: "/home/pi/test.acph"
: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(fname)
for item in acph_list:
acph_writer.remove("<root>", str(item))
acph_writer.write()
def exist_acph(fname: str, acph: str) -> bool:
"""
checks if a entry exist
:param fname: str
file from 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(fname)
for item in acph_reader.get_infos(["<root>"]).items().index(0):
if acph in item["childs"]:
return True
else:
return False

373
aionlib/config.py Normal file
View File

@ -0,0 +1,373 @@
#!/usr/bin/python3
from . import is_aion
from ._utils import no_aion
if is_aion:
from ._utils import import_aion_internal_file as _import_aion_internal_files
_config = _import_aion_internal_files("config")
class Aion:
def __init__(self) -> None:
if is_aion:
self._aion_config = _config.Aion()
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"]
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
"""
if is_aion:
return self._aion_config.get_hotword_file()
else:
no_aion()
def get_language(self) -> str:
"""
get sett language locale
:return: str
returns language locale
syntax: <language locale>
example: "en_US"
:since: 0.1.0
"""
if is_aion:
return self._aion_config.get_language()
else:
no_aion()
def get_listening_mode(self) -> str:
"""
get set listening mode
:return: str
returns listening mode
syntax: <listening mode>
example: "auto"
:since: 0.1.0
"""
if is_aion:
return self._aion_config.get_listening_mode()
else:
no_aion()
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
"""
if is_aion:
return int(self._aion_config.get_pid_manipulation_number())
else:
no_aion()
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
"""
if is_aion:
return self._aion_config.get_stt_engine()
else:
no_aion()
def get_time_format(self) -> int:
"""
get set time format
:return: str
returns time format
syntax: <time format>
example: 24
:return: None
:since: 0.1.0
"""
if is_aion:
return int(self._aion_config.get_time_format())
else:
no_aion()
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"
:return: None
:since: 0.1.0
"""
if is_aion:
return self._aion_config.get_tts_engine()
else:
no_aion()
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
"""
if is_aion:
self._aion_config.set_hotword_file(hotword_file)
else:
no_aion()
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
"""
if is_aion:
self._aion_config.set_language(language)
else:
no_aion()
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
"""
if is_aion:
self._aion_config.set_listening_mode(listening_mode)
else:
no_aion()
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
"""
if is_aion:
self._aion_config.set_pid_manipulation_number(pid_manipulation_number)
else:
no_aion()
def set_stt_engine(self, stt_engine: str) -> None:
"""
sets the spech-to-text engine
:param stt_engine : str
new speech-to-text engine
syntax: <speech-to-text engine>
example: "google"
:return: None
:since: 0.1.0
"""
if is_aion:
self._aion_config.set_stt_engine(stt_engine)
else:
no_aion()
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
"""
if is_aion:
self._aion_config.set_time_format(time_format)
else:
no_aion()
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
"""
if is_aion:
self._aion_config.set_tts_engine(tts_engine)
else:
no_aion()
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
"""
if is_aion:
_config.add_entry(name=name, text=text, attrib=attrib, parent_name=parent_name, parent_attrib=parent_attrib)
else:
no_aion()
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
"""
if is_aion:
_config.delete_entry(name=name, parent_name=parent_name, parent_attrib=parent_attrib)
else:
no_aion()
def get_entry(name: str, parent_name: str = None, parent_attrib: dict = {}) -> None:
"""
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
"""
if is_aion:
return _config.get_entry(name=name, parent_name=parent_name, parent_attrib=parent_attrib)
else:
no_aion()
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
"""
if is_aion:
_config.update_entry(name=name, text=text, attrib=attrib.update(extra), parent_name=parent_name)
else:
no_aion()

171
aionlib/language.py Normal file
View File

@ -0,0 +1,171 @@
#!/usr/bin/python3
from . import is_aion
from ._utils import no_aion
def add_entry(fname: str, package, entry_dict: dict = {}) -> None:
"""
adds an new entry(s) to from argument 'language_locale' given language
:param fname: str
file name of the file you want to add the entry(s)
language locale from the language to which the entry(s) is/are to be added
syntax: <language locale>
example: "de_DE"
:param package: str
package name to which the entry belongs
syntax: "<package name>"
example: "test_package"
: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
"""
from os.path import isfile
if isfile(fname) is False:
raise FileNotFoundError("the file " + fname + " doesn't exist")
from ._utils import BaseXMLWriter
lng_adder = BaseXMLWriter(fname)
for entry, text in entry_dict.items():
if exist_entry(fname, package, entry) is True:
raise IndexError("the entry " + entry + " already exist")
lng_adder.add("<root>", package + "." + str(entry), text=str(text))
lng_adder.write()
def create_lng_file(language_locale: str, extra_dict: dict = {}, **extra: str) -> 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
package name you want to add specific entries
syntax: {<name of the package you want to add entries>: {{<name of the entry>: <text of the entry>}}
example: {"test_package": {"test_entry": "This is the text for the test text entry"}}
:param extra: kwargs, optional
package name you want to add specific entries
syntax: <name of the package you want to add entries>={<name of the entry>: <text of the entry>}
example: test_package={"test_success": "The test was executed successfully", "text_error": "The test wasn't executed successfully"}
:return: None
:since: 0.1.0
"""
from ._utils import BaseXMLBuilder
from os import getcwd
from os.path import isfile
if isfile(getcwd() + "/" + language_locale + ".lng"):
raise FileExistsError("the language file " + language_locale + ".lng already")
lng_file = BaseXMLBuilder(language_locale)
for package, entry_dict in extra_dict.items():
for entry_name, entry_text in entry_dict.items():
lng_file.create_root_element(language_locale, str(package) + "." + str(entry_name), text=str(entry_text))
for package, entry_dict in extra.items():
for entry_name, entry_text in entry_dict.items():
lng_file.create_root_element(language_locale, str(package) + "." + str(entry_name), text=str(entry_text))
lng_file.write(language_locale + ".lng")
def delete_entry(fname: str, package: str, entry_list: list = []) -> None:
"""
deletes entries from '<language_locale>.lng'
:param fname: str
path to file you want to delete entries
syntax: <fname>
example: "en_US.lng"
:param package: str
name of the package from which the entries should be deleted
syntax: <package 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
"""
from ._utils import BaseXMLWriter
lng_writer = BaseXMLWriter(fname)
for item in entry_list:
lng_writer.remove("language", str(package) + "." + str(item))
def exist_entry(fname: str, package: str, entry: str) -> bool:
"""
checks if a entry exist
:param fname: str
file from which the entry should be search
syntax: <language locale>
example: "en_US"
:param package: str
package name from the entry
syntax: <package name>
example: "test"
:param entry: str
entry name of package (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
"""
from ._utils import BaseXMLReader
entry = entry.replace(" ", "_")
lng_reader = BaseXMLReader(fname)
for item in lng_reader.get_infos(["<root>"]).items().index(0):
if package + "." + 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
"""
if is_aion:
from ._utils import import_aion_internal_file as _import_aion_internal_file
return _import_aion_internal_file("language").start(skill=skill, entry=entry, format=format)
else:
no_aion()

621
aionlib/logging.py Normal file
View File

@ -0,0 +1,621 @@
#!/usr/bin/python3
from . import aion_data_path, is_aion
from ._utils import no_aion
from time import time as _time
class LogAion:
"""
class for adding own logs to the aion logger
:since: 0.1.0
"""
def __init__(self) -> None:
"""
set all class variables
:return: None
:since: 0.1.0
"""
if is_aion:
from ._utils import import_aion_internal_file as _import_aion_internal_file
self._aion_logger = _import_aion_internal_file("logging").LogAll(aion_data_path + "/logs/aion.log",
critical_fname=aion_data_path + "/logs/critical.log",
debug_fname=aion_data_path + "/logs/debug.log",
error_fname=aion_data_path + "/logs/error.log",
info_fname=aion_data_path + "/logs/info.log",
warning_fname=aion_data_path + "/logs/warning.log")
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
"""
if is_aion:
self._aion_logger.critical(msg=msg, lineno=lineno)
else:
no_aion()
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
"""
if is_aion:
self._aion_logger.debug(msg=msg, lineno=lineno)
else:
no_aion()
def error(self, msg: str, lineno: int = 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
"""
if is_aion:
self._aion_logger.error(msg=msg, lineno=lineno)
else:
no_aion()
def info(self, msg: str, lineno: int = 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
"""
if is_aion:
self._aion_logger.info(msg=msg, lineno=lineno)
else:
no_aion()
def warning(self, msg: str, lineno: int = 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
"""
if is_aion:
self._aion_logger.warning(msg=msg, lineno=lineno)
else:
no_aion()
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))

670
aionlib/plugin.py Normal file
View File

@ -0,0 +1,670 @@
#!/usr/bin/python3
from . import aion_data_path as _aion_data_path
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
"""
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("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("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 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
"""
from . import is_aion
from .utils import is_dict_in_dict
from ._utils import no_aion, BaseXMLReader
run_after = {}
if is_aion:
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
else:
no_aion()
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
"""
from . import is_aion
from .utils import is_dict_in_dict
from ._utils import no_aion, BaseXMLReader
run_before = {}
if is_aion:
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
else:
no_aion()
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 _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
"""
from os import getcwd, listdir
write_dict = {}
if isinstance(author, str) is False:
raise TypeError("argument 'author' must be str, got " + type(author).__name__)
write_dict["author"] = author
if isinstance(main_file, str) is False:
raise TypeError("argument 'main_file' must be str, got " + type(author).__name__)
if main_file not in listdir(getcwd()):
raise FileNotFoundError("couldn't find the file " + main_file + " in current directory")
if main_file[:-3] == plugin_name is False:
raise NameError("the file name from " + main_file + " must be same as the argument 'name' (" + plugin_name + ")")
if main_file not in listdir(getcwd()):
raise FileNotFoundError("couldn't find the file '" + main_file + "' in current directory")
write_dict["main_file"] = main_file
if isinstance(plugin_name, str) is False:
raise TypeError("argument 'plugin_name' must be str, got " + type(plugin_name).__name__)
write_dict["plugin_name"] = plugin_name
if isinstance(skill, str) is False:
raise TypeError("argument 'plugin_name' must be dict, got " + type(plugin_methods).__name__)
write_dict["skill"] = skill
if isinstance(plugin_methods, dict) is False:
raise TypeError("argument 'plugin_name' must be dict, got " + type(plugin_methods).__name__)
write_dict["plugin_methods"] = plugin_methods
if isinstance(version, str) is False:
raise TypeError("argument 'version' must be str, got " + type(version).__name__)
write_dict["version"] = version
# ----- #
if isinstance(additional_directories, (list, tuple)) is False:
raise TypeError("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("couldn't find the directory " + directory + " in current directory")
write_dict["additional_directories"] = additional_directories
if isinstance(description, str) is False:
raise TypeError("argument 'description' must be str, got " + type(description).__name__)
write_dict["description"] = description
if isinstance(language_locales, (list, tuple)) is False:
raise TypeError("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("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("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("argument 'license' must be str, got " + type(license).__name__)
write_dict["license"] = license
if isinstance(required_python3_packages, (list, tuple)) is False:
raise TypeError("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: str, 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()")

374
aionlib/skill.py Normal file
View File

@ -0,0 +1,374 @@
#!/usr/bin/python3
from . 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.activate_phrase_list = activate_phrase.split("__and__")
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,
main_file: str,
skill_name: 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
"""
from os import getcwd, listdir
write_dict = {}
if isinstance(author, str) is False:
raise TypeError("argument 'author' must be str, got " + type(author).__name__)
write_dict["author"] = author
if isinstance(language_locales, (list, tuple)) is False:
raise TypeError("argument 'language_locales' must be list or tuple, got " + type(language_locales).__name__)
write_dict["language_locales"] = language_locales
if isinstance(main_file, str) is False:
raise TypeError("argument 'main_file' must be str, got " + type(author).__name__)
if main_file not in listdir(getcwd()):
raise FileNotFoundError("couldn't find the file " + main_file + " in current directory")
if main_file[:-3] == skill_name is False:
raise NameError("the file name from " + main_file + " must be same as the argument 'name' (" + skill_name + ")")
if main_file not in listdir(getcwd()):
raise FileNotFoundError("couldn't find the file '" + main_file + "' in current directory")
write_dict["main_file"] = main_file
if isinstance(skill_name, str) is False:
raise TypeError("argument 'skill_name' must be str, got " + type(skill_name).__name__)
write_dict["pskill_name"] = skill_name
if isinstance(version, str) is False:
raise TypeError("argument 'version' must be str, got " + type(version).__name__)
write_dict["version"] = version
# ----- #
if isinstance(additional_directories, (list, tuple)) is False:
raise TypeError("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("couldn't find the directory " + directory + " in current directory")
write_dict["additional_directories"] = additional_directories
if isinstance(description, str) is False:
raise TypeError("argument 'description' must be str, got " + type(description).__name__)
write_dict["description"] = description
if isinstance(language_dict, dict) is False:
raise TypeError("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("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("argument 'license' must be str, got " + type(license).__name__)
write_dict["license"] = license
if isinstance(required_python3_packages, (list, tuple)) is False:
raise TypeError("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("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("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 get_all_skills() -> list:
"""
returns all installed skills
:return: list
returns list of all installed skills
syntax: [<skill>]
example: ["skills"]
:return: None
:since: 0.1.0
"""
from . import is_aion
from ._utils import no_aion, BaseXMLReader
if is_aion:
return BaseXMLReader(skills_file).get_infos("<root>").items().index(0)[0]["childs"]
else:
no_aion()
return []
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
"""
from . import is_aion
from ._utils import no_aion, BaseXMLReader
if is_aion:
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
else:
no_aion()
return {}

550
aionlib/utils.py Normal file
View File

@ -0,0 +1,550 @@
#!/usr/bin/python3
def download_youtube_audio(url: str, path: str, output_format: str = "mp3") -> None:
"""
downloads youtube audio by url
:param url: str
the url from which the audio should be downloaded
syntax: <url>
example: "https://youtu.be/MAlSjtxy5ak"
:param path: str
the path where the downloaded audio should be saved
syntax: <path>
example: "/home/pi/{title}"
NOTE: in your path you can use the following things:
"author" channel name of the creator
"category" category of the video
"dislikes" number of dislikes on the video
"duration" duration time of the video (HH:MM:SS)
"likes" number of likes on the video
"title" title of the video
"views" number of views on the video
:param output_format: str, optional
output format of the audio
syntax: <output format>
example: "mp3"
:return: None
:since: 0.1.0
"""
from . import is_aion
from ._utils import no_aion
if is_aion:
from os import system
from os.path import isdir, isfile
from pafy import new
from urllib.request import urlopen
source = new(url)
source_url = source.getbestaudio().url
source_extension = source.getbestaudio().extension
if isfile(path + "." + source_extension):
raise FileExistsError(path + " must be an non existing file")
elif isdir(path):
raise IsADirectoryError("path must be path to file, not path to directory")
path = path.format({"author": source.author, "category": source.category, "dislikes": source.dislikes, "duration": source.duration, "likes": source.likes, "title": source.title, "views": source.viewcount})
with open(path + "." + source_extension, "wb") as file:
file.write(bytes(urlopen(source_url).read()))
file.close()
system("ffmpeg -i " + path + "." + source_extension + " " + path + "." + output_format)
else:
no_aion()
def download_youtube_video(url: str, path: str, output_format: str = "mp4") -> None:
"""
downloads youtube video by url
:param url: str
the url from which the video should be downloaded
syntax: <url>
example: "https://youtu.be/MAlSjtxy5ak"
:param path: str
the path where the downloaded video should be saved
syntax: <path>
example: "/home/pi/{title}"
NOTE: in your path you can use the following things:
"author" channel name of the creator
"category" category of the video
"dislikes" number of dislikes on the video
"duration" duration time of the video (HH:MM:SS)
"likes" number of likes on the video
"title" title of the video
"views" number of views on the video
:param output_format: str, optional
output format of the video
syntax: <output format>
example: "mp4"
:return: None
:since: 0.1.0
"""
from . import is_aion
from ._utils import no_aion
if is_aion:
from os import system
from os.path import isdir, isfile
from pafy import new
from urllib.request import urlopen
source = new(url)
source_url = source.getbestvideo().url
source_extension = source.getbestvideo().extension
if isfile(path + "." + source_extension):
raise FileExistsError(path + " must be an not existing file")
elif isdir(path):
raise IsADirectoryError("path must be path to file, not path to directory")
path = path.format({"author": source.author, "category": source.category, "dislikes": source.dislikes, "duration": source.duration, "likes": source.likes, "title": source.title, "views": source.viewcount})
with open(path + "." + source_extension, "wb") as file:
file.write(bytes(urlopen(source_url).read()))
file.close()
system("ffmpeg -i " + path + "." + source_extension + " " + path + "." + output_format)
else:
no_aion()
def get_full_directory_data(directory: str) -> list:
"""
returns list of all files and directories of given directory back (subdirectories with subfiles, subsubdirectories with subsubfiles, ... included)
:param directory: str
path of directory from which you want to get the data
syntax: <directory path>
example: "/home/pi"
:return: list
list of all files and directories (subdirectories with subfiles, subsubdirectories with subsubfiles, ... included)
syntax: [<path>]
example: ["/home/pi/test", "/home/pi/test/test.py"]
:return: None
:since: 0.1.0
"""
from os import walk
from os.path import join
data = []
for path, subdirs, files in walk(directory):
for name in files:
data.append(join(path, name))
return data
def get_full_youtube_audio_url(search_element: str) -> str:
"""
search youtube for the search element and gives the first youtube url back
:param search_element: str
the element you want to search
syntax: <search element>
example: "Every programming tutorial"
:return: str
the youtube url from the search element
syntax: <url>
example: "https://youtu.be/MAlSjtxy5ak"
:since: 0.1.0
"""
import urllib.parse, urllib.request
from pafy import new
from re import findall
search_query = urllib.parse.urlencode({"search_query": 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())
return new(str("https://www.youtube.com/watch?v=" + search_results[0])).getbestaudio().url
except IndexError:
pass
def get_full_youtube_video_url(search_element: str) -> str:
"""
search youtube for the search element and gives the first youtube url back
:param search_element: str
the element you want to search
syntax: <search element>
example: "Every programming tutorial"
:return: str
the youtube url from the search element
syntax: <url>
example: "https://youtu.be/MAlSjtxy5ak"
:since: 0.1.0
"""
import urllib.parse, urllib.request
from pafy import new
from re import findall
search_query = urllib.parse.urlencode({"search_query": 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())
return new(str("https://www.youtube.com/watch?v=" + search_results[0])).getbestvideo().url
except IndexError:
pass
def get_line_number(fname: str, search_element: str, full_line: bool = True, strip: bool = True) -> int:
"""
returns the line number of an element in a file
:param fname: str
name of the file you want to search for the element
syntax: <file name>
example: "test_file"
:param search_element: str
element you want to get the line number of
syntax: <search element>
example: "test_search_element"
:param full_line: bool
sets if the 'search_element' should be the FULL line (True) or if the 'search_element' should be IN the line (False)
syntax: <boolean>
example: False
:param strip: bool
sets if the line of the should be striped before search the 'search_element' in it
syntax: <boolean>
example: False
:return: int
returns the line number of the 'search_element'
syntax: <line number>
example: 69
:since: 0.1.0
"""
from os.path import isfile
if isfile(fname) is False:
raise FileNotFoundError(fname + " don't exist")
line_number = -1
if full_line and strip:
for line in open(fname):
line_number = line_number + 1
if line.strip() == search_element:
return line_number
elif full_line and strip is False:
for line in open(fname):
line_number = line_number + 1
if line == search_element:
return line_number
elif full_line is False and strip:
for line in open(fname):
line_number = line_number + 1
if search_element in line.strip():
return line_number
else:
for line in open(fname):
line_number = line_number + 1
if search_element in line:
return line_number
raise EOFError("couldn't get line number of " + search_element)
def get_youtube_url(search_element: str) -> str:
"""
search youtube for the search element and gives the first youtube url back
:param search_element: str
the element you want to search
syntax: <search element>
example: "Every programming tutorial"
:return: str
the youtube url from the search element
syntax: <url>
example: "https://youtu.be/MAlSjtxy5ak"
:since: 0.1.0
"""
import re, urllib.parse, urllib.request
search_query = urllib.parse.urlencode({"search_query": search_element})
html_content = urllib.request.urlopen("https://www.youtube.com/results?search_query=" + search_query)
search_results = re.findall(r'href=\"\/watch\?v=(.{11})', html_content.read().decode())
return str("https://www.youtube.com/watch?v=" + search_results[0])
def is_dict_in_dict(dict1: dict, dict2: dict) -> bool:
"""
checks if dict key-value pairs exist in another dict
:param dict1: dict
dictionary you want to check if it is included in another dictionary
syntax: {"key": "value"}
example: {"a": "b"}
:param dict2: dict
dictionary you want to see if there is another dictionary in it
syntax: {"key": "value"}
example: {"a": "b", "c": "d"}
:return: boolean
returns if 'dict1' is in 'dict2'
syntax: <boolean>
example: True
:since: 0.1.0
"""
for key, value in dict1.items():
if key in dict2:
if dict2[key] == value:
pass
else:
return False
else:
return False
return True
def is_element_in_file(fname: str, element: str) -> bool:
"""
checks if an element is in a file
:param fname: str
file name of file
syntax: <file name>
example: "/home/pi/test.py"
:param element: str
element you want to check if in file
syntax: <element>
example: "test"
:return: bool
returns True or False is element is in file
syntax: <boolean>
example: True
:since: 0.1.0
"""
is_in_file = False
for line in open(fname, "r"):
if element in line:
is_in_file = True
break
return is_in_file
def is_internet_connected() -> bool:
"""
checks if the internet is connected
:return: bool
returns True or False if internet is connected
syntax: <boolean>
example: True
:since: 0.1.0
"""
import socket
try:
socket.gethostbyname("google.com")
internet = True
except OSError:
internet = False
except:
internet = False
print("An unexpected error appeard")
return internet
def is_root() -> bool:
"""
checks if the function from which this function is called run as root
:return: bool
returns True or False if the function from which this function is called run as root
syntax: <boolean>
example: True
:since: 0.1.0
"""
from os import geteuid
if geteuid() == 0:
return True
elif geteuid() == 1000:
return False
def remove_brackets(string: str) -> str:
"""
removes all brackets and the text which is between the brackets
:param string: str
string from which you want to remove the brackets
syntax: <string>
example: "Hello, this is(wedcwerfwe) an [sdvsfvv] random text{ervweg}"
:return: str
string without brackets and the text between them
syntax: <string without brackets>
example: "Hello, this is an random text"
:since: 0.1.0
"""
finished_string = ""
square_brackets = 0
parentheses = 0
for brackets in string:
if brackets == "[":
square_brackets += 1
elif brackets == "(":
parentheses += 1
elif brackets == "]" and square_brackets > 0:
square_brackets -= 1
elif brackets == ")" and parentheses > 0:
parentheses -= 1
elif square_brackets == 0 and parentheses == 0:
finished_string += brackets
return finished_string
def remove_space(string: str, space: str = " ") -> str:
"""
removes all the space from string which is equal or higher than from argument 'space' given space
:param string: str
string from which you want to remove space
syntax: <string>
example: "This string has to much space"
:param space: str, optional
space size from which you want to start to remove
syntax: <space>
example: " "
NOTE: '" "' will be replaced with '" "'
:return: str
returns the string without the given space and higher
syntax: <string>
example: "This string has to much space"
:since: 0.1.0
"""
while True:
if space in string:
string = string.replace(space, "")
space = space + " "
if len(space) >= len(string):
break
string = string.strip()
return string
def remove_string_characters(string: str, characters_to_remove: (list, tuple)) -> str:
"""
removes in argument 'characters_to_remove' given characters from given string
:param string: str
string from which you want to remove the characters
syntax: <string>
example: "This string hello has its to much word me"
:param characters_to_remove: list
list of characters you want to remove from string
syntax: [<character>]
example: ["hello", "its", "me"]
:return: str
returns string without in given characters to remove
syntax: <string>
example: "This string has to much word"
:since: 0.1.0
"""
for char in characters_to_remove:
if char in string:
string = string.replace(char, "")
return string
def remove_string_sequence(string: str, start: str, end: str, include: bool = False) -> str:
"""
removes all characters from a string between the given 'start' and 'end' element
:param string: str
the string from which the sequence should be removed from
syntax: "<string>"
example: "Test lol random words string"
:param start: str
start character
syntax: "<start character>"
example: "lol"
:param end: str
end character
syntax: "<end character>"
example: "words"
:param include: bool
'True' if the given start and end character should be included in the return string, False if not
syntax: <boolean>
example: False
:return: str
string without the sequence between 'start' and 'end'
syntax: "<string>"
example: "Test string"
:since: 0.1.0
"""
if include:
return string.replace(string[string.find(start) - len(start):string.find(end)], "")
return string.replace(string[string.find(start):string.find(end) + len(end)], "")
def replace_line(fname: str, line_number: int, new_line: str) -> None:
"""
replaces a line in a file
:param fname: str
filename from which you want to replace the line
syntax: <filename>
example: "/home/pi/test.txt"
:param line_number: int
line number of line you want to replace
syntax: <line number>
example: 5
:param new_line: str
line content with which the line should be replaced
syntax: <new line>
example: "This is the new line"
:return: None
:since: 0.1.0
"""
from os.path import isfile
line_number = int(line_number)
if isfile(fname) is False:
raise FileNotFoundError(fname + " don't exist")
lines = open(fname).readlines()
lines[line_number] = new_line + "\n"
with open(fname, "w") as file:
file.writelines(lines)
file.close()
def vlc(url_or_file_path: str, video: bool = False) -> None:
"""
plays audio from url or file path
:param url_or_file_path: str
the url or the path of the file you want to play
syntax: <url or path>
example: "https://youtu.be/MAlSjtxy5ak"
:param video: bool, optional
sets True or False if video should be played (if the file had one)
syntax: <boolean>
example: False
:return: None
:since: 0.1.0
"""
from os import system
if isinstance(video, bool) is False:
raise TypeError("expected " + str(bool.__name__) + " for video, got " + str(type(video).__name__))
if video is True:
system("cvlc --play-and-exit " + url_or_file_path)
else:
system("cvlc --play-and-exit --no-video " + url_or_file_path)

195
aionlib/variable.py Normal file
View File

@ -0,0 +1,195 @@
#!/usr/bin/python3
from . import is_linux
_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 . import is_linux
from os.path import isfile as _isfile
self._user_variables = {}
if _isfile(_aion_variable_file) and is_linux is False:
self._aion_open_variable_file = open(_aion_variable_file, "rw")
else:
self._aion_open_variable_file = None
def add_variable(self, variable_name, value):
"""
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, "rw")
self._user_variables[variable_name] = value
def close(self):
"""
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):
"""
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
"""
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("the variable " + variable_name + " doesn't exists")
else:
try:
return _default_variables[variable_name]
except KeyError:
if variable_name in self._user_variables:
return self._user_variables[variable_name]
raise KeyError("the variable " + variable_name + " doesn't exists")
def inititalize_variables(self, additional_variables={}):
"""
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
"""
if is_linux:
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):
"""
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 .utils import remove_space, replace_line
except ImportError:
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, "rw")
return
if found is False:
raise KeyError("the variable " + variable_name + " doesn't exists")
def set_value(self, variable_name, value):
"""
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 .utils import remove_space, replace_line
except ImportError:
from utils import remove_space, replace_line
found = False
if variable_name in self._user_variables:
self._user_variables[variable_name] = value
found = True
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, "rw")
return
if found is False:
raise KeyError("the variable " + variable_name + " doesn't exists")

21
setup.py Normal file
View File

@ -0,0 +1,21 @@
from setuptools import find_packages, setup
setup(name="aionlib",
version="0.1.0",
author="blueShard",
description="Library support for the 'aion' project",
license="MPL-2.0",
classifiers=[
"Development Status :: 4 - Beta",
"Environment :: Console",
"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
"Operating System :: Unix",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Topic :: Home Automation"],
python_requires=">=3.6.*",
install_requires=["colorama"],
packages=find_packages())