[config] Suppression des nones dans le toml, sauvegarde de la config au chargement pour ajouter les nouveaux parametres
[bot-base] Gestion des erreurs
This commit is contained in:
parent
1966b69d53
commit
75f524c509
@ -5,6 +5,7 @@ import inspect
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
import toml
|
import toml
|
||||||
@ -85,7 +86,8 @@ class BotBase(discord.Client):
|
|||||||
# Check if module exists
|
# Check if module exists
|
||||||
if not os.path.isdir(os.path.join(self.config["modules_folder"], module)):
|
if not os.path.isdir(os.path.join(self.config["modules_folder"], module)):
|
||||||
self.warning(f"Attempt to load unknown module {module}.")
|
self.warning(f"Attempt to load unknown module {module}.")
|
||||||
raise errors.ModuleNotFoundError(f"Module {module} not found in modules folder ({self.config['modules_folder']}.)")
|
raise errors.ModuleNotFoundError(
|
||||||
|
f"Module {module} not found in modules folder ({self.config['modules_folder']}.)")
|
||||||
if not os.path.isfile(os.path.join(self.config["modules_folder"], module, "infos.toml")):
|
if not os.path.isfile(os.path.join(self.config["modules_folder"], module, "infos.toml")):
|
||||||
self.warning(f"Attempt to load incompatible module {module}: no infos.toml found")
|
self.warning(f"Attempt to load incompatible module {module}: no infos.toml found")
|
||||||
raise errors.IncompatibleModuleError(f"Module {module} is incompatible: no infos.toml found.")
|
raise errors.IncompatibleModuleError(f"Module {module} is incompatible: no infos.toml found.")
|
||||||
@ -102,7 +104,7 @@ class BotBase(discord.Client):
|
|||||||
self.warning(f"Attempt to load incompatible module {module}: need bot version {infos['bot_version']} "
|
self.warning(f"Attempt to load incompatible module {module}: need bot version {infos['bot_version']} "
|
||||||
f"and you have {__version__}")
|
f"and you have {__version__}")
|
||||||
raise errors.IncompatibleModuleError(f"Module {module} is not compatible with your current bot version "
|
raise errors.IncompatibleModuleError(f"Module {module} is not compatible with your current bot version "
|
||||||
f"(need {infos['bot_version']} and you have {__version__}).")
|
f"(need {infos['bot_version']} and you have {__version__}).")
|
||||||
# Check dependencies
|
# Check dependencies
|
||||||
if infos.get("dependencies"):
|
if infos.get("dependencies"):
|
||||||
for dep, version in infos["dependencies"].items():
|
for dep, version in infos["dependencies"].items():
|
||||||
@ -113,13 +115,17 @@ class BotBase(discord.Client):
|
|||||||
self.warning(f"Attempt to load incompatible module {module}: (require {dep} ({version}) "
|
self.warning(f"Attempt to load incompatible module {module}: (require {dep} ({version}) "
|
||||||
f"and you have {dep} ({self.modules[dep]['infos']['version']})")
|
f"and you have {dep} ({self.modules[dep]['infos']['version']})")
|
||||||
raise errors.IncompatibleModuleError(f"Module {module} is not compatible with your current install "
|
raise errors.IncompatibleModuleError(f"Module {module} is not compatible with your current install "
|
||||||
f"(require {dep} ({version}) and you have {dep} "
|
f"(require {dep} ({version}) and you have {dep} "
|
||||||
f"({self.modules[dep]['infos']['version']})")
|
f"({self.modules[dep]['infos']['version']})")
|
||||||
|
|
||||||
# Check if module is meta
|
# Check if module is meta
|
||||||
if infos.get("metamodule", False) == False:
|
if infos.get("metamodule", False) == False:
|
||||||
# Check if module have __main_class__
|
# Check if module have __main_class__
|
||||||
imported = importlib.import_module(module)
|
try:
|
||||||
|
imported = importlib.import_module(module)
|
||||||
|
except Exception as e:
|
||||||
|
self.warning(f"Attempt to load incompatible module {module}: failed import")
|
||||||
|
raise e
|
||||||
try:
|
try:
|
||||||
main_class = imported.__main_class__
|
main_class = imported.__main_class__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@ -139,8 +145,9 @@ class BotBase(discord.Client):
|
|||||||
dispatch = main_class.__dispatch__
|
dispatch = main_class.__dispatch__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
self.warning(f"Attempt to load incompatible module {module}: __dispatch_ not found")
|
self.warning(f"Attempt to load incompatible module {module}: __dispatch_ not found")
|
||||||
raise errors.IncompatibleModuleError(f"Module {module} mainclass ({main_class}) does not provide __dispatch__"
|
raise errors.IncompatibleModuleError(
|
||||||
f" attribute)")
|
f"Module {module} mainclass ({main_class}) does not provide __dispatch__"
|
||||||
|
f" attribute)")
|
||||||
# Check if __dispatch__ is function
|
# Check if __dispatch__ is function
|
||||||
if not inspect.isfunction(imported.__main_class__.__dispatch__):
|
if not inspect.isfunction(imported.__main_class__.__dispatch__):
|
||||||
self.warning(f"Attempt to load incompatible module {module}: __dispatch__ is not a function")
|
self.warning(f"Attempt to load incompatible module {module}: __dispatch__ is not a function")
|
||||||
@ -178,7 +185,7 @@ class BotBase(discord.Client):
|
|||||||
"dispatch": dispatch,
|
"dispatch": dispatch,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
else: # Module is metamodule
|
else: # Module is metamodule
|
||||||
self.info(f"Add modules {module} to current modules")
|
self.info(f"Add modules {module} to current modules")
|
||||||
self.modules.update({
|
self.modules.update({
|
||||||
module: {
|
module: {
|
||||||
@ -196,16 +203,19 @@ class BotBase(discord.Client):
|
|||||||
for module in self.modules.values():
|
for module in self.modules.values():
|
||||||
module["dispatch"](event, *args, **kwargs)
|
module["dispatch"](event, *args, **kwargs)
|
||||||
|
|
||||||
|
async def on_error(self, event_method, exc, *args, **kwargs):
|
||||||
|
self.error(f"Error in {event_method}: \n{exc}")
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
def info(self, *args, **kwargs):
|
def info(self, *args, **kwargs):
|
||||||
if self.log:
|
if self.log:
|
||||||
self.log.info(*args, **kwargs)
|
self.log.info(*args, **kwargs)
|
||||||
self.dispatch("log_info", *args, **kwargs)
|
self.dispatch("log_info", *args, **kwargs)
|
||||||
|
|
||||||
def error(self, *args, **kwargs):
|
def error(self, e, *args, **kwargs):
|
||||||
if self.log:
|
if self.log:
|
||||||
self.log.error(*args, **kwargs)
|
self.log.error(e, *args, **kwargs)
|
||||||
self.dispatch("log_error", *args, **kwargs)
|
self.dispatch("log_error", e, *args, **kwargs)
|
||||||
|
|
||||||
def warning(self, *args, **kwargs):
|
def warning(self, *args, **kwargs):
|
||||||
if self.log:
|
if self.log:
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
import toml
|
import toml
|
||||||
@ -75,8 +76,9 @@ class Config:
|
|||||||
>>> config = Config("doctest_config.toml")
|
>>> config = Config("doctest_config.toml")
|
||||||
>>> config.register("my_parameter", factory(Int))
|
>>> config.register("my_parameter", factory(Int))
|
||||||
>>> config.set({"my_parameter": 3})
|
>>> config.set({"my_parameter": 3})
|
||||||
>>> config.save()
|
>>> config.save() #doctest: +SKIP
|
||||||
"""
|
"""
|
||||||
|
os.makedirs(os.path.dirname(self.path), exist_ok=True)
|
||||||
with open(self.path, 'w') as file:
|
with open(self.path, 'w') as file:
|
||||||
toml.dump({k: v.to_save() for k, v in self.fields.items()}, file)
|
toml.dump({k: v.to_save() for k, v in self.fields.items()}, file)
|
||||||
|
|
||||||
@ -90,11 +92,11 @@ class Config:
|
|||||||
>>> config = Config("doctest_config.toml")
|
>>> config = Config("doctest_config.toml")
|
||||||
>>> config.register("my_parameter", factory(Int))
|
>>> config.register("my_parameter", factory(Int))
|
||||||
>>> config.set({"my_parameter": 3})
|
>>> config.set({"my_parameter": 3})
|
||||||
>>> config.save()
|
>>> config.save() #doctest: +SKIP
|
||||||
>>> new_config = Config("doctest_config.toml")
|
>>> new_config = Config("doctest_config.toml")
|
||||||
>>> new_config.register("my_parameter", factory(Int))
|
>>> new_config.register("my_parameter", factory(Int))
|
||||||
>>> new_config.load()
|
>>> new_config.load() #doctest: +SKIP
|
||||||
>>> new_config["my_parameter"]
|
>>> new_config["my_parameter"] #doctest: +SKIP
|
||||||
3
|
3
|
||||||
|
|
||||||
:return: None
|
:return: None
|
||||||
@ -103,7 +105,8 @@ class Config:
|
|||||||
with open(self.path, 'r') as file:
|
with open(self.path, 'r') as file:
|
||||||
self.set(toml.load(file))
|
self.set(toml.load(file))
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
self.save()
|
pass
|
||||||
|
self.save()
|
||||||
|
|
||||||
def __getitem__(self, item: str) -> typing.Any:
|
def __getitem__(self, item: str) -> typing.Any:
|
||||||
"""
|
"""
|
||||||
|
@ -1,36 +1,57 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
import typing
|
||||||
|
|
||||||
|
import discord
|
||||||
|
|
||||||
from config.config_types.base_type import BaseType
|
from config.config_types.base_type import BaseType
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from main import LBI
|
from bot_base import BotBase
|
||||||
|
|
||||||
|
|
||||||
class Channel(BaseType):
|
class Channel(BaseType):
|
||||||
client: LBI
|
client: BotBase
|
||||||
|
|
||||||
def __init__(self, client):
|
def __init__(self, client):
|
||||||
self.value = None
|
self.value = 0
|
||||||
|
self.channel_instance = None
|
||||||
self.client = client
|
self.client = client
|
||||||
|
|
||||||
def check_value(self, value):
|
def check_value(self, value):
|
||||||
|
id = value
|
||||||
|
if isinstance(value, discord.Guild):
|
||||||
|
id = value.id
|
||||||
|
if not self.client.is_ready():
|
||||||
|
self.client.warning(f"No check for channel {value} because client is not initialized!")
|
||||||
|
return True
|
||||||
|
if self.client.get_channel(id):
|
||||||
|
return True
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set(self, value):
|
def set(self, value):
|
||||||
if self.check_value(value):
|
if not self.check_value(value):
|
||||||
self.value = value
|
raise ValueError("Tentative de définir une valeur incompatible")
|
||||||
return
|
self.value = value
|
||||||
raise ValueError("Tentative de définir une valeur incompatible")
|
self._update()
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
return self.value
|
self._update()
|
||||||
|
return self.channel_instance or self.value
|
||||||
|
|
||||||
def to_save(self):
|
def to_save(self):
|
||||||
return self.value
|
return self.value or 0
|
||||||
|
|
||||||
def load(self, value):
|
def load(self, value):
|
||||||
|
|
||||||
if self.check_value(value):
|
if self.check_value(value):
|
||||||
raise ValueError("Tentative de charger une donnée incompatible.")
|
raise ValueError("Tentative de charger une donnée incompatible.")
|
||||||
self.value = value
|
self.set(value)
|
||||||
|
self._update()
|
||||||
|
|
||||||
|
def _update(self):
|
||||||
|
if self.client.is_ready() and self.channel_instance is None:
|
||||||
|
self.channel_instance = self.client.get_channel(self.value)
|
||||||
|
else:
|
||||||
|
self.channel_instance = None
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ class Guild(BaseType):
|
|||||||
>>> Guild(client) #doctest: +SKIP
|
>>> Guild(client) #doctest: +SKIP
|
||||||
<config_types.discord_type.Guild object with value None>
|
<config_types.discord_type.Guild object with value None>
|
||||||
"""
|
"""
|
||||||
self.value = None
|
self.value = 0
|
||||||
self.guild_instance = None
|
self.guild_instance = None
|
||||||
self.client = client
|
self.client = client
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ class Guild(BaseType):
|
|||||||
if isinstance(value, discord.Guild):
|
if isinstance(value, discord.Guild):
|
||||||
id = value.id
|
id = value.id
|
||||||
if not self.client.is_ready():
|
if not self.client.is_ready():
|
||||||
self.client.warning("No check for guild `value` because client is not initialized!")
|
self.client.warning(f"No check for guild {value} because client is not initialized!")
|
||||||
return True
|
return True
|
||||||
if self.client.get_guild(id):
|
if self.client.get_guild(id):
|
||||||
return True
|
return True
|
||||||
@ -119,7 +119,7 @@ class Guild(BaseType):
|
|||||||
:return: Current id
|
:return: Current id
|
||||||
:rtype: Optional[int]
|
:rtype: Optional[int]
|
||||||
"""
|
"""
|
||||||
return self.value
|
return self.value or 0
|
||||||
|
|
||||||
def load(self, value):
|
def load(self, value):
|
||||||
"""
|
"""
|
||||||
@ -140,6 +140,7 @@ class Guild(BaseType):
|
|||||||
if self.check_value(value):
|
if self.check_value(value):
|
||||||
raise ValueError("Tentative de charger une donnée incompatible.")
|
raise ValueError("Tentative de charger une donnée incompatible.")
|
||||||
self.set(value)
|
self.set(value)
|
||||||
|
self._update()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f'<config_types.discord_types.guild object with value {self.value}>'
|
return f'<config_types.discord_types.guild object with value {self.value}>'
|
||||||
|
Loading…
Reference in New Issue
Block a user