[main] Update some docstrings, remove config check

[doc] Put all config_types on same page, add link to python and discord.py doc
[config] Add some doc, solve KeyError when loading config file
[config-types] Add some doc, add guild type
This commit is contained in:
Louis Chauvet 2020-04-21 02:59:08 +02:00
parent bca15ac34d
commit 3f416c5682
Signed by: fomys
GPG Key ID: 1ECA046A9615ABA0
21 changed files with 446 additions and 219 deletions

View File

@ -15,7 +15,7 @@ matplotlib = "*"
humanize = "*"
pytest = "*"
sphinx = "*"
sphinx-autodoc-typehints = "*"
sphinx-rtd-theme = "*"
[dev-packages]

66
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "d28e37a13dd269630941deb023da5ac886931fc05525fbf5d150df8a7320969b"
"sha256": "83d48f54ad14a40d4bc3b81715c5ef5bb4e604b11a7da3e9ad4db62826ff37ae"
},
"pipfile-spec": 6,
"requires": {
@ -333,29 +333,29 @@
},
"numpy": {
"hashes": [
"sha256:1598a6de323508cfeed6b7cd6c4efb43324f4692e20d1f76e1feec7f59013448",
"sha256:1b0ece94018ae21163d1f651b527156e1f03943b986188dd81bc7e066eae9d1c",
"sha256:2e40be731ad618cb4974d5ba60d373cdf4f1b8dcbf1dcf4d9dff5e212baf69c5",
"sha256:4ba59db1fcc27ea31368af524dcf874d9277f21fd2e1f7f1e2e0c75ee61419ed",
"sha256:59ca9c6592da581a03d42cc4e270732552243dc45e87248aa8d636d53812f6a5",
"sha256:5e0feb76849ca3e83dd396254e47c7dba65b3fa9ed3df67c2556293ae3e16de3",
"sha256:6d205249a0293e62bbb3898c4c2e1ff8a22f98375a34775a259a0523111a8f6c",
"sha256:6fcc5a3990e269f86d388f165a089259893851437b904f422d301cdce4ff25c8",
"sha256:82847f2765835c8e5308f136bc34018d09b49037ec23ecc42b246424c767056b",
"sha256:87902e5c03355335fc5992a74ba0247a70d937f326d852fc613b7f53516c0963",
"sha256:9ab21d1cb156a620d3999dd92f7d1c86824c622873841d6b080ca5495fa10fef",
"sha256:a1baa1dc8ecd88fb2d2a651671a84b9938461e8a8eed13e2f0a812a94084d1fa",
"sha256:a244f7af80dacf21054386539699ce29bcc64796ed9850c99a34b41305630286",
"sha256:a35af656a7ba1d3decdd4fae5322b87277de8ac98b7d9da657d9e212ece76a61",
"sha256:b1fe1a6f3a6f355f6c29789b5927f8bd4f134a4bd9a781099a7c4f66af8850f5",
"sha256:b5ad0adb51b2dee7d0ee75a69e9871e2ddfb061c73ea8bc439376298141f77f5",
"sha256:ba3c7a2814ec8a176bb71f91478293d633c08582119e713a0c5351c0f77698da",
"sha256:cd77d58fb2acf57c1d1ee2835567cd70e6f1835e32090538f17f8a3a99e5e34b",
"sha256:cdb3a70285e8220875e4d2bc394e49b4988bdb1298ffa4e0bd81b2f613be397c",
"sha256:deb529c40c3f1e38d53d5ae6cd077c21f1d49e13afc7936f7f868455e16b64a0",
"sha256:e7894793e6e8540dbeac77c87b489e331947813511108ae097f1715c018b8f3d"
"sha256:0aa2b318cf81eb1693fcfcbb8007e95e231d7e1aa24288137f3b19905736c3ee",
"sha256:163c78c04f47f26ca1b21068cea25ed7c5ecafe5f5ab2ea4895656a750582b56",
"sha256:1e37626bcb8895c4b3873fcfd54e9bfc5ffec8d0f525651d6985fcc5c6b6003c",
"sha256:264fd15590b3f02a1fbc095e7e1f37cdac698ff3829e12ffdcffdce3772f9d44",
"sha256:3d9e1554cd9b5999070c467b18e5ae3ebd7369f02706a8850816f576a954295f",
"sha256:40c24960cd5cec55222963f255858a1c47c6fa50a65a5b03fd7de75e3700eaaa",
"sha256:46f404314dbec78cb342904f9596f25f9b16e7cf304030f1339e553c8e77f51c",
"sha256:4847f0c993298b82fad809ea2916d857d0073dc17b0510fbbced663b3265929d",
"sha256:48e15612a8357393d176638c8f68a19273676877caea983f8baf188bad430379",
"sha256:6725d2797c65598778409aba8cd67077bb089d5b7d3d87c2719b206dc84ec05e",
"sha256:99f0ba97e369f02a21bb95faa3a0de55991fd5f0ece2e30a9e2eaebeac238921",
"sha256:a41f303b3f9157a31ce7203e3ca757a0c40c96669e72d9b6ee1bce8507638970",
"sha256:a4305564e93f5c4584f6758149fd446df39fd1e0a8c89ca0deb3cce56106a027",
"sha256:a551d8cc267c634774830086da42e4ba157fa41dd3b93982bc9501b284b0c689",
"sha256:a6bc9432c2640b008d5f29bad737714eb3e14bb8854878eacf3d7955c4e91c36",
"sha256:c60175d011a2e551a2f74c84e21e7c982489b96b6a5e4b030ecdeacf2914da68",
"sha256:e46e2384209c91996d5ec16744234d1c906ab79a701ce1a26155c9ec890b8dc8",
"sha256:e607b8cdc2ae5d5a63cd1bec30a15b5ed583ac6a39f04b7ba0f03fcfbf29c05b",
"sha256:e94a39d5c40fffe7696009dbd11bc14a349b377e03a384ed011e03d698787dd3",
"sha256:eb2286249ebfe8fcb5b425e5ec77e4736d53ee56d3ad296f8947f67150f495e3",
"sha256:fdee7540d12519865b423af411bd60ddb513d2eb2cd921149b732854995bbf8b"
],
"version": "==1.18.2"
"version": "==1.18.3"
},
"packaging": {
"hashes": [
@ -471,11 +471,11 @@
},
"sphinx": {
"hashes": [
"sha256:50972d83b78990fd61d0d3fe8620814cae53db29443e92c13661bc43dff46ec8",
"sha256:8411878f4768ec2a8896b844d68070204f9354a831b37937989c2e559d29dffc"
"sha256:3145d87d0962366d4c5264c39094eae3f5788d01d4b1a12294051bfe4271d91b",
"sha256:d7c6e72c6aa229caf96af82f60a0d286a1521d42496c226fe37f5a75dcfe2941"
],
"index": "pypi",
"version": "==3.0.1"
"version": "==3.0.2"
},
"sphinx-autodoc-typehints": {
"hashes": [
@ -485,6 +485,14 @@
"index": "pypi",
"version": "==1.10.3"
},
"sphinx-rtd-theme": {
"hashes": [
"sha256:00cf895504a7895ee433807c62094cf1e95f065843bf3acd17037c3e9a2becd4",
"sha256:728607e34d60456d736cc7991fd236afb828b21b82f956c5ea75f94c8414040a"
],
"index": "pypi",
"version": "==0.4.3"
},
"sphinxcontrib-applehelp": {
"hashes": [
"sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a",
@ -537,10 +545,10 @@
},
"urllib3": {
"hashes": [
"sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc",
"sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"
"sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527",
"sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"
],
"version": "==1.25.8"
"version": "==1.25.9"
},
"wcwidth": {
"hashes": [

View File

@ -1,3 +1,3 @@
from .base import Config
from config.base import Config
__all__ = ["Config"]

View File

@ -1,18 +1,18 @@
from __future__ import annotations
from typing import Dict, Type, Any, TYPE_CHECKING
import typing
import toml
if TYPE_CHECKING:
from config.config_types.base_type import BaseType
BaseType = typing.TypeVar("BaseType")
class Config:
#: Path of config file
#: :class:`str`: Path of config file
path: str
#: Current fields
fields: Dict[str, BaseType]
#: :class:`typing.Type` [:class:`BaseType`]: Current fields
fields: typing.Dict[str, BaseType]
def __init__(self, path: str) -> None:
"""
@ -22,15 +22,12 @@ class Config:
>>> config = Config("doctest_config.toml")
:param path: Path of config file
:type path: str
:rtype: None
:rtype: None
:param str path: Path of config file
"""
self.fields = {}
self.path = path
def register(self, name: str, type_: Type[BaseType]) -> None:
def register(self, name: str, type_: typing.Type[BaseType]) -> None:
"""
Register option
@ -40,12 +37,8 @@ class Config:
>>> config = Config("doctest_config.toml")
>>> config.register("my_parameter", factory(Int))
:param name: Name of config parameter
:param type_: Type of config parameter
:type name: str
:type type_: Type[BaseType]
:return: None
:rtype: None
:param str name: Name of config parameter
:param typing.Type[BaseType] type_: Type of config parameter
"""
self.fields.update({
name: type_()
@ -64,11 +57,13 @@ class Config:
:type values: dict
:param values: dict of parameters
:return: None
:rtype: None
"""
for k, v in values.items():
try:
self.fields[k].set(v)
except KeyError:
# TODO: trouver un moyen de warn
pass
def save(self) -> None:
"""
@ -81,13 +76,11 @@ class Config:
>>> config.register("my_parameter", factory(Int))
>>> config.set({"my_parameter": 3})
>>> config.save()
:return: None
"""
with open(self.path, 'w') as file:
toml.dump({k: v.to_save() for k, v in self.fields.items()}, file)
def load(self, create: bool = False) -> None:
def load(self) -> None:
"""
Load config from ``self.file``
@ -104,8 +97,6 @@ class Config:
>>> new_config["my_parameter"]
3
:param create: Create config file if not exists
:return: None
"""
try:
@ -114,9 +105,11 @@ class Config:
except FileNotFoundError:
self.save()
def __getitem__(self, item: str) -> Any:
def __getitem__(self, item: str) -> typing.Any:
"""
Save config to ``self.file``
Get field from config
:param str item: Config field to get
Basic usage:
@ -126,7 +119,5 @@ class Config:
>>> config.set({"my_parameter": 3})
>>> print(config["my_parameter"])
3
:return: None
"""
return self.fields[item].get()

View File

@ -1,11 +1,11 @@
from typing import Optional
import typing
from config.config_types.base_type import BaseType
class Bool(BaseType):
#: Current value of parameter
value: Optional[bool]
#: :class:`typing.Optional` [:class:`bool`]: Current value
value: typing.Optional[bool]
def __init__(self) -> None:
"""
@ -52,8 +52,9 @@ class Bool(BaseType):
>>> my_bool.check_value(5)
True
:param value: value to check
:param bool value: value to check
:return: True if value is correct
:rtype: bool
"""
try:
bool(value)
@ -70,14 +71,13 @@ class Bool(BaseType):
>>> my_bool = Bool()
>>> my_bool.set(34)
:param value: Value to set
:return: None
:param bool value: Value to set
"""
if not self.check_value(value):
raise ValueError("Tentative de définir une valeur incompatible")
self.value = bool(value)
def get(self) -> Optional[int]:
def get(self) -> typing.Optional[bool]:
"""
Get value of parameter
@ -89,10 +89,11 @@ class Bool(BaseType):
True
:return: Value of parameter
:rtype: typing.Optional[bool]
"""
return self.value
def to_save(self) -> int:
def to_save(self) -> bool:
"""
Build a serializable object
@ -105,6 +106,7 @@ class Bool(BaseType):
True
:return: Current value
:rtype: bool
"""
return self.value
@ -117,8 +119,7 @@ class Bool(BaseType):
>>> my_bool.get()
True
:param value: Value to load
:return: None
:param bool value: Value to load
"""
if not self.check_value(value):
raise ValueError("Tentative de charger une donnée incompatible.")

View File

@ -1,11 +1,11 @@
from typing import Optional
import typing
from config.config_types.base_type import BaseType
class Color(BaseType):
#: Current value
value: Optional[int]
#: :class:`typing.Optional` [:class:`int`]: Current value
value: typing.Optional[int]
def __init__(self) -> None:
"""
@ -40,8 +40,9 @@ class Color(BaseType):
>>> my_color.check_value(0x1000000)
False
:param value: value to check
:param int value: value to check
:return: True if value is correct
:rtype: bool
"""
try:
int(value)
@ -58,14 +59,13 @@ class Color(BaseType):
>>> my_color = Color()
>>> my_color.set(34)
:param value: Value to set
:return: None
:param int value: Value to set
"""
if not self.check_value(value):
raise ValueError("Tentative de définir une valeur incompatible")
self.value = int(value)
def get(self) -> Optional[int]:
def get(self) -> typing.Optional[int]:
"""
Get value of parameter
@ -77,6 +77,7 @@ class Color(BaseType):
34
:return: Value of parameter
:rtype: typing.Optional[int]
"""
return self.value
@ -93,6 +94,7 @@ class Color(BaseType):
34
:return: Current value
:rtype: int
"""
return self.value
@ -105,8 +107,7 @@ class Color(BaseType):
>>> my_color.get()
True
:param value: Value to load
:return: None
:param int value: Value to load
"""
if not self.check_value(value):
raise ValueError("Tentative de charger une donnée incompatible.")

View File

@ -1,19 +1,54 @@
from typing import Type
import typing
from config.config_types.base_type import BaseType
class Dict(BaseType):
type_key: Type[BaseType]
type_value: Type[BaseType]
#: :class:`typing.Type` [:class:`BaseType`]: Type for key
type_key: typing.Type[BaseType]
#: :class:`typing.Type` [:class:`BaseType`]: Type for value
type_value: typing.Type[BaseType]
def __init__(self, type_key, type_value):
def __init__(self, type_key: typing.Type[BaseType], type_value: typing.Type[BaseType]):
"""
Config type for dictionnary
:Basic usage:
>>> from config.config_types import factory, Int, Float
>>> Dict(factory(Int), factory(Float))
<config_types.Dict<<config_types.Int with parameters () {}>: <config_types.Float with parameters () {}>> object with value None>
:param typing.Type[BaseType] type_key: Type of keys
:param typing.Type[BaseType] type_value: Type of values
"""
self.type_key = type_key
self.type_value = type_value
self.values = None
def check_value(self, value):
"""Check if value is good"""
def check_value(self, value: typing.Dict[typing.Any, typing.Any]) -> bool:
"""
Check if value is good
:Basic usage:
>>> from config.config_types import factory, Int, Float
>>> my_dict = Dict(factory(Int), factory(Float))
>>> my_dict.check_value("ere")
False
>>> my_dict.check_value(23)
False
>>> my_dict.check_value({23:0.75})
True
>>> my_dict.check_value({"er":0.75})
False
>>> my_dict.check_value({34:"er"})
False
:param typing.Dict[typing.Any, typing.Any] value: Value to check
:return: True if value is correct
:rtype: bool
"""
o_key = self.type_key()
o_value = self.type_value()
if type(value) == dict:
@ -21,12 +56,24 @@ class Dict(BaseType):
if not (o_key.check_value(k) and o_value.check_value(v)):
return False
return True
if (type(value) == list or type(value) == tuple) and len(value) == 2:
return o_key.check_value(value[0]) and o_value.check_value(value[1])
return False
def set(self, value):
"""Check and set value"""
def set(self, value: typing.Dict[typing.Any, typing.Any]) -> None:
"""
Set value
:Basic usage:
>>> from config.config_types import factory, Int, Float
>>> my_dict = Dict(factory(Int), factory(Float))
>>> my_dict.set({34: 0.75})
>>> my_dict.set("error") # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
ValueError: ...
:raise ValueError: if attempt to set invalid value
:param typing.Dict[typing.Any, typing.Any] value: Value to set
"""
new_dict = dict()
if not self.check_value(value):
raise ValueError("Tentative de définir une valeur incompatible")
@ -38,21 +85,57 @@ class Dict(BaseType):
new_dict.update({new_key: new_value})
self.values = new_dict
def get(self):
"""Get value"""
def get(self) -> typing.Dict[typing.Any, typing.Any]:
"""
Get value
:Basic usage:
>>> from config.config_types import factory, Int, Float
>>> my_dict = Dict(factory(Int), factory(Float))
>>> my_dict.set({34: 0.75})
>>> my_dict.get()
{34: 0.75}
:return: Current value
:rtype: typing.Dict[typing.Any, typing.Any]
"""
if self.values is not None:
return {k.get(): v.get() for k, v in self.values.items()}
return dict()
def to_save(self):
"""Build a serializable data to save"""
def to_save(self) -> typing.List[typing.List[typing.Any]]:
"""
Build a serializable data to save
>>> from config.config_types import factory, Int, Float
>>> my_dict = Dict(factory(Int), factory(Float))
>>> my_dict.set({34: 0.75})
>>> my_dict.to_save()
[[34, 0.75]]
:return: Dict as list of key, value tuples
:rtype: typing.List[typing.List[typing.Any]]
"""
# Construction d'une liste de liste: [[key, value], ...]
if self.values is not None:
return [[k.to_save(), v.to_save()] for k, v in self.values.items()]
return list()
def load(self, value):
"""Fill with value"""
def load(self, value: typing.List[typing.List[typing.Any]]) -> None:
"""
Load value from saved data
:Basic usage:
>>> from config.config_types import factory, Int, Float
>>> my_dict = Dict(factory(Int), factory(Float))
>>> my_dict.load([[34, 0.75]])
>>> my_dict.get()
{34: 0.75}
:param typing.List[typing.List[typing.Any]] value:
"""
new_values = dict()
for v in value:
new_key = self.type_key()
@ -61,3 +144,6 @@ class Dict(BaseType):
new_value.load(v[1])
new_values.update({new_key: new_value})
self.values = new_values
def __repr__(self):
return f'<config_types.Dict<{self.type_key}: {self.type_value}> object with value {self.values}>'

View File

@ -1,36 +1,150 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import typing
import discord
from config.config_types.base_type import BaseType
if TYPE_CHECKING:
from main import LBI
LBI = typing.TypeVar('LBI')
class Guild(BaseType):
#: :class:`LBI`: Client instance for checking
client: LBI
#: :class:`typing.Optional` [:class:`int`]: Current guild id
value: typing.Optional[int]
#: :class:`typing.Optional` [:class:`discord.Guild`]: Current guild instance
guild_instance: typing.Optional[discord.Guild]
def __init__(self, client):
def __init__(self, client: LBI) -> None:
"""
Base Guild type for config.
:param LBI client: Client instance
:Basic usage:
>>> Guild(client) #doctest: +SKIP
<config_types.discord_type.Guild object with value None>
"""
self.value = None
self.guild_instance = None
self.client = client
def check_value(self, value):
def check_value(self, value: typing.Union[int, discord.Guild]) -> bool:
"""
Check if value is correct
If bot is not connected, always True
:Basic usage:
>>> my_guild = Guild(client) #doctest: +SKIP
>>> my_guild.check_value(invalid_id_or_guild) #doctest: +SKIP
False
>>> my_guild.check_value(valid_id_or_guild) #doctest: +SKIP
True
:param value: Value to test
:type value: Union[int, discord.Guild]
:return: True if guild exists
"""
id = value
if isinstance(value, discord.Guild):
id = value.id
if not self.client.is_ready():
self.client.warn("No check for guild `value` because client is not initialized!")
return True
if self.client.get_guild(id):
return True
return True
def set(self, value):
if self.check_value(value):
self.value = value
return
def set(self, value: typing.Union[int, discord.Guild]):
"""
Set value of parameter
:Basic usage:
>>> my_guild = Guild(client) #doctest: +SKIP
>>> my_guild.set(valid_id_or_guild) #doctest: +SKIP
>>> my_guild.set(invalid_id_or_guild) #doctest: +SKIP +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
ValueError: ...
:raise ValueError: if attempt to set invalid value
:param value: value to set
:type value: Union[int, discord.Guild]
"""
if not self.check_value(value):
raise ValueError("Tentative de définir une valeur incompatible")
self.value = value
self._update()
def get(self):
return self.value
def get(self) -> typing.Union[int, discord.Guild]:
"""
Get value of parameter
def to_save(self):
:Basic usage:
>>> my_guild = Guild(client) #doctest: +SKIP
>>> my_guild.set(valid_id_or_guild) #doctest: +SKIP
>>> my_guild.get() #doctest: +SKIP
<discord.guild.Guild at 0x...>
If client is not connected:
>>> my_guild = Guild(client) #doctest: +SKIP
>>> my_guild.set(valid_id_or_guild) #doctest: +SKIP
>>> my_guild.get() #doctest: +SKIP
23411424132412
:return: Guild object if client is connected, else id
:rtype: Union[int, discord.Guild]
"""
self._update()
return self.guild_instance or self.value
def to_save(self) -> typing.Optional:
"""
Return id of guild
:Basic usage:
>>> my_guild = Guild(client) #doctest: +SKIP
>>> my_guild.set(valid_id_or_guild) #doctest: +SKIP
>>> my_guild.to_save() #doctest: +SKIP
123412412421
:return: Current id
:rtype: Optional[int]
"""
return self.value
def load(self, value):
"""
Load value from config
:Basic usage:
>>> my_guild = Guild(client) #doctest: +SKIP
>>> my_guild.set(valid_id) #doctest: +SKIP
>>> my_guild.set(invalid_id) #doctest: +SKIP +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
ValueError: ...
:raise ValueError: if attempt to set invalid value
:param value: value to set
:type value: Union[int, discord.Guild]
"""
if self.check_value(value):
raise ValueError("Tentative de charger une donnée incompatible.")
self.value = value
self.set(value)
def __repr__(self):
return f'<config_types.discord_types.guild object with value {self.value}>'
def _update(self):
if self.client.is_ready() and self.guild_instance is None:
self.guild_instance = self.client.get_guild(self.value)
else:
self.guild_instance = None

View File

@ -1,17 +1,17 @@
from typing import Optional
import typing
from config.config_types.base_type import BaseType
class Float(BaseType):
#: Max value for parameter
max: Optional[float]
max: typing.Optional[float]
#: Min value for parameter
min: Optional[float]
min: typing.Optional[float]
#: Current value of parameter
value: Optional[float]
value: typing.Optional[float]
def __init__(self, min: Optional[float] = None, max: Optional[float] = None) -> None:
def __init__(self, min: typing.Optional[float] = None, max: typing.Optional[float] = None) -> None:
"""
Base Float type for config
@ -26,14 +26,14 @@ class Float(BaseType):
>>> Float(min=10, max=20)
<config_types.Float object with value None, min=10 max=20>
:param min: Minimal value for parameter
:param max: Maximal value for parameter
:param float min: Minimal value for parameter
:param float max: Maximal value for parameter
"""
self.value = None
self.min = min
self.max = max
def check_value(self, value):
def check_value(self, value: float) -> bool:
"""
Check if value is a correct int
@ -67,8 +67,9 @@ class Float(BaseType):
>>> ten_to_twenty.check_value(23.34)
False
:param value: value to check
:param float value: value to check
:return: True if value is correct
:rtype: bool
"""
try:
float(value)
@ -81,7 +82,7 @@ class Float(BaseType):
return False
return True
def set(self, value):
def set(self, value: float) -> None:
"""
Set value of parameter
@ -94,14 +95,13 @@ class Float(BaseType):
ValueError: ...
:raise ValueError: if attempt to set invalid value
:param value: Value to set
:return: None
:param float value: Value to set
"""
if not self.check_value(value):
raise ValueError("Tentative de définir une valeur incompatible")
self.value = float(value)
def get(self):
def get(self) -> float:
"""
Get value of parameter
@ -113,10 +113,11 @@ class Float(BaseType):
-0.75
:return: Value of parameter
:rtype: float
"""
return self.value
def to_save(self):
def to_save(self) -> float:
"""
Build a serializable object
@ -129,10 +130,11 @@ class Float(BaseType):
0.75
:return: Current value
:rtype: float
"""
return self.value
def load(self, value):
def load(self, value: float):
"""
Load serialized value
@ -141,8 +143,7 @@ class Float(BaseType):
>>> my_float.get()
0.75
:param value: Value to load
:return: None
:param float value: Value to load
"""
if not self.check_value(value):
raise ValueError("Tentative de charger une donnée incompatible.")

View File

@ -1,20 +1,20 @@
from typing import Optional, List
import typing
from config.config_types.base_type import BaseType
class Int(BaseType):
#: Max value for parameter
max: Optional[int]
#: Min value for parameter
min: Optional[int]
#: List of valid values for parameter
values: Optional[List[int]]
#: Current value of parameter
value: Optional[int]
#: :class:`typing.Optional` [:class:`int`]: Max value for parameter
max: typing.Optional[int]
#: :class:`typing.Optional` [:class:`int`]: Min value for parameter
min: typing.Optional[int]
#: :class:`typing.Optional` [:class:`typing.List` [:class:`int`]]: List of valid values for parameter
values: typing.Optional[typing.List[int]]
#: :class:`typing.Optional` [:class:`int`] Current value of parameter
value: typing.Optional[int]
def __init__(self, min: Optional[int] = None, max: Optional[int] = None,
values: Optional[List[int]] = None) -> None:
def __init__(self, min: typing.Optional[int] = None, max: typing.Optional[int] = None,
values: typing.Optional[typing.List[int]] = None) -> None:
"""
Base Int type for config
@ -35,9 +35,9 @@ class Int(BaseType):
ValueError: ...
:raise ValueError: If min and/or max are set when using values
:param min: Min value for this parameter
:param max: Max value for this parameter
:param values: This parameter can only be in one of these values (raise ValueError if min or max are set with values)
:param typing.Optional[int] min: Min value for this parameter
:param typing.Optional[int] max: Max value for this parameter
:param typing.Optional[typing.List[int]] values: This parameter can only be in one of these values (raise ValueError if min or max are set with values)
"""
self.value = None
if values is not None and (min is not None or max is not None):
@ -84,8 +84,8 @@ class Int(BaseType):
>>> prime.check_value(5)
True
:param value: value to check
:return: True if value is correct
:param int value: value to check
:return bool: True if value is correct
"""
try:
int(value)
@ -114,14 +114,13 @@ class Int(BaseType):
ValueError: ...
:raise ValueError: if attempt to set invalid value
:param value: Value to set
:return: None
:param int value: Value to set
"""
if not self.check_value(value):
raise ValueError("Tentative de définir une valeur incompatible")
self.value = int(value)
def get(self) -> Optional[int]:
def get(self) -> typing.Optional[int]:
"""
Get value of parameter
@ -133,6 +132,7 @@ class Int(BaseType):
34
:return: Value of parameter
:rtype: Optional[int]
"""
return self.value
@ -149,6 +149,7 @@ class Int(BaseType):
34
:return: Current value
:rtype: int
"""
return self.value
@ -161,8 +162,7 @@ class Int(BaseType):
>>> my_int.get()
34
:param value: Value to load
:return: None
:param int value: Value to load
"""
if not self.check_value(value):
raise ValueError("Tentative de charger une donnée incompatible.")

View File

@ -1,16 +1,15 @@
import typing
from typing import Type
from config.config_types.base_type import BaseType
class List(BaseType):
#: Current list of value
#: :class:`typing.List` [:class:`BaseType`]: Current list of value
values: typing.List[BaseType]
#: Type of values
type_: Type[BaseType]
#: :class:`typing.Type` [:class:`BaseType`]: Type of values
type_: typing.Type[BaseType]
def __init__(self, type_: Type[BaseType]) -> None:
def __init__(self, type_: typing.Type[BaseType]) -> None:
"""
Base List type for config
@ -22,7 +21,7 @@ class List(BaseType):
>>> List(factory(Float))
<config_types.List of <config_types.Float with parameters () {}> objects with values []>
:param type_: Type of items
:param typing.Type[BaseType] type_: Type of items
"""
self.type_ = type_
self.values = []
@ -42,8 +41,9 @@ class List(BaseType):
>>> my_list.check_value([345, 34, 23, 45, 34, 46, 35, 2345, 'rt'])
False
:param value: Value to check
:param typing.List[typing.Any] value: Value to check
:return: True if value is correct
:rtype: bool
"""
new_object = self.type_()
try:
@ -67,8 +67,7 @@ class List(BaseType):
ValueError: ...
>>> my_list.set([45,])
:param value: Value to set
:return: None
:param typing.List[typing.Any] value: Value to set
"""
if not self.check_value(value):
raise ValueError('Tentative de définir une valeur incompatible')
@ -93,6 +92,7 @@ class List(BaseType):
:raise ValueError: If config is empty
:return: Value of parameter
:rtype: typing.List[typing.Any]
"""
return [v.get() for v in self.values]
@ -111,6 +111,7 @@ class List(BaseType):
[34]
:return: Current value
:rtype: typing.List[typing.Any]
"""
return [v.to_save() for v in self.values]
@ -124,8 +125,7 @@ class List(BaseType):
>>> my_list.get()
[34]
:param value: Value to load
:return: None
:param typing.List[typing.Any] value: Value to load
"""
if not self.check_value(value):
raise ValueError("Tentative de charger une donnée incompatible.")

View File

@ -28,7 +28,7 @@ class Str(BaseType):
>>> my_str.check_value(45)
True
:param value: Value to test
:param str value: Value to test
:return: True if value is usable as str
"""
try:
@ -48,7 +48,7 @@ class Str(BaseType):
>>> my_str.set(34)
:raise ValueError: if attempt to set invalid value
:param value: Value to set
:param str value: Value to set
:return: None
"""
if not self.check_value(value):
@ -74,11 +74,34 @@ class Str(BaseType):
return self.value
def to_save(self) -> str:
"""Build a serializable data to save"""
"""
Build a serializable data to save
:Basic usage:
>>> my_str = Str()
>>> my_str.set(34)
>>> my_str.to_save()
'34'
:todo: Vérifier que l'utf8 casse pas tout
:return: Current string content
:rtype: str
"""
return self.value
def load(self, value: str) -> None:
"""Fill with value"""
"""
Load value
:Basic usage:
>>> my_str = Str()
>>> my_str.load("34")
>>> my_str.get()
'34'
"""
if not self.check_value(value):
raise ValueError("Tentative de charger une donnée incompatible.")
self.value = value

22
main.py
View File

@ -122,10 +122,9 @@ class Module:
"""
return list of dependencies version
:raise IncompatibleModule: If bot_version is not properly formated (there must be min and max keys for each dependencies)
:return: list of dependencies version
:rtype: dict
:raises IncompatibleModule: If bot_version is not properly formated (there must be min and max keys for each
dependencies)
"""
with open(os.path.join("modules", self.name, "version.json")) as file:
versions = json.load(file)
@ -231,13 +230,14 @@ class LBI(discord.Client):
debug = log_LBI.debug
info = log_LBI.info
warning = log_LBI.warning
warn = warning
error = log_LBI.error
critical = log_LBI.critical
def __init__(self, config: Config = None, *args, **kwargs):
super().__init__(*args, **kwargs)
if config is None:
config = Config(path="data/config.toml")
config = Config(path="data/config.toml", client=self)
self.reloading = False
self.by_id = ClientById(self)
self.ready = False
@ -362,13 +362,10 @@ class LBI(discord.Client):
super().dispatch(event, *args, **kwargs)
# Dispatch to modules
for module in self.modules.values():
if module["initialized_class"].config["configured"]:
module["initialized_class"].dispatch(event, *args, **kwargs)
else:
self.warning(f"Module {module['initialized_class'].name} is not configured.")
# @async_event
async def on_error(self, event_method, *args, **kwargs):
"""Function called when error happend"""
# This event is special because it is call directly
self.error(traceback.format_exc())
for module in self.modules.values():
@ -401,12 +398,13 @@ class ClientById:
if msg is None:
raise discord.NotFound(None, "Message not found")
async def edit_message(self, id_, *args, **kwargs):
"""Edit message by id_
async def edit_message(self, id, *args, **kwargs):
"""
Edit message by id
:param id_: Id of the message to edit
:type id_: int"""
message = await self.fetch_message(id_)
:param id: Id of the message to edit
:type id: int"""
message = await self.fetch_message(id)
return await message.edit(**kwargs)
async def remove_reaction(self, id_message, *args, **kwargs):

View File

@ -39,10 +39,13 @@ class BaseClass:
self.config.register("authorized_users",
factory(config_types.List, factory(config_types.discord_types.User, client)))
self.config.register("command_text", factory(config_types.Str))
self.config.register("configured", factory(config_types.Bool))
self.config.set({"help_active": True, "color": 0x000000, "auth_everyone": False, "authorized_roles": [],
"authorized_users": [], "command_text": self.name.lower(), "configured": True})
self.config.load(create=True)
self.config.set({"help_active": True,
"color": 0x000000,
"auth_everyone": False,
"authorized_roles": [],
"authorized_users": [],
"command_text": self.name.lower()})
self.config.load()
async def send_help(self, channel):
embed = discord.Embed(

View File

@ -1,10 +0,0 @@
config.config\_types.discord package
====================================
Module contents
---------------
.. automodule:: config.config_types.discord_types
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,20 +0,0 @@
config.config\_types package
============================
Module contents
---------------
.. automodule:: config.config_types
:members:
:undoc-members:
:show-inheritance:
Subpackages
-----------
.. toctree::
:maxdepth: 4
config.config_types.discord_types

View File

@ -10,10 +10,21 @@ Module contents
:undoc-members:
:show-inheritance:
Subpackages
-----------
Config types
------------
.. toctree::
:maxdepth: 4
Base types
^^^^^^^^^^
.. automodule:: config.config_types
:members:
:undoc-members:
:show-inheritance:
config.config_types
Discord types
^^^^^^^^^^^^^
.. automodule:: config.config_types.discord_types
:members:
:undoc-members:
:show-inheritance:

10
source/api/main.rst Normal file
View File

@ -0,0 +1,10 @@
main package
============
Module contents
---------------
.. automodule:: main
:members:
:undoc-members:
:show-inheritance:

View File

@ -6,3 +6,4 @@ API Reference
config
utils
main

View File

@ -31,7 +31,9 @@ release = '0.0.1'
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx_autodoc_typehints',
'sphinx.ext.intersphinx',
'sphinx.ext.viewcode',
'sphinx.ext.todo',
]
# Add any paths that contain templates here, relative to this directory.
@ -47,7 +49,7 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'classic'
html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@ -55,5 +57,12 @@ html_theme = 'classic'
html_static_path = ['_static']
pygments_style = 'sphinx'
set_type_checking_flag = True
autoclass_content = 'both'
autodoc_mock_imports = ['aiohttp']
autodoc_typehint = "signature"
todo_include_todos = True
intersphinx_mapping = {
'python': ('https://docs.python.org/3/', None),
'discord': ('https://discordpy.readthedocs.io/en/latest/', None)
}

View File

@ -7,7 +7,7 @@ Welcome to Python Discord Bot's documentation!
==============================================
.. toctree::
:maxdepth: 2
:maxdepth: 4
:caption: Contents:
module_creation/index