From cd12d01d937bf13d66ca68c2647b0d9cd9b94600 Mon Sep 17 00:00:00 2001 From: ElBe <90863907+ElBe-Plaq@users.noreply.github.com> Date: Sun, 29 Jan 2023 16:19:31 +0100 Subject: [PATCH] Update to v1.6b --- Bot/functions.py | 315 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 231 insertions(+), 84 deletions(-) diff --git a/Bot/functions.py b/Bot/functions.py index 719bf3b..4a6468c 100644 --- a/Bot/functions.py +++ b/Bot/functions.py @@ -1,118 +1,265 @@ ''' Functions for the discord.py Bot. © by ElBe. +Version: 1.6 -Version: 1.2 +NOTE: Async functions in this file cause errors and should not be created. ''' #Imports -import json -import os +import discord + import colorama import datetime -import re +import json +import logging +import os +import platform +import prettytable import requests +import sqlite3 +import typing #Bot modules import errors +#Setup +colorama.init() + +#Variables class variables(): '''All variables used in this module.''' - standart_config_file = 'config.json' - standart_datetime_format = datetime.date.isoformat + + standard_logging_file: typing.Final[str] = 'data\\log\\' + str(datetime.datetime.today()) + '.txt' + standard_datetime_format: typing.Final[str] = '%Y-%m-%d %H:%M:%S' + standard_logging_format: typing.Final[str] = colorama.Fore.LIGHTBLUE_EX + '{timestamp}' + colorama.Style.RESET_ALL + ' [{color}{level}' + colorama.Style.RESET_ALL + '] {name} {message}' + standard_config_file: typing.Final[str] = 'data\\config.json' + standard_database_file: typing.Final[str] = 'data\\bot.db' + standard_intents: typing.Final[discord.Intents] = discord.Intents.all() class json_module(): - def get_config(name: str, file = variables.standart_config_file): - '''Returns a value from the given/standart JSON file.''' - with open(file, 'r') as f: - return json.load(f)[name] + '''Module for dealing with JSON files.''' - def write_json(data, show_text = False, file = variables.standart_config_file): - '''Writes the text to the given/standart JSON file.''' - with open(file, 'w') as f: - json.dump(data, f) - f.close() + def __init__(self, file: str = variables.standard_config_file) -> None: + '''Sets a file to be read. - if show_text: - print(console.log('Data ' + str(data) + ' added to ' + str(file) + '.')) + Args: + file (str, optional): File to read. Defaults to variables.standard_config_file. + + Returns: + None + ''' + + self.file = file + + def get_value(name: str, file: str = variables.standard_config_file) -> object: #TODO: Change all occurrences + '''Returns a value parsed from a JSON config file. + + Args: + name (str): Name of the key to be parsed. + file (str, optional): Relative path to the json config file. Default to 'data\\config.json'. + + Returns: + object: Object parsed from the JSON file. + ''' + try: + with open(file, 'r') as f: + return json.load(f)[name] + except Exception as e: + return errors.DataLoadingError(e.__cause__) + + def write_json(data: object, file: str) -> None: + '''Writes data to a JSON file. + + Args: + data (object): Data to insert. + file (str): Relative path to the json file. + ''' + try: + with open(file, 'w') as f: + json.dump(data, f) + f.close() + except Exception as e: + return errors.DataWritingError(e.__cause__) + + def __str__(self) -> str: + '''Returns contents of the file as a string. + + Returns: + str: Contents of the file. + ''' + + with open(self.file, 'r') as f: + return str(f.read()) + +class database(): + '''Still in beta!''' + def __init__(self, database: str = variables.standard_database_file) -> None: + self.database = sqlite3.connect(database) + self.cursor = database.cursor() + + def get_value(self, key: str, table: str, whereKey: str, whereValue: str) -> object: + self.cursor.execute('SELECT ' + key + ' FROM ' + table + ' WHERE ' + whereKey + ' = ' + whereValue) + return self.cursor.fetchall() + + def insert_value(self, key: str) -> object: + pass class console(): - def info(text: str): - '''Returns a info text.''' - i = 0 - if len(re.findall('\n', text)) > 1: - text = '\n' + text - search = len(re.findall('\n', text)) - - if search > 1: - for i in range(search): - text = text.replace('\n', '//n[' + colorama.Fore.LIGHTBLUE_EX + str(i + 1) + colorama.Style.RESET_ALL + '] ', 1) - i = i + 1 - text = text.replace('//n', '\n') - return colorama.Fore.LIGHTBLUE_EX + str(datetime.datetime.now().strftime('%d.%m.%Y %T')) + colorama.Style.RESET_ALL + ' [' + colorama.Fore.GREEN + 'INFO' + colorama.Style.RESET_ALL + '] ' + text - - def error(text: str): - '''Returns a error text.''' - i = 0 - if len(re.findall('\n', text)) > 1: - text = '\n' + text - search = len(re.findall('\n', text)) - - if search > 1: - for i in range(search): - text = text.replace('\n', '//n[' + colorama.Fore.LIGHTBLUE_EX + str(i + 1) + colorama.Style.RESET_ALL + '] ', 1) - i = i + 1 - text = text.replace('//n', '\n') - return colorama.Fore.LIGHTBLUE_EX + str(datetime.datetime.now().strftime('%d.%m.%Y %T')) + colorama.Style.RESET_ALL + ' [' + colorama.Fore.RED + 'ERROR' + colorama.Style.RESET_ALL + '] ' + text - - def warn(text: str): - '''Returns a warn text.''' - i = 0 - if len(re.findall('\n', text)) > 1: - text = '\n' + text - search = len(re.findall('\n', text)) - - if search > 1: - for i in range(search): - text = text.replace('\n', '//n[' + colorama.Fore.LIGHTBLUE_EX + str(i + 1) + colorama.Style.RESET_ALL + '] ', 1) - i = i + 1 - text = text.replace('//n', '\n') - return colorama.Fore.LIGHTBLUE_EX + str(datetime.datetime.now().strftime('%d.%m.%Y %T')) + colorama.Style.RESET_ALL + ' [' + colorama.Fore.YELLOW + 'WARNING' + colorama.Style.RESET_ALL + '] ' + text - - def log(text: str): - '''Returns a log text.''' - i = 0 - if len(re.findall('\n', text)) > 1: - text = '\n' + text - search = len(re.findall('\n', text)) - - if search > 1: - for i in range(search): - text = text.replace('\n', '//n[' + colorama.Fore.LIGHTBLUE_EX + str(i + 1) + colorama.Style.RESET_ALL + '] ', 1) - i = i + 1 - text = text.replace('//n', '\n') - return colorama.Fore.LIGHTBLUE_EX + str(datetime.datetime.now().strftime('%d.%m.%Y %T')) + colorama.Style.RESET_ALL + ' [LOG] ' + text - - def clear(): + def clear() -> None: '''Clear the console.''' - os.system('cls') + if platform.system() == 'Windows': + os.system('cls') + else: + os.system('clear') - def crusor_up(): - '''Changes the position of the crusor to the line above.''' + def cursor_up() -> None: + '''Changes the position of the cursor to the line above.''' print('\x1b[1A') - def erase_line(): + def erase_line() -> None: '''Erases the current line.''' print('\x1b[2K') - def erase_last(): + def erase_last() -> None: '''Erases the last line.''' print('\x1b[1A' + '\x1b[2K' + '\x1b[1A') -class outdated(): - def __init__(package: str, min_version: str): - min_version_int = int(min_version.replace('.','')) +class translate_text(): + def __init__(category: str, text: str) -> str: #TODO: Add language system (LATER) + '''MODULE IS TURNED OFF''' + return + + #language = str(json_module.get_config('Config')['Language']) + #if category == 'B': + # return json_module.get_config('Bot', 'data/lang/' + language + '/bot.json')[text] + #elif category == 'C': + # return json_module.get_config('Commands', 'data/lang/' + language + '/commands.json')[text] + #elif category == 'CC': + # return json_module.get_config('Command creator', 'data/lang/' + language + '/command_creator.json')[text] + #elif category == 'E': + # return json_module.get_config('Error', 'data/lang/' + language + '/errors.json')[text] + #elif category == 'F': + # return json_module.get_config('Functions', 'data\\lang\\' + language + '\\functions.json')[text] + #elif category == 'R': + # with open('data\\lang\\' + json_module.get_config('Config')['Language'] + '\\rules.txt', 'r') as f: + # return f.read() + #else: + # errors.UnexpectedValueError('B, C, CC, E, F, R', category) + +class formation(): + def format_table(table: prettytable.PrettyTable): + '''Format prettytable.PrettyTables to look better. + + Args: + table (prettytable.PrettyTable): Table to format. + + Returns: + table: Formatted table. + ''' + + table.vertical_char = '│' + table.horizontal_char = '─' + table.junction_char = '┼' + table.left_junction_char = '├' + table.right_junction_char = '┤' + table.top_left_junction_char = '┌' + table.top_right_junction_char = '┐' + table.top_junction_char = '┬' + table.bottom_left_junction_char = '└' + table.bottom_right_junction_char = '┘' + table.bottom_junction_char = '┴' + + return table + +class create_command(): + def __init__(self, json: dict) -> None: + '''Creates a command with given json data. + + Args: + json (dict): Json data to use when creating the command. + + Returns: + None + ''' + + self.json = json + try: - latest_version = int(str(json.loads(requests.get('https://pypi.python.org/pypi/' + package + '/json').text)['info']['version']).replace('.', '')) + requests.post('https://discord.com/api/v10/applications/' + str(json_module.get_config('Config')['Application ID']) + '/commands', headers={'Authorization': 'Bot ' + str(json_module.get_config('Config')['Token'])}, json=json) except Exception as e: - print(console.error('Package not found.')) \ No newline at end of file + print('Error while trying to create the command /' + str(json['name']) + '.\n' + str(e)) + + def __str__(self) -> str: + '''String representation of the command creator. + + Returns: + str: The string representation of the command creator. + ''' + + return 'Trying to create command /' + self.json['name'] + ' with json:' + str(self.json) + +class log(): + def __init__(self, message: str, level: str) -> None: + '''Logs a message on the given level. + + Args: + message (str): Message to log. + level (str): Level to log with. Has to be 'CRITICAL','ERROR','WARNING','INFO' or'DEBUG'. Defaults to 'DEBUG'. + + Returns: + None + ''' + + self.message = message + self.level = level if level is not None else self.default_level + + + def setup(self, format: str = variables.standard_logging_format, default_level: str = 'DEBUG', default_name: str = 'ROOT') -> None: + '''Sets up logging with the given format, a default level and a default name for unnamed loggers. + + Args: + format (str, optional): Format for logging. Has to contain '{message}', '{level}' and '{timestamp}'. Can contain '{name}' and '{color}'. Defaults to variables.standard_logging_format. + default_level (str, optional): Default logging level. Has to be 'CRITICAL','ERROR','WARNING','INFO' or'DEBUG'. Defaults to 'DEBUG'. + default_name (str, optional): Default logger name. Each function can have its own logger or logger. Defaults to 'ROOT'. + + Returns: + None + ''' + + self.format = format + self.default_level = default_level + self.default_name = default_name + + def __str__(self): + '''String representation of the logged message. + + Returns: + str: The string representation of the logged message. + ''' + + return #TODO: add return value + +class download(): + def __init__(url: str, file: str) -> None: + '''ATTENTION: The download function is still in experimental state! Errors are expected and should be reported. + + Downloads a file from the specified url to the specified file in the download directory. + + Args: + url (str): URL to download file from. + file (str): File name to write to. Don't include path. + + Returns: + None + ''' + + if os.path.splitext(url)[1] == os.path.splitext(file)[1]: + if os.path.exists(os.path.expanduser('~\\Downloads\\' + file)): + raise FileExistsError('File ' + file + ' already exists') + else: + with open(os.path.expanduser('~\\Downloads\\' + file), 'x') as f: + for line in str(str(requests.get(url).content).replace('b\'', '')).split('\\n')[:-1]: + f.write(line + '\n') + else: + errors.FileExtensionError('File extension from ' + url + ' is not the same as the file extension from ' + file + '.')