Skip to content

Commit

Permalink
Merge pull request #117 from PaulMarisOUMary/refactor
Browse files Browse the repository at this point in the history
Fix type hinting warnings
  • Loading branch information
PaulMarisOUMary committed Jun 10, 2023
2 parents 2bd48e7 + 0466774 commit a7daf76
Show file tree
Hide file tree
Showing 36 changed files with 380 additions and 333 deletions.
76 changes: 46 additions & 30 deletions .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,54 @@
- [Database](#database)
- [SQL tables structure](#sql-tables-structure)
- [Workflows](#workflows)

## About the project

This discord bot was made for an IT School in 2020. It has a lot of features including all the latest features from discord.py. Made by student(s) for students.

<a name="major-features"/>

> **Note**: Major features
> - [ContextMenus](https://discordpy.readthedocs.io/en/latest/interactions/api.html#discord.app_commands.ContextMenu) (Right-click commands)
> - [AppCommands](https://discordpy.readthedocs.io/en/latest/interactions/api.html#discord.app_commands.AppCommand) (Slash-commands)
> - [HybridCommands](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HybridCommand) (Slash-commands + Commands)
> - [Groups](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Group)
> - [Commands](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Group)
> - [Custom-Modals](https://discordpy.readthedocs.io/en/latest/interactions/api.html#discord.ui.Modal) (Forms)
> - [Custom-Views](https://discordpy.readthedocs.io/en/latest/interactions/api.html?#discord.ui.View) (Buttons, Dropdown, ..)
> - [Cogs](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Cog)/[GroupCogs](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html?highlight=cogs#discord.ext.commands.GroupCog)
> - Custom prefix per guild
> - Dynamic structure (Does not require a reboot to apply changes in files)
> - Database support (SQL)
> - Error handling
> - Logging
> - Multiple configs
> - Powerful, dev & debuging commands
> - Metrics about usage of the bot
> - Language detector & Translation
> - And more..
### Major features

- Administrative Tools
- Custom prefix per guild
- Invite tracker
- Developement
- ANSI color support
- Dynamic structure (Does not require a reboot to apply changes in code & files)
- Database support (SQL)
- Error handling
- Image processing
- Logging
- Multiple configs
- Metrics about usage of the bot
- Powerful, dev & debuging commands
- Utility functions
- Socket communication system
- Discord support
- [AppCommands](https://discordpy.readthedocs.io/en/latest/interactions/api.html#discord.app_commands.AppCommand) (Slash-commands)
- [Cogs](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Cog)/[GroupCogs](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html?highlight=cogs#discord.ext.commands.GroupCog)
- [Commands](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Group)
- [ContextMenus](https://discordpy.readthedocs.io/en/latest/interactions/api.html#discord.app_commands.ContextMenu) (Right-click commands)
- [Custom-Modals](https://discordpy.readthedocs.io/en/latest/interactions/api.html#discord.ui.Modal) (Forms)
- [Custom-Views](https://discordpy.readthedocs.io/en/latest/interactions/api.html?#discord.ui.View) (Buttons, Dropdown, ..)
- [Groups](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Group)
- [HybridCommands](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HybridCommand) (Slash-commands + Commands)
- User Interaction
- Custom Help command
- Dynamic Starboard
- Language detector & Translation
- Private text channel on demand (cog: privatetext)
- Private vocal channel on demand (cog: privatevocal)
- And more..

### Built with

- [Python](https://python.org/) >= 3.8
- [discord.py](https://discordpy.readthedocs.io) >= 2.1.0
- [Python 3](https://python.org/) >= 3.8
- [discord.py](https://discordpy.readthedocs.io/en/stable/) == stable
- SQL
- MariaDB (or MySQL)

> **Note** More about requirements in the [requirements.txt](https://github.com/PaulMarisOUMary/Discord-Bot/blob/main/requirements.txt) file.
## Getting started

### Python Prerequisites
Expand Down Expand Up @@ -95,11 +110,11 @@ $ pip install -r requirements.txt
> 1. set the `"use_database"` field to `false` in the `/config/database.json` file.
> 2. in the folder `/cogs` you should remove the following files (which are using the database): `birthday.py`, `croissants.py`, `invite.py`, `me.py`, `metrics.py`, `starboard.py`.
> **Note** If you have planned to use a database:
> - you should use a SQL Database.
> - reconfigure the "server" section from `/config/database.json`.
> - you can change the structure of each SQL tables if needed.
> - if so you should reconfigure some keys/values of the `/config/cogs.json`.
If you have planned to use a database:
- you should use a SQL Database.
- reconfigure the "server" section from `/config/database.json`.
- you can change the structure of each SQL tables if needed.
- if so you should reconfigure some keys/values of the `/config/cogs.json`.

### SQL tables structure

Expand All @@ -109,9 +124,10 @@ $ pip install -r requirements.txt
```sql
CREATE TABLE IF NOT EXISTS `table_birthday`
(
`guild_id` BIGINT unsigned NOT NULL,
`user_id` BIGINT unsigned NOT NULL,
`user_birth` DATE NOT NULL,
UNIQUE(`user_id`)
CONSTRAINT `me_per_guild` UNIQUE (`guild_id`, `user_id`)
)
ENGINE = InnoDB,
CHARACTER SET utf8mb4,
Expand Down Expand Up @@ -241,4 +257,4 @@ WantedBy=multi-user.target

<img height="25px" src="https://contrib.rocks/image?repo=PaulMarisOUMary/Discord-Bot" />

</a>
</a>
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ cython_debug/
.vscode/

# Project
# Untrack tracked config files: git update-index --assume-unchanged ./config/*.json
config

# MacOS (should be included in your local .gitignore)
Expand Down
23 changes: 18 additions & 5 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from os import listdir

class Bot(DiscordBot):
def __init__(self, **kwargs):
def __init__(self, **kwargs) -> None:
super().__init__(
activity = discord.Game(name = "Booting.."),
allowed_mentions=discord.AllowedMentions(everyone=False),
Expand All @@ -19,15 +19,15 @@ def __init__(self, **kwargs):
**kwargs,
)

async def startup(self):
async def startup(self) -> None:
"""Sync application commands"""
await self.wait_until_ready()

# Sync application commands
synced = await self.tree.sync()
self.log(message = f"Application commands synced ({len(synced)})", name = "discord.startup")

async def setup_hook(self):
async def setup_hook(self) -> None:
"""Initialize the bot, database, prefixes & cogs."""
await super().setup_hook()

Expand All @@ -42,8 +42,21 @@ async def setup_hook(self):
if __name__ == '__main__':
clean_close() # Avoid Windows EventLoopPolicy Error

bot = Bot()
bot.logger, streamHandler = set_logging(file_level=logging.INFO, console_level=logging.INFO, filename="discord.log")
bot = Bot(
intents = discord.Intents(
emojis = True,
guild_scheduled_events = True,
guilds = True,
invites = True,
members = True,
message_content = True,
messages = True,
presences = True,
reactions = True,
voice_states = True,
),
)
bot.logger, streamHandler = set_logging(file_level = logging.INFO, console_level = logging.INFO, filename = "discord.log")
bot.run(
bot.config["bot"]["token"],
reconnect = True,
Expand Down
4 changes: 2 additions & 2 deletions classes/ansi.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ def _to_color(*colors_code: str) -> str:
return f"{ESCAPE}[{';'.join(colors_code)}m"

class StackANSI():
def __init__(self, num: int):
self.series = [num]
def __init__(self, num: int) -> None:
self.series: list[int] = [num]

def __add__(self, __x: 'SingleANSI') -> 'StackANSI':
self.series.append(__x.value)
Expand Down
10 changes: 5 additions & 5 deletions classes/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@
import argparse

class ClientProtocol(asyncio.Protocol):
def __init__(self, message, on_con_lost):
def __init__(self, message, on_con_lost) -> None:
self.message = message
self.on_con_lost = on_con_lost

def connection_made(self, transport: asyncio.Transport):
def connection_made(self, transport: asyncio.Transport) -> None:
transport.write(self.message.encode())

def data_received(self, data: bytes):
def data_received(self, data: bytes) -> None:
if not data == bytes(self.message, encoding="utf-8"):
raise ValueError("Data received seems corruped.")

def connection_lost(self, exc):
def connection_lost(self, exc) -> None:
self.on_con_lost.set_result(True)

async def main(args):
async def main(args: argparse.Namespace) -> None:
loop = asyncio.get_running_loop()

on_con_lost = loop.create_future()
Expand Down
10 changes: 5 additions & 5 deletions classes/discordbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class DiscordBot(commands.Bot):
usedatabase: bool = True
"""Whether the bot should use the database or not."""

def __init__(self,**kwargs):
def __init__(self,**kwargs) -> None:
"""Initialize the bot.
Parameters
Expand All @@ -56,7 +56,7 @@ def __init__(self,**kwargs):

super().__init__(command_prefix = command_prefix, **kwargs)

def log(self, message: str, name: str, level: int = LOG_INFO, **kwargs):
def log(self, message: str, name: str, level: int = LOG_INFO, **kwargs) -> None:
"""Log a message to the console and the log file.
Parameters
Expand All @@ -81,10 +81,10 @@ def __prefix_callable(self, client: Self, message: Message) -> List[str]:
prefix = self.config["bot"]["default_prefix"]
return commands.when_mentioned_or(prefix)(client, message)

async def on_ready(self):
async def on_ready(self) -> None:
self.log( message = f"Logged as: {self.user} | discord.py{discord_version} Guilds: {len(self.guilds)} Users: {len(self.users)} Config: {len(self.config)} Database: {self.usedatabase}", name = "discord.on_ready")

async def setup_hook(self):
async def setup_hook(self) -> None:
# Retrieve the bot's application info
self.appinfo = await self.application_info()

Expand All @@ -99,7 +99,7 @@ async def setup_hook(self):
for data in await self.database.select(self.config["bot"]["prefix_table"]["table"], "*"):
self.prefixes[data[0]] = data[1]

async def close(self):
async def close(self) -> None:
if self.usedatabase:
await self.database.close()
self.log(message = "Database connection closed", name = "discord.close")
Expand Down
21 changes: 17 additions & 4 deletions classes/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from os.path import dirname, abspath, join, basename, splitext
from sys import modules
from types import ModuleType
from typing import Union
from typing import Generator, NoReturn, Union

from classes.discordbot import DiscordBot

Expand Down Expand Up @@ -47,7 +47,7 @@ async def cogs_manager(bot: DiscordBot, mode: str, cogs: list[str]) -> None:
except Exception as e:
raise e

def reload_views():
def reload_views() -> Generator[str, None, None]:
mods = [module[1] for module in modules.items() if isinstance(module[1], ModuleType)]
for mod in mods:
try:
Expand Down Expand Up @@ -80,7 +80,13 @@ def set_logging(file_level: int = logging.DEBUG, console_level: int = logging.IN

def clean_close() -> None:
if platform.system().lower() == 'windows':
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # type: ignore (Windows only)

async def dummy_awaitable_callable(*args, **kwargs) -> NoReturn:
raise NotImplementedError("This function is a dummy function and is not meant to be called.")

def dummy_callable(*args, **kwargs) -> NoReturn:
raise NotImplementedError("This function is a dummy function and is not meant to be called.")

def bot_has_permissions(**perms: bool):
"""A decorator that add specified permissions to Command.extras and add bot_has_permissions check to Command with specified permissions.
Expand Down Expand Up @@ -108,4 +114,11 @@ def wrapped(command: Union[app_commands.Command, commands.HybridCommand, command

return command

return wrapped
return wrapped

class GuildContext(commands.Context):
author: discord.Member
guild: discord.Guild
channel: Union[discord.VoiceChannel, discord.TextChannel, discord.Thread]
me: discord.Member
prefix: str
Loading

0 comments on commit a7daf76

Please sign in to comment.