Documentation for 2.0

This commit is contained in:
grey-cat-1908 2022-02-17 19:14:39 +03:00
parent 13cb66bc3c
commit c6ccde127b
33 changed files with 663 additions and 274 deletions

1
.gitignore vendored
View file

@ -9,3 +9,4 @@ docs/_build
boticordpy.egg-info boticordpy.egg-info
test.py test.py
/.pytest_cache /.pytest_cache
/docs/build/

13
.readthedocs.yml Normal file
View file

@ -0,0 +1,13 @@
version: 2
sphinx:
configuration: docs/source/conf.py
build:
image: latest
python:
version: "3.8"
install:
- requirements: requirements.txt
- requirements: requirements-docs.txt

View file

@ -1,3 +1,84 @@
<h1 align="center">Boticordpy 2.0</h1> <p align="center">
<img width="520" src="https://media.discordapp.net/attachments/825242846616354821/939773822582808606/boticordrs_banner.png" alt="">
</p>
<p align="center">Currently in development</p> <p align="center">
<b>
The easiest way to use Boticord API in Python.
<span> · </span>
<a href="https://py.boticord.top/">Docs</a>
</b>
</p>
<p align="center">
<a href="https://pypi.org/project/boticordpy/"><img src="https://img.shields.io/pypi/dm/boticordpy?style=flat-square" alt=""></a>
<a href="https://pypi.org/project/boticordpy/"><img src="https://img.shields.io/pypi/v/boticordpy?style=flat-square" alt=""></a>
<a href="https://py.boticord.top/"><img src="https://img.shields.io/readthedocs/boticordpy?style=flat-square" alt=""></a>
</p>
<h2>Features</h2>
* Object-oriented
* Full Boticord API Coverage
* Modern Pythonic API using `async`/`await` syntax
* Boticord Webhooks
* It is not necessary to use any particular library to interact with the Discord API.
<h2>Installation</h2>
<b>Python 3.6 or newer is required.</b>
Enter one of these commands to install the library:
```
pip install boticordpy
```
```
python3 -m pip install boticordpy
```
Or just clone the repo: https://github.com/boticord/boticordpy
<h2>Examples</h2>
You can find other examples in an examples folder.
**Discord.py Autopost example**
```py
from discord.ext import commands
from boticordpy import BoticordClient
bot = commands.Bot(command_prefix="!")
async def get_stats():
return {"servers": len(bot.guilds), "shards": 0, "users": len(bot.users)}
async def on_success_posting():
print("stats posting successfully")
boticord_client = BoticordClient("your_api_token")
autopost = (
boticord_client.autopost()
.init_stats(get_stats)
.on_success(on_success_posting)
)
bot.run("bot token")
```
<h2>Links</h2>
* [PyPi](https://pypi.org/project/boticordpy)
* [Documentation](https://py.boticord.top)
* [Github](https://github.com/boticord/boticordpy)
* [Boticord](https://boticord.top/)
* [Support](https://boticord.top/boticord)
<h2>Help</h2>
If You need any help we recommend you to check the documentation. You can find us [here](https://boticord.top/boticord). Main developer `Marakarka#0575`

View file

@ -13,5 +13,6 @@ __copyright__ = 'Copyright 2022 Marakarka'
__version__ = '2.0.1a' __version__ = '2.0.1a'
from .client import BoticordClient from .client import BoticordClient
from .webhook import Webhook
from .types import * from .types import *

View file

@ -5,6 +5,14 @@ from . import exceptions as bexc
class AutoPost: class AutoPost:
"""
You can use this class to post stats automatically.
Args:
client (:obj:`~.client.BoticordClient`)
An instance of BoticordClient.
"""
__slots__ = ( __slots__ = (
"client", "client",
"_interval", "_interval",
@ -28,9 +36,24 @@ class AutoPost:
@property @property
def is_running(self) -> bool: def is_running(self) -> bool:
"""
Is autopost running?
"""
return self._task is not None and not self._task.done() return self._task is not None and not self._task.done()
def on_success(self, callback: typing.Any = None): def on_success(self, callback: typing.Any = None):
"""
Registers success callback.
.. warning::
Callback functions must be a **coroutine**. If they aren't, then you might get unexpected
errors. In order to turn a function into a coroutine they must be ``async def``
functions.
This method can be used as a decorator (if you want).
"""
if callback is not None: if callback is not None:
self._success = callback self._success = callback
return self return self
@ -45,6 +68,18 @@ class AutoPost:
return inner return inner
def on_error(self, callback: typing.Any = None): def on_error(self, callback: typing.Any = None):
"""
Registers error callback.
.. warning::
Callback functions must be a **coroutine**. If they aren't, then you might get unexpected
errors. In order to turn a function into a coroutine they must be ``async def``
functions.
The callback function requires to take Exception argument.
This method can be used as a decorator (if you want).
"""
if callback is not None: if callback is not None:
self._error = callback self._error = callback
return self return self
@ -59,6 +94,17 @@ class AutoPost:
return inner return inner
def init_stats(self, callback: typing.Any = None): def init_stats(self, callback: typing.Any = None):
"""
Registers a function that will return stats. Registered Function Must return dictionary.
.. warning::
Callback functions must be a **coroutine**. If they aren't, then you might get unexpected
errors. In order to turn a function into a coroutine they must be ``async def``
functions.
This method can be used as a decorator (if you want).
"""
if callback is not None: if callback is not None:
self._stats = callback self._stats = callback
return self return self
@ -74,9 +120,19 @@ class AutoPost:
@property @property
def interval(self) -> float: def interval(self) -> float:
"""The interval between posting stats."""
return self._interval return self._interval
def set_interval(self, seconds: int) -> "AutoPost": def set_interval(self, seconds: int) -> "AutoPost":
"""
Sets the interval between posting stats.
Args:
seconds (:obj:`int`)
The interval.
Raises:
:obj:`ValueError`
Boticord recommends not to set interval lower than 900 seconds!
"""
if seconds < 900: if seconds < 900:
raise ValueError("no. Boticord recommends not to set interval lower than 900 seconds!") raise ValueError("no. Boticord recommends not to set interval lower than 900 seconds!")
@ -103,6 +159,13 @@ class AutoPost:
await asyncio.sleep(self._interval) await asyncio.sleep(self._interval)
def start(self): def start(self):
"""
Starts the loop.
Raises:
:obj:`~.exceptions.InternalException`
If there's no callback (for getting stats) provided or the autopost is already running.
"""
if not hasattr(self, "_stats"): if not hasattr(self, "_stats"):
raise bexc.InternalException("You must provide stats") raise bexc.InternalException("You must provide stats")
@ -114,6 +177,9 @@ class AutoPost:
return task return task
def stop(self) -> None: def stop(self) -> None:
"""
Stops the autopost.
"""
if not self.is_running: if not self.is_running:
return None return None

View file

@ -6,6 +6,15 @@ from .autopost import AutoPost
class BoticordClient: class BoticordClient:
"""Represents a client that can be used to interact with the Boticord API.
Note:
Remember that every http method can return http exception.
Args:
token (:obj:`str`)
Your bot's Boticord API Token.
"""
__slots__ = ( __slots__ = (
"http", "http",
"_autopost", "_autopost",
@ -14,20 +23,53 @@ class BoticordClient:
http: HttpClient http: HttpClient
def __init__(self, token=None, **kwargs): def __init__(self, token=None):
self._token = token self._token = token
self._autopost: typing.Optional[AutoPost] = None self._autopost: typing.Optional[AutoPost] = None
self.http = HttpClient(token) self.http = HttpClient(token)
async def get_bot_info(self, bot_id: int) -> boticord_types.Bot: async def get_bot_info(self, bot_id: int) -> boticord_types.Bot:
"""Gets information about specified bot.
Args:
bot_id (:obj:`int`)
Id of the bot
Returns:
:obj:`~.types.Bot`:
Bot object.
"""
response = await self.http.get_bot_info(bot_id) response = await self.http.get_bot_info(bot_id)
return boticord_types.Bot(**response) return boticord_types.Bot(**response)
async def get_bot_comments(self, bot_id: int) -> list: async def get_bot_comments(self, bot_id: int) -> list:
"""Gets list of comments of specified bot.
Args:
bot_id (:obj:`int`)
Id of the bot
Returns:
:obj:`list` [ :obj:`~.types.SingleComment` ]:
List of comments.
"""
response = await self.http.get_bot_comments(bot_id) response = await self.http.get_bot_comments(bot_id)
return [boticord_types.SingleComment(**comment) for comment in response] return [boticord_types.SingleComment(**comment) for comment in response]
async def post_bot_stats(self, servers: int = 0, shards: int = 0, users: int = 0) -> dict: async def post_bot_stats(self, servers: int = 0, shards: int = 0, users: int = 0) -> dict:
"""Post Bot's stats.
Args:
servers ( :obj:`int` )
Bot's servers count
shards ( :obj:`int` )
Bot's shards count
users ( :obj:`int` )
Bot's users count
Returns:
:obj:`dict`:
Boticord API Response status
"""
response = await self.http.post_bot_stats({ response = await self.http.post_bot_stats({
"servers": servers, "servers": servers,
"shards": shards, "shards": shards,
@ -36,30 +78,94 @@ class BoticordClient:
return response return response
async def get_server_info(self, server_id: int) -> boticord_types.Server: async def get_server_info(self, server_id: int) -> boticord_types.Server:
"""Gets information about specified server.
Args:
server_id (:obj:`int`)
Id of the server
Returns:
:obj:`~.types.Server`:
Server object.
"""
response = await self.http.get_server_info(server_id) response = await self.http.get_server_info(server_id)
return boticord_types.Server(**response) return boticord_types.Server(**response)
async def get_server_comments(self, server_id: int) -> list: async def get_server_comments(self, server_id: int) -> list:
"""Gets list of comments of specified server.
Args:
server_id (:obj:`int`)
Id of the server
Returns:
:obj:`list` [ :obj:`~.types.SingleComment` ]:
List of comments.
"""
response = await self.http.get_server_comments(server_id) response = await self.http.get_server_comments(server_id)
return [boticord_types.SingleComment(**comment) for comment in response] return [boticord_types.SingleComment(**comment) for comment in response]
async def post_server_stats(self, payload: dict) -> dict: async def post_server_stats(self, payload: dict) -> dict:
"""Post Server's stats. You must be Boticord-Service bot.
Args:
payload (:obj:`dict`)
Custom data (Use Boticord API docs.)
Returns:
:obj:`dict`:
Boticord API Response.
"""
response = await self.post_server_stats(payload) response = await self.post_server_stats(payload)
return response return response
async def get_user_info(self, user_id: int) -> boticord_types.UserProfile: async def get_user_info(self, user_id: int) -> boticord_types.UserProfile:
"""Gets information about specified user.
Args:
user_id (:obj:`int`)
Id of the user
Returns:
:obj:`~.types.UserProfile`:
User Profile object.
"""
response = await self.get_user_info(user_id) response = await self.get_user_info(user_id)
return boticord_types.UserProfile(**response) return boticord_types.UserProfile(**response)
async def get_user_comments(self, user_id: int) -> boticord_types.UserComments: async def get_user_comments(self, user_id: int) -> boticord_types.UserComments:
"""Gets comments of specified user.
Args:
user_id (:obj:`int`)
Id of the user
Returns:
:obj:`~.types.UserComments`:
User comments on Bots and Servers pages.
"""
response = await self.get_user_comments(user_id) response = await self.get_user_comments(user_id)
return boticord_types.UserComments(**response) return boticord_types.UserComments(**response)
async def get_user_bots(self, user_id: int) -> list: async def get_user_bots(self, user_id: int) -> list:
"""Gets list of bots of specified user.
Args:
user_id (:obj:`int`)
Id of the user
Returns:
:obj:`list` [ :obj:`~.types.SimpleBot` ]:
List of simple information about users bots.
"""
response = await self.get_user_bots(user_id) response = await self.get_user_bots(user_id)
return [boticord_types.SimpleBot(**bot) for bot in response] return [boticord_types.SimpleBot(**bot) for bot in response]
def autopost(self) -> AutoPost: def autopost(self) -> AutoPost:
"""Returns a helper instance for auto-posting.
Returns:
:obj:`~.autopost.AutoPost`: An instance of AutoPost.
"""
if self._autopost is not None: if self._autopost is not None:
return self._autopost return self._autopost

View file

@ -6,6 +6,19 @@ from . import exceptions
class HttpClient: class HttpClient:
"""
Represents an HTTP client sending HTTP requests to the Top.gg API.
Args:
token (:obj:`str`)
Your bot's Boticord API Token.
Keyword Arguments:
session: `aiohttp session`_
The `aiohttp session`_ used for requests to the API.
loop: `asyncio loop`
"""
def __init__(self, auth_token, **kwargs): def __init__(self, auth_token, **kwargs):
self.token = auth_token self.token = auth_token
self.API_URL = "https://api.boticord.top/v1/" self.API_URL = "https://api.boticord.top/v1/"
@ -18,6 +31,8 @@ class HttpClient:
method: str, method: str,
endpoint: str, endpoint: str,
**kwargs): **kwargs):
"""Send requests to the API"""
kwargs["headers"] = { kwargs["headers"] = {
"Content-Type": "application/json", "Content-Type": "application/json",
"Authorization": self.token "Authorization": self.token
@ -48,28 +63,37 @@ class HttpClient:
raise exceptions.HTTPException(response) raise exceptions.HTTPException(response)
def get_bot_info(self, bot_id: int): def get_bot_info(self, bot_id: int):
"""Get information about the specified bot"""
return self.make_request("GET", f"bot/{bot_id}") return self.make_request("GET", f"bot/{bot_id}")
def get_bot_comments(self, bot_id: int): def get_bot_comments(self, bot_id: int):
"""Get list of specified bot comments"""
return self.make_request("GET", f"bot/{bot_id}/comments") return self.make_request("GET", f"bot/{bot_id}/comments")
def post_bot_stats(self, stats: dict): def post_bot_stats(self, stats: dict):
"""Post bot's stats"""
return self.make_request("POST", "stats", json=stats) return self.make_request("POST", "stats", json=stats)
def get_server_info(self, server_id: int): def get_server_info(self, server_id: int):
"""Get information about specified server"""
return self.make_request("GET", f"server/{server_id}") return self.make_request("GET", f"server/{server_id}")
def get_server_comments(self, server_id: int): def get_server_comments(self, server_id: int):
"""Get list of specified server comments"""
return self.make_request("GET", f"server/{server_id}/comments") return self.make_request("GET", f"server/{server_id}/comments")
def post_server_stats(self, payload: dict): def post_server_stats(self, payload: dict):
"""Post server's stats"""
return self.make_request("POST", "server", json=payload) return self.make_request("POST", "server", json=payload)
def get_user_info(self, user_id: int): def get_user_info(self, user_id: int):
"""Get information about the user"""
return self.make_request("GET", f"profile/{user_id}") return self.make_request("GET", f"profile/{user_id}")
def get_user_comments(self, user_id: int): def get_user_comments(self, user_id: int):
"""Get specified user's comments"""
return self.make_request("GET", f"user/{user_id}/comments") return self.make_request("GET", f"user/{user_id}/comments")
def get_user_bots(self, user_id: int): def get_user_bots(self, user_id: int):
"""Get bots of specified user"""
return self.make_request("GET", f"bots/{user_id}") return self.make_request("GET", f"bots/{user_id}")

View file

@ -109,9 +109,12 @@ class Bot(ApiData):
bumps: int bumps: int
"""Bumps count""" """Bumps count"""
prefix: str added: str
"""How many times users have added the bot?""" """How many times users have added the bot?"""
prefix: str
"""Bot's commands prefix"""
permissions: int permissions: int
"""Bot's permissions""" """Bot's permissions"""
@ -256,6 +259,7 @@ class SimpleBot(ApiData):
"""Bot's Id""" """Bot's Id"""
short_code: typing.Optional[str] short_code: typing.Optional[str]
"""Bot's page short code"""
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**parse_response_dict(kwargs)) super().__init__(**parse_response_dict(kwargs))
@ -265,8 +269,13 @@ class CommentData(ApiData):
"""This model represents comment data (from webhook response)""" """This model represents comment data (from webhook response)"""
vote: dict vote: dict
"""Comment vote data"""
old: typing.Optional[str] old: typing.Optional[str]
"""Old content of the comment"""
new: typing.Optional[str] new: typing.Optional[str]
"""New content of the comment"""
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**parse_response_dict(kwargs)) super().__init__(**parse_response_dict(kwargs))
@ -298,8 +307,13 @@ class BumpResponse(ApiData):
"""This model represents a webhook response (`bot bump`).""" """This model represents a webhook response (`bot bump`)."""
type: str type: str
"""Type of response (`bump`)"""
user: str user: str
"""Id of user who did the action"""
at: int at: int
"""Timestamp of the action"""
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**parse_webhook_response_dict(kwargs)) super().__init__(**parse_webhook_response_dict(kwargs))
@ -309,10 +323,19 @@ class CommentResponse(ApiData):
"""This model represents a webhook response (`comment`).""" """This model represents a webhook response (`comment`)."""
type: str type: str
"""Type of response (`comment`)"""
user: str user: str
"""Id of user who did the action"""
comment: CommentData comment: CommentData
"""Information about the comment"""
reason: typing.Optional[str] reason: typing.Optional[str]
"""Is comment deleted? so, why?"""
at: int at: int
"""Timestamp of the action"""
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**parse_webhook_response_dict(kwargs)) super().__init__(**parse_webhook_response_dict(kwargs))

View file

@ -8,6 +8,18 @@ import aiohttp
class Webhook: class Webhook:
"""Represents a client that can be used to work with Boticord Webhooks.
IP of the server - your machine IP. (`0.0.0.0`)
Args:
x_hook_key (:obj:`str`)
X-hook-key to check the auth of incoming request.
endpoint_name (:obj:`str`)
Name of endpoint (for example: `/bot`)
Keyword Arguments:
loop: `asyncio loop`
"""
__slots__ = ( __slots__ = (
"_webserver", "_webserver",
"_listeners", "_listeners",
@ -30,6 +42,11 @@ class Webhook:
self._loop = kwargs.get('loop') or asyncio.get_event_loop() self._loop = kwargs.get('loop') or asyncio.get_event_loop()
def listener(self, response_type: str): def listener(self, response_type: str):
"""Decorator to set the listener.
Args:
response_type (:obj:`str`)
Type of response (Check reference page)
"""
def inner(func): def inner(func):
if not asyncio.iscoroutinefunction(func): if not asyncio.iscoroutinefunction(func):
raise TypeError(f"<{func.__qualname__}> must be a coroutine function") raise TypeError(f"<{func.__qualname__}> must be a coroutine function")
@ -39,6 +56,13 @@ class Webhook:
return inner return inner
def register_listener(self, response_type: str, callback: typing.Any): def register_listener(self, response_type: str, callback: typing.Any):
"""Method to set the listener.
Args:
response_type (:obj:`str`)
Type of response (Check reference page)
callback (:obj:`function`)
Coroutine Callback Function
"""
if not asyncio.iscoroutinefunction(callback): if not asyncio.iscoroutinefunction(callback):
raise TypeError(f"<{func.__qualname__}> must be a coroutine function") raise TypeError(f"<{func.__qualname__}> must be a coroutine function")
@ -46,6 +70,7 @@ class Webhook:
return self return self
async def _interaction_handler(self, request: aiohttp.web.Request) -> web.Response: async def _interaction_handler(self, request: aiohttp.web.Request) -> web.Response:
"""Interaction handler"""
auth = request.headers.get("X-Hook-Key") auth = request.headers.get("X-Hook-Key")
if auth == self._x_hook_key: if auth == self._x_hook_key:
@ -74,21 +99,31 @@ class Webhook:
self._is_running = True self._is_running = True
def start(self, port: int) -> None: def start(self, port: int) -> None:
"""Method to start the webhook server
Args:
port (:obj:`int`)
Port to start the webserver
"""
self._loop.create_task(self._run(port)) self._loop.create_task(self._run(port))
@property @property
def is_running(self) -> bool: def is_running(self) -> bool:
"""If the server running?"""
return self._is_running return self._is_running
@property @property
def listeners(self) -> dict: def listeners(self) -> dict:
"""Dictionary of listeners (`type`: `callback function`)"""
return self._listeners return self._listeners
@property @property
def app(self) -> web.Application: def app(self) -> web.Application:
"""Web application that handles incoming requests"""
return self.__app return self.__app
async def close(self) -> None: async def close(self) -> None:
"""Stop the webhooks server"""
await self._webserver.stop() await self._webserver.stop()
self._is_running = False self._is_running = False

2
docs-requirements.txt Normal file
View file

@ -0,0 +1,2 @@
sphinx_rtd_theme
sphinx

View file

@ -5,8 +5,8 @@
# from the environment for the first two. # from the environment for the first two.
SPHINXOPTS ?= SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build SPHINXBUILD ?= sphinx-build
SOURCEDIR = . SOURCEDIR = source
BUILDDIR = _build BUILDDIR = build
# Put it first so that "make" without argument is like "make help". # Put it first so that "make" without argument is like "make help".
help: help:

View file

@ -1,12 +0,0 @@
.. currentmodule:: boticordpy
.. exceptions:
Exceptions
==============
This page describes all the exceptions of boticordpy module.
.. automodule:: boticordpy.exceptions
:members:

View file

@ -1,31 +0,0 @@
.. BoticordPy documentation master file, created by
sphinx-quickstart on Sat Aug 7 21:14:56 2021.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to BoticordPy's documentation!
======================================
This is a documentation for simple python module to work with the boticord api.
======================================
.. toctree::
:maxdepth: 2
:caption: Contents:
quickstart
main
modules
webhook
reference
exceptions
Links
=====
* :ref:`search`
* `PyPi <https://pypi.org/project/boticordpy>`_
* `GitHub <https://github.com/grey-cat-1908/boticordpy>`_
* `Boticord <https://boticord.top/>`_

View file

@ -1,13 +0,0 @@
.. currentmodule:: boticordpy
.. main:
Main
===================
This class is used to make it much easier to use the Boticord API.
BoticordClient
---------------
.. autoclass:: boticordpy.BoticordClient
:members:

35
docs/make.bat Normal file
View file

@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

View file

@ -1,23 +0,0 @@
.. currentmodule:: boticordpy
.. modules:
Modules
==============
This page describes all the modules of boticordpy.
Bots
------------
.. autoclass:: boticordpy.modules.Bots
:members:
Servers
------------
.. autoclass:: boticordpy.modules.Servers
:members:
Users
------------
.. autoclass:: boticordpy.modules.Users
:members:

View file

@ -1,84 +0,0 @@
.. currentmodule:: boticordpy
.. quickstart:
Quickstart
==========
Installation
------------
Enter one of these commands to install the library:
::
pip install boticordpy
::
python3 -m pip install boticordpy
Or just clone the repo: https://github.com/grey-cat-1908/boticordpy
Examples
-------------------------
**Without Using Cogs System**
Post bot stats when bot is ready.
::
from discord.ext import commands
from boticordpy import BoticordClient
bot = commands.Bot(command_prefix="!")
boticord = BoticordClient(bot, "your-boticord-token")
@bot.event
async def on_ready():
stats = {"servers": len(bot.guilds), "shards": bot.shard_count, "users": len(bot.users)}
await boticord.Bots.post_stats(stats)
bot.run("your-bot-token")
..
**Using Cogs System**
Cog with automatically stats post (every 15 minutes) + bot's owner command that can be used to post stats.
::
from discord.ext import commands
from boticordpy import BoticordClient
class BoticordCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.boticord = BoticordClient(self.bot, "your-boticord-token")
self.boticord.start_loop()
@commands.command(name="boticord-update")
@commands.is_owner()
async def boticord_update(self, ctx):
"""
This commands can be used by owner to post stats to boticord
"""
stats = {"servers": len(self.bot.guilds), "shards": 0, "users": len(self.bot.users)}
await self.boticord.Bots.post_stats(stats)
def setup(bot):
bot.add_cog(BoticordCog(bot))
..

View file

@ -1,64 +0,0 @@
.. currentmodule:: boticordpy
.. reference:
Reference
==============
Event Reference
---------------
Example of event creation:
::
from discord.ext import commands
from boticordpy import BoticordWebhook, BoticordClient
bot = commands.Bot(command_prefix="!")
boticord = BoticordClient(bot, "boticord-api-token")
boticord_webhook = BoticordWebhook(bot, boticord).bot_webhook("/bot", "X-Hook-Key")
boticord_webhook.run(5000)
@boticord.event("edit_bot_comment")
async def on_boticord_comment_edit(data):
print(data)
You can name the function whatever you want, but the decorator must always specify an existing event as an argument.
.. warning::
All the events must be a **coroutine**. If they aren't, then you might get unexpected
errors. In order to turn a function into a coroutine they must be ``async def``
functions.
Here you can find some information about events:
+------------------------+----------------------------------+
| Boticord Events | Returns Type |
+========================+==================================+
| new_bot_comment | types.Comment |
+------------------------+----------------------------------+
| edit_bot_comment | types.EditedComment |
+------------------------+----------------------------------+
| delete_bot_comment | types.Comment |
+------------------------+----------------------------------+
| new_bot_bump | types.BotVote |
+------------------------+----------------------------------+
| new_server_comment | Raw Data |
+------------------------+----------------------------------+
| edit_server_comment | Raw Data |
+------------------------+----------------------------------+
| delete_server_comment | Raw Data |
+------------------------+----------------------------------+
You can find more events in Boticord Documentation.
Types
------------
.. automodule:: boticordpy.types
:members:

View file

@ -1 +0,0 @@
boticordpy

View file

@ -0,0 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400&display=swap');
* {
font-family: 'Roboto', sans-serif!important;
}

20
docs/source/api.rst Normal file
View file

@ -0,0 +1,20 @@
.. currentmodule:: boticordpy
.. api:
#############
API Reference
#############
API Reference for the BoticordPY Module
Index:
.. toctree::
:maxdepth: 2
api/client
api/autopost
api/exceptions
api/types
api/webhook

View file

@ -0,0 +1,7 @@
####################
AutoPost API Reference
####################
.. automodule:: boticordpy.autopost
:members:
:inherited-members:

View file

@ -0,0 +1,7 @@
####################
Client API Reference
####################
.. automodule:: boticordpy.client
:members:
:inherited-members:

View file

@ -0,0 +1,7 @@
####################
Exceptions API Reference
####################
.. automodule:: boticordpy.exceptions
:members:
:inherited-members:

View file

@ -0,0 +1,6 @@
####################
Models API Reference
####################
.. automodule:: boticordpy.types
:members:

View file

@ -0,0 +1,7 @@
####################
Webhook API Reference
####################
.. automodule:: boticordpy.webhook
:members:
:inherited-members:

View file

@ -10,27 +10,24 @@
# add these directories to sys.path here. If the directory is relative to the # add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here. # documentation root, use os.path.abspath to make it absolute, like shown here.
# #
import os # import os
import sys # import sys
import re # sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('..'))
# -- Project information ----------------------------------------------------- # -- Project information -----------------------------------------------------
import sys
import os
sys.path.insert(0, os.path.abspath("../.."))
project = 'BoticordPY' project = 'BoticordPY'
copyright = '2021, Grey Cat' copyright = '2022, Victor Kotlin (Marakarka)'
author = 'Grey Cat' author = 'Victor Kotlin (Marakarka)'
with open('../discord/__init__.py') as f: # The full version, including alpha/beta/rc tags
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', f.read(), re.MULTILINE).group(1) release = '2.0.0'
# The full version, including alpha/beta/rc tags.
release = version
# This assumes a tag is available for final releases
branch = 'master' if version.endswith('a') else 'v' + version
# -- General configuration --------------------------------------------------- # -- General configuration ---------------------------------------------------
@ -39,9 +36,11 @@ branch = 'master' if version.endswith('a') else 'v' + version
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # ones.
extensions = [ extensions = [
'sphinx.ext.napoleon', "sphinx.ext.napoleon",
'sphinx.ext.ifconfig', "sphinx.ext.autodoc",
'sphinx_rtd_theme' "sphinx.ext.viewcode",
"sphinx.ext.autosectionlabel",
"sphinx.ext.extlinks",
] ]
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
@ -50,8 +49,13 @@ templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path. # This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] exclude_patterns = []
intersphinx_mapping = {
"py": ("https://docs.python.org/3", None),
"discord": ("https://discordpy.readthedocs.io/en/latest/", None),
"aiohttp": ("https://docs.aiohttp.org/en/stable/", None),
}
# -- Options for HTML output ------------------------------------------------- # -- Options for HTML output -------------------------------------------------
@ -59,9 +63,16 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# a list of builtin themes. # a list of builtin themes.
# #
html_theme = "sphinx_rtd_theme" html_theme = "sphinx_rtd_theme"
html_show_sourcelink = False
html_theme_options = {
}
# Add any paths that contain custom static files (such as style sheets) here, # Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css". # so a file named "custom.css" will overwrite the builtin "custom.css".
html_static_path = ['_static'] html_static_path = ['_static']
def setup(app):
app.add_css_file('custom.css')

23
docs/source/index.rst Normal file
View file

@ -0,0 +1,23 @@
Welcome to BoticordPy's documentation!
======================================
This is a documentation for wrapper for Boticord API.
======================================
.. toctree::
:maxdepth: 2
:caption: Documentation:
quickstart
api
other
Links
=====
* :ref:`search`
* `PyPi <https://pypi.org/project/boticordpy>`_
* `GitHub <https://github.com/grey-cat-1908/boticordpy>`_
* `Boticord <https://boticord.top/>`_
* `Boticord Support <https://boticord.top/boticord>`_

41
docs/source/other.rst Normal file
View file

@ -0,0 +1,41 @@
.. currentmodule:: boticordpy
.. other:
Other Information
=================
##########
Listeners
##########
List of listeners for webhooks
+------------------------+----------------------------------+
| Boticord Events | Meaning |
+========================+==================================+
| new_bot_comment | On new bot comment |
+------------------------+----------------------------------+
| edit_bot_comment | On bot comment edit |
+------------------------+----------------------------------+
| delete_bot_comment | On bot comment delete |
+------------------------+----------------------------------+
| new_bot_bump | On new bot bump |
+------------------------+----------------------------------+
| new_server_comment | On new server comment |
+------------------------+----------------------------------+
| edit_server_comment | On server comment edit |
+------------------------+----------------------------------+
| delete_server_comment | On server comment delete |
+------------------------+----------------------------------+
##################
Callback functions
##################
.. warning::
Callback functions must be a **coroutine**. If they aren't, then you might get unexpected
errors. In order to turn a function into a coroutine they must be ``async def``
functions.

View file

@ -0,0 +1,85 @@
.. currentmodule:: boticordpy
.. quickstart:
Quickstart
==========
**For more examples or information about other features check Github-Repo.**
Installation
------------
Enter one of these commands to install the library:
::
pip install boticordpy
::
python3 -m pip install boticordpy
Or just clone the repo: https://github.com/boticord/boticordpy
Examples
-------------------------
**Discord.py Autopost example**
::
from discord.ext import commands
from boticordpy import BoticordClient
bot = commands.Bot(command_prefix="!")
async def get_stats():
return {"servers": len(bot.guilds), "shards": 0, "users": len(bot.users)}
async def on_success_posting():
print("stats posting successfully")
boticord_client = BoticordClient("your_api_token")
autopost = (
boticord_client.autopost()
.init_stats(get_stats)
.on_success(on_success_posting)
)
bot.run("bot token")
..
**Discord.py Webhooks example**
::
from discord.ext import commands
from boticordpy import webhook
bot = commands.Bot(command_prefix="!")
async def edit_bot_comment(data):
print(data.comment.new)
boticord_webhook = webhook.Webhook("x-hook-key", "bot").register_listener("edit_bot_comment", edit_bot_comment)
boticord_webhook.start(5000)
bot.run("bot token")
..

View file

@ -1,8 +0,0 @@
.. currentmodule:: boticordpy
.. webhook:
Webhooks
---------------
.. autoclass:: boticordpy.BoticordWebhook
:members:

25
examples/autopost.py Normal file
View file

@ -0,0 +1,25 @@
# You can use disnake or nextcord or something like this.
# (THIS EXAMPLE IS NOT TESTED. IF YOU HAVE ANY PROBLEMS - ASK DEVELOPER PLEASE)
from discord.ext import commands
from boticordpy import BoticordClient
bot = commands.Bot(command_prefix="!")
async def get_stats():
return {"servers": len(bot.guilds), "shards": 0, "users": len(bot.users)}
async def on_success_posting():
print("stats posting successfully")
boticord_client = BoticordClient("your_api_token")
autopost = (
boticord_client.autopost()
.init_stats(get_stats)
.on_success(on_success_posting)
)
bot.run("bot token")

View file

@ -1,15 +1,13 @@
import pathlib import pathlib
from setuptools import setup from setuptools import setup, find_packages
import re import re
HERE = pathlib.Path(__file__).parent HERE = pathlib.Path(__file__).parent
requirements = []
with open('requirements.txt') as f: with open('requirements.txt') as f:
requirements = f.read().splitlines() requirements = f.read().splitlines()
version = ''
with open('boticordpy/__init__.py') as f: with open('boticordpy/__init__.py') as f:
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', f.read(), re.MULTILINE).group(1) version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', f.read(), re.MULTILINE).group(1)
@ -33,23 +31,19 @@ if version.endswith(('a', 'b', 'rc')):
README = (HERE / "README.md").read_text(encoding="utf8") README = (HERE / "README.md").read_text(encoding="utf8")
packages = [
'boticordpy',
'boticordpy.modules'
]
setup( setup(
name="boticordpy", name="boticordpy",
project_urls={ project_urls={
"Documentation": "https://py.boticord.top/en/stable", "Documentation": "https://py.boticord.top/en/stable",
"Issue tracker": "https://github.com/boticord/boticordpy/issues", "Issue tracker": "https://github.com/boticord/boticordpy/issues",
}, },
packages=packages, packages=find_packages(),
version=version, version=version,
description="A Python wrapper for Boticord api", python_requires=">= 3.6",
description="A Python wrapper for Boticord API",
long_description=README, long_description=README,
long_description_content_type="text/markdown", long_description_content_type="text/markdown",
url="https://github.com/grey-cat-1908/boticordpy", url="https://github.com/boticord/boticordpy",
author="KerdokuCat", author="KerdokuCat",
author_email="support@kerdoku.top", author_email="support@kerdoku.top",
license="MIT", license="MIT",