Coder Social home page Coder Social logo

disco's Introduction

disco

PyPI PyPI TravisCI

Disco is an extensive and extendable Python 2.x/3.x library for the Discord API. Disco boasts the following major features:

  • Expressive, functional interface that gets out of the way
  • Built for high-performance and efficiency
  • Configurable and modular, take the bits you need
  • Full support for Python 2.x/3.x
  • Evented networking and IO using Gevent

Installation

Disco was built to run both as a generic-use library, and a standalone bot toolkit. Installing disco is as easy as running pip install disco-py, however some extra packages are recommended for power-users, namely:

Name Reason
requests[security] adds packages for a proper SSL implementation
ujson faster json parser, improves performance
erlpack (2.x), earl-etf (3.x) ETF parser run with the --encoder=etf flag
gipc Gevent IPC, required for autosharding

Examples

Simple bot using the builtin bot authoring tools:

from disco.bot import Bot, Plugin


class SimplePlugin(Plugin):
    # Plugins provide an easy interface for listening to Discord events
    @Plugin.listen('ChannelCreate')
    def on_channel_create(self, event):
        event.channel.send_message('Woah, a new channel huh!')

    # They also provide an easy-to-use command component
    @Plugin.command('ping')
    def on_ping_command(self, event):
        event.msg.reply('Pong!')

    # Which includes command argument parsing
    @Plugin.command('echo', '<content:str...>')
    def on_echo_command(self, event, content):
        event.msg.reply(content)

Using the default bot configuration, we can now run this script like so:

python -m disco.cli --token="MY_DISCORD_TOKEN" --run-bot --plugin simpleplugin

And commands can be triggered by mentioning the bot (configured by the BotConfig.command_require_mention flag):

disco's People

Contributors

a00git avatar b1naryth1ef avatar blindjoker avatar bunnyhero avatar butuzov avatar cakedan avatar casperdcl avatar elderlabs avatar enkoder avatar genesis-root avatar kevthegame-dev avatar kyriog avatar lewishogan avatar majora320 avatar maxer456 avatar mikevb1 avatar mrlotu avatar noahh99 avatar one-nub avatar pixelinc avatar seklfreak avatar slice avatar slicedlime avatar spencersharkey avatar swarley avatar thatguyjustin avatar thatiemsz avatar watchful1 avatar wolfiri avatar z64 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

disco's Issues

Not getting messages in a guild?

Hi

I'm trying to use your module, though I'm running through a lot of trouble. I'm using your example code from the home page, but my bot only answers to commands in DMs, not on the guild I added him (he's currently online, but doesn't answer to ping). Did I miss something?

Thanks

Voice

One of the big remaining tasks for me to feel comfortable moving disco out of the "early alpha" phase is a proper voice implementation. Me and @jhgg have talked in length about this, and thrown some ideas around, but I think the best path forward is to just take stab at it and try to figure out the sharp edges as we go.

Typo in README.md

"Disco was built to run both as a generic-use library, and a standalone bot toolkit. Installing disco is as easy as running pip install disco-py"

This should probably be "pip install disco.py". I'm very, very embarrassed to say how long this messed me up...

event instances but no access to CommandEvent class

I'm using vscode. It has this quirk, not sure about other IDEs. But I guess if it was common practice than vscode Python plugin would've taken it into account too.

I can write

from disco.bot import CommandEvent

but intellisense does not show CommandEvent there. And pylint can't see it either (flake8 can).
(UPD: python 3.4.3. Got ImportError: cannot import name 'CommandEvent'.)

Then, if I write

class SimplePlugin(Plugin):
    @Plugin.command('ping')
    def on_ping_command(self, event: CommandEvent):
        event.msg.reply('Pong!')

I have no autocompletion for event object properties and to type information popup.

As a workaround, I can write

from disco.types.message import Message

class SimplePlugin(Plugin):
    @Plugin.command('ping')
    def on_ping_command(self, event):
        msg = event.msg  # type: Message
        msg.reply('Pong!')

and get autocompletion and type information for msg at least.

The reason is that Python plugin for vscode does not look for imports and types information any further than __all__ in __init__.py, and there is no CommandEvent there. This behaviour can be considered questionable, but they might have their reasons too. Performance, for example.

I think it would be better design for disco.py itself if all the objects accessible to programmer will have classes properly accessible too.

UPD: I wrote all of this without actually running my code, relying only on IDE response. After getting ImportError on start, it's all more significant now.

python_disco doesn't dance

...isn't that the purpose of the library? The slogan for this library is "Discord Python library for people that like to dance", but, what does dancing have to do with anything? How do I get the dancing capabilities? I assume this means the bot can "jump", I guess through dependencies, if that makes sense? Like, the mod log plugin can "jump", aka raise the bans to the mod log, but what else can the dancing do?

Python 3.8 Support

Hi, I was looking to use this library, but it doesn't support Python 3.8, due to gevent still being on 1.3. I would've bumped the version up to 1.5 in a PR, which is what supports 3.8, but that version of gevent is still in an alpha stage. Every other dependency works out of the box, from what I can tell.

Infinite recursion when accessing an attribute of GatewayEvent

For example, with:

class Cat(Plugin):
    @Plugin.listen('Ready')
    def meow(self, event):
        print(event.guilds)

I get the following error:

Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/gevent/greenlet.py", line 536, in run
    result = self._run(*self.args, **self.kwargs)
  File "/usr/lib/python3.6/site-packages/holster/emitter.py", line 70, in _call
    func(*args, **kwargs)
  File "/usr/lib/python3.6/site-packages/holster/emitter.py", line 45, in __call__
    return self.func(*args, **kwargs)
  File "/home/crudites/Python/disco/bot/plugin.py", line 284, in dispatch
    if hasattr(event, 'guild'):
  File "/home/crudites/Python/disco/gateway/events.py", line 67, in __getattr__
    if hasattr(self, '_proxy'):
  File "/home/crudites/Python/disco/gateway/events.py", line 67, in __getattr__
    if hasattr(self, '_proxy'):
  File "/home/crudites/Python/disco/gateway/events.py", line 67, in __getattr__
    if hasattr(self, '_proxy'):
  [Previous line repeated 284 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object

... which is kind of understandable when you look a the definition of GatewayEvent.__getattr__.


The problem comes from the fact that hasattr() is implemented using getattr() in Python, thus some weird gymnastic is required to do what you're trying to do there.

I suggest the following modification for GatewayEvent:

def __getattr__(self, name):
    try:
        object.__getattribute__(self, '_proxy')
    except AttributeError:
        return object.__getattribute__(self, name)
    else:
        return getattr(object.__getattribute__(self, self._proxy), name)

I also modified the last line so that when self._proxy is not an attribute of self, it does not get stuck into an infinite recursion as well, and properly propagates the exception.

I tested it locally, and it works.

Missing license

There is a badge claiming that the repository is under the MIT license, however, the license doesn't appear anywhere. If it could be added that would make contributions much easier.

disco.api.client.APIClient.guilds_members_list only returns 1 member

The official API documentation indicates that the default number of members returned is 1.

The current implementation of disco.api.client.APIClient.guilds_members_list uses the default value with no possibility of setting limit to a desired value.

Since the maximum possible value for limit is 1000, it might be a good idea to implement an auxillary function that returns the whole list of guild members, by concatenating multiple calls to the API.

AttributeError: python3: undefined symbol: opus_strerror

Following your examples, I was attempting to re-create the music.py plugin, into my bot. However, it joins fine, but when I try to play a youtube video, I receive this error:

... Some gevent stuff, I don't believe it to be relavent, just dispatching the event.
in dispatch
    result = func(event, *args, **kwargs)
  File "/home/runner/.site-packages/disco/bot/command.py", line 161, in __call__
    return self.func(*args, **kwargs)
  File "/home/runner/plugins/music.py", line 53, in on_play
    item = YoutubeDLInput(url).pipe(BufferedOpusEncoderPlayable)
  File "/home/runner/.site-packages/disco/voice/playable.py", line 38, in pipe
    child = other(self, *args, **kwargs)
  File "/home/runner/.site-packages/disco/voice/playable.py", line 206, in __init__
    OpusEncoder.__init__(self, self.sampling_rate, self.channels)
  File "/home/runner/.site-packages/disco/voice/opus.py", line 87, in __init__
    super(OpusEncoder, self).__init__(library_path)
  File "/home/runner/.site-packages/disco/voice/opus.py", line 45, in __init__
    func = getattr(self.lib, name)
  File "/usr/local/lib/python3.6/ctypes/__init__.py", line 361, in __getattr__
    func = self.__getitem__(name)
  File "/usr/local/lib/python3.6/ctypes/__init__.py", line 366, in __getitem__
    func = self._FuncPtr((name_or_ordinal, self))
AttributeError: python3: undefined symbol: opus_strerror```

I looked everywhere, however I could not find someone else with a similar issue. This is my source code:
https://repl.it/@21natzil/Discord-Bot

TypeError when passing youtubedl bufferedopus object through to player

When using a voice system similar to the examples , Disco's voice been throwing the exception for me below since what I suspect was #130.

  File "src/gevent/greenlet.py", line 716, in gevent._greenlet.Greenlet.run
  File "/usr/local/lib/python3.6/dist-packages/disco/voice/playable.py", line 213, in _encoder_loop
    raw = self.source.read(self.frame_size)
  File "/usr/local/lib/python3.6/dist-packages/disco/voice/playable.py", line 115, in read
    self._buffer = BufferedIO(data)
TypeError: initial_value must be str or None, not bytes
2019-04-06T13:49:19Z <Greenlet "Greenlet-0" at 0x7efcbfbcc548: <bound method BufferedOpusEncoderPlayable._encoder_loop of <disco.voice.playable.BufferedOpusEncoderPlayable object at 0x7efcbe91c348>>> failed with TypeError```

Bounty: Documentation

The number one historical issue with Disco has been a lack of quality documentation. This issue mostly stems from my particular disdain with the Sphinx documentation engine and the lack of consistency with docstrings in Python projects. I originally attempted to build biblio--a custom documentation engine--as a solution to this problem, however its still unfinished and would require a decent amount of frontend work to generate high quality documentation.

This issue represents a "bounty" I'm offering to anyone thats interested in picking up the slack and providing a documentation solution which results in automatically generated high quality documentation based on docstrings in the code and a separate set of rich text (in some markdown format) prose/instructional content. The following requirements apply:

  • Existing docstrings should be made consistent with whatever docstring format is required. No new documentation needs to be added.
  • Documentation generation should be scriptable in our CI environment (travis right now).
  • The output should be a human readable HTML website with a modernish/simplistic design (not utilizing proprietary assets).
  • Work should be based off the staging/v1.0.0 branch.

Since Disco is a relatively small project thats entirely maintained by me I'm looking to offer a very-mediocre (but hopefully semi-inspiring) 150$ (US)* bounty towards this goal. As an alternative I'd be willing to offer a negotiable amount of my personal time for another open source project, reviewing code, or otherwise consulting with you. The bounty is at the end of the day up to my discretion. Feel free to reach out to me in our Discord channel if you'd like more clarification or any other questions answered.

*I'd be paying out via Paypal (or to a charity of your choice), if that doesn't work we'll have to negotiate something else separately

Tutorial cli error

Whenever i try to connect the bot using the guidelines from the tutorial, i get this error. At first it was a invalid token, fixed that by regenerating a new token, but now i get this error. Is there something i am missing or overlooking?

Windows 10 Pro
Disco-py = v0.0.12rc4

(everdream-env) PS C:\Users\Faraash> python -m disco.cli --config config.json
[INFO] 2018-02-11 15:54:04,566 - HTTPClient:271 - GET https://discordapp.com/api/v7/gateway (None)
[INFO] 2018-02-11 15:54:04,983 - GatewayClient:147 - Opening websocket connection to URL wss://gateway.discord.gg?v=6&encoding=json&compress=zlib-stream
[INFO] 2018-02-11 15:54:05,294 - GatewayClient:212 - WS Opened: sending identify payload
[INFO] 2018-02-11 15:54:05,295 - GatewayClient:122 - Received HELLO, starting heartbeater...
[INFO] 2018-02-11 15:54:05,413 - GatewayClient:247 - WS Closed: [4004] Authentication failed. (1)
[INFO] 2018-02-11 15:54:05,413 - GatewayClient:257 - Will attempt to reconnect after 5 seconds
[INFO] 2018-02-11 15:54:10,413 - GatewayClient:147 - Opening websocket connection to URL wss://gateway.discord.gg?v=6&encoding=json&compress=zlib-stream
[INFO] 2018-02-11 15:54:10,707 - GatewayClient:212 - WS Opened: sending identify payload
[INFO] 2018-02-11 15:54:10,707 - GatewayClient:122 - Received HELLO, starting heartbeater...
[INFO] 2018-02-11 15:54:10,831 - GatewayClient:247 - WS Closed: [4004] Authentication failed. (2)
[INFO] 2018-02-11 15:54:10,831 - GatewayClient:257 - Will attempt to reconnect after 10 seconds
[INFO] 2018-02-11 15:54:20,832 - GatewayClient:147 - Opening websocket connection to URL wss://gateway.discord.gg?v=6&encoding=json&compress=zlib-stream
[INFO] 2018-02-11 15:54:21,169 - GatewayClient:212 - WS Opened: sending identify payload
[INFO] 2018-02-11 15:54:21,174 - GatewayClient:122 - Received HELLO, starting heartbeater...
[INFO] 2018-02-11 15:54:21,317 - GatewayClient:247 - WS Closed: [4004] Authentication failed. (3)
[INFO] 2018-02-11 15:54:21,318 - GatewayClient:257 - Will attempt to reconnect after 15 seconds
[INFO] 2018-02-11 15:54:36,318 - GatewayClient:147 - Opening websocket connection to URL wss://gateway.discord.gg?v=6&encoding=json&compress=zlib-stream
[INFO] 2018-02-11 15:54:36,619 - GatewayClient:212 - WS Opened: sending identify payload
[INFO] 2018-02-11 15:54:36,619 - GatewayClient:122 - Received HELLO, starting heartbeater...
[WARNING] 2018-02-11 15:54:36,620 - GatewayClient:88 - Received HEARTBEAT without HEARTBEAT_ACK, forcing a fresh reconnect
[ERROR] 2018-02-11 15:54:36,736 - websocket:53 - close status: 4000
[INFO] 2018-02-11 15:54:36,737 - GatewayClient:247 - WS Closed: [None] None (4)
[INFO] 2018-02-11 15:54:36,737 - GatewayClient:257 - Will attempt to reconnect after 20 seconds
[INFO] 2018-02-11 15:54:56,737 - GatewayClient:147 - Opening websocket connection to URL wss://gateway.discord.gg?v=6&encoding=json&compress=zlib-stream
[INFO] 2018-02-11 15:54:57,023 - GatewayClient:212 - WS Opened: sending identify payload
[INFO] 2018-02-11 15:54:57,024 - GatewayClient:122 - Received HELLO, starting heartbeater...
[INFO] 2018-02-11 15:54:57,154 - GatewayClient:247 - WS Closed: [4004] Authentication failed. (5)
[INFO] 2018-02-11 15:54:57,155 - GatewayClient:257 - Will attempt to reconnect after 25 seconds
[INFO] 2018-02-11 15:55:22,156 - GatewayClient:147 - Opening websocket connection to URL wss://gateway.discord.gg?v=6&encoding=json&compress=zlib-stream
[INFO] 2018-02-11 15:55:22,461 - GatewayClient:212 - WS Opened: sending identify payload
[INFO] 2018-02-11 15:55:22,462 - GatewayClient:122 - Received HELLO, starting heartbeater...
[INFO] 2018-02-11 15:55:22,584 - GatewayClient:247 - WS Closed: [4004] Authentication failed. (6)
Traceback (most recent call last):
File "S:\Faraash\Documents\Everdream\everdream-env\lib\site-packages\gevent\greenlet.py", line 536, in run
result = self._run(*self.args, **self.kwargs)
File "S:\Faraash\Documents\Everdream\everdream-env\lib\site-packages\holster\emitter.py", line 72, in call
return self.callback(*args, **kwargs)
File "S:\Faraash\Documents\Everdream\everdream-env\lib\site-packages\disco\gateway\client.py", line 250, in on_close
raise Exception('Failed to reconnect after {} attempts, giving up'.format(self.max_reconnects))
Exception: Failed to reconnect after 5 attempts, giving up
Sun Feb 11 15:55:22 2018 <Greenlet at 0x21f7445e768: <holster.emitter.EmitterSubscription object at 0x0000021F7446D6D8>(4004, 'Authentication failed.')> failed with Exception

Newer release on pypi

Hello,

I guess this is more or less a follow up on issue #170.

Installing disco-py from pip prove to be challenging. The version on pypi depends on an older version of gevent. This older version of gevent doesn't compile with python 3.8.

So, it's pretty much uninstallable from the pypi repository on any system that adopted python 3.8 already.

Group abbreviations conflict

From a group set ["spam","config","copypasta","LoL","level"], bot.compute_group_abbrev() results in {"level":"l","copypasta":"co","LoL":"L","spam":"s"} as opposed to {"level":"l","config":"con","copypasta":"cop","LoL":"L","spam":"s"}.

My temporary workaround was:

        for group in groups:
            for i in range(1, len(group)):
                if not group[:i] in self.group_abbrev.values():
                    self.group_abbrev[group] = group[:i]
                    break
                conflict = {k: k[:i+1] for k, v in self.group_abbrev.items() if v == group[:i]}
                self.group_abbrev.update(conflict)

Permission Calculation Error With Channel Overwrites

When accessing the bot's permissions via, the embed_links permission value seems broken as by doing this:

from disco.bot import Plugin

class TestingPlugin(Plugin):
    @Plugin.listen("MessageCreate")
    def message_create_event(self, event):
        print(event.message.channel.get_permissions(
            self.state.me
        ).can(
            16384 # permission value for `embed_links`
        ))

It returns the following states after getting the permissions calculation, the output is as follows, taking into account the different permission areas that could happen

Guild Base Permission + Channel Overwrite  =  Output
False + (Denied, Neutral)  =  False (As expected)
False + Allowed  =  True (As expected)
True + (Neutral, Allowed)  =  True (As expected)
True + Denied  =  True (Uh oh, that should be overwritten to False)

so, is there something happening here on Discord's end but I don't think so as it seems to be pretty consistent with getting the other permission values. I haven't tested all of them, but embed links is the one I've encountered having this problem.





(note: PixeL also has a similar problem when using the code snippet:

bot_perms = event.channel.get_permissions(self.state.me.id)
if bot_perms.administrator or bot_perms.embed_links:

)

Add support for animated emoji.

Currently animated emoji aren't supported.

The animated field needs to be added to the Emoji and GuildEmoji type, and the __str__ method has to be modified to add the a for animated emoji.

Documentation

This is a blocker for the initial public release. I'd love to have some nice rtfm documentation similar to discord.py, although hopefully more along the lines of peewee. I'm not sure what the best way to do this is, as I despise spinx/rst, but there may just not be a better option.

Should dive into this more when I get time.

Permissions Support

We need to support bitwise permissions, something like the following would be great:

# Basic checks
channel.can(user, Permissions.READ_MESSAGES)
channel.can(user, Permissions.CONNECT)
channel.can(user, Permissions.CONNECT, Permissions.SPEAK)

# Editing member overwrite
member = guild.get_member(user)
overwrite = channel.get_overwrite(member)
overwrite.permissions += Permissions.SEND_MESSAGES
overwrite.save()

# Editing role permissions
role = guild.get_role(role_id)
role.permissions.send_messages = False
role.save()

Commands arguments with aliases

When a command has aliases, only the last alias will work with arguments.

Example:

@Plugin.command('help', '<plugin:str>', aliases=['commands', 'foo', 'bar'], description='Show a list of commands.')

help somePluginName
Bot will reply with help requires 1 arguments (passed 0)

commands somePluginName
Bot will reply with commands requires 1 arguments (passed 0)

foo somePluginName
Bot will reply with foo requires 1 arguments (passed 0)

bar somePluginName
Command will run normally.

Python 3, voice, and StringIO

When trying to use voice in Python 3 (3.6.0, Windows 10 Pro CU, x64), I ran into a problem.

...snip...
  File "C:\Users\<me>\AppData\Local\Programs\Python\Python36\lib\site-packages\disco\voice\playable.py", line 17, in <module>
    from StringIO import StringIO
ModuleNotFoundError: No module named 'StringIO'

Apparently caused by this code block:

try:
    from cStringIO import cStringIO as StringIO
except:
    from StringIO import StringIO

I Googled the problem, and it turned up that StringIO.StringIO itself is not available in Python 3. Instead, it was moved to io package (so it's io.StringIO in py3). The solution is apparently nesting this one step further, however further research shows that it might lead to issues (str vs bytes). The solution I came up with is:

try:
    from cStringIO import cStringIO as StringIO
except:
    try:
        from StringIO import StringIO
    except:
        from io import StringIO

However due to earlier mentioned implications and my limited Python experience, I am not certain whether I can just throw that in without breaking anything.

OSError with music example bot when requesting to play an url.

Unable to play sound from a Youtube url with the music bot that comes as an example bot. Installed disco on a clean Debian image.
OS Version

Distributor ID:	Debian
Description:	Debian GNU/Linux 9.7 (stretch)
Release:	9.7
Codename:	stretch

Installation

sudo pip install disco-py
sudo pip install disco-py[voice]
sudo pip install disco-py[music]
sudo pip install disco-py[performance]

Commands
The following commands are executed in discord.

@testbot join
@testbot play https://www.youtube.com/watch?v=pvT7mDwZ7Hw

Log

[INFO] 2019-01-31 14:50:09,388 - Bot:485 - Adding plugin module at path "music"
[INFO] 2019-01-31 14:50:09,530 - HTTPClient:271 - GET https://discordapp.com/api/v7/gateway (None)
[INFO] 2019-01-31 14:50:09,782 - GatewayClient:147 - Opening websocket connection to URL `wss://gateway.discord.gg?v=6&encoding=json&compress=zlib-stream`
[INFO] 2019-01-31 14:50:10,042 - GatewayClient:212 - WS Opened: sending identify payload
[INFO] 2019-01-31 14:50:10,043 - GatewayClient:122 - Received HELLO, starting heartbeater...
[INFO] 2019-01-31 14:50:10,173 - GatewayClient:126 - Received READY
[INFO] 2019-01-31 14:50:27,891 - VoiceClient:178 - [<VoiceClient #Entertainment #4>] Recieved VOICE_SERVER_UPDATE (state = awaiting_endpoint / endpoint = eu-central974.discord.gg:80)
[INFO] 2019-01-31 14:50:27,982 - VoiceClient:117 - [<VoiceClient #Entertainment #4>] Recieved Voice HELLO payload, starting heartbeater
[INFO] 2019-01-31 14:50:27,987 - VoiceClient:122 - [<VoiceClient #Entertainment #4>] Recived Voice READY payload, attempting to negotiate voice connection w/ remote
[INFO] 2019-01-31 14:50:28,000 - VoiceClient:159 - [<VoiceClient #Entertainment #4>] Recieved session description, connection completed
[youtube] pvT7mDwZ7Hw: Downloading webpage
[youtube] pvT7mDwZ7Hw: Downloading video info webpage
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/gevent/greenlet.py", line 536, in run
    result = self._run(*self.args, **self.kwargs)
  File "/usr/local/lib/python2.7/dist-packages/disco/voice/playable.py", line 213, in _encoder_loop
    raw = self.source.read(self.frame_size)
  File "/usr/local/lib/python2.7/dist-packages/disco/voice/playable.py", line 114, in read
    data, _ = self.proc.communicate()
  File "/usr/local/lib/python2.7/dist-packages/disco/voice/playable.py", line 144, in proc
    self._proc = subprocess.Popen(args, stdin=None, stdout=subprocess.PIPE)
  File "/usr/local/lib/python2.7/dist-packages/gevent/subprocess.py", line 585, in __init__
    reraise(*exc_info)
  File "/usr/local/lib/python2.7/dist-packages/gevent/subprocess.py", line 554, in __init__
    restore_signals, start_new_session)
  File "/usr/local/lib/python2.7/dist-packages/gevent/subprocess.py", line 1312, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory
Thu Jan 31 14:50:42 2019 <Greenlet at 0x7f25204cab90: <bound method BufferedOpusEncoderPlayable._encoder_loop of <disco.voice.playable.BufferedOpusEncoderPlayable object at 0x7f251edd5440>>> failed with OSError

@everyone role is not included in GuildMember.roles

... which would make perfect sense since everyone by definition has this role, except that when computing permissions for a channel, any overwrites for @everyone are not taken into account.

I did some digging of my own, and discovered that the official API does not include the @everyone role in its responses despite the documentation not saying anything about it, and from what I have read so far on this library, it appears that the library simply takes what the official API gives.

A quick solution would be to take @everyone into account when computing permissions, except that other problems may arise from the absence of @everyone in GuildMember.roles. Another solution would be to not only fix the way permissions are computed for a channel, but also to warn the oblivious developer using the library that @everyone is absent from a member's list of roles.

I did not issue a Pull Request as I am not familiar enough (yet) with the library to make careful changes.

error when running in Python 2.7

[INFO] 2019-11-05 06:41:24,025 - HTTPClient:272 - GET https://discordapp.com/api/v7/gateway (None)
[INFO] 2019-11-05 06:41:24,080 - GatewayClient:148 - Opening websocket connection to URL `wss://gateway.discord.gg?v=6&encoding=json&compress=zlib-stream`
[INFO] 2019-11-05 06:41:24,153 - GatewayClient:213 - WS Opened: sending identify payload
[INFO] 2019-11-05 06:41:24,155 - GatewayClient:123 - Received HELLO, starting heartbeater...
[INFO] 2019-11-05 06:41:25,591 - GatewayClient:127 - Received READY
Traceback (most recent call last):
  File "src/gevent/greenlet.py", line 716, in gevent._greenlet.Greenlet.run
  File "build/bdist.linux-x86_64/egg/disco/util/emitter.py", line 77, in __call__
    return self.callback(*args, **kwargs)
  File "build/bdist.linux-x86_64/egg/disco/gateway/client.py", line 99, in handle_dispatch
    obj = GatewayEvent.from_dispatch(self.client, packet)
  File "build/bdist.linux-x86_64/egg/disco/gateway/events.py", line 42, in from_dispatch
    raise Exception('Could not find cls for {} ({})'.format(data['t'], data))
Exception: Could not find cls for PRESENCES_REPLACE ({u'd': [], u's': 4, u't': u'PRESENCES_REPLACE', u'op': 0})
2019-11-04T21:41:26Z <Greenlet "Greenlet-0" at 0x7f758d4c2998: <disco.util.emitter.EmitterSubscription object at 0x7f758d51efd0>({u'd': [], u's': 4, u't': u'PRESENCES_REPLACE', u')> failed with Exception

I got this error somehow. Running python2.7 with the staging/v1.0.0 branch. I reran the same command over and over afterwards, but didn't get this error again.

Disco doesn't dance (fails on startup)

I receive an error when trying to start my bot, even if I empty out the bot entirely. I have verified there are no errors in my code and that my token is correct.

Traceback (most recent call last):
  File "C:\Users\evany\AppData\Local\Programs\Python\Python36-32\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Users\evany\AppData\Local\Programs\Python\Python36-32\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\evany\AppData\Local\Programs\Python\Python36-32\lib\site-packages\disco\cli.py", line 99, in <module>
    disco_main(True)
  File "C:\Users\evany\AppData\Local\Programs\Python\Python36-32\lib\site-packages\disco\cli.py", line 74, in disco_main
    client = Client(config)
  File "C:\Users\evany\AppData\Local\Programs\Python\Python36-32\lib\site-packages\disco\client.py", line 91, in __init__
    self.events = Emitter(gevent.spawn)
TypeError: __init__() takes 1 positional argument but 2 were given

MessageUpdate not sending a full message object

Hey, so when I have the bot return a response with an embed. It triggers both the MessageCreate and MessageUpdate gateway events.

Which when triggering the MessageUpdate event, it sends a message object with the event.message.author.bot attribute being False (bypassing the bot ignoring) and then when you call the the get_commands_for_message() function, it returns this error, which means that the message object that the bot is sending to the MessageUpdate listeners isn't complete from my knowledge. I have no idea how this would be fixed on my end if it is something that I have caused.

(Thanks for such an awesome library btw)

PY3/General Issues

With current version there are couple problems when it comes to the PY3

  • disco/types/channel.py:301 in py2 map returns list, whereas in py3 it returns a generator
  • With python3.6, gevent has to be updated to 1.2.0 or above, and most of the time requests[security] is required or SSLContext ends up in infinite recursion when using gevent monkey patches
  • disco/types/base.py:221 It is possible that obj argument is None therefore an exception occurs since bytes does not accept NoneType
  • Plugin reload simply doesn't work, I think it is because module is in the stack, expecting a return from Bots reload_plugin, so when attempting to reload module - it fails to reload it. Spawning a separate greenlet for it seems to work though since it returns immediately.

PluginConfig not found

I get an ImportError when trying to import PluginClass:

responder.py:

from disco.bot import Plugin, PluginConfig

class ResponderPluginConfig(PluginConfig):
    var1 = 'test'

@Plugin.with_config(ResponderPluginConfig)
class ResponderPlugin(Plugin):
    @Plugin.command('ping')
    def on_ping_command(self, event):
        event.msg.reply('pong!')
  File ".../plugins/responder.py", line 1, in <module>
    from disco.bot import Plugin, PluginConfig
ImportError: cannot import name 'PluginConfig'

I can't seem to find it anywhere in the code either.

Rework Storage

The current storage implementation is messy, and leaves a lot to be desired when building simple plugins. I want to focus on straining this down to it's bare minimum and making it useable for the only realistic use case; small/simple bots and plugins.

Update Comparison Page in Github Wiki.

Update the comparison page in the wiki page so that discord-py has the Autosharding as a check mark. (rather than an X) since It now does actually have auto-sharding.

Also, maybe not needed, but it might be nice if you would allow other users to edit the wiki as then we can keep that stuff updated without needing to bother you. (As I know you can be quite busy at times, and it can always be nice to have a few helpers keep some stuff up-to-date on the documentation side of things)

user.get_avatar_url() returns a broken URL?

I noticed that when I used this function, the returned URL would have extra characters. An example is this one.

https://cdn.discordapp.com/avatars/68847303431041024/b'7cea5b05de921120b246094cde6272a6'.webp?size=256

For some reason there is an extra b and ' characters in the avatar id string. If you tried that URL it would lead to a cloudflare "Bad Gateway" page. It really should be this.

https://cdn.discordapp.com/avatars/68847303431041024/7cea5b05de921120b246094cde6272a6.webp?size=256

and to temporarily get around it, I had to do this.

embed.set_thumbnail(url=member.user.get_avatar_url(fmt='png', size=256).replace("b'","").replace("'",""))

Not sure if this was just me. ๐Ÿค”

Guilds voice_states cache sometimes corrupts itself

Sometimes (I guess during a Discord Gateway problem, such as a restart), the guild voice_states still contains invalid entries.
In my case, voice_states still contains a state for a player which says is still in a channel, but according to Discord Client, there's nobody in that channel.

Here's a gif of what happen:
Gif of problem

If it may help, here's how I use voice_states in my VoiceStateUpdate event.

As a workaround, is there any way to "force update" the voice_states array, using a scheduled task?

Thanks for your help! :D

Tutorial doesn't work

I followed up with the tutorial, and everything functioned fine until I tried to test the command and nothing showed up in the console except for the basic connection info. I tried to check the issue by increasing the log level but it turns out that log level is broken as well:
AttributeError: module 'logging' has no attribute '1'

"unrecognized arguments" error is returned even if it shouldn't

I'm encountering a weird bug which looks like directly related to Disco. I've registered a command which signature is:

stats <username, required> <database, optional, default "invasion"> <date, optional, default None>

So I'm invoking this command by sending the following message:

@botName stats epocdotfr invasion 2018-02-02

However the bot (Disco itself) answers by the message unrecognized arguments: 2018-02-02. Note everything is working fine apart this error message being automatically sent. When I don't send the date argument, it's empty. When I send it I can get its value from args.date (value doesn't matter, it may be a date, blah, whatever).

Here's the decorators of this command handler:

@Plugin.command('stats', aliases=['statistics'], parser=True)
@Plugin.parser.add_argument('username')
@Plugin.parser.add_argument('database', choices=['invasion', 'pacific'], nargs='?', default='invasion')
@Plugin.parser.add_argument('date', nargs='?')
def on_stats_command(self, event, args):
    # ...

I tried to reproduce the problem in plain-old Python using ArgParse with the exact reproduction of the command options, no problem.

I don't understand what I'm doing wrong ๐Ÿค”

Instructions not clear **** got stuck in fan (I know it is alpha! ;) )

Hi there

I was trying to start with a simple discord bot and I think your lib ist the right way to do this. Clearly it is still alpha and I have no problem with changing code. But I was not able to get the example up and running, since i do not understand how to get it connecting to my server/channel.

Can you provide some information how to tackle this? Thanks :)

TypeError on update_prescence()

Not sure if I am just being dumb here but no matter how I pass the GameType to the game object it gives an error similar to the one below

Traceback (most recent call last):
  File "/home/james/.local/lib/python2.7/site-packages/gevent/greenlet.py", line 536, in run
    result = self._run(*self.args, **self.kwargs)
  File "/home/james/.local/lib/python2.7/site-packages/holster/emitter.py", line 72, in __call__
    return self.callback(*args, **kwargs)
  File "/home/james/.local/lib/python2.7/site-packages/disco/bot/plugin.py", line 335, in dispatch
    result = func(event, *args, **kwargs)
  File "plugins/events.py", line 9, in on_ready
    self.client.update_presence(self, 'ONLINE', user.Game(GameType.LISTENING.value, "for ;help"))
  File "/home/james/.local/lib/python2.7/site-packages/disco/types/base.py", line 321, in __init__
    self.load(obj, **kwargs)
  File "/home/james/.local/lib/python2.7/site-packages/disco/types/base.py", line 336, in load
    return self.load_into(self, *args, **kwargs)
  File "/home/james/.local/lib/python2.7/site-packages/disco/types/base.py", line 342, in load_into
    raw = obj[field.src_name]
TypeError: 'int' object has no attribute '__getitem__'

And my code looks like this:

from disco.bot import Bot, Plugin
from disco.types import user
from disco.types.user import GameType

class EventsPlugin(Plugin):
    @Plugin.listen('Ready')
    def on_ready(self, event):
        print(GameType.LISTENING.value)
        self.client.update_presence(self, 'ONLINE', user.Game(GameType.LISTENING.value, "for ;help"))

V1

At this point, disco is approaching a stable and mature lib fairly quickly. Both myself and Discord as a company utilize disco for bots we run, and so far the results have shown disco to be rather stable. This issue will serve as a meta-point of the last few things required to really get disco into a stable v1 phase.

  • Full, searchable, easily readable, pretty documentation
  • Cleanup interface naming
  • More testing around non-API components (storage, command parsing, etc)
  • Cleanup performance
  • Cleanup configuration

I'm sure there will be some more minor things required to get this out the door, but that list was whats on the top of my mind.

Question

How is config for commands for ping set?

Adding a 'ready' listener results in a ReccursionError.

Regardless of whether the function contains anything, if your code contains a ready listener, it will result in a ReccursionError on line 156 in the __init__ of _tblib.py

@Plugin.listen('Ready')
def on_ready(self, event):
    pass

Missing attribute in GuildMemberAdd event

According to Discord docs, GuildMemberAdd should be adding an extra guild_id field to the user object passed in the event: https://discordapp.com/developers/docs/topics/gateway#guild-member-add

But right now, if you try to access that field, you get an AttributeError:
guild_id-throwing-attributeerror-in-guildmemberadd

It looks like the user object is being passed without the guild_id field ever being added, since its other member variables work just fine. However, since the user object is all that is being passed, there is no way to tell what guild/server the user actually joined.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.