mirror of
https://github.com/MelisaDev/melisa.git
synced 2024-09-22 19:22:01 +03:00
docs, update docstrings, fix recursion
This commit is contained in:
parent
345a728973
commit
a5ebb9a972
15 changed files with 612 additions and 45 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -24,7 +24,7 @@ _testing.py
|
||||||
# Packaging
|
# Packaging
|
||||||
*.egg-info
|
*.egg-info
|
||||||
bin
|
bin
|
||||||
build
|
docs/build
|
||||||
dist
|
dist
|
||||||
MANIFEST
|
MANIFEST
|
||||||
|
|
||||||
|
|
10
.readthedocs.yml
Normal file
10
.readthedocs.yml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
sphinx:
|
||||||
|
configuration: docs/source/conf.py
|
||||||
|
|
||||||
|
python:
|
||||||
|
version: "3.8"
|
||||||
|
install:
|
||||||
|
- requirements: requirements.txt
|
||||||
|
- requirements: docs-requirements.txt
|
3
docs-requirements.txt
Normal file
3
docs-requirements.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
furo
|
||||||
|
sphinxcontrib_trio
|
||||||
|
sphinx_design
|
20
docs/Makefile
Normal file
20
docs/Makefile
Normal 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 = source
|
||||||
|
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)
|
37
docs/make.bat
Normal file
37
docs/make.bat
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
@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
|
||||||
|
|
||||||
|
@pause
|
46
docs/source/_static/custom.css
Normal file
46
docs/source/_static/custom.css
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
.py-attribute-table {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: row;
|
||||||
|
margin: 0 2em;
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.py-attribute-table-column {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.py-attribute-table-column:not(:first-child) {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.py-attribute-table-column > span {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
main .py-attribute-table-column > ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 4px 0;
|
||||||
|
padding-left: 0;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.py-attribute-table-entry {
|
||||||
|
margin: 0;
|
||||||
|
padding: 2px 0 2px 0.2em;
|
||||||
|
display: flex;
|
||||||
|
line-height: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.py-attribute-table-entry > a {
|
||||||
|
padding-left: 0.5em;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.py-attribute-table-badge {
|
||||||
|
flex-basis: 3em;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 0.9em;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
16
docs/source/client.rst
Normal file
16
docs/source/client.rst
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
.. currentmodule:: melisa
|
||||||
|
|
||||||
|
Melisa Module
|
||||||
|
=============
|
||||||
|
|
||||||
|
Client
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. attributetable:: Client
|
||||||
|
|
||||||
|
.. autoclass:: Client
|
||||||
|
:exclude-members: listen
|
||||||
|
:inherited-members:
|
||||||
|
|
||||||
|
.. automethod:: Client.listen()
|
||||||
|
:decorator:
|
75
docs/source/conf.py
Normal file
75
docs/source/conf.py
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# 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 -----------------------------------------------------
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
sys.path.append(os.path.abspath("../.."))
|
||||||
|
sys.path.append(os.path.abspath('extensions'))
|
||||||
|
|
||||||
|
|
||||||
|
project = 'Melisa'
|
||||||
|
copyright = '2022, MelisaDev'
|
||||||
|
author = 'MelisaDev'
|
||||||
|
|
||||||
|
# The full version, including alpha/beta/rc tags
|
||||||
|
release = '0.0.1'
|
||||||
|
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
|
extensions = [
|
||||||
|
'sphinx_design',
|
||||||
|
"sphinx.ext.napoleon",
|
||||||
|
"sphinx.ext.autodoc",
|
||||||
|
"sphinx.ext.viewcode",
|
||||||
|
"sphinx.ext.autosectionlabel",
|
||||||
|
"sphinx.ext.extlinks",
|
||||||
|
"sphinxcontrib_trio",
|
||||||
|
"attributable"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
exclude_patterns = []
|
||||||
|
|
||||||
|
intersphinx_mapping = {
|
||||||
|
"py": ("https://docs.python.org/3", None),
|
||||||
|
"aiohttp": ("https://docs.aiohttp.org/en/stable/", None),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
|
html_theme = 'furo'
|
||||||
|
html_theme_options = {
|
||||||
|
"sidebar_hide_name": True,
|
||||||
|
}
|
||||||
|
pygments_style = 'monokai'
|
||||||
|
default_dark_mode = True
|
||||||
|
html_static_path = ['_static']
|
||||||
|
html_css_files = ["custom.css"]
|
||||||
|
|
||||||
|
rst_prolog = """
|
||||||
|
.. |coro| replace:: This function is a |coroutine_link|_.
|
||||||
|
.. |maybecoro| replace:: This function *could be a* |coroutine_link|_.
|
||||||
|
.. |coroutine_link| replace:: *coroutine*
|
||||||
|
.. _coroutine_link: https://docs.python.org/3/library/asyncio-task.html#coroutine
|
||||||
|
"""
|
286
docs/source/extensions/attributable.py
Normal file
286
docs/source/extensions/attributable.py
Normal file
|
@ -0,0 +1,286 @@
|
||||||
|
"""
|
||||||
|
I am so sorry, but i found this extension somewhere in the internet.
|
||||||
|
IT LOOKS REALLY BEAUTIFUL!
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sphinx.util.docutils import SphinxDirective
|
||||||
|
from sphinx.locale import _
|
||||||
|
from docutils import nodes
|
||||||
|
from sphinx import addnodes
|
||||||
|
|
||||||
|
from collections import OrderedDict, namedtuple
|
||||||
|
import importlib
|
||||||
|
import inspect
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
class attributetable(nodes.General, nodes.Element):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class attributetablecolumn(nodes.General, nodes.Element):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class attributetabletitle(nodes.TextElement):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class attributetableplaceholder(nodes.General, nodes.Element):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class attributetablebadge(nodes.TextElement):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class attributetable_item(nodes.Part, nodes.Element):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def visit_attributetable_node(self, node):
|
||||||
|
class_ = node["python-class"]
|
||||||
|
self.body.append(
|
||||||
|
f'<div class="py-attribute-table" data-move-to-id="{class_}">'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def visit_attributetablecolumn_node(self, node):
|
||||||
|
self.body.append(self.starttag(
|
||||||
|
node, 'div', CLASS='py-attribute-table-column')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def visit_attributetabletitle_node(self, node):
|
||||||
|
self.body.append(self.starttag(node, 'span'))
|
||||||
|
|
||||||
|
|
||||||
|
def visit_attributetablebadge_node(self, node):
|
||||||
|
attributes = {
|
||||||
|
'class': 'py-attribute-table-badge',
|
||||||
|
'title': node['badge-type'],
|
||||||
|
}
|
||||||
|
self.body.append(self.starttag(node, 'span', **attributes))
|
||||||
|
|
||||||
|
|
||||||
|
def visit_attributetable_item_node(self, node):
|
||||||
|
self.body.append(self.starttag(
|
||||||
|
node, 'li', CLASS='py-attribute-table-entry')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def depart_attributetable_node(self, node):
|
||||||
|
self.body.append('</div>')
|
||||||
|
|
||||||
|
|
||||||
|
def depart_attributetablecolumn_node(self, node):
|
||||||
|
self.body.append('</div>')
|
||||||
|
|
||||||
|
|
||||||
|
def depart_attributetabletitle_node(self, node):
|
||||||
|
self.body.append('</span>')
|
||||||
|
|
||||||
|
|
||||||
|
def depart_attributetablebadge_node(self, node):
|
||||||
|
self.body.append('</span>')
|
||||||
|
|
||||||
|
|
||||||
|
def depart_attributetable_item_node(self, node):
|
||||||
|
self.body.append('</li>')
|
||||||
|
|
||||||
|
|
||||||
|
_name_parser_regex = re.compile(r'(?P<module>[\w.]+\.)?(?P<name>\w+)')
|
||||||
|
|
||||||
|
|
||||||
|
class PyAttributeTable(SphinxDirective):
|
||||||
|
has_content = False
|
||||||
|
required_arguments = 1
|
||||||
|
optional_arguments = 0
|
||||||
|
final_argument_whitespace = False
|
||||||
|
option_spec = {}
|
||||||
|
|
||||||
|
def parse_name(self, content):
|
||||||
|
path, name = _name_parser_regex.match(content).groups()
|
||||||
|
if path:
|
||||||
|
modulename = path.rstrip('.')
|
||||||
|
else:
|
||||||
|
modulename = self.env.temp_data.get('autodoc:module')
|
||||||
|
if not modulename:
|
||||||
|
modulename = self.env.ref_context.get('py:module')
|
||||||
|
if modulename is None:
|
||||||
|
raise RuntimeError('modulename somehow None for %s in %s.' % (
|
||||||
|
content, self.env.docname))
|
||||||
|
|
||||||
|
return modulename, name
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""If you're curious on the HTML this is meant to generate:
|
||||||
|
<div class="py-attribute-table">
|
||||||
|
<div class="py-attribute-table-column">
|
||||||
|
<span>_('Attributes')</span>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="...">
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="py-attribute-table-column">
|
||||||
|
<span>_('Methods')</span>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="..."></a>
|
||||||
|
<span class="py-attribute-badge" title="decorator">D</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
However, since this requires the tree to be complete
|
||||||
|
and parsed, it'll need to be done at a different stage and then
|
||||||
|
replaced.
|
||||||
|
"""
|
||||||
|
content = self.arguments[0].strip()
|
||||||
|
node = attributetableplaceholder('')
|
||||||
|
modulename, name = self.parse_name(content)
|
||||||
|
node['python-doc'] = self.env.docname
|
||||||
|
node['python-module'] = modulename
|
||||||
|
node['python-class'] = name
|
||||||
|
node['python-full-name'] = f'{modulename}.{name}'
|
||||||
|
return [node]
|
||||||
|
|
||||||
|
|
||||||
|
def build_lookup_table(env):
|
||||||
|
# Given an environment, load up a lookup table of
|
||||||
|
# full-class-name: objects
|
||||||
|
result = {}
|
||||||
|
domain = env.domains['py']
|
||||||
|
|
||||||
|
ignored = {
|
||||||
|
'data', 'exception', 'module', 'class',
|
||||||
|
}
|
||||||
|
|
||||||
|
for (fullname, _, objtype, docname, _, _) in domain.get_objects():
|
||||||
|
if objtype in ignored:
|
||||||
|
continue
|
||||||
|
|
||||||
|
classname, _, child = fullname.rpartition('.')
|
||||||
|
try:
|
||||||
|
result[classname].append(child)
|
||||||
|
except KeyError:
|
||||||
|
result[classname] = [child]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
TableElement = namedtuple('TableElement', 'fullname label badge')
|
||||||
|
|
||||||
|
|
||||||
|
def process_attributetable(app, doctree, fromdocname):
|
||||||
|
env = app.builder.env
|
||||||
|
|
||||||
|
lookup = build_lookup_table(env)
|
||||||
|
for node in doctree.traverse(attributetableplaceholder):
|
||||||
|
modulename, classname, fullname = node['python-module'], node['python-class'], node['python-full-name']
|
||||||
|
groups = get_class_results(lookup, modulename, classname, fullname)
|
||||||
|
table = attributetable('')
|
||||||
|
for label, subitems in groups.items():
|
||||||
|
if not subitems:
|
||||||
|
continue
|
||||||
|
table.append(class_results_to_node(
|
||||||
|
label, sorted(subitems, key=lambda c: c.label)))
|
||||||
|
|
||||||
|
table['python-class'] = fullname
|
||||||
|
|
||||||
|
node.replace_self([table] if table else [])
|
||||||
|
|
||||||
|
|
||||||
|
def get_class_results(lookup, modulename, name, fullname):
|
||||||
|
module = importlib.import_module(modulename)
|
||||||
|
cls = getattr(module, name)
|
||||||
|
|
||||||
|
groups = OrderedDict([
|
||||||
|
(_('Attributes'), []),
|
||||||
|
(_('Methods'), []),
|
||||||
|
])
|
||||||
|
|
||||||
|
try:
|
||||||
|
members = lookup[fullname]
|
||||||
|
except KeyError:
|
||||||
|
return groups
|
||||||
|
|
||||||
|
for attr in members:
|
||||||
|
attrlookup = f'{fullname}.{attr}'
|
||||||
|
key = _('Attributes')
|
||||||
|
badge = None
|
||||||
|
label = attr
|
||||||
|
value = None
|
||||||
|
|
||||||
|
for base in cls.__mro__:
|
||||||
|
value = base.__dict__.get(attr)
|
||||||
|
if value is not None:
|
||||||
|
break
|
||||||
|
|
||||||
|
if value is not None:
|
||||||
|
doc = value.__doc__ or ''
|
||||||
|
if inspect.iscoroutinefunction(value) or doc.startswith('|coro|'):
|
||||||
|
key = _('Methods')
|
||||||
|
badge = attributetablebadge('async', 'async')
|
||||||
|
badge['badge-type'] = _('coroutine')
|
||||||
|
elif isinstance(value, classmethod):
|
||||||
|
key = _('Methods')
|
||||||
|
label = f'{name}.{attr}'
|
||||||
|
badge = attributetablebadge('cls', 'cls')
|
||||||
|
badge['badge-type'] = _('classmethod')
|
||||||
|
elif (
|
||||||
|
inspect.isfunction(value)
|
||||||
|
or isinstance(value, staticmethod)
|
||||||
|
):
|
||||||
|
if (
|
||||||
|
doc.startswith(('A decorator', 'A shortcut decorator'))
|
||||||
|
or label in ("event", "loop")
|
||||||
|
):
|
||||||
|
# finicky but surprisingly consistent
|
||||||
|
badge = attributetablebadge('@', '@')
|
||||||
|
badge['badge-type'] = _('decorator')
|
||||||
|
key = _('Methods')
|
||||||
|
else:
|
||||||
|
key = _('Methods')
|
||||||
|
badge = attributetablebadge('def', 'def')
|
||||||
|
badge['badge-type'] = _('method')
|
||||||
|
|
||||||
|
groups[key].append(TableElement(
|
||||||
|
fullname=attrlookup, label=label, badge=badge))
|
||||||
|
|
||||||
|
return groups
|
||||||
|
|
||||||
|
|
||||||
|
def class_results_to_node(key, elements):
|
||||||
|
title = attributetabletitle(key, key)
|
||||||
|
ul = nodes.bullet_list('')
|
||||||
|
for element in elements:
|
||||||
|
ref = nodes.reference('', '', internal=True,
|
||||||
|
refuri='#' + element.fullname,
|
||||||
|
anchorname='',
|
||||||
|
*[nodes.Text(element.label)])
|
||||||
|
para = addnodes.compact_paragraph('', '', ref)
|
||||||
|
if element.badge is not None:
|
||||||
|
ul.append(attributetable_item('', element.badge, para))
|
||||||
|
else:
|
||||||
|
ul.append(attributetable_item('', para))
|
||||||
|
|
||||||
|
return attributetablecolumn('', title, ul)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
app.add_directive('attributetable', PyAttributeTable)
|
||||||
|
app.add_node(attributetable, html=(
|
||||||
|
visit_attributetable_node, depart_attributetable_node))
|
||||||
|
app.add_node(attributetablecolumn, html=(
|
||||||
|
visit_attributetablecolumn_node, depart_attributetablecolumn_node))
|
||||||
|
app.add_node(attributetabletitle, html=(
|
||||||
|
visit_attributetabletitle_node, depart_attributetabletitle_node))
|
||||||
|
app.add_node(attributetablebadge, html=(
|
||||||
|
visit_attributetablebadge_node, depart_attributetablebadge_node))
|
||||||
|
app.add_node(attributetable_item, html=(
|
||||||
|
visit_attributetable_item_node, depart_attributetable_item_node))
|
||||||
|
app.add_node(attributetableplaceholder)
|
||||||
|
app.connect('doctree-resolved', process_attributetable)
|
15
docs/source/index.rst
Normal file
15
docs/source/index.rst
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
Welcome to Melisa's documentation!
|
||||||
|
==================================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: Documentation:
|
||||||
|
|
||||||
|
client
|
||||||
|
models/index
|
||||||
|
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
|
* :ref:`search`
|
7
docs/source/models/index.rst
Normal file
7
docs/source/models/index.rst
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Melisa Models
|
||||||
|
=====================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
user
|
30
docs/source/models/user.rst
Normal file
30
docs/source/models/user.rst
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
.. currentmodule:: melisa.models
|
||||||
|
|
||||||
|
Melisa Models User
|
||||||
|
===========================
|
||||||
|
|
||||||
|
User
|
||||||
|
----
|
||||||
|
|
||||||
|
PremiumTypes
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: PremiumTypes()
|
||||||
|
|
||||||
|
UserFlags
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: UserFlags()
|
||||||
|
|
||||||
|
VisibilityTypes
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: VisibilityTypes()
|
||||||
|
|
||||||
|
User
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
.. attributetable:: User
|
||||||
|
|
||||||
|
.. autoclass:: User()
|
||||||
|
|
|
@ -11,7 +11,33 @@ from typing import Dict, List, Union
|
||||||
|
|
||||||
|
|
||||||
class Client:
|
class Client:
|
||||||
def __init__(self, token, intents, **kwargs):
|
"""
|
||||||
|
This is the main instance which is between the programmer and the Discord API.
|
||||||
|
|
||||||
|
This Client represents your bot.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
token : :class:`str`
|
||||||
|
The token to login (you can found it in the developer portal)
|
||||||
|
intents : :class:`~objects.app.intents.Intents`
|
||||||
|
The Discord Intents values.
|
||||||
|
activity : :class:`~models.user.presence.BotActivity`
|
||||||
|
The Activity to set (on connecting)
|
||||||
|
status : :class:`str`
|
||||||
|
The Status to set (on connecting). Can be generated using :class:`~models.user.presence.StatusType`
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
user: :class:`~models.user.user.User`
|
||||||
|
The user object of the client
|
||||||
|
http: :class:`~core.http.HTTPClient`
|
||||||
|
HTTP client for the http-requests to the Discord API
|
||||||
|
shards: :class:`Dict[int, Shard]`
|
||||||
|
Bot's shards.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, token, intents, *, activity=None, status: str = None):
|
||||||
self.shards: Dict[int, Shard] = {}
|
self.shards: Dict[int, Shard] = {}
|
||||||
self.http = HTTPClient(token)
|
self.http = HTTPClient(token)
|
||||||
self._events = {}
|
self._events = {}
|
||||||
|
@ -19,26 +45,26 @@ class Client:
|
||||||
self.guilds = []
|
self.guilds = []
|
||||||
self.user = None
|
self.user = None
|
||||||
|
|
||||||
self.loop = asyncio.get_event_loop()
|
self._loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
self._gateway_info = self.loop.run_until_complete(self._get_gateway())
|
self._gateway_info = self._loop.run_until_complete(self._get_gateway())
|
||||||
|
|
||||||
self.intents = intents
|
self.intents = intents
|
||||||
self._token = token
|
self._token = token
|
||||||
|
|
||||||
self._activity = kwargs.get("activity")
|
self._activity = activity
|
||||||
self._status = kwargs.get("status")
|
self._status = status
|
||||||
|
|
||||||
async def _get_gateway(self):
|
async def _get_gateway(self):
|
||||||
"""Get Gateway information"""
|
"""Get Gateway information"""
|
||||||
return GatewayBotInfo.from_dict(await self.http.get("gateway/bot"))
|
return GatewayBotInfo.from_dict(await self.http.get("gateway/bot"))
|
||||||
|
|
||||||
def listen(self, callback: Coro):
|
def listen(self, callback: Coro):
|
||||||
"""Method to set the listener.
|
"""Method or Decorator to set the listener.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
callback (:obj:`function`)
|
callback : :class:`melisa.utils.types.Coro`
|
||||||
Coroutine Callback Function
|
Coroutine Callback Function
|
||||||
"""
|
"""
|
||||||
if not asyncio.iscoroutinefunction(callback):
|
if not asyncio.iscoroutinefunction(callback):
|
||||||
|
@ -53,8 +79,8 @@ class Client:
|
||||||
"""
|
"""
|
||||||
inited_shard = Shard(self, 0, 1)
|
inited_shard = Shard(self, 0, 1)
|
||||||
|
|
||||||
asyncio.ensure_future(inited_shard.launch(activity=self._activity, status=self._status), loop=self.loop)
|
asyncio.ensure_future(inited_shard.launch(activity=self._activity, status=self._status), loop=self._loop)
|
||||||
self.loop.run_forever()
|
self._loop.run_forever()
|
||||||
|
|
||||||
def run_shards(self, num_shards: int, *, shard_ids: List[int] = None):
|
def run_shards(self, num_shards: int, *, shard_ids: List[int] = None):
|
||||||
"""
|
"""
|
||||||
|
@ -64,9 +90,6 @@ class Client:
|
||||||
----------
|
----------
|
||||||
num_shards : :class:`int`
|
num_shards : :class:`int`
|
||||||
The endpoint to send the request to.
|
The endpoint to send the request to.
|
||||||
|
|
||||||
Keyword Arguments:
|
|
||||||
|
|
||||||
shard_ids: Optional[:class:`List[int]`]
|
shard_ids: Optional[:class:`List[int]`]
|
||||||
List of Ids of shards to start.
|
List of Ids of shards to start.
|
||||||
"""
|
"""
|
||||||
|
@ -76,8 +99,8 @@ class Client:
|
||||||
for shard_id in shard_ids:
|
for shard_id in shard_ids:
|
||||||
inited_shard = Shard(self, shard_id, num_shards)
|
inited_shard = Shard(self, shard_id, num_shards)
|
||||||
|
|
||||||
asyncio.ensure_future(inited_shard.launch(activity=self._activity, status=self._status), loop=self.loop)
|
asyncio.ensure_future(inited_shard.launch(activity=self._activity, status=self._status), loop=self._loop)
|
||||||
self.loop.run_forever()
|
self._loop.run_forever()
|
||||||
|
|
||||||
def run_autosharded(self):
|
def run_autosharded(self):
|
||||||
"""
|
"""
|
||||||
|
@ -89,8 +112,8 @@ class Client:
|
||||||
for shard_id in shard_ids:
|
for shard_id in shard_ids:
|
||||||
inited_shard = Shard(self, shard_id, num_shards)
|
inited_shard = Shard(self, shard_id, num_shards)
|
||||||
|
|
||||||
asyncio.ensure_future(inited_shard.launch(activity=self._activity, status=self._status), loop=self.loop)
|
asyncio.ensure_future(inited_shard.launch(activity=self._activity, status=self._status), loop=self._loop)
|
||||||
self.loop.run_forever()
|
self._loop.run_forever()
|
||||||
|
|
||||||
async def fetch_user(self, user_id: Union[Snowflake, str, int]):
|
async def fetch_user(self, user_id: Union[Snowflake, str, int]):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -95,13 +95,12 @@ class Gateway:
|
||||||
await self.resume()
|
await self.resume()
|
||||||
|
|
||||||
async def check_heartbeating(self):
|
async def check_heartbeating(self):
|
||||||
await asyncio.sleep(20)
|
while True:
|
||||||
|
await asyncio.sleep(20)
|
||||||
|
|
||||||
if self._last_send + 60.0 < time.perf_counter():
|
if self._last_send + 60.0 < time.perf_counter():
|
||||||
await self.ws.close(code=4000)
|
await self.ws.close(code=4000)
|
||||||
await self.handle_close(4000)
|
await self.handle_close(4000)
|
||||||
|
|
||||||
await self.check_heartbeating()
|
|
||||||
|
|
||||||
async def send(self, payload: str) -> None:
|
async def send(self, payload: str) -> None:
|
||||||
await self.ws.send_str(payload)
|
await self.ws.send_str(payload)
|
||||||
|
|
|
@ -111,36 +111,40 @@ class User(APIObjectBase):
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
id:
|
id: :class:`~melisa.utils.types.Snowflake`
|
||||||
the user's id
|
the user's id
|
||||||
username:
|
username: :class:`str`
|
||||||
the user's username, not unique across the platform
|
the user's username, not unique across the platform
|
||||||
discriminator:
|
discriminator: :class:`int`
|
||||||
the user's 4-digit discord-tag
|
the user's 4-digit discord-tag
|
||||||
avatar:
|
avatar: :class:`str`
|
||||||
the user's avatar hash
|
the user's avatar hash
|
||||||
bot:
|
bot: :class:`bool`
|
||||||
whether the user belongs to an OAuth2 application
|
whether the user belongs to an OAuth2 application
|
||||||
system:
|
system: :class:`bool`
|
||||||
whether the user is an Official Discord System user (part of the urgent message system)
|
whether the user is an Official Discord System user (part of the urgent message system)
|
||||||
mfa_enabled:
|
mfa_enabled: :class:`bool`
|
||||||
whether the user has two factor enabled on their account
|
whether the user has two factor enabled on their account
|
||||||
banner:
|
banner: :class:`str`
|
||||||
the user's banner hash
|
the user's banner hash
|
||||||
accent_color:
|
accent_color: :class:`int`
|
||||||
the user's banner color encoded as an integer representation of hexadecimal color code
|
the user's banner color encoded as an integer representation of hexadecimal color code
|
||||||
locale:
|
locale: :class:`str`
|
||||||
the user's chosen language option
|
the user's chosen language option
|
||||||
verified:
|
verified: :class:`bool`
|
||||||
whether the email on this account has been verified
|
whether the email on this account has been verified
|
||||||
email:
|
email: :class:`str`
|
||||||
the user's email
|
the user's email
|
||||||
flags:
|
flags: :class:`~models.user.user.UserFlags`
|
||||||
the flags on a user's account
|
the flags on a user's account
|
||||||
premium_type:
|
premium_type: :class:`int`
|
||||||
the type of Nitro subscription on a user's account
|
the type of Nitro subscription on a user's account
|
||||||
public_flags:
|
public_flags: :class:`int`
|
||||||
the public flags on a user's account
|
the public flags on a user's account
|
||||||
|
premium: :class:`PremiumTypes`
|
||||||
|
The user their premium type in a usable enum.
|
||||||
|
mention: :class:`str`
|
||||||
|
The user's mention string. (<@id>)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
id: APINullable[Snowflake] = None
|
id: APINullable[Snowflake] = None
|
||||||
|
@ -187,10 +191,6 @@ class User(APIObjectBase):
|
||||||
""":class:`str`: The user's mention string. (<@id>)"""
|
""":class:`str`: The user's mention string. (<@id>)"""
|
||||||
return "<@{}>".format(self.id)
|
return "<@{}>".format(self.id)
|
||||||
|
|
||||||
@property
|
def avatar_url(self) -> str:
|
||||||
def avatar_url(self):
|
"""Avatar url (from the Discord CDN server)"""
|
||||||
"""Avatar url (from the discord cdn server)"""
|
return "https://cdn.discordapp.com/avatars/{}/{}.png?size=1024".format(self.id, self.avatar)
|
||||||
return (
|
|
||||||
"https://cdn.discordapp.com/avatars/{}/{}.png".format(self.id, self.avatar),
|
|
||||||
"?size=1024"
|
|
||||||
)
|
|
||||||
|
|
Loading…
Reference in a new issue