From 3f416c56822a98bb8958d3f9c110977fc2a0b853 Mon Sep 17 00:00:00 2001 From: Louis Chauvet Date: Tue, 21 Apr 2020 02:59:08 +0200 Subject: [PATCH] [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 --- Pipfile | 2 +- Pipfile.lock | 66 ++++---- config/__init__.py | 2 +- config/base.py | 49 +++--- config/config_types/bool.py | 21 +-- config/config_types/color.py | 19 +-- config/config_types/dict.py | 118 +++++++++++++-- config/config_types/discord_types/guild.py | 142 ++++++++++++++++-- config/config_types/float.py | 35 ++--- config/config_types/int.py | 42 +++--- config/config_types/list.py | 22 +-- config/config_types/str.py | 31 +++- main.py | 24 ++- modules/base/Base.py | 11 +- .../api/config.config_types.discord_types.rst | 10 -- source/api/config.config_types.rst | 20 --- source/api/config.rst | 21 ++- source/api/main.rst | 10 ++ source/api/modules.rst | 1 + source/conf.py | 17 ++- source/index.rst | 2 +- 21 files changed, 446 insertions(+), 219 deletions(-) delete mode 100644 source/api/config.config_types.discord_types.rst delete mode 100644 source/api/config.config_types.rst create mode 100644 source/api/main.rst diff --git a/Pipfile b/Pipfile index 29d51d3..2587526 100644 --- a/Pipfile +++ b/Pipfile @@ -15,7 +15,7 @@ matplotlib = "*" humanize = "*" pytest = "*" sphinx = "*" -sphinx-autodoc-typehints = "*" +sphinx-rtd-theme = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index c49701a..18b8580 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -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": [ diff --git a/config/__init__.py b/config/__init__.py index 11f8bdc..1f266ee 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -1,3 +1,3 @@ -from .base import Config +from config.base import Config __all__ = ["Config"] diff --git a/config/base.py b/config/base.py index cd9f331..f70a636 100644 --- a/config/base.py +++ b/config/base.py @@ -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(): - self.fields[k].set(v) + 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() diff --git a/config/config_types/bool.py b/config/config_types/bool.py index ca08029..8cd1d79 100644 --- a/config/config_types/bool.py +++ b/config/config_types/bool.py @@ -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.") diff --git a/config/config_types/color.py b/config/config_types/color.py index fd098ee..c7392af 100644 --- a/config/config_types/color.py +++ b/config/config_types/color.py @@ -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.") diff --git a/config/config_types/dict.py b/config/config_types/dict.py index 5d6ed3f..d9e84d3 100644 --- a/config/config_types/dict.py +++ b/config/config_types/dict.py @@ -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)) + : > 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' object with value {self.values}>' diff --git a/config/config_types/discord_types/guild.py b/config/config_types/discord_types/guild.py index 161491e..3e65214 100644 --- a/config/config_types/discord_types/guild.py +++ b/config/config_types/discord_types/guild.py @@ -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 + + """ 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 - raise ValueError("Tentative de définir une valeur incompatible") + def set(self, value: typing.Union[int, discord.Guild]): + """ + Set value of parameter - def get(self): - return self.value + :Basic usage: - def to_save(self): + >>> 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) -> typing.Union[int, discord.Guild]: + """ + Get value of parameter + + :Basic usage: + + >>> my_guild = Guild(client) #doctest: +SKIP + >>> my_guild.set(valid_id_or_guild) #doctest: +SKIP + >>> my_guild.get() #doctest: +SKIP + + + 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'' + + 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 diff --git a/config/config_types/float.py b/config/config_types/float.py index eebfd65..325a655 100644 --- a/config/config_types/float.py +++ b/config/config_types/float.py @@ -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) - :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.") diff --git a/config/config_types/int.py b/config/config_types/int.py index 8357e85..2a5a64a 100644 --- a/config/config_types/int.py +++ b/config/config_types/int.py @@ -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.") diff --git a/config/config_types/list.py b/config/config_types/list.py index f9dde70..70fa392 100644 --- a/config/config_types/list.py +++ b/config/config_types/list.py @@ -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)) 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.") diff --git a/config/config_types/str.py b/config/config_types/str.py index 25fd27c..be699da 100644 --- a/config/config_types/str.py +++ b/config/config_types/str.py @@ -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 diff --git a/main.py b/main.py index b19ff73..92e32c7 100644 --- a/main.py +++ b/main.py @@ -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.") + module["initialized_class"].dispatch(event, *args, **kwargs) - # @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): diff --git a/modules/base/Base.py b/modules/base/Base.py index d5c1cef..c63bf32 100644 --- a/modules/base/Base.py +++ b/modules/base/Base.py @@ -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( diff --git a/source/api/config.config_types.discord_types.rst b/source/api/config.config_types.discord_types.rst deleted file mode 100644 index 0753f7f..0000000 --- a/source/api/config.config_types.discord_types.rst +++ /dev/null @@ -1,10 +0,0 @@ -config.config\_types.discord package -==================================== - -Module contents ---------------- - -.. automodule:: config.config_types.discord_types - :members: - :undoc-members: - :show-inheritance: diff --git a/source/api/config.config_types.rst b/source/api/config.config_types.rst deleted file mode 100644 index 2eb808a..0000000 --- a/source/api/config.config_types.rst +++ /dev/null @@ -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 - diff --git a/source/api/config.rst b/source/api/config.rst index 19e34a8..8c81f84 100644 --- a/source/api/config.rst +++ b/source/api/config.rst @@ -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 \ No newline at end of file + +Discord types +^^^^^^^^^^^^^ + +.. automodule:: config.config_types.discord_types + :members: + :undoc-members: + :show-inheritance: diff --git a/source/api/main.rst b/source/api/main.rst new file mode 100644 index 0000000..d8b156b --- /dev/null +++ b/source/api/main.rst @@ -0,0 +1,10 @@ +main package +============ + +Module contents +--------------- + +.. automodule:: main + :members: + :undoc-members: + :show-inheritance: diff --git a/source/api/modules.rst b/source/api/modules.rst index ed29e2c..dd2b41e 100644 --- a/source/api/modules.rst +++ b/source/api/modules.rst @@ -6,3 +6,4 @@ API Reference config utils + main diff --git a/source/conf.py b/source/conf.py index 3775b97..9bd00d1 100644 --- a/source/conf.py +++ b/source/conf.py @@ -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' \ No newline at end of file +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) +} diff --git a/source/index.rst b/source/index.rst index 0f2421a..9c85fbc 100644 --- a/source/index.rst +++ b/source/index.rst @@ -7,7 +7,7 @@ Welcome to Python Discord Bot's documentation! ============================================== .. toctree:: - :maxdepth: 2 + :maxdepth: 4 :caption: Contents: module_creation/index