Compare commits

..

No commits in common. "main" and "v4.0.0" have entirely different histories.
main ... v4.0.0

13 changed files with 72 additions and 204 deletions

View File

@ -1,90 +0,0 @@
name: Upload Python Package
on:
release:
types: [ published ]
permissions:
contents: read
jobs:
release-build:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Build release distributions
run: |
python -m pip install build
python -m build
- name: Upload distributions
uses: christopherhx/gitea-upload-artifact@v4
with:
name: release-dists
path: dist/
gitea-publish:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
needs:
- release-build
permissions:
id-token: write
environment:
name: gitea
url: https://git.end-play.xyz/profitroll/-/packages/pypi/libbot
env:
GITHUB_WORKFLOW_REF: ${{ gitea.workflow_ref }}
INPUT_REPOSITORY_URL: https://git.end-play.xyz/api/packages/profitroll/pypi
steps:
- name: Retrieve release distributions
uses: christopherhx/gitea-download-artifact@v4
with:
name: release-dists
path: dist/
- name: Publish package distributions to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_GITEA_API_TOKEN }}
repository-url: https://git.end-play.xyz/api/packages/profitroll/pypi
pypi-publish:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
needs:
- release-build
permissions:
id-token: write
environment:
name: pypi
env:
GITHUB_WORKFLOW_REF: ${{ gitea.workflow_ref }}
steps:
- name: Retrieve release distributions
uses: christopherhx/gitea-download-artifact@v4
with:
name: release-dists
path: dist/
- name: Publish package distributions to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_PYPI_API_TOKEN }}

View File

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

View File

@ -36,20 +36,19 @@ pip install libbot[pycord,speed]
### Pyrogram
```python
import sys
from libbot.pyrogram.classes import PyroClient
from libbot.pyrogram import PyroClient
def main():
client: PyroClient = PyroClient()
client = PyroClient(scheduler=scheduler)
try:
client.run()
except KeyboardInterrupt:
print("Shutting down...")
finally:
sys.exit()
if client.scheduler is not None:
client.scheduler.shutdown()
exit()
if __name__ == "__main__":
@ -59,33 +58,29 @@ if __name__ == "__main__":
### Pycord
```python
import asyncio
from asyncio import AbstractEventLoop
from discord import Intents
from libbot.utils import config_get
from libbot.pycord.classes import PycordBot
from libbot import sync
from libbot.pycord import PycordBot
async def main():
intents: Intents = Intents.default()
bot: PycordBot = PycordBot(intents=intents)
intents = Intents.default()
bot = PycordBot(intents=intents)
bot.load_extension("cogs")
try:
await bot.start(config_get("bot_token", "bot"))
await bot.start(sync.config_get("bot_token", "bot"))
except KeyboardInterrupt:
print("Shutting down...")
logger.warning("Shutting down...")
await bot.close()
if __name__ == "__main__":
loop: AbstractEventLoop = asyncio.get_event_loop()
loop = asyncio.get_event_loop()
loop.run_until_complete(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,4 +0,0 @@
# Examples
If you're looking for Pyrogram usage examples, please take a look at
the [PyrogramBotBase](https://git.end-play.xyz/profitroll/PyrogramBotBase) repository.

View File

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

View File

@ -1,12 +1,11 @@
black==24.10.0
build==1.2.2.post1
isort==5.13.2
mypy==1.14.1
mypy==1.14.0
pylint==3.3.3
pytest-asyncio==0.25.1
pytest-asyncio==0.25.0
pytest-cov==6.0.0
pytest==8.3.4
tox==4.23.2
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.2"
__version__ = "4.0.0"
__license__ = "GPL3"
__author__ = "Profitroll"

View File

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

View File

@ -1,13 +1,9 @@
import logging
from logging import Logger
from pathlib import Path
from typing import Any, Dict
from typing_extensions import override
from ...i18n.classes import BotLocale
from ...utils import json_read
try:
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.schedulers.background import BackgroundScheduler
@ -15,21 +11,32 @@ try:
except ImportError as 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):
@override
def __init__(
self,
*args,
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,
self,
*args,
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,
):
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__(
debug_guilds=(self.config["bot"]["debug_guilds"] if self.config["debug"] else None),

View File

@ -1 +0,0 @@
from .color import color_from_hex, hex_from_color

View File

@ -1,35 +0,0 @@
from discord import Colour
def _int_from_hex(hex_string: str) -> int:
try:
return int(hex_string, base=16)
except Exception as exc:
raise ValueError("Input string must be a valid HEX code.") from exc
def _hex_from_int(color_int: int) -> str:
if not 0 <= color_int <= 0xFFFFFF:
raise ValueError("Color's value must be in the range 0 to 0xFFFFFF.")
return f"#{color_int:06x}"
def color_from_hex(hex_string: str) -> Colour:
"""Convert valid hexadecimal string to discord.Colour.
:param hex_string: Hexadecimal string to convert into Colour object
:type hex_string: str
:return: Colour object
"""
return Colour(_int_from_hex(hex_string))
def hex_from_color(color: Colour) -> str:
"""Convert discord.Colour to hexadecimal string.
:param color: Colour object to convert into the string
:type color: Colour
:return: Hexadecimal string in #XXXXXX format
"""
return _hex_from_int(color.value)

View File

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

View File

@ -2,7 +2,6 @@ import asyncio
import logging
import sys
from datetime import datetime, timedelta
from logging import Logger
from os import cpu_count, getpid
from pathlib import Path
from time import time
@ -10,12 +9,6 @@ from typing import Any, Dict, List
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:
import pyrogram
from apscheduler.schedulers.asyncio import AsyncIOScheduler
@ -42,33 +35,42 @@ try:
except ImportError:
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):
@override
def __init__(
self,
name: str = "bot_client",
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: str | Path | None = None,
plugins_root: str = "plugins",
plugins_exclude: List[str] | None = None,
sleep_threshold: int = 120,
max_concurrent_transmissions: int = 1,
commands_source: Dict[str, dict] | None = None,
scoped_commands: bool | None = None,
i18n_bot_info: bool = False,
scheduler: AsyncIOScheduler | BackgroundScheduler | None = None,
**kwargs,
self,
name: str = "bot_client",
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: str | Path | None = None,
plugins_root: str = "plugins",
plugins_exclude: List[str] | None = None,
sleep_threshold: int = 120,
max_concurrent_transmissions: int = 1,
commands_source: Dict[str, dict] | None = None,
scoped_commands: bool | None = None,
i18n_bot_info: bool = False,
scheduler: AsyncIOScheduler | BackgroundScheduler | None = None,
**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__(
name=name,
@ -209,7 +211,7 @@ class PyroClient(Client):
@override
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:
try:
await self.send_message(
@ -308,7 +310,7 @@ class PyroClient(Client):
# in it, if there are any. Then adds them to self.commands
for handler in self.dispatcher.groups[0]:
if isinstance(handler, MessageHandler) and (
hasattr(handler.filters, "base") or hasattr(handler.filters, "other")
hasattr(handler.filters, "base") or hasattr(handler.filters, "other")
):
for entry in [handler.filters.base, handler.filters.other]:
if hasattr(entry, "commands"):
@ -319,8 +321,8 @@ class PyroClient(Client):
return command_sets
def add_command(
self,
command: str,
self,
command: str,
) -> None:
"""Add command to the bot's internal commands list