Skip to content

Commit

Permalink
next (#10)
Browse files Browse the repository at this point in the history
* Add example command / cog file. (#9)

* Added poetry script for running the subclassed bot.

* Added example runner script for testing.

* Fixed bug after moving logging out to init file.
  • Loading branch information
Rob authored Feb 15, 2021
1 parent f9ced4c commit 6c74ab4
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 15 deletions.
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# Testing
examples/commands/

# JetBrains
.idea/

Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [2.1.0] -- 2021-15-02

### Added
- The subclassed bot can now be run via a poetry script `poetry run example`.
- The `examples` directory now includes a sample command directory & cog file to
demonstrate the expected tree and code structure. (#9)


## [2.0.0] -- 2021-30-01

### Changed
Expand Down
16 changes: 16 additions & 0 deletions cogwatch/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
"""
dpymenus -- Simplified menus for discord.py developers.
"""

__title__ = "cogwatch"
__author__ = "Rob Wagner <rob@robwagner.dev>"
__license__ = "MIT"
__copyright__ = "Copyright 2020-2021 Rob Wagner"
__version__ = "2.1.0"

import logging

from cogwatch.cogwatch import Watcher, watch


logger = logging.getLogger("cogwatch")
logger.addHandler(logging.NullHandler())
15 changes: 6 additions & 9 deletions cogwatch/cogwatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
from discord.ext import commands
from watchgod import Change, awatch

logger = logging.getLogger("cogwatch")
logger.addHandler(logging.NullHandler())


class Watcher:
"""The core cogwatch class -- responsible for starting up watchers and managing cogs.
Expand Down Expand Up @@ -133,7 +130,7 @@ async def start(self):
if self.loop is None:
self.loop = asyncio.get_event_loop()

logger.info(f"Watching for file changes in {Path.cwd() / self.path}...")
logging.info(f"Watching for file changes in {Path.cwd() / self.path}...")
self.loop.create_task(self._start())

async def load(self, cog_dir: str):
Expand All @@ -145,7 +142,7 @@ async def load(self, cog_dir: str):
except Exception as exc:
self.cog_error(exc)
else:
logger.info(f"Cog Loaded: {cog_dir}")
logging.info(f"Cog Loaded: {cog_dir}")

async def unload(self, cog_dir: str):
"""Unloads a cog file into the client."""
Expand All @@ -154,7 +151,7 @@ async def unload(self, cog_dir: str):
except Exception as exc:
self.cog_error(exc)
else:
logger.info(f"Cog Unloaded: {cog_dir}")
logging.info(f"Cog Unloaded: {cog_dir}")

async def reload(self, cog_dir: str):
"""Attempts to atomically reload the file into the client."""
Expand All @@ -163,16 +160,16 @@ async def reload(self, cog_dir: str):
except Exception as exc:
self.cog_error(exc)
else:
logger.info(f"Cog Reloaded: {cog_dir}")
logging.info(f"Cog Reloaded: {cog_dir}")

@staticmethod
def cog_error(exc: Exception):
"""Logs exceptions. TODO: Need thorough exception handling."""
if isinstance(exc, (commands.ExtensionError, SyntaxError)):
logger.exception(exc)
logging.exception(exc)

async def _preload(self):
logger.info("Preloading...")
logging.info("Preloading...")
for cog in {(file.stem, file) for file in Path(Path.cwd() / self.path).rglob("*.py")}:
new_dir = self.get_dotted_cog_path(cog[1])
await self.load(".".join([new_dir, cog[0]]))
Expand Down
14 changes: 14 additions & 0 deletions examples/commands/ping.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from discord.ext import commands


class Ping(commands.Cog):
def __init__(self, client):
self.client = client

@commands.command()
async def ping(self, ctx):
await ctx.reply("Pong!")


def setup(client):
client.add_cog(Ping(client))
42 changes: 41 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "cogwatch"
version = "2.0.0"
version = "2.1.0"
description = "Automatic hot-reloading for your discord.py command files."
authors = ["Rob Wagner <13954303+robertwayne@users.noreply.github.com>"]
license = "MIT"
Expand All @@ -16,14 +16,19 @@ classifiers=[
'Development Status :: 5 - Production/Stable',
]

[tool.poetry.scripts]
example = 'runner:__poetry_run'

[tool.poetry.dependencies]
python = "^3.7"
"discord.py" = "^1.5"
watchgod = "0.7"

[tool.poetry.dev-dependencies]
pytest = "^6.1.2"
pytest = "^6.1"
black = "^20.8b1"
python-dotenv = '^0.15'
uvloop = "^0.15.1"

[tool.black]
line-length = 120
Expand Down
57 changes: 57 additions & 0 deletions runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# This is a testing module which interfaces with the documentation examples. You will need to
# have an environment variable called "COGWATCH_BOT_TOKEN" set in order for this to run. This
# module must live in the root directory.
#
# You can run this file directly or with `poetry run example`.

import asyncio
import logging
import os
import sys

from cogwatch import watch
from discord.ext import commands
from dotenv import load_dotenv

try:
import uvloop
except ImportError:
uvloop = None

logging.basicConfig(level=logging.INFO)

if sys.platform in {"linux", "macos"}:
uvloop.install()
logging.info("Using `uvloop` asyncio event loop.")

load_dotenv()


class ExampleRunner(commands.Bot):
def __init__(self):
super().__init__(command_prefix=".")

@watch(path="examples/commands", preload=True)
async def on_ready(self):
logging.info("Bot ready.")

async def on_message(self, message):
logging.info(message)

if message.author.bot:
return

await self.process_commands(message)


async def main():
client = ExampleRunner()
await client.start(os.getenv("COGWATCH_BOT_TOKEN"))


def __poetry_run():
asyncio.run(main())


if __name__ == "__main__":
asyncio.run(main())

0 comments on commit 6c74ab4

Please sign in to comment.