Compare commits

...

21 Commits

Author SHA1 Message Date
bfcb067ba5 Merge pull request 'v4.0.1' (#170) from dev into main
All checks were successful
Analysis / SonarCloud (push) Successful in 39s
Tests / Build and Test (3.11) (push) Successful in 1m18s
Tests / Build and Test (3.12) (push) Successful in 1m35s
Tests / Build and Test (3.13) (push) Successful in 1m21s
Reviewed-on: #170
2024-12-29 17:18:48 +02:00
kku
3cdd6da506 Added typing_extensions to the dependencies
All checks were successful
Analysis / SonarCloud (push) Successful in 58s
Analysis / SonarCloud (pull_request) Successful in 37s
Tests / Build and Test (3.11) (pull_request) Successful in 1m21s
Tests / Build and Test (3.12) (pull_request) Successful in 1m27s
Tests / Build and Test (3.13) (pull_request) Successful in 1m49s
2024-12-29 16:06:45 +01:00
kku
d24e94b57e Tests are now for 3.11+
All checks were successful
Analysis / SonarCloud (push) Successful in 44s
2024-12-27 18:33:51 +01:00
95584c0e63 Slight documentation improvements
All checks were successful
Analysis / SonarCloud (push) Successful in 46s
2024-12-27 00:37:54 +01:00
a38b55d270 Merge pull request 'v4.0.0' (#169) from dev into main
Some checks failed
Analysis / SonarCloud (push) Successful in 42s
Tests / Build and Test (3.10) (push) Failing after 57s
Tests / Build and Test (3.11) (push) Successful in 1m4s
Tests / Build and Test (3.12) (push) Successful in 1m13s
Tests / Build and Test (3.9) (push) Failing after 57s
Reviewed-on: #169
2024-12-26 19:59:34 +02:00
a13ef83e82 Merge pull request '4.0.0' (#168) from overhaul-v4 into dev
Some checks failed
Analysis / SonarCloud (push) Successful in 40s
Analysis / SonarCloud (pull_request) Successful in 52s
Tests / Build and Test (3.10) (pull_request) Failing after 58s
Tests / Build and Test (3.11) (pull_request) Successful in 1m5s
Tests / Build and Test (3.12) (pull_request) Successful in 1m16s
Tests / Build and Test (3.9) (pull_request) Failing after 58s
Reviewed-on: #168
2024-12-26 19:44:56 +02:00
0ce4ddcf7c Fixed two broken references
Some checks failed
Analysis / SonarCloud (pull_request) Successful in 42s
Tests / Build and Test (3.10) (pull_request) Failing after 57s
Tests / Build and Test (3.11) (pull_request) Successful in 1m2s
Tests / Build and Test (3.12) (pull_request) Successful in 1m11s
Tests / Build and Test (3.9) (pull_request) Has been cancelled
2024-12-26 18:37:55 +01:00
aa2c778a6a Removed legacy usage of Union[] 2024-12-26 18:36:57 +01:00
a47a508ecf Update dependency pylint to v3.3.3
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 34s
Tests / Build and Test (3.10) (pull_request) Successful in 1m2s
Tests / Build and Test (3.11) (pull_request) Successful in 1m1s
Tests / Build and Test (3.12) (pull_request) Successful in 1m14s
Tests / Build and Test (3.9) (pull_request) Successful in 1m3s
Analysis / SonarCloud (push) Successful in 39s
2024-12-24 05:27:30 +02:00
bdd649bdbe Update dependency types-aiofiles to v24.1.0.20241221
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 38s
Tests / Build and Test (3.10) (pull_request) Successful in 1m4s
Tests / Build and Test (3.11) (pull_request) Successful in 1m2s
Tests / Build and Test (3.12) (pull_request) Successful in 1m9s
Tests / Build and Test (3.9) (pull_request) Successful in 1m6s
Analysis / SonarCloud (push) Successful in 44s
2024-12-21 05:18:48 +02:00
e6d9beec81 Update dependency mypy to v1.14.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 35s
Tests / Build and Test (3.10) (pull_request) Successful in 3m26s
Tests / Build and Test (3.11) (pull_request) Successful in 1m15s
Tests / Build and Test (3.12) (pull_request) Successful in 1m7s
Tests / Build and Test (3.9) (pull_request) Successful in 1m5s
Analysis / SonarCloud (push) Successful in 46s
2024-12-20 17:47:59 +02:00
9907cc50f1 Merge pull request 'v3.3.1' (#160) from dev into main
All checks were successful
Analysis / SonarCloud (push) Successful in 46s
Tests / Build and Test (3.10) (push) Successful in 1m3s
Tests / Build and Test (3.11) (push) Successful in 1m1s
Tests / Build and Test (3.12) (push) Successful in 1m8s
Tests / Build and Test (3.9) (push) Successful in 1m3s
Reviewed-on: #160
2024-12-16 23:57:08 +02:00
1b60257bc5 Merge pull request 'v3.3.0' (#159) from dev into main
All checks were successful
Analysis / SonarCloud (push) Successful in 43s
Tests / Build and Test (3.10) (push) Successful in 1m2s
Tests / Build and Test (3.11) (push) Successful in 1m2s
Tests / Build and Test (3.12) (push) Successful in 1m8s
Tests / Build and Test (3.9) (push) Successful in 1m4s
Reviewed-on: #159
2024-12-16 23:48:07 +02:00
171e36a491 Merge pull request 'v3.2.3' (#118) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m2s
Tests / test (3.11) (push) Successful in 58s
Tests / test (3.8) (push) Successful in 1m4s
Tests / test (3.9) (push) Successful in 1m1s
Reviewed-on: #118
2024-07-10 00:07:54 +03:00
c419c684aa Merge pull request 'v3.2.2' (#107) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m10s
Tests / test (3.11) (push) Successful in 1m4s
Tests / test (3.8) (push) Successful in 1m6s
Tests / test (3.9) (push) Successful in 1m7s
Reviewed-on: #107
2024-05-26 22:44:18 +03:00
748b2b2abb Merge pull request 'v3.2.1' (#106) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m3s
Tests / test (3.11) (push) Successful in 1m23s
Tests / test (3.8) (push) Successful in 1m7s
Tests / test (3.9) (push) Successful in 1m7s
Reviewed-on: #106
2024-05-26 17:53:00 +03:00
52c2e5cc13 Merge pull request 'v3.2.0' (#105) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m4s
Tests / test (3.11) (push) Successful in 1m2s
Tests / test (3.8) (push) Successful in 1m29s
Tests / test (3.9) (push) Successful in 1m4s
Reviewed-on: #105
2024-05-26 17:29:44 +03:00
55c61e3fce Merge pull request 'v3.1.0' (#102) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 55s
Tests / test (3.11) (push) Successful in 55s
Tests / test (3.8) (push) Successful in 57s
Tests / test (3.9) (push) Successful in 1m27s
Reviewed-on: #102
2024-05-19 16:22:17 +03:00
b9550032ba Merge pull request 'Update to 3.0.1' (#98) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 57s
Tests / test (3.11) (push) Successful in 54s
Tests / test (3.8) (push) Successful in 1m8s
Tests / test (3.9) (push) Successful in 55s
Reviewed-on: #98
2024-05-15 00:19:03 +03:00
5ba763246b Merge pull request 'Update to 3.0.0' (#52) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m15s
Tests / test (3.11) (push) Successful in 1m14s
Tests / test (3.8) (push) Successful in 1m14s
Tests / test (3.9) (push) Successful in 1m22s
Reviewed-on: #52
2024-01-04 00:06:50 +02:00
f0ffdf096d Merge pull request 'Pycord support initial release' (#48) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m8s
Tests / test (3.11) (push) Successful in 1m5s
Tests / test (3.8) (push) Successful in 1m43s
Tests / test (3.9) (push) Successful in 1m3s
Reviewed-on: #48
2023-12-27 15:00:41 +02:00
20 changed files with 155 additions and 168 deletions

View File

@@ -15,7 +15,7 @@ jobs:
container: catthehacker/ubuntu:act-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]
python-version: [ "3.11", "3.12", "3.13" ]
steps:
- uses: actions/checkout@v3

View File

@@ -36,18 +36,17 @@ pip install libbot[pycord,speed]
### Pyrogram
```python
from libbot.pyrogram import PyroClient
from libbot.pyrogram.classes import PyroClient
def main():
client = PyroClient(scheduler=scheduler)
client: PyroClient = PyroClient()
try:
client.run()
except KeyboardInterrupt:
print("Shutting down...")
finally:
if client.scheduler is not None:
client.scheduler.shutdown()
exit()
@@ -59,20 +58,20 @@ if __name__ == "__main__":
```python
from discord import Intents
from libbot import sync
from libbot.pycord import PycordBot
from libbot.utils import config_get
from libbot.pycord.classes import PycordBot
async def main():
intents = Intents.default()
bot = PycordBot(intents=intents)
intents: Intents = Intents.default()
bot: PycordBot = PycordBot(intents=intents)
bot.load_extension("cogs")
try:
await bot.start(sync.config_get("bot_token", "bot"))
await bot.start(config_get("bot_token", "bot"))
except KeyboardInterrupt:
logger.warning("Shutting down...")
print("Shutting down...")
await bot.close()
@@ -83,4 +82,5 @@ if __name__ == "__main__":
## Config examples
For bot config examples please check the examples directory. Without a valid config file, the bot won't start at all, so you need to make sure the correct config file is used.
For bot config examples please check the examples directory. Without a valid config file, the bot won't start at all, so
you need to make sure the correct config file is used.

View File

@@ -1 +1,2 @@
aiofiles>=23.0.0
aiofiles>=23.0.0
typing_extensions~=4.12.2

View File

@@ -1,11 +1,12 @@
black==24.10.0
build==1.2.2.post1
isort==5.13.2
mypy==1.13.0
pylint==3.3.2
mypy==1.14.0
pylint==3.3.3
pytest-asyncio==0.25.0
pytest-cov==6.0.0
pytest==8.3.4
tox==4.23.2
types-aiofiles==24.1.0.20240626
twine==6.0.1
types-aiofiles==24.1.0.20241221
types-ujson==5.10.0.20240515

View File

@@ -1,4 +1,4 @@
__version__ = "4.0.0"
__version__ = "4.0.1"
__license__ = "GPL3"
__author__ = "Profitroll"

View File

@@ -1,15 +1,15 @@
from typing import Any, List, Optional, Union
from typing import Any, List, Optional
class ConfigKeyError(Exception):
"""Raised when config key is not found.
### Attributes:
* key (`Union[str, List[str]]`): Missing config key.
* key (`str | List[str]`): Missing config key.
"""
def __init__(self, key: Union[str, List[str]]) -> None:
self.key: Union[str, List[str]] = key
def __init__(self, key: str | List[str]) -> None:
self.key: str | List[str] = key
super().__init__(
f"Config key {'.'.join(key) if isinstance(key, list) else key} is missing. Please set in your config file."
)
@@ -22,12 +22,12 @@ class ConfigValueError(Exception):
"""Raised when config key's value is invalid.
### Attributes:
* key (`Union[str, List[str]]`): Invalid config key.
* key (`str | List[str]`): Invalid config key.
* value (`Optional[Any]`): Key's correct value.
"""
def __init__(self, key: Union[str, List[str]], value: Optional[Any] = None) -> None:
self.key: Union[str, List[str]] = key
def __init__(self, key: str | List[str], value: Optional[Any] = None) -> None:
self.key: str | List[str] = key
self.value: Optional[Any] = value
super().__init__(
f"Config key {'.'.join(key) if isinstance(key, list) else key} has invalid value. {f'Must be {value}. ' if value else ''}Please set in your config file."

View File

@@ -1,13 +1,13 @@
from os import listdir, PathLike
from pathlib import Path
from typing import Any, Dict, Union, List
from typing import Any, Dict, List
from ..utils.config import config_get
from ..utils.json import json_read
from ..utils.syncs import asyncable
def _get_valid_locales(locales_root: Union[str, PathLike[str]]) -> List[str]:
def _get_valid_locales(locales_root: str | PathLike[str]) -> List[str]:
return [".".join(entry.split(".")[:-1]) for entry in listdir(locales_root)]
@@ -15,19 +15,19 @@ def _get_valid_locales(locales_root: Union[str, PathLike[str]]) -> List[str]:
def _(
key: str,
*args: str,
locale: Union[str, None] = "en",
locales_root: Union[str, Path] = Path("locale"),
locale: str | None = "en",
locales_root: str | Path = Path("locale"),
) -> Any:
"""Get value of locale string
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`.
* locale (`Union[str, None]`): Locale to looked up in. Defaults to `"en"`.
* locales_root (`Union[str, Path]`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
* *args (`str`): Path to key like: `dict[args][key]`.
* 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")`.
### Returns:
* `Any`: Value of provided locale key. Is usually `str`, `dict` or `list`
* `Any`: Value of provided locale key. Is usually `str`, `Dict[str, Any]` or `List[Any]`
"""
if locale is None:
locale: str = config_get("locale")
@@ -55,19 +55,19 @@ def _(
async def _(
key: str,
*args: str,
locale: Union[str, None] = "en",
locales_root: Union[str, Path] = Path("locale"),
locale: str | None = "en",
locales_root: str | Path = Path("locale"),
) -> Any:
"""Get value of locale string
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`.
* locale (`Union[str, None]`): Locale to looked up in. Defaults to `"en"`.
* locales_root (`Union[str, Path]`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
* *args (`str`): Path to key like: `dict[args][key]`.
* 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")`.
### Returns:
* `Any`: Value of provided locale key. Is usually `str`, `dict` or `list`
* `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
@@ -93,19 +93,19 @@ async def _(
@asyncable
def in_all_locales(key: str, *args: str, locales_root: Union[str, Path] = Path("locale")) -> list:
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
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`.
* locales_root (`Union[str, Path]`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
* *args (`str`): Path to key like: `dict[args][key]`.
* locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
### Returns:
* `list`: List of values in all locales
* `List[Any]`: List of values in all locales
"""
output: List[str] = []
output: List[Any] = []
for locale in _get_valid_locales(locales_root):
try:
@@ -127,19 +127,19 @@ def in_all_locales(key: str, *args: str, locales_root: Union[str, Path] = Path("
@in_all_locales.asynchronous
async def in_all_locales(key: str, *args: str, locales_root: Union[str, Path] = Path("locale")) -> list:
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
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`.
* locales_root (`Union[str, Path]`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
* *args (`str`): Path to key like: `dict[args][key]`.
* locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
### Returns:
* `list`: List of values in all locales
* `List[Any]`: List of values in all locales
"""
output = []
output: List[Any] = []
for locale in _get_valid_locales(locales_root):
try:
@@ -162,17 +162,17 @@ async def in_all_locales(key: str, *args: str, locales_root: Union[str, Path] =
@asyncable
def in_every_locale(
key: str, *args: str, locales_root: Union[str, Path] = Path("locale")
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:
* key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`.
* locales_root (`Union[str, Path]`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
* *args (`str`): Path to key like: `dict[args][key]`.
* locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
### 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] = {}
@@ -198,17 +198,17 @@ def in_every_locale(
@in_every_locale.asynchronous
async def in_every_locale(
key: str, *args: str, locales_root: Union[str, Path] = Path("locale")
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:
* key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`.
* locales_root (`Union[str, Path]`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
* *args (`str`): Path to key like: `dict[args][key]`.
* locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
### 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] = {}

View File

@@ -1,6 +1,6 @@
from os import listdir
from pathlib import Path
from typing import Any, Dict, Union, List
from typing import Any, Dict, List
from ...utils.config import config_get
from ...utils.json import json_read
@@ -11,8 +11,8 @@ class BotLocale:
def __init__(
self,
default_locale: Union[str, None] = "en",
locales_root: Union[str, Path] = Path("locale"),
default_locale: str | None = "en",
locales_root: str | Path = Path("locale"),
) -> None:
if isinstance(locales_root, str):
locales_root = Path(locales_root)
@@ -29,16 +29,16 @@ class BotLocale:
for locale in valid_locales:
self.locales[locale] = json_read(Path(f"{locales_root}/{locale}.json"))
def _(self, key: str, *args: str, locale: Union[str, None] = None) -> Any:
def _(self, key: str, *args: str, locale: str | None = None) -> Any:
"""Get value of locale string
### Args:
* key (`str`): The last key of the locale's keys path
* *args (`list`): Path to key like: `dict[args][key]`
* locale (`Union[str, None]`, *optional*): Locale to looked up in. Defaults to config's `"locale"` value
* *args (`str`): Path to key like: `dict[args][key]`
* locale (`str | None`, *optional*): Locale to looked up in. Defaults to config's `"locale"` value
### Returns:
* `Any`: Value of provided locale key. Is usually `str`, `dict` or `list`
* `Any`: Value of provided locale key. Is usually `str`, `Dict[str, Any]` or `List[Any]`
"""
if locale is None:
locale: str = self.default
@@ -63,17 +63,17 @@ class BotLocale:
except KeyError:
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:
def in_all_locales(self, key: str, *args: str) -> List[Any]:
"""Get value of the provided key and path in all available locales
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`.
* *args (`str`): Path to key like: `dict[args][key]`.
### Returns:
* `list`: List of values in all locales
* `List[Any]`: List of values in all locales
"""
output: List[str] = []
output: List[Any] = []
for name, locale in self.locales.items():
try:
@@ -98,10 +98,10 @@ class BotLocale:
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`.
* *args (`str`): Path to key like: `dict[args][key]`.
### 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] = {}

View File

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

View File

@@ -1,6 +1,6 @@
import logging
from pathlib import Path
from typing import Any, Dict, Union
from typing import Any, Dict
from typing_extensions import override
@@ -26,10 +26,10 @@ class PycordBot(Bot):
def __init__(
self,
*args,
config: Union[Dict[str, Any], None] = None,
config_path: Union[str, Path] = Path("config.json"),
locales_root: Union[str, Path, None] = None,
scheduler: Union[AsyncIOScheduler, BackgroundScheduler, None] = None,
config: Dict[str, Any] | None = None,
config_path: str | Path = Path("config.json"),
locales_root: str | Path | None = None,
scheduler: AsyncIOScheduler | BackgroundScheduler | None = None,
**kwargs,
):
if config is None:
@@ -56,7 +56,7 @@ class PycordBot(Bot):
self.in_all_locales = self.bot_locale.in_all_locales
self.in_every_locale = self.bot_locale.in_every_locale
self.scheduler: Union[AsyncIOScheduler, BackgroundScheduler, None] = scheduler
self.scheduler: AsyncIOScheduler | BackgroundScheduler | None = scheduler
@override
async def start(self, token: str, reconnect: bool = True, scheduler_start: bool = True) -> None:

View File

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

View File

@@ -5,7 +5,7 @@ from datetime import datetime, timedelta
from os import cpu_count, getpid
from pathlib import Path
from time import time
from typing import Any, Dict, List, Union
from typing import Any, Dict, List
from typing_extensions import override
@@ -48,22 +48,22 @@ class PyroClient(Client):
def __init__(
self,
name: str = "bot_client",
owner: Union[int, None] = None,
config: Union[Dict[str, Any], None] = None,
config_path: Union[str, Path] = Path("config.json"),
api_id: Union[int, None] = None,
api_hash: Union[str, None] = None,
bot_token: Union[str, None] = None,
owner: int | None = None,
config: Dict[str, Any] | None = None,
config_path: str | Path = Path("config.json"),
api_id: int | None = None,
api_hash: str | None = None,
bot_token: str | None = None,
workers: int = min(32, cpu_count() + 4),
locales_root: Union[str, Path, None] = None,
locales_root: str | Path | None = None,
plugins_root: str = "plugins",
plugins_exclude: Union[List[str], None] = None,
plugins_exclude: List[str] | None = None,
sleep_threshold: int = 120,
max_concurrent_transmissions: int = 1,
commands_source: Union[Dict[str, dict], None] = None,
scoped_commands: Union[bool, None] = None,
commands_source: Dict[str, dict] | None = None,
scoped_commands: bool | None = None,
i18n_bot_info: bool = False,
scheduler: Union[AsyncIOScheduler, BackgroundScheduler, None] = None,
scheduler: AsyncIOScheduler | BackgroundScheduler | None = None,
**kwargs,
):
if config is None:
@@ -113,7 +113,7 @@ class PyroClient(Client):
self.in_all_locales = self.bot_locale.in_all_locales
self.in_every_locale = self.bot_locale.in_every_locale
self.scheduler: Union[AsyncIOScheduler, BackgroundScheduler, None] = scheduler
self.scheduler: AsyncIOScheduler | BackgroundScheduler | None = scheduler
self.scopes_placeholders: Dict[str, int] = {"owner": self.owner}
@@ -173,7 +173,7 @@ class PyroClient(Client):
)
logger.info(
"Bot's info for the locale %s has been updated",
self.code,
code,
)
except KeyError:
logger.warning(
@@ -238,7 +238,7 @@ class PyroClient(Client):
except SystemExit as exc:
raise SystemExit("Bot has been shut down, this is not an application error!") from exc
async def collect_commands(self) -> Union[List[CommandSet], None]:
async def collect_commands(self) -> List[CommandSet] | None:
"""Gather list of the bot's commands
### Returns:
@@ -309,7 +309,9 @@ class PyroClient(Client):
# This part here looks into the handlers and looks for commands
# in it, if there are any. Then adds them to self.commands
for handler in self.dispatcher.groups[0]:
if isinstance(handler, MessageHandler):
if isinstance(handler, MessageHandler) and (
hasattr(handler.filters, "base") or hasattr(handler.filters, "other")
):
for entry in [handler.filters.base, handler.filters.other]:
if hasattr(entry, "commands"):
for command in entry.commands:
@@ -338,7 +340,7 @@ class PyroClient(Client):
command,
)
async def register_commands(self, command_sets: Union[List[CommandSet], None] = None) -> None:
async def register_commands(self, command_sets: List[CommandSet] | None = None) -> None:
"""Register commands stored in bot's 'commands' attribute"""
if command_sets is None:
@@ -365,7 +367,7 @@ class PyroClient(Client):
language_code=command_set.language_code,
)
async def remove_commands(self, command_sets: Union[List[CommandSet], None] = None) -> None:
async def remove_commands(self, command_sets: List[CommandSet] | None = None) -> None:
"""Remove commands stored in bot's 'commands' attribute"""
if command_sets is None:

View File

@@ -1,5 +1,5 @@
from dataclasses import dataclass
from typing import List, Union
from typing import List
try:
from pyrogram.types import (
@@ -13,9 +13,7 @@ try:
BotCommandScopeDefault,
)
except ImportError as exc:
raise ImportError(
"You need to install libbot[pyrogram] in order to use this class."
) from exc
raise ImportError("You need to install libbot[pyrogram] in order to use this class.") from exc
@dataclass
@@ -23,13 +21,13 @@ class CommandSet:
"""Command stored in PyroClient's 'commands' attribute"""
commands: List[BotCommand]
scope: Union[
BotCommandScopeDefault,
BotCommandScopeAllPrivateChats,
BotCommandScopeAllGroupChats,
BotCommandScopeAllChatAdministrators,
BotCommandScopeChat,
BotCommandScopeChatAdministrators,
BotCommandScopeChatMember,
] = BotCommandScopeDefault
scope: (
BotCommandScopeDefault
| BotCommandScopeAllPrivateChats
| BotCommandScopeAllGroupChats
| BotCommandScopeAllChatAdministrators
| BotCommandScopeChat
| BotCommandScopeChatAdministrators
| BotCommandScopeChatMember
) = BotCommandScopeDefault
language_code: str = ""

View File

@@ -1,5 +1,5 @@
from pathlib import Path
from typing import Any, Union, Dict
from typing import Any, Dict
from ..json import json_read, json_write
from ..misc import nested_delete, nested_set
@@ -14,14 +14,14 @@ DEFAULT_CONFIG_LOCATION: str = "config.json"
@asyncable
def config_get(key: str, *path: str, config_file: Union[str, Path] = DEFAULT_CONFIG_LOCATION) -> Any:
def config_get(key: str, *path: str, config_file: str | Path = DEFAULT_CONFIG_LOCATION) -> Any:
"""Get a value of the config key by its path provided
For example, `foo.bar.key` has a path of `"foo", "bar"` and the key `"key"`
### Args:
* key (`str`): Key that contains the value
* *path (`str`): Path to the key that contains the value
* config_file (`Union[str, Path]`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
* config_file (`str | Path`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Returns:
* `Any`: Key's value
@@ -53,14 +53,14 @@ def config_get(key: str, *path: str, config_file: Union[str, Path] = DEFAULT_CON
@config_get.asynchronous
async def config_get(key: str, *path: str, config_file: Union[str, Path] = DEFAULT_CONFIG_LOCATION) -> Any:
async def config_get(key: str, *path: str, config_file: str | Path = DEFAULT_CONFIG_LOCATION) -> Any:
"""Get a value of the config key by its path provided
For example, `foo.bar.key` has a path of `"foo", "bar"` and the key `"key"`
### Args:
* key (`str`): Key that contains the value
* *path (`str`): Path to the key that contains the value
* config_file (`Union[str, Path]`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
* config_file (`str | Path`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Returns:
* `Any`: Key's value
@@ -92,16 +92,14 @@ async def config_get(key: str, *path: str, config_file: Union[str, Path] = DEFAU
@asyncable
def config_set(
key: str, value: Any, *path: str, config_file: Union[str, Path] = DEFAULT_CONFIG_LOCATION
) -> None:
def config_set(key: str, value: Any, *path: str, config_file: str | Path = DEFAULT_CONFIG_LOCATION) -> None:
"""Set config's key by its path to the value
### Args:
* key (`str`): Key that leads to the value
* value (`Any`): Any JSON serializable data
* *path (`str`): Path to the key of the target
* config_file (`Union[str, Path]`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
* config_file (`str | Path`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Raises:
* `KeyError`: Key is not found under path provided
@@ -111,7 +109,7 @@ def config_set(
@config_set.asynchronous
async def config_set(
key: str, value: Any, *path: str, config_file: Union[str, Path] = DEFAULT_CONFIG_LOCATION
key: str, value: Any, *path: str, config_file: str | Path = DEFAULT_CONFIG_LOCATION
) -> None:
"""Set config's key by its path to the value
@@ -119,7 +117,7 @@ async def config_set(
* key (`str`): Key that leads to the value
* value (`Any`): Any JSON serializable data
* *path (`str`): Path to the key of the target
* config_file (`Union[str, Path]`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
* config_file (`str | Path`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Raises:
* `KeyError`: Key is not found under path provided
@@ -132,7 +130,7 @@ def config_delete(
key: str,
*path: str,
missing_ok: bool = False,
config_file: Union[str, Path] = DEFAULT_CONFIG_LOCATION,
config_file: str | Path = DEFAULT_CONFIG_LOCATION,
) -> None:
"""Set config's key by its path
@@ -140,7 +138,7 @@ def config_delete(
* key (`str`): Key to delete
* *path (`str`): Path to the key of the target
* missing_ok (`bool`): Do not raise an exception if the key is missing. Defaults to `False`
* config_file (`Union[str, Path]`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
* config_file (`str | Path`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Raises:
* `KeyError`: Key is not found under path provided and `missing_ok` is `False`
@@ -161,7 +159,7 @@ async def config_delete(
key: str,
*path: str,
missing_ok: bool = False,
config_file: Union[str, Path] = DEFAULT_CONFIG_LOCATION,
config_file: str | Path = DEFAULT_CONFIG_LOCATION,
) -> None:
"""Set config's key by its path
@@ -169,7 +167,7 @@ async def config_delete(
* key (`str`): Key to delete
* *path (`str`): Path to the key of the target
* missing_ok (`bool`): Do not raise an exception if the key is missing. Defaults to `False`
* config_file (`Union[str, Path]`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
* config_file (`str | Path`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Raises:
* `KeyError`: Key is not found under path provided and `missing_ok` is `False`

View File

@@ -1,5 +1,5 @@
from pathlib import Path
from typing import Any, Union
from typing import Any
import aiofiles
@@ -13,11 +13,11 @@ except ImportError:
@asyncable
def json_read(path: Union[str, Path]) -> Any:
def json_read(path: str | Path) -> Any:
"""Read contents of a JSON file
### Args:
* path (`Union[str, Path]`): Path-like object or path as a string
* path (`str | Path`): Path-like object or path as a string
### Returns:
* `Any`: File contents
@@ -29,11 +29,11 @@ def json_read(path: Union[str, Path]) -> Any:
@json_read.asynchronous
async def json_read(path: Union[str, Path]) -> Any:
async def json_read(path: str | Path) -> Any:
"""Read contents of a JSON file
### Args:
* path (`Union[str, Path]`): Path-like object or path as a string
* path (`str | Path`): Path-like object or path as a string
### Returns:
* `Any`: File contents
@@ -45,12 +45,12 @@ async def json_read(path: Union[str, Path]) -> Any:
@asyncable
def json_write(data: Any, path: Union[str, Path]) -> None:
def json_write(data: Any, path: str | Path) -> None:
"""Write contents to a JSON file
### Args:
* data (`Any`): Contents to write. Must be a JSON serializable
* path (`Union[str, Path]`): Path-like object or path as a string of a destination
* path (`str | Path`): Path-like object or path as a string of a destination
"""
with open(str(path), mode="w", encoding="utf-8") as f:
f.write(
@@ -61,12 +61,12 @@ def json_write(data: Any, path: Union[str, Path]) -> None:
@json_write.asynchronous
async def json_write(data: Any, path: Union[str, Path]) -> None:
async def json_write(data: Any, path: str | Path) -> None:
"""Write contents to a JSON file
### Args:
* data (`Any`): Contents to write. Must be a JSON serializable
* path (`Union[str, Path]`): Path-like object or path as a string of a destination
* path (`str | Path`): Path-like object or path as a string of a destination
"""
async with aiofiles.open(str(path), mode="w", encoding="utf-8") as f:
await f.write(

View File

@@ -1,8 +1,6 @@
from pathlib import Path
from typing import Any, List, Union
from typing import Any, List
import pytest
from libbot.i18n import BotLocale
@@ -20,14 +18,12 @@ from libbot.i18n import BotLocale
def test_bot_locale_get(
key: str,
args: List[str],
locale: Union[str, None],
locale: str | None,
expected: Any,
bot_locale: BotLocale,
):
assert (
bot_locale._(key, *args, locale=locale)
if locale is not None
else bot_locale._(key, *args)
bot_locale._(key, *args, locale=locale) if locale is not None else bot_locale._(key, *args)
) == expected
@@ -39,9 +35,7 @@ def test_bot_locale_get(
("nested", ["callbacks", "default"], ["sure", "авжеж"]),
],
)
def test_i18n_in_all_locales(
key: str, args: List[str], expected: Any, bot_locale: BotLocale
):
def test_i18n_in_all_locales(key: str, args: List[str], expected: Any, bot_locale: BotLocale):
assert (bot_locale.in_all_locales(key, *args)) == expected
@@ -53,7 +47,5 @@ def test_i18n_in_all_locales(
("nested", ["callbacks", "default"], {"en": "sure", "uk": "авжеж"}),
],
)
def test_i18n_in_every_locale(
key: str, args: List[str], expected: Any, bot_locale: BotLocale
):
def test_i18n_in_every_locale(key: str, args: List[str], expected: Any, bot_locale: BotLocale):
assert (bot_locale.in_every_locale(key, *args)) == expected

View File

@@ -1,8 +1,7 @@
from pathlib import Path
from typing import Any, List, Union
from typing import Any, List
import pytest
from libbot import i18n
@@ -21,7 +20,7 @@ from libbot import i18n
async def test_i18n_get(
key: str,
args: List[str],
locale: Union[str, None],
locale: str | None,
expected: Any,
location_locale: Path,
):
@@ -41,12 +40,8 @@ async def test_i18n_get(
("nested", ["callbacks", "default"], ["sure", "авжеж"]),
],
)
async def test_i18n_in_all_locales(
key: str, args: List[str], expected: Any, location_locale: Path
):
assert (
await i18n.in_all_locales(key, *args, locales_root=location_locale)
) == expected
async def test_i18n_in_all_locales(key: str, args: List[str], expected: Any, location_locale: Path):
assert (await i18n.in_all_locales(key, *args, locales_root=location_locale)) == expected
@pytest.mark.asyncio
@@ -58,9 +53,5 @@ async def test_i18n_in_all_locales(
("nested", ["callbacks", "default"], {"en": "sure", "uk": "авжеж"}),
],
)
async def test_i18n_in_every_locale(
key: str, args: List[str], expected: Any, location_locale: Path
):
assert (
await i18n.in_every_locale(key, *args, locales_root=location_locale)
) == expected
async def test_i18n_in_every_locale(key: str, args: List[str], expected: Any, location_locale: Path):
assert (await i18n.in_every_locale(key, *args, locales_root=location_locale)) == expected

View File

@@ -1,5 +1,5 @@
from pathlib import Path
from typing import Any, List, Union
from typing import Any, List
import pytest
from libbot.i18n import _, in_all_locales, in_every_locale
@@ -19,7 +19,7 @@ from libbot.i18n import _, in_all_locales, in_every_locale
def test_i18n_get(
key: str,
args: List[str],
locale: Union[str, None],
locale: str | None,
expected: Any,
location_locale: Path,
):

View File

@@ -4,7 +4,7 @@ except ImportError:
from json import dumps, JSONDecodeError
from pathlib import Path
from typing import Any, Union
from typing import Any
import pytest
from libbot.utils import json_read, json_write
@@ -24,7 +24,7 @@ from libbot.utils import json_read, json_write
("tests/data/empty.json", {}),
],
)
async def test_json_read_valid(path: Union[str, Path], expected: Any):
async def test_json_read_valid(path: str | Path, expected: Any):
assert await json_read(path) == expected
@@ -36,7 +36,7 @@ async def test_json_read_valid(path: Union[str, Path], expected: Any):
("tests/data/nonexistent.json", FileNotFoundError),
],
)
async def test_json_read_invalid(path: Union[str, Path], expected: Any):
async def test_json_read_invalid(path: str | Path, expected: Any):
with pytest.raises(expected):
await json_read(path)
@@ -55,7 +55,7 @@ async def test_json_read_invalid(path: Union[str, Path], expected: Any):
({}, "tests/data/empty.json"),
],
)
async def test_json_write(data: Any, path: Union[str, Path]):
async def test_json_write(data: Any, path: str | Path):
await json_write(data, path)
assert Path(path).is_file()

View File

@@ -4,7 +4,7 @@ except ImportError:
from json import dumps, JSONDecodeError
from pathlib import Path
from typing import Any, Union
from typing import Any
import pytest
from libbot.utils import json_read, json_write
@@ -23,7 +23,7 @@ from libbot.utils import json_read, json_write
("tests/data/empty.json", {}),
],
)
def test_json_read_valid(path: Union[str, Path], expected: Any):
def test_json_read_valid(path: str | Path, expected: Any):
assert json_read(path) == expected
@@ -34,7 +34,7 @@ def test_json_read_valid(path: Union[str, Path], expected: Any):
("tests/data/nonexistent.json", FileNotFoundError),
],
)
def test_json_read_invalid(path: Union[str, Path], expected: Any):
def test_json_read_invalid(path: str | Path, expected: Any):
with pytest.raises(expected):
assert json_read(path) == expected
@@ -52,7 +52,7 @@ def test_json_read_invalid(path: Union[str, Path], expected: Any):
({}, "tests/data/empty.json"),
],
)
def test_json_write(data: Any, path: Union[str, Path]):
def test_json_write(data: Any, path: str | Path):
json_write(data, path)
assert Path(path).is_file()