Compare commits

..

4 Commits

Author SHA1 Message Date
a458788841 Added device info and bot prefix
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 41s
Tests / Build and Test (3.11) (pull_request) Successful in 1m17s
Tests / Build and Test (3.12) (pull_request) Successful in 1m58s
Tests / Build and Test (3.13) (pull_request) Successful in 1m21s
2025-01-04 18:01:49 +01:00
b76f727263 Replaced MatrixBot.config with MatrixBot.bot_config because .config is already used by smbl
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 1m52s
Tests / Build and Test (3.11) (pull_request) Successful in 1m18s
Tests / Build and Test (3.12) (pull_request) Successful in 1m22s
Tests / Build and Test (3.13) (pull_request) Successful in 1m23s
2025-01-04 17:49:44 +01:00
kku
5a244f603d TEST: Publishing Action
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 40s
Tests / Build and Test (3.11) (pull_request) Successful in 1m18s
Tests / Build and Test (3.12) (pull_request) Successful in 1m28s
Tests / Build and Test (3.13) (pull_request) Successful in 1m24s
2025-01-02 13:51:36 +01:00
kku
9bc4d0348d WIP: Matrix support (with SMBL) 2025-01-01 22:35:17 +01:00
18 changed files with 202 additions and 315 deletions

View File

@@ -1,20 +0,0 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@@ -1,61 +0,0 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
import os
import sys
from datetime import datetime
from typing import List, Dict, Any
import libbot
sys.path.insert(0, os.path.abspath(".."))
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project: str = "LibBotUniversal"
author: str = libbot.__author__
version: str = libbot.__version__
release: str = version
copyright: str = f"{datetime.now().year} {author}"
html_title: str = f"{project} v{version} Documentation"
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions: List[str] = [
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinx.ext.viewcode",
"sphinx.ext.viewcode",
"sphinx.ext.napoleon",
"sphinx_copybutton",
]
templates_path: List[str] = ["_templates"]
exclude_patterns: List[str] = ["_build", "Thumbs.db", ".DS_Store"]
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme: str = "furo"
html_static_path: List[str] = ["_static"]
html_theme_options: Dict[str, Any] = {
"source_repository": "https://git.end-play.xyz/profitroll/LibBotUniversal",
"source_branch": "main",
"source_directory": "docs/",
"light_css_variables": {
"font-stack": "'Outfit', sans-serif",
},
}
resource_links: Dict[str, Any] = {
"issues": "https://git.end-play.xyz/profitroll/LibBotUniversal/issues",
"examples": "https://git.end-play.xyz/profitroll/LibBotUniversal/tree/main/examples",
}

View File

@@ -1,29 +0,0 @@
Welcome to LibBotUniversal
=============================
LibBotUniversal (AKA libbot) simplifies development and maintenance of different chatbots.
Getting started
*****************************
There are a few pages to take a look at if you're just getting started.
* Installing the library
* Creating your first bot
* Examples of different bots
Getting help
*****************************
If you are looking for help or want to report a bug, we got you covered.
* Bug reports are being submitted on the repo's issue tracker.
Package
*****************************
.. toctree::
:maxdepth: 1
:caption: API reference
modules

View File

@@ -1,35 +0,0 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)
if "%1" == "" goto help
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

View File

@@ -1,7 +0,0 @@
libbot
======
.. toctree::
:maxdepth: 5
libbot

View File

@@ -28,7 +28,7 @@ dependencies = { file = "requirements/_.txt" }
[tool.setuptools.dynamic.optional-dependencies] [tool.setuptools.dynamic.optional-dependencies]
dev = { file = "requirements/dev.txt" } dev = { file = "requirements/dev.txt" }
docs = { file = "requirements/docs.txt" } matrix = { file = "requirements/matrix.txt" }
pycord = { file = "requirements/pycord.txt" } pycord = { file = "requirements/pycord.txt" }
pyrogram = { file = "requirements/pyrogram.txt" } pyrogram = { file = "requirements/pyrogram.txt" }
speed = { file = "requirements/speed.txt" } speed = { file = "requirements/speed.txt" }

View File

@@ -3,7 +3,7 @@ build==1.2.2.post1
isort==5.13.2 isort==5.13.2
mypy==1.14.1 mypy==1.14.1
pylint==3.3.3 pylint==3.3.3
pytest-asyncio==0.25.1 pytest-asyncio==0.25.0
pytest-cov==6.0.0 pytest-cov==6.0.0
pytest==8.3.4 pytest==8.3.4
tox==4.23.2 tox==4.23.2

View File

@@ -1,3 +0,0 @@
furo==2024.8.6
sphinx==8.1.3
sphinx_copybutton==0.5.2

1
requirements/matrix.txt Normal file
View File

@@ -0,0 +1 @@
simplematrixbotlib~=2.12.1

View File

@@ -4,8 +4,8 @@ from typing import Any, List, Optional
class ConfigKeyError(Exception): class ConfigKeyError(Exception):
"""Raised when config key is not found. """Raised when config key is not found.
Args: ### Attributes:
key (str | List[str]): Missing config key * key (`str | List[str]`): Missing config key.
""" """
def __init__(self, key: str | List[str]) -> None: def __init__(self, key: str | List[str]) -> None:
@@ -21,9 +21,9 @@ class ConfigKeyError(Exception):
class ConfigValueError(Exception): class ConfigValueError(Exception):
"""Raised when config key's value is invalid. """Raised when config key's value is invalid.
Args: ### Attributes:
key (str | List[str]): Invalid config key * key (`str | List[str]`): Invalid config key.
value (Optional[Any]): Key's correct value * value (`Optional[Any]`): Key's correct value.
""" """
def __init__(self, key: str | List[str], value: Optional[Any] = None) -> None: def __init__(self, key: str | List[str], value: Optional[Any] = None) -> None:

View File

@@ -18,16 +18,16 @@ def _(
locale: str | None = "en", locale: str | None = "en",
locales_root: str | Path = Path("locale"), locales_root: str | Path = Path("locale"),
) -> Any: ) -> Any:
"""Get value of the locale string. """Get value of locale string
Args: ### Args:
key (str): The last key of the locale's keys path * key (`str`): The last key of the locale's keys path.
*args (str): Path to key like: `dict[args][key]` * *args (`str`): Path to key like: `dict[args][key]`.
locale (str | None): Locale to be looked up in. Defaults to `"en"` * locale (`str | None`): Locale to looked up in. Defaults to `"en"`.
locales_root (str | Path, optional):Folder where locales are located. Defaults to `Path("locale")` * locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
Returns: ### Returns:
Any: Value of provided locale key. Is usually `str`, `Dict[str, Any]` or `List[Any]` * `Any`: Value of provided locale key. Is usually `str`, `Dict[str, Any]` or `List[Any]`
""" """
if locale is None: if locale is None:
locale: str = config_get("locale") locale: str = config_get("locale")
@@ -58,16 +58,16 @@ async def _(
locale: str | None = "en", locale: str | None = "en",
locales_root: str | Path = Path("locale"), locales_root: str | Path = Path("locale"),
) -> Any: ) -> Any:
"""Get value of the locale string. """Get value of locale string
Args: ### Args:
key (str): The last key of the locale's keys path * key (`str`): The last key of the locale's keys path.
*args (str): Path to key like: `dict[args][key]` * *args (`str`): Path to key like: `dict[args][key]`.
locale (str | None): Locale to be looked up in. Defaults to `"en"` * locale (`str | None`): Locale to looked up in. Defaults to `"en"`.
locales_root (str | Path, optional):Folder where locales are located. Defaults to `Path("locale")` * locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
Returns: ### Returns:
Any: Value of provided locale key. Is usually `str`, `Dict[str, Any]` or `List[Any]` * `Any`: Value of provided locale key. Is usually `str`, `Dict[str, Any]` or `List[Any]`
""" """
locale: str = config_get("locale") if locale is None else locale locale: str = config_get("locale") if locale is None else locale
@@ -94,16 +94,17 @@ async def _(
@asyncable @asyncable
def in_all_locales(key: str, *args: str, locales_root: str | Path = Path("locale")) -> List[Any]: def in_all_locales(key: str, *args: str, locales_root: str | Path = Path("locale")) -> List[Any]:
"""Get value of the provided key and path in all available locales. """Get value of the provided key and path in all available locales
Args: ### Args:
key (str): The last key of the locale's keys path * key (`str`): The last key of the locale's keys path.
*args (str): Path to key like: `dict[args][key]` * *args (`str`): Path to key like: `dict[args][key]`.
locales_root (str | Path, optional): Folder where locales are located. Defaults to `Path("locale")` * locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
Returns: ### Returns:
List[Any]: List of values in all locales * `List[Any]`: List of values in all locales
""" """
output: List[Any] = [] output: List[Any] = []
for locale in _get_valid_locales(locales_root): for locale in _get_valid_locales(locales_root):
@@ -127,15 +128,15 @@ def in_all_locales(key: str, *args: str, locales_root: str | Path = Path("locale
@in_all_locales.asynchronous @in_all_locales.asynchronous
async def in_all_locales(key: str, *args: str, locales_root: str | Path = Path("locale")) -> List[Any]: async def in_all_locales(key: str, *args: str, locales_root: str | Path = Path("locale")) -> List[Any]:
"""Get value of the provided key and path in all available locales. """Get value of the provided key and path in all available locales
Args: ### Args:
key (str): The last key of the locale's keys path * key (`str`): The last key of the locale's keys path.
*args (str): Path to key like: `dict[args][key]` * *args (`str`): Path to key like: `dict[args][key]`.
locales_root (str | Path, optional): Folder where locales are located. Defaults to `Path("locale")` * locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
Returns: ### Returns:
List[Any]: List of values in all locales * `List[Any]`: List of values in all locales
""" """
output: List[Any] = [] output: List[Any] = []
@@ -160,17 +161,20 @@ async def in_all_locales(key: str, *args: str, locales_root: str | Path = Path("
@asyncable @asyncable
def in_every_locale(key: str, *args: str, locales_root: str | Path = Path("locale")) -> Dict[str, Any]: def in_every_locale(
"""Get value of the provided key and path in every available locale with locale tag. key: str, *args: str, locales_root: str | Path = Path("locale")
) -> Dict[str, Any]:
"""Get value of the provided key and path in every available locale with locale tag
Args: ### Args:
key (str): The last key of the locale's keys path * key (`str`): The last key of the locale's keys path.
*args (str): Path to key like: `dict[args][key]` * *args (`str`): Path to key like: `dict[args][key]`.
locales_root (str | Path, optional): Folder where locales are located. Defaults to `Path("locale")` * locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
Returns: ### Returns:
Dict[str, Any]: Locale is a key, and it's value from locale file is a value * `Dict[str, Any]`: Locale is a key, and it's value from locale file is a value
""" """
output: Dict[str, Any] = {} output: Dict[str, Any] = {}
for locale in _get_valid_locales(locales_root): for locale in _get_valid_locales(locales_root):
@@ -196,15 +200,15 @@ def in_every_locale(key: str, *args: str, locales_root: str | Path = Path("local
async def in_every_locale( async def in_every_locale(
key: str, *args: str, locales_root: str | Path = Path("locale") key: str, *args: str, locales_root: str | Path = Path("locale")
) -> Dict[str, Any]: ) -> Dict[str, Any]:
"""Get value of the provided key and path in every available locale with locale tag. """Get value of the provided key and path in every available locale with locale tag
Args: ### Args:
key (str): The last key of the locale's keys path * key (`str`): The last key of the locale's keys path.
*args (str): Path to key like: `dict[args][key]` * *args (`str`): Path to key like: `dict[args][key]`.
locales_root (str | Path, optional): Folder where locales are located. Defaults to `Path("locale")` * locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
Returns: ### Returns:
Dict[str, Any]: Locale is a key, and it's value from locale file is a value * `Dict[str, Any]`: Locale is a key, and it's value from locale file is a value
""" """
output: Dict[str, Any] = {} output: Dict[str, Any] = {}

View File

@@ -14,11 +14,6 @@ class BotLocale:
default_locale: str | None = "en", default_locale: str | None = "en",
locales_root: str | Path = Path("locale"), locales_root: str | Path = Path("locale"),
) -> None: ) -> None:
"""
Args:
default_locale (str | None): Default bot's locale. Defaults to `"en"`
locales_root (str | Path): Folder where locales are located. Defaults to `Path("locale")`
"""
if isinstance(locales_root, str): if isinstance(locales_root, str):
locales_root = Path(locales_root) locales_root = Path(locales_root)
elif not isinstance(locales_root, Path): elif not isinstance(locales_root, Path):
@@ -35,15 +30,15 @@ class BotLocale:
self.locales[locale] = json_read(Path(f"{locales_root}/{locale}.json")) self.locales[locale] = json_read(Path(f"{locales_root}/{locale}.json"))
def _(self, key: str, *args: str, locale: str | None = None) -> Any: def _(self, key: str, *args: str, locale: str | None = None) -> Any:
"""Get value of locale string. """Get value of locale string
Args: ### Args:
key (str): The last key of the locale's keys path * key (`str`): The last key of the locale's keys path
*args (str): Path to key like: `dict[args][key]` * *args (`str`): Path to key like: `dict[args][key]`
locale (str | None, optional): Locale to be looked up in. Defaults to config's `"locale"` value * locale (`str | None`, *optional*): Locale to looked up in. Defaults to config's `"locale"` value
Returns: ### Returns:
Any: Value of provided locale key. Is usually `str`, `Dict[str, Any]` or `List[Any]` * `Any`: Value of provided locale key. Is usually `str`, `Dict[str, Any]` or `List[Any]`
""" """
if locale is None: if locale is None:
locale: str = self.default locale: str = self.default
@@ -69,14 +64,14 @@ class BotLocale:
return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"' return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
def in_all_locales(self, key: str, *args: str) -> List[Any]: def in_all_locales(self, key: str, *args: str) -> List[Any]:
"""Get value of the provided key and path in all available locales. """Get value of the provided key and path in all available locales
Args: ### Args:
key (str): The last key of the locale's keys path * key (`str`): The last key of the locale's keys path.
*args (str): Path to key like: `dict[args][key]` * *args (`str`): Path to key like: `dict[args][key]`.
Returns: ### Returns:
List[Any]: List of values in all locales * `List[Any]`: List of values in all locales
""" """
output: List[Any] = [] output: List[Any] = []
@@ -99,14 +94,14 @@ class BotLocale:
return output return output
def in_every_locale(self, key: str, *args: str) -> Dict[str, Any]: def in_every_locale(self, key: str, *args: str) -> Dict[str, Any]:
"""Get value of the provided key and path in every available locale with locale tag. """Get value of the provided key and path in every available locale with locale tag
Args: ### Args:
key (str): The last key of the locale's keys path * key (`str`): The last key of the locale's keys path.
*args (str): Path to key like: `dict[args][key]` * *args (`str`): Path to key like: `dict[args][key]`.
Returns: ### Returns:
Dict[str, Any]: Locale is a key, and it's value from locale file is a value * `Dict[str, Any]`: Locale is a key, and it's value from locale file is a value
""" """
output: Dict[str, Any] = {} output: Dict[str, Any] = {}

View File

@@ -0,0 +1,2 @@
# This file is left empty on purpose
# Adding imports here will cause import errors when libbot[matrix] is not installed

View File

@@ -0,0 +1 @@
from .bot import MatrixBot

View File

@@ -0,0 +1,80 @@
import logging
from logging import Logger
from pathlib import Path
from typing import Dict, Any
from typing_extensions import override
from ... import __version__ as __libbot_version__
from ...i18n.classes import BotLocale
from ...utils import json_read
try:
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.schedulers.background import BackgroundScheduler
from simplematrixbotlib import Bot, Creds, Config
except ImportError as exc:
raise ImportError("You need to install libbot[matrix] in order to use this class.") from exc
logger: Logger = logging.getLogger(__name__)
class MatrixBot(Bot):
@override
def __init__(
self,
config: Dict[str, Any] | None = None,
config_path: str | Path = Path("config.json"),
locales_root: str | Path | None = None,
scheduler: AsyncIOScheduler | BackgroundScheduler | None = None,
smbl_creds: Creds = None,
smbl_config: Config = None,
):
self.bot_config: Dict[str, Any] = config if config is not None else json_read(config_path)
super().__init__(
creds=(
smbl_creds
if smbl_creds is not None
else Creds(
homeserver=self.bot_config["bot"]["homeserver"],
username=self.bot_config["bot"]["username"],
password=self.bot_config["bot"]["password"],
device_name=(
f"LibBotUniversal v{__libbot_version__}"
if "device_name" not in self.bot_config["bot"]
else self.bot_config["bot"]["device_name"]
),
)
),
config=smbl_config,
)
self.bot_prefix: str = (
"!" if "prefix" not in self.bot_config["bot"] else self.bot_config["bot"]["prefix"]
)
self.bot_locale: BotLocale = BotLocale(
default_locale=self.bot_config["locale"],
locales_root=(Path("locale") if locales_root is None else locales_root),
)
self.default_locale: str = self.bot_locale.default
self.locales: Dict[str, Any] = self.bot_locale.locales
self._ = self.bot_locale._
self.in_all_locales = self.bot_locale.in_all_locales
self.in_every_locale = self.bot_locale.in_every_locale
self.scheduler: AsyncIOScheduler | BackgroundScheduler | None = scheduler
@override
def run(
self, scheduler_start: bool = True, scheduler_shutdown: bool = True, scheduler_wait: bool = True
) -> None:
if self.scheduler is not None and scheduler_start:
self.scheduler.start()
super().run()
if self.scheduler is not None and scheduler_shutdown:
self.scheduler.shutdown(scheduler_wait)

View File

@@ -1,13 +1,9 @@
import logging import logging
from logging import Logger
from pathlib import Path from pathlib import Path
from typing import Any, Dict from typing import Any, Dict
from typing_extensions import override from typing_extensions import override
from ...i18n.classes import BotLocale
from ...utils import json_read
try: try:
from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.schedulers.background import BackgroundScheduler
@@ -15,11 +11,17 @@ try:
except ImportError as exc: except ImportError as exc:
raise ImportError("You need to install libbot[pycord] in order to use this class.") from exc raise ImportError("You need to install libbot[pycord] in order to use this class.") from exc
logger: Logger = logging.getLogger(__name__) try:
from ujson import loads
except ImportError:
from json import loads
from ...i18n.classes import BotLocale
logger = logging.getLogger(__name__)
class PycordBot(Bot): class PycordBot(Bot):
# TODO Write a docstring
@override @override
def __init__( def __init__(
self, self,
@@ -30,17 +32,11 @@ class PycordBot(Bot):
scheduler: AsyncIOScheduler | BackgroundScheduler | None = None, scheduler: AsyncIOScheduler | BackgroundScheduler | None = None,
**kwargs, **kwargs,
): ):
""" if config is None:
with open(config_path, "r", encoding="utf-8") as f:
Args: self.config: dict = loads(f.read())
*args: else:
config: self.config = config
config_path:
locales_root:
scheduler:
**kwargs:
"""
self.config: Dict[str, Any] = config if config is not None else json_read(config_path)
super().__init__( super().__init__(
debug_guilds=(self.config["bot"]["debug_guilds"] if self.config["debug"] else None), debug_guilds=(self.config["bot"]["debug_guilds"] if self.config["debug"] else None),
@@ -62,30 +58,15 @@ class PycordBot(Bot):
self.scheduler: AsyncIOScheduler | BackgroundScheduler | None = scheduler self.scheduler: AsyncIOScheduler | BackgroundScheduler | None = scheduler
# TODO Write a docstring
@override @override
async def start(self, token: str, reconnect: bool = True, scheduler_start: bool = True) -> None: async def start(self, token: str, reconnect: bool = True, scheduler_start: bool = True) -> None:
"""
Args:
token:
reconnect:
scheduler_start:
"""
if self.scheduler is not None and scheduler_start: if self.scheduler is not None and scheduler_start:
self.scheduler.start() self.scheduler.start()
await super().start(token, reconnect=reconnect) await super().start(token, reconnect=reconnect)
# TODO Write a docstring
@override @override
async def close(self, scheduler_shutdown: bool = True, scheduler_wait: bool = True) -> None: async def close(self, scheduler_shutdown: bool = True, scheduler_wait: bool = True) -> None:
"""
Args:
scheduler_shutdown:
scheduler_wait:
"""
if self.scheduler is not None and scheduler_shutdown: if self.scheduler is not None and scheduler_shutdown:
self.scheduler.shutdown(scheduler_wait) self.scheduler.shutdown(scheduler_wait)

View File

@@ -16,24 +16,20 @@ def _hex_from_int(color_int: int) -> str:
def color_from_hex(hex_string: str) -> Colour: def color_from_hex(hex_string: str) -> Colour:
"""Convert valid hexadecimal string to :class:`discord.Colour`. """Convert valid hexadecimal string to discord.Colour.
Args: :param hex_string: Hexadecimal string to convert into Colour object
hex_string (str): Hexadecimal string to convert into :class:`discord.Colour` object :type hex_string: str
:return: Colour object
Returns:
Colour: :class:`discord.Colour` object
""" """
return Colour(_int_from_hex(hex_string)) return Colour(_int_from_hex(hex_string))
def hex_from_color(color: Colour) -> str: def hex_from_color(color: Colour) -> str:
"""Convert :class:`discord.Colour` to hexadecimal string. """Convert discord.Colour to hexadecimal string.
Args: :param color: Colour object to convert into the string
color (Colour): :class:`discord.Colour` object to convert into the string :type color: Colour
:return: Hexadecimal string in #XXXXXX format
Returns:
str: Hexadecimal string in #XXXXXX format
""" """
return _hex_from_int(color.value) return _hex_from_int(color.value)

View File

@@ -2,20 +2,13 @@ import asyncio
import logging import logging
import sys import sys
from datetime import datetime, timedelta from datetime import datetime, timedelta
from logging import Logger
from os import cpu_count, getpid from os import cpu_count, getpid
from pathlib import Path from pathlib import Path
from time import time from time import time
from typing import Any, Dict, List, Optional from typing import Any, Dict, List
from typing_extensions import override from typing_extensions import override
from .command import PyroCommand
from .commandset import CommandSet
from ...i18n import _
from ...i18n.classes import BotLocale
from ...utils import json_read
try: try:
import pyrogram import pyrogram
from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.schedulers.asyncio import AsyncIOScheduler
@@ -42,11 +35,15 @@ try:
except ImportError: except ImportError:
from json import dumps, loads from json import dumps, loads
logger: Logger = logging.getLogger(__name__) from ...i18n.classes import BotLocale
from ...i18n import _
from .command import PyroCommand
from .commandset import CommandSet
logger = logging.getLogger(__name__)
class PyroClient(Client): class PyroClient(Client):
# TODO Write a docstring
@override @override
def __init__( def __init__(
self, self,
@@ -69,7 +66,11 @@ class PyroClient(Client):
scheduler: AsyncIOScheduler | BackgroundScheduler | None = None, scheduler: AsyncIOScheduler | BackgroundScheduler | None = None,
**kwargs, **kwargs,
): ):
self.config: Dict[str, Any] = config if config is not None else json_read(config_path) if config is None:
with open(config_path, "r", encoding="utf-8") as f:
self.config: dict = loads(f.read())
else:
self.config = config
super().__init__( super().__init__(
name=name, name=name,
@@ -120,12 +121,6 @@ class PyroClient(Client):
@override @override
async def start(self, register_commands: bool = True, scheduler_start: bool = True) -> None: async def start(self, register_commands: bool = True, scheduler_start: bool = True) -> None:
"""Start the bot and it's services.
Args:
register_commands (bool, optional): Register commands on start. Defaults to `True`
scheduler_start (bool, optional): Start the scheduler on start. Defaults to `True`
"""
await super().start() await super().start()
self.start_time = time() self.start_time = time()
@@ -218,13 +213,6 @@ class PyroClient(Client):
async def stop( async def stop(
self, exit_completely: bool = True, scheduler_shutdown: bool = True, scheduler_wait: bool = True self, exit_completely: bool = True, scheduler_shutdown: bool = True, scheduler_wait: bool = True
) -> None: ) -> None:
"""Stop the bot and it's services.
Args:
exit_completely (bool, optional): Exit the program. Defaults to `True`
scheduler_shutdown (bool): Shutdown the scheduler. Defaults to `True`
scheduler_wait (bool): Wait for tasks to finish. Defaults to `True`
"""
try: try:
await self.send_message( await self.send_message(
chat_id=( chat_id=(
@@ -251,10 +239,10 @@ class PyroClient(Client):
raise SystemExit("Bot has been shut down, this is not an application error!") from exc raise SystemExit("Bot has been shut down, this is not an application error!") from exc
async def collect_commands(self) -> List[CommandSet] | None: async def collect_commands(self) -> List[CommandSet] | None:
"""Gather list of the bot's commands. """Gather list of the bot's commands
Returns: ### Returns:
List[CommandSet]: List of the commands' sets * `List[CommandSet]`: List of the commands' sets.
""" """
command_sets = None command_sets = None
@@ -336,10 +324,10 @@ class PyroClient(Client):
self, self,
command: str, command: str,
) -> None: ) -> None:
"""Add command to the bot's internal commands list. """Add command to the bot's internal commands list
Args: ### Args:
command (str): Command's name * command (`str`)
""" """
self.commands.append( self.commands.append(
PyroCommand( PyroCommand(
@@ -352,12 +340,9 @@ class PyroClient(Client):
command, command,
) )
async def register_commands(self, command_sets: Optional[List[CommandSet]] = None) -> None: async def register_commands(self, command_sets: List[CommandSet] | None = None) -> None:
"""Register commands stored in bot's 'commands' attribute. """Register commands stored in bot's 'commands' attribute"""
Args:
command_sets (List[CommandSet], optional): List of command sets. Commands will be parsed from bot's 'commands' attribute if not provided
"""
if command_sets is None: if command_sets is None:
commands = [ commands = [
BotCommand(command=command.command, description=command.description) BotCommand(command=command.command, description=command.description)
@@ -382,12 +367,9 @@ class PyroClient(Client):
language_code=command_set.language_code, language_code=command_set.language_code,
) )
async def remove_commands(self, command_sets: Optional[List[CommandSet]] = None) -> None: async def remove_commands(self, command_sets: List[CommandSet] | None = None) -> None:
"""Remove commands stored in bot's 'commands' attribute. """Remove commands stored in bot's 'commands' attribute"""
Args:
command_sets (List[CommandSet], optional): List of command sets. Commands with scope :class:`pyrogram.types.BotCommandScopeDefault` will be removed if not provided
"""
if command_sets is None: if command_sets is None:
logger.info("Removing commands with a default scope 'BotCommandScopeDefault'") logger.info("Removing commands with a default scope 'BotCommandScopeDefault'")
await self.delete_bot_commands(BotCommandScopeDefault()) await self.delete_bot_commands(BotCommandScopeDefault())