generated from Damego/python-pypi-project-template
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
279 additions
and
198 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,15 @@ | ||
import interactions | ||
from interactions_restful import setup | ||
from interactions_restful.backends.fast_api import FastAPI | ||
from fastapi import FastAPI | ||
|
||
from interactions_restful.backends.fastapi import FastAPIHandler | ||
|
||
app = FastAPI() | ||
client = interactions.Client(token="TOKEN") | ||
FastAPIHandler(client, app) | ||
|
||
client = interactions.Client() | ||
setup(client, FastAPI, "localhost", 8000) | ||
client.load_extension("exts.my_ext") | ||
|
||
|
||
@interactions.listen() | ||
async def on_startup(): | ||
print(f"Bot `{client.user.username}` started up") | ||
|
||
|
||
client.start("TOKEN") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
from .decorators import * | ||
from .extension import * | ||
from .decorators import * # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,82 @@ | ||
from abc import ABC, abstractmethod | ||
from typing import Callable, Coroutine | ||
import asyncio | ||
import inspect | ||
from asyncio import Task | ||
from typing import Any, Callable, Coroutine, Protocol | ||
|
||
__all__ = ("BaseApi", "BaseRouter") | ||
from interactions import CallbackObject, Client | ||
|
||
from .manager import APIManager | ||
|
||
class BaseRouter(ABC): | ||
@abstractmethod | ||
def add_endpoint_method(self, coro: Callable[..., Coroutine], endpoint: str, method: str, **kwargs): | ||
pass | ||
__all__ = ("BaseAPIHandler", "BaseRouterWrapper") | ||
|
||
|
||
class BaseApi(ABC): | ||
@abstractmethod | ||
def __init__(self, host: str, port: int, **kwargs): | ||
pass | ||
class BaseRouterWrapper(Protocol): | ||
def add_endpoint_method( | ||
self, coro: Callable[..., Coroutine], endpoint: str, method: str, **kwargs | ||
): | ||
... | ||
|
||
@abstractmethod | ||
def add_endpoint_method(self, coro: Callable[..., Coroutine], endpoint: str, method: str, **kwargs): | ||
pass | ||
|
||
class BaseAPIHandler: | ||
bot: Client | ||
app: Any | ||
task: Task | None | ||
api_client: APIManager | ||
|
||
def __init__(self, bot: Client, app: Any): | ||
self.bot = bot | ||
self.app = app | ||
self.task = None | ||
self.api_client = APIManager(self.bot, self) | ||
|
||
# there's a problem deferring starting up the bot to an asgi server - | ||
# sys.modules[__main__] will be replaced with the asgi server's module | ||
# this means any files that were in the file where the bot is will be lost | ||
|
||
# we can't actually fully work around this - not perfectly, anyway | ||
# what we can somewhat rely on is that people are using the api wrappers | ||
# in their main file - you could place it somewhere else, but why would | ||
# you want to? | ||
# regardless, we exploit this by getting the module of the caller of the | ||
# api wrapper - in this, we have to go two calls back because the subclasses | ||
# count as a call | ||
# we can then use that module as the module to get the commands from during startup | ||
stack = inspect.stack() | ||
self.__original_module = inspect.getmodule(stack[2][0]) | ||
|
||
@staticmethod | ||
@abstractmethod | ||
def create_router(**kwargs) -> BaseRouter: | ||
pass | ||
def create_router(**kwargs) -> BaseRouterWrapper: | ||
... | ||
|
||
def add_router(self, router: BaseRouterWrapper): | ||
... | ||
|
||
def remove_router(self, router: BaseRouterWrapper): | ||
... | ||
|
||
def add_endpoint_method( | ||
self, coro: Callable[..., Coroutine], endpoint: str, method: str, **kwargs | ||
): | ||
... | ||
|
||
async def startup(self): | ||
commands = inspect.getmembers( | ||
self.__original_module, lambda x: isinstance(x, CallbackObject) | ||
) | ||
for command in commands: | ||
self.bot.add_command(command[1]) | ||
|
||
route_callables = inspect.getmembers( | ||
self.__original_module, predicate=lambda x: getattr(x, "__api__", False) | ||
) | ||
for callable in route_callables: | ||
callback = callable[1] | ||
data: dict = callback.__api__ | ||
self.add_endpoint_method(callback, data["endpoint"], data["method"], **data["kwargs"]) | ||
|
||
def add_router(self, router: BaseRouter): | ||
pass | ||
self.task = asyncio.create_task(self.bot.astart()) | ||
|
||
@abstractmethod | ||
async def run(self): | ||
pass | ||
async def shutdown(self): | ||
await self.bot.stop() | ||
if self.task: | ||
self.task.cancel() |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
from typing import Callable, Coroutine | ||
|
||
from fastapi import APIRouter, FastAPI | ||
from interactions import Client | ||
|
||
from ..abc import BaseAPIHandler, BaseRouterWrapper | ||
|
||
__all__ = ("FastAPIHandler",) | ||
|
||
|
||
class FastAPIRouterWrapper(BaseRouterWrapper): | ||
def __init__(self, **kwargs): | ||
kwargs.pop("name") # neccessary only for quart | ||
self.api_router = APIRouter(**kwargs) | ||
|
||
def add_endpoint_method( | ||
self, coro: Callable[..., Coroutine], endpoint: str, method: str, **kwargs | ||
): | ||
self.api_router.add_api_route(endpoint, coro, methods=[method], **kwargs) | ||
|
||
|
||
class FastAPIHandler(BaseAPIHandler): | ||
app: FastAPI | ||
|
||
def __init__(self, bot: Client, app: FastAPI): | ||
super().__init__(bot, app) | ||
self.app.add_event_handler("startup", self.startup) | ||
self.app.add_event_handler("shutdown", self.shutdown) | ||
|
||
@staticmethod | ||
def create_router(**kwargs): | ||
return FastAPIRouterWrapper(**kwargs) | ||
|
||
def add_router(self, router: FastAPIRouterWrapper): | ||
self.app.include_router(router.api_router) | ||
|
||
def remove_router(self, router: FastAPIRouterWrapper): | ||
paths_to_check = frozenset( | ||
f"{router.api_router.prefix}{r.path}" for r in router.api_router.routes | ||
) | ||
for i, r in enumerate(self.app.router.routes): | ||
if r.path in paths_to_check: # type: ignore | ||
del self.app.router.routes[i] | ||
|
||
def add_endpoint_method( | ||
self, coro: Callable[..., Coroutine], endpoint: str, method: str, **kwargs | ||
): | ||
self.app.add_api_route(endpoint, coro, methods=[method], **kwargs) |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.