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
|
||||
*.egg-info
|
||||
bin
|
||||
build
|
||||
docs/build
|
||||
dist
|
||||
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:
|
||||
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.http = HTTPClient(token)
|
||||
self._events = {}
|
||||
|
@ -19,26 +45,26 @@ class Client:
|
|||
self.guilds = []
|
||||
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._token = token
|
||||
|
||||
self._activity = kwargs.get("activity")
|
||||
self._status = kwargs.get("status")
|
||||
self._activity = activity
|
||||
self._status = status
|
||||
|
||||
async def _get_gateway(self):
|
||||
"""Get Gateway information"""
|
||||
return GatewayBotInfo.from_dict(await self.http.get("gateway/bot"))
|
||||
|
||||
def listen(self, callback: Coro):
|
||||
"""Method to set the listener.
|
||||
"""Method or Decorator to set the listener.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
callback (:obj:`function`)
|
||||
callback : :class:`melisa.utils.types.Coro`
|
||||
Coroutine Callback Function
|
||||
"""
|
||||
if not asyncio.iscoroutinefunction(callback):
|
||||
|
@ -53,8 +79,8 @@ class Client:
|
|||
"""
|
||||
inited_shard = Shard(self, 0, 1)
|
||||
|
||||
asyncio.ensure_future(inited_shard.launch(activity=self._activity, status=self._status), loop=self.loop)
|
||||
self.loop.run_forever()
|
||||
asyncio.ensure_future(inited_shard.launch(activity=self._activity, status=self._status), loop=self._loop)
|
||||
self._loop.run_forever()
|
||||
|
||||
def run_shards(self, num_shards: int, *, shard_ids: List[int] = None):
|
||||
"""
|
||||
|
@ -64,9 +90,6 @@ class Client:
|
|||
----------
|
||||
num_shards : :class:`int`
|
||||
The endpoint to send the request to.
|
||||
|
||||
Keyword Arguments:
|
||||
|
||||
shard_ids: Optional[:class:`List[int]`]
|
||||
List of Ids of shards to start.
|
||||
"""
|
||||
|
@ -76,8 +99,8 @@ class Client:
|
|||
for shard_id in shard_ids:
|
||||
inited_shard = Shard(self, shard_id, num_shards)
|
||||
|
||||
asyncio.ensure_future(inited_shard.launch(activity=self._activity, status=self._status), loop=self.loop)
|
||||
self.loop.run_forever()
|
||||
asyncio.ensure_future(inited_shard.launch(activity=self._activity, status=self._status), loop=self._loop)
|
||||
self._loop.run_forever()
|
||||
|
||||
def run_autosharded(self):
|
||||
"""
|
||||
|
@ -89,8 +112,8 @@ class Client:
|
|||
for shard_id in shard_ids:
|
||||
inited_shard = Shard(self, shard_id, num_shards)
|
||||
|
||||
asyncio.ensure_future(inited_shard.launch(activity=self._activity, status=self._status), loop=self.loop)
|
||||
self.loop.run_forever()
|
||||
asyncio.ensure_future(inited_shard.launch(activity=self._activity, status=self._status), loop=self._loop)
|
||||
self._loop.run_forever()
|
||||
|
||||
async def fetch_user(self, user_id: Union[Snowflake, str, int]):
|
||||
"""
|
||||
|
|
|
@ -95,14 +95,13 @@ class Gateway:
|
|||
await self.resume()
|
||||
|
||||
async def check_heartbeating(self):
|
||||
while True:
|
||||
await asyncio.sleep(20)
|
||||
|
||||
if self._last_send + 60.0 < time.perf_counter():
|
||||
await self.ws.close(code=4000)
|
||||
await self.handle_close(4000)
|
||||
|
||||
await self.check_heartbeating()
|
||||
|
||||
async def send(self, payload: str) -> None:
|
||||
await self.ws.send_str(payload)
|
||||
|
||||
|
|
|
@ -111,36 +111,40 @@ class User(APIObjectBase):
|
|||
|
||||
Attributes
|
||||
----------
|
||||
id:
|
||||
id: :class:`~melisa.utils.types.Snowflake`
|
||||
the user's id
|
||||
username:
|
||||
username: :class:`str`
|
||||
the user's username, not unique across the platform
|
||||
discriminator:
|
||||
discriminator: :class:`int`
|
||||
the user's 4-digit discord-tag
|
||||
avatar:
|
||||
avatar: :class:`str`
|
||||
the user's avatar hash
|
||||
bot:
|
||||
bot: :class:`bool`
|
||||
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)
|
||||
mfa_enabled:
|
||||
mfa_enabled: :class:`bool`
|
||||
whether the user has two factor enabled on their account
|
||||
banner:
|
||||
banner: :class:`str`
|
||||
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
|
||||
locale:
|
||||
locale: :class:`str`
|
||||
the user's chosen language option
|
||||
verified:
|
||||
verified: :class:`bool`
|
||||
whether the email on this account has been verified
|
||||
email:
|
||||
email: :class:`str`
|
||||
the user's email
|
||||
flags:
|
||||
flags: :class:`~models.user.user.UserFlags`
|
||||
the flags on a user's account
|
||||
premium_type:
|
||||
premium_type: :class:`int`
|
||||
the type of Nitro subscription on a user's account
|
||||
public_flags:
|
||||
public_flags: :class:`int`
|
||||
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
|
||||
|
@ -187,10 +191,6 @@ class User(APIObjectBase):
|
|||
""":class:`str`: The user's mention string. (<@id>)"""
|
||||
return "<@{}>".format(self.id)
|
||||
|
||||
@property
|
||||
def avatar_url(self):
|
||||
"""Avatar url (from the discord cdn server)"""
|
||||
return (
|
||||
"https://cdn.discordapp.com/avatars/{}/{}.png".format(self.id, self.avatar),
|
||||
"?size=1024"
|
||||
)
|
||||
def avatar_url(self) -> str:
|
||||
"""Avatar url (from the Discord CDN server)"""
|
||||
return "https://cdn.discordapp.com/avatars/{}/{}.png?size=1024".format(self.id, self.avatar)
|
||||
|
|
Loading…
Reference in a new issue