fix setup.py

This commit is contained in:
grey-cat-1908 2021-08-24 21:20:10 +03:00
commit bf8eba17af
28 changed files with 752 additions and 0 deletions

8
.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
.idea
venv
.git
.DS_Store
__pycache__
.egg-info
dist
docs/_build

7
LICENSE.txt Normal file
View file

@ -0,0 +1,7 @@
Copyright 2021 Victor Kotlin
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

35
README.md Normal file
View file

@ -0,0 +1,35 @@
<h1 align="center">Boticordpy</h1>
<p align="center">Модуль для работы с <a href="https://boticord.top/">Boticord</a> API</p>
<p align="center">
<img src="https://img.shields.io/pypi/dm/boticordpy" alt="">
</p>
---
* [Документация](https://boticordpy.readthedocs.io/)
* [Исходный код](https://github.com/grey-cat-1908/boticordpy)
---
### Примеры
Публикуем статистику нашего бота в Boticord.
```Python
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_connect():
stats = {"servers": len(bot.guilds), "shards": bot.shard_count, "users": len(bot.users)}
await boticord.Bots.postStats(stats)
bot.run("your-bot-token")
```

View file

@ -0,0 +1,49 @@
Metadata-Version: 2.1
Name: boticordpy
Version: 1.3.5
Summary: Simple Python Module for boticord api
Home-page: https://github.com/grey-cat-1908/boticordpy
Author: KerdokuCat
Author-email: support@kerdoku.top
License: MIT
Description: <h1 align="center">Boticordpy</h1>
<p align="center">Модуль для работы с <a href="https://boticord.top/">Boticord</a> API</p>
<p align="center">
<img src="https://img.shields.io/pypi/dm/boticordpy" alt="">
</p>
---
* [Документация](https://boticordpy.readthedocs.io/)
* [Исходный код](https://github.com/grey-cat-1908/boticordpy)
---
### Примеры
Публикуем статистику нашего бота в Boticord.
```Python
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_connect():
stats = {"servers": len(bot.guilds), "shards": bot.shard_count, "users": len(bot.users)}
await boticord.Bots.postStats(stats)
bot.run("your-bot-token")
```
Platform: UNKNOWN
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Description-Content-Type: text/markdown

View file

@ -0,0 +1,12 @@
LICENSE.txt
README.md
setup.py
boticordpy/__init__.py
boticordpy/client.py
boticordpy/config.py
boticordpy/exceptions.py
boticordpy.egg-info/PKG-INFO
boticordpy.egg-info/SOURCES.txt
boticordpy.egg-info/dependency_links.txt
boticordpy.egg-info/requires.txt
boticordpy.egg-info/top_level.txt

View file

@ -0,0 +1 @@

View file

@ -0,0 +1,2 @@
discord.py
aiohttp

View file

@ -0,0 +1 @@
boticordpy

1
boticordpy/__init__.py Normal file
View file

@ -0,0 +1 @@
from .client import BoticordClient

44
boticordpy/client.py Normal file
View file

@ -0,0 +1,44 @@
from discord.ext import commands
from typing import Union
import asyncio
import aiohttp
from .modules import Bots, Servers, Users
class BoticordClient:
"""
This class is used to make it much easier to use the Boticord API.
Parameters
----------
bot : :class:`commands.Bot` | :class:`commands.AutoShardedBot`
The discord.py Bot instance
token : :class:`str`
boticord api key
Attributes
----------
Bots : :class:`modules.bots.Bots`
:class:`modules.bots.Bots` with all arguments filled.
Servers : :class:`modules.servers.Servers`
:class:`modules.servers.Servers` with all arguments filled.
Users : :class:`modules.users.Users`
:class:`modules.users.Users` with all arguments filled.
"""
__slots__ = (
"Bots",
"Servers",
"Users"
)
bot: Union[commands.Bot, commands.AutoShardedBot]
def __init__(self, bot, token=None, **kwargs):
loop = kwargs.get('loop') or asyncio.get_event_loop()
session = kwargs.get('session') or aiohttp.ClientSession(loop=loop)
self.Bots = Bots(bot, token=token, loop=loop, session=session)
self.Servers = Servers(bot, token=token, loop=loop, session=session)
self.Users = Users(token=token, loop=loop, session=session)

12
boticordpy/config.py Normal file
View file

@ -0,0 +1,12 @@
from . import exceptions
class Config:
local_api = "https://boticord.top/api"
general_api = "https://api.boticord.top/v1"
http_exceptions = {401: exceptions.Unauthorized,
403: exceptions.Forbidden,
404: exceptions.NotFound,
429: exceptions.ToManyRequests,
500: exceptions.ServerError,
503: exceptions.ServerError}

50
boticordpy/exceptions.py Normal file
View file

@ -0,0 +1,50 @@
class BoticordException(Exception):
"""Base exception class for boticordpy.
This could be caught to handle any exceptions thrown from this library.
"""
class HTTPException(BoticordException):
"""Exception that's thrown when an HTTP request operation fails.
Attributes
----------
response:
The response of the failed HTTP request.
message:
The text of the error. Could be an empty string.
"""
def __init__(self, response, message):
self.response = response
if isinstance(message, dict):
self.text = message.get('message', '')
self.code = message.get('code', 0)
else:
self.text = message
fmt = f"{self.response.reason} (Status code: {self.response.status})"
if self.text:
fmt = f"{fmt}: {self.text}"
super().__init__(fmt)
class Unauthorized(HTTPException):
"""Exception that's thrown when status code 401 occurs."""
class Forbidden(HTTPException):
"""Exception that's thrown when status code 403 occurs."""
class NotFound(HTTPException):
"""Exception that's thrown when status code 404 occurs."""
class ToManyRequests(HTTPException):
"""Exception that's thrown when status code 429 occurs."""
class ServerError(HTTPException):
"""Exception that's thrown when status code 500 or 503 occurs."""

View file

@ -0,0 +1,3 @@
from .bots import Bots
from .servers import Servers
from .users import Users

View file

@ -0,0 +1,86 @@
import json
from aiohttp import ClientResponse
from typing import Union
import aiohttp
import asyncio
from ..config import Config
async def _json_or_text(response: ClientResponse) -> Union[dict, str]:
text = await response.text()
if response.headers['Content-Type'] == 'application/json; charset=utf-8':
return json.loads(text)
return text
class Bots:
"""
Class with methods to work with Boticord API Bots.
Parameters
----------
bot : :class:`commands.Bot` | :class:`commands.AutoShardedBot`
The discord.py Bot instance
"""
def __init__(self, bot, **kwargs):
self.bot = bot
self.token = kwargs.get('token')
self.loop = kwargs.get('loop') or asyncio.get_event_loop()
self.session = kwargs.get('session') or aiohttp.ClientSession(loop=self.loop)
async def getBotInfo(self, botID: int):
"""
Returns information about discord bot with the given ID.
Parameters
----------
botID : :class:`int`
Discord Bot's ID
"""
headers = {}
async with self.session.get(f'{Config.general_api}/bot/{botID}', headers=headers) as resp:
data = await _json_or_text(resp)
status = Config.http_exceptions.get(resp.status)
if status is not None:
raise status
return data
async def getBotComments(self, botID: int):
"""
Returns comments of the discord bot with the given ID.
Parameters
----------
botID : :class:`int`
Discord Bot's ID
"""
headers = {}
async with self.session.get(f'{Config.general_api}/bot/{botID}/comments', headers=headers) as resp:
data = await _json_or_text(resp)
status = Config.http_exceptions.get(resp.status)
if status is not None:
raise status
return data
async def postStats(self, stats: dict):
"""
Post stats to Boticord API.
Parameters
----------
stats: :class:`dict`
A dictionary of {``guilds``: :class:`int`, ``shards``: :class:`int`, ``users``: :class:`int`}
"""
if not self.token:
return "Require Authentication"
headers = {"Authorization": self.token}
async with self.session.post(f'{Config.local_api}/stats', headers=headers, json=stats) as resp:
data = await _json_or_text(resp)
status = Config.http_exceptions.get(resp.status)
if status is not None:
raise status
return data

View file

@ -0,0 +1,108 @@
import json
from aiohttp import ClientResponse
from typing import Union
import aiohttp
import asyncio
import discord
from ..config import Config
async def _json_or_text(response: ClientResponse) -> Union[dict, str]:
text = await response.text()
if response.headers['Content-Type'] == 'application/json; charset=utf-8':
return json.loads(text)
return text
class Servers:
"""
Class with methods to work with Boticord API Servers.
Parameters
----------
bot : :class:`commands.Bot` | :class:`commands.AutoShardedBot`
The discord.py Bot instance
"""
def __init__(self, bot, **kwargs):
self.bot = bot
self.token = kwargs.get('token')
self.loop = kwargs.get('loop') or asyncio.get_event_loop()
self.session = kwargs.get('session') or aiohttp.ClientSession(loop=self.loop)
async def getServerInfo(self, serverID: int):
"""
Returns information about discord server with the given ID.
Parameters
----------
serverID : :class:`int`
Discord Server's ID
"""
headers = {}
async with self.session.get(f'{Config.general_api}/server/{serverID}', headers=headers) as resp:
data = await _json_or_text(resp)
status = Config.http_exceptions.get(resp.status)
if status is not None:
raise status
return data
async def getServerComments(self, serverID: int):
"""
Returns comments of the discord server with the given ID.
Parameters
----------
serverID : :class:`int`
Discord Server's ID
"""
headers = {}
async with self.session.get(f'{Config.general_api}/server/{serverID}/comments', headers=headers) as resp:
data = await _json_or_text(resp)
status = Config.http_exceptions.get(resp.status)
if status is not None:
raise status
return data
async def postServerStats(self, message: discord.Message, custom_stats: dict = None):
"""
Post server stats to Boticord API.
Parameters
----------
message: :class:`discord.Message`
Message object of used command.
custom_stats: :class:`dict`
Dict with custom server stats. (Optional)
"""
if not self.token:
return "Require Authentication"
if custom_stats is None:
guild = message.guild
guild_owner = guild.owner
stats = {
"serverID": str(guild.id),
"up": 1,
"status": 1,
"serverName": guild.name,
"serverAvatar": str(guild.icon_url),
"serverMembersAllCount": guild.member_count,
"serverMembersOnlineCount": 0,
"serverOwnerTag": guild_owner.name + "#" + guild_owner.discriminator,
"serverOwnerID": str(guild_owner.id)
}
else:
stats = custom_stats
headers = {"Authorization": self.token}
async with self.session.post(f'{Config.general_api}/server', headers=headers, json=stats) as resp:
data = await _json_or_text(resp)
status = Config.http_exceptions.get(resp.status)
if status is not None:
raise status
return data

View file

@ -0,0 +1,78 @@
import json
from aiohttp import ClientResponse
from typing import Union
import aiohttp
import asyncio
from ..config import Config
async def _json_or_text(response: ClientResponse) -> Union[dict, str]:
text = await response.text()
if response.headers['Content-Type'] == 'application/json; charset=utf-8':
return json.loads(text)
return text
class Users:
"""
Class with methods to work with Boticord API Users.
"""
def __init__(self, **kwargs):
self.token = kwargs.get('token')
self.loop = kwargs.get('loop') or asyncio.get_event_loop()
self.session = kwargs.get('session') or aiohttp.ClientSession(loop=self.loop)
async def getUserInfo(self, userID: int):
"""
Returns information about discord user with the given ID.
Parameters
----------
userID : :class:`int`
Discord User's ID
"""
headers = {}
async with self.session.get(f'{Config.general_api}/profile/{userID}', headers=headers) as resp:
data = await _json_or_text(resp)
status = Config.http_exceptions.get(resp.status)
if status is not None:
raise status
return data
async def getUserComments(self, userID: int):
"""
Returns comments of discord user with the given ID.
Parameters
----------
userID : :class:`int`
Discord User's ID
"""
headers = {}
async with self.session.get(f'{Config.general_api}/profile/{userID}/comments', headers=headers) as resp:
data = await _json_or_text(resp)
status = Config.http_exceptions.get(resp.status)
if status is not None:
raise status
return data
async def getUserBots(self, userID: int):
"""
Returns bots of discord user with the given ID.
Parameters
----------
userID : :class:`int`
Discord User's ID
"""
headers = {}
async with self.session.get(f'{Config.general_api}/bots/{userID}', headers=headers) as resp:
data = await _json_or_text(resp)
status = Config.http_exceptions.get(resp.status)
if status is not None:
raise status
return data

20
docs/Makefile Normal file
View file

@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

59
docs/conf.py Normal file
View file

@ -0,0 +1,59 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# 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.
#
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
# -- Project information -----------------------------------------------------
project = 'BoticordPY'
copyright = '2021, Grey Cat'
author = 'Grey Cat'
# The full version, including alpha/beta/rc tags
release = '1.3.2'
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.napoleon',
'sphinx.ext.ifconfig',
'sphinx_rtd_theme'
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = "sphinx_rtd_theme"
html_show_sourcelink = False
# 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,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

12
docs/exceptions.rst Normal file
View file

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

29
docs/index.rst Normal file
View file

@ -0,0 +1,29 @@
.. 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
exceptions
Links
=====
* :ref:`search`
* `PyPi <https://pypi.org/project/boticordpy>`_
* `GitHub <https://github.com/grey-cat-1908/boticordpy>`_
* `Boticord <https://boticord.top/>`_

13
docs/main.rst Normal file
View file

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

23
docs/modules.rst Normal file
View file

@ -0,0 +1,23 @@
.. 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:

50
docs/quickstart.rst Normal file
View file

@ -0,0 +1,50 @@
.. 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
Post Bot Stats
-------------------------
Let's post our bot's stats to Boticord.
::
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_connect():
stats = {"servers": len(bot.guilds), "shards": bot.shard_count, "users": len(bot.users)}
await boticord.Bots.postStats(stats)
bot.run("your-bot-token")
..

1
docs/requirements.txt Normal file
View file

@ -0,0 +1 @@
boticordpy

15
examples/postdata.py Normal file
View file

@ -0,0 +1,15 @@
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_connect():
stats = {"servers": len(bot.guilds), "shards": bot.shard_count, "users": len(bot.users)}
await boticord.Bots.postStats(stats)
bot.run("your-bot-token")

2
requirements.txt Normal file
View file

@ -0,0 +1,2 @@
discord.py
aiohttp

2
setuo.cfg Normal file
View file

@ -0,0 +1,2 @@
[metadata]
description-file = README.md

29
setup.py Normal file
View file

@ -0,0 +1,29 @@
import pathlib
from setuptools import setup
# The directory containing this file
HERE = pathlib.Path(__file__).parent
# The text of the README file
README = (HERE / "README.md").read_text(encoding="utf8")
# This call to setup() does all the work
setup(
name="boticordpy",
packages = ['boticordpy'],
version="1.3.5",
description="Simple Python Module for boticord api",
long_description=README,
long_description_content_type="text/markdown",
url="https://github.com/grey-cat-1908/boticordpy",
author="KerdokuCat",
author_email="support@kerdoku.top",
license="MIT",
classifiers=[
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
],
install_requires=["discord.py", "aiohttp"],
)