4 Commits
9 changed files with 133 additions and 66 deletions
+7
View File
@@ -0,0 +1,7 @@
{
"python.analysis.diagnosticSeverityOverrides": {
"reportOptionalMemberAccess": "warning",
"reportArgumentType": "information",
"reportAttributeAccessIssue": "warning"
}
}
+6 -3
View File
@@ -1,4 +1,7 @@
FROM python:3.11.9-slim FROM python:3.12.3-slim
# install uv
COPY --from=ghcr.io/astral-sh/uv:0.6.5 /uv /uvx /bin/
WORKDIR /home WORKDIR /home
@@ -8,6 +11,6 @@ COPY pyproject.toml pyproject.toml
COPY cogs cogs/ COPY cogs cogs/
RUN pip install --upgrade pip && pip install poetry && poetry export -f requirements.txt --output requirements.txt && pip install -r requirements.txt RUN uv sync --frozen --no-dev
CMD ["python3", "-u", "./main.py"] CMD ["uv", "run", "./main.py"]
+3 -7
View File
@@ -1,6 +1,4 @@
""" """Cog loader. Adds all command cogs to the bot."""
Cog loader. Adds all command cogs to the bot.
"""
from nextcord.ext import commands from nextcord.ext import commands
@@ -9,8 +7,6 @@ from cogs.commands.hi import HiCog
# This function will be called when this extension is loaded. # This function will be called when this extension is loaded.
# It is necessary to add these functions to the bot. # It is necessary to add these functions to the bot.
def setup(bot: commands.Bot): def setup(bot: commands.Bot) -> None:
""" """Add all command classes to bot."""
Adds all command classes to bot.
"""
bot.add_cog(HiCog(bot)) bot.add_cog(HiCog(bot))
+6 -13
View File
@@ -1,29 +1,22 @@
""" """Example command file."""
Example command file.
"""
import nextcord import nextcord
from nextcord.ext import commands from nextcord.ext import commands
class HiCog(commands.Cog, name="Test commands."): class HiCog(commands.Cog, name="Test commands."):
""" """Class holds commands for testing."""
Class holds commands for testing.
"""
def __init__(self, bot) -> None: def __init__(self, bot: nextcord.Bot) -> None:
"""
Default constructor for HelpCog class. Does nothing.
"""
self.bot = bot self.bot = bot
@nextcord.slash_command() @nextcord.slash_command()
async def hi(self, interaction: nextcord.Interaction): async def hi(self, interaction: nextcord.Interaction) -> None:
""" """
Says hi Says hi.
Args: Args:
interaction (nextcord.Interaction): Interaction to reply to. interaction (nextcord.Interaction): Interaction to reply to.
"""
"""
await interaction.response.send_message("Hi!", ephemeral=True) await interaction.response.send_message("Hi!", ephemeral=True)
+21 -28
View File
@@ -1,65 +1,58 @@
"""Main file for bot."""
import logging import logging
import os import os
import sys
import hydra
import nextcord import nextcord
from hydra.core.config_store import ConfigStore
from nextcord.ext import commands from nextcord.ext import commands
from config import BotConfig from settings import settings
cs = ConfigStore.instance() nextcord_logger = logging.getLogger("nextcord")
cs.store(name="${REPO_NAME}_config", node=BotConfig) nextcord_logger.setLevel(logging.DEBUG)
nextcord_handler = logging.FileHandler(filename="nextcord.log", encoding="utf-8", mode="w")
logger = logging.getLogger("nextcord") nextcord_handler.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(name)s: %(message)s"))
logger.setLevel(logging.DEBUG) nextcord_logger.addHandler(nextcord_handler)
handler = logging.FileHandler(filename="nextcord.log", encoding="utf-8", mode="w")
handler.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(name)s: %(message)s"))
logger.addHandler(handler)
@hydra.main(config_path="conf", config_name="config") def main() -> None:
def main(cfg: BotConfig):
""" """
Main function for the bot. Sets config, intents, then connects the bot to discord. Set config, intents, then connects the bot to discord.
Args: Args:
cfg (BotConfig): The local configs to use. cfg (BotConfig): The local configs to use.
"""
# Allows privledged intents for monitoring members joining, roles editing, and role assignments """
# Allows privileged intents for monitoring members joining, roles editing, and role assignments
# These need to be enabled in the developer portal as well # These need to be enabled in the developer portal as well
intents = nextcord.Intents.default() intents = nextcord.Intents.default()
# Required in order to read messages (eg. prefix commands) # Required in order to read messages (eg. prefix commands)
intents.message_content = True intents.message_content = True
# To enable the guilds priveleged intent: # To enable the guilds privileged intent:
# intents.guilds = True # intents.guilds = True
# To enable the members priveleged intent: # To enable the members privileged intent:
# intents.members = True # intents.members = True
bot = commands.Bot(intents=intents) bot = commands.Bot(intents=intents)
bot.config = cfg
# Get the modules of all cogs whose directory structure is ./cogs/<module_name> # Get the modules of all cogs whose directory structure is ./cogs/<module_name>
for folder in os.listdir("cogs"): for folder in os.listdir("cogs"):
bot.load_extension(f"cogs.{folder}") bot.load_extension(f"cogs.{folder}")
@bot.listen() @bot.listen()
async def on_ready(): async def on_ready() -> None:
"""When Discord is connected""" """When Discord is connected."""
assert bot.user is not None if bot.user is None:
print("Discord connection failed.")
return
print(f"{bot.user.name} has connected to Discord!") print(f"{bot.user.name} has connected to Discord!")
# Run Discord bot # Run Discord bot
bot.run(bot.config.params.discord_token) bot.run(settings.params.discord_token)
if __name__ == "__main__": if __name__ == "__main__":
sys.argv.append("hydra.job.chdir=False") main()
sys.argv.append("hydra/job_logging=none")
sys.argv.append("hydra/hydra_logging=none")
main() # pylint: disable=no-value-for-parameter
+33 -13
View File
@@ -1,21 +1,21 @@
[tool.poetry] [project]
name = "${REPO_NAME}" name = "${REPO_NAME}"
version = "0.1.0" version = "0.1.0"
description = "" description = ""
authors = ["${REPO_OWNER}"] authors = [{name="${REPO_OWNER}", email=""}]
readme = "README.md" readme = "README.md"
dependencies = [
"nextcord>=2.6.0",
"python-dotenv>=1.0.1",
"sqlmodel>=0.0.22",
"dataclass-wizard[yaml]>=0.22.3,<1.0.0",
]
requires-python = ">=3.12"
[tool.poetry.dependencies] [tool.uv]
python = "^3.11" dev-dependencies = ["ruff>=0.7.2"]
hydra-core = "1.3.2"
nextcord = "2.6.1"
python-dotenv = "1.0.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.ruff] [tool.ruff]
# Exclude a variety of commonly ignored directories. # Exclude a variety of commonly ignored directories.
exclude = [ exclude = [
@@ -58,8 +58,28 @@ target-version = "py38"
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. # Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or # Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
# McCabe complexity (`C901`) by default. # McCabe complexity (`C901`) by default.
select = ["E4", "E7", "E9", "F", "D100", "D1"] select = ["ALL"]
ignore = ["D107"] ignore = [
"B008", # I build SlashOptions as arguments.
"COM812",
"COM819",
"D107", # don't want docstrings on init functions
"D203",
"D206",
"D212",
"D300",
"E111",
"E114",
"E117",
"ISC001",
"ISC002",
"PD011", # doesn't like me using '.values' on embeds....
"Q000",
"Q001",
"Q002",
"Q003",
"W191",
]
# Allow fix for all enabled rules (when `--fix`) is provided. # Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"] fixable = ["ALL"]
+29
View File
@@ -0,0 +1,29 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"lockFileMaintenance": {
"automerge": true
},
"major": {
"automerge": false,
"automergeType": "pr"
},
"minor": {
"automerge": true,
"automergeType": "branch"
},
"patch": {
"automerge": true,
"automergeType": "branch"
},
"pin": {
"automerge": true,
"automergeType": "branch"
},
"ignoreTests": true,
"dockerfile": {
"minor": {
"automerge": false,
"automergeType": "pr"
}
}
}
-2
View File
@@ -1,2 +0,0 @@
nextcord==2.4.2
hydra-core==1.3.2
+28
View File
@@ -0,0 +1,28 @@
"""File contains classes defining ${REPO_NAME} settings structure."""
from dataclasses import dataclass
from dataclass_wizard import YAMLWizard
CONFIG_LOCATION = "conf/config.yaml"
@dataclass
class Params:
"""Class defines start parameters that shouldn't be changed."""
discord_token: str
@dataclass
class Settings(YAMLWizard):
"""Class defines all configs required for ${REPO_NAME}."""
params: Params
def save(self) -> None:
"""Save settings to the yaml file."""
self.to_yaml_file(CONFIG_LOCATION)
settings = Settings.from_yaml_file(CONFIG_LOCATION)