Coder Social home page Coder Social logo

pydle's Introduction

pydle

Python IRC library.

pydle is a compact, flexible and standards-abiding IRC library for Python 3.6 through 3.9.

Features

  • Well-organized: Thanks to the modularized feature system, it's not hard to find what you're looking for in the well-organised source code.
  • Standards-abiding: Based on RFC1459 with some small extension tweaks, with full support of optional extension standards:
  • Asynchronous: IRC is an asynchronous protocol and so should be a library that implements it. Coroutines are used to process events from the server asynchronously.
  • Modularised and extensible: Features on top of RFC1459 are implemented as separate modules for a user to pick and choose, and write their own. Broad features are written to be as extensible as possible.
  • Liberally licensed: The 3-clause BSD license ensures you can use it everywhere.

Basic Usage

pip install pydle

From there, you can import pydle and subclass pydle.Client for your own functionality.

To enable SSL support, install the sasl extra. pip install pydle[sasl]

Setting a nickname and starting a connection over TLS:

import pydle

# Simple echo bot.
class MyOwnBot(pydle.Client):
    async def on_connect(self):
         await self.join('#bottest')

    async def on_message(self, target, source, message):
         # don't respond to our own messages, as this leads to a positive feedback loop
         if source != self.nickname:
            await self.message(target, message)

client = MyOwnBot('MyBot', realname='My Bot')
client.run('irc.rizon.net', tls=True, tls_verify=False)

But wait, I want to handle multiple clients!

No worries! Use pydle.ClientPool like such:

pool = pydle.ClientPool()
for i in range(10):
    client = MyOwnBot('MyBot' + str(i))
    pool.connect(client, 'irc.rizon.net', 6697, tls=True, tls_verify=False)

# This will make sure all clients are treated in a fair way priority-wise.
pool.handle_forever()

Furthermore, since pydle is simply asyncio-based, you can run the client in your own event loop, like this:

import asyncio

client = MyOwnBot('MyBot')
loop = asyncio.get_event_loop()
asyncio.ensure_future(client.connect('irc.rizon.net', tls=True, tls_verify=False), loop=loop)
loop.run_forever()

Customization

If you want to customize bot features, you can subclass pydle.BasicClient and one or more features from pydle.features or your own feature classes, like such:

# Only support RFC1459 (+small features), CTCP and our own ACME extension to IRC.
class MyFeaturedBot(pydle.features.ctcp.CTCPSupport, acme.ACMESupport, rfc1459.RFC1459Support):
    pass

To create your own features, just subclass from pydle.BasicClient and start adding callbacks for IRC messages:

# Support custom ACME extension.
class ACMESupport(pydle.BasicClient):
    async def on_raw_999(self, source, params):
        """ ACME's custom 999 numeric tells us to change our nickname. """
        nickname = params[0]
        await self.set_nickname(nickname)

FAQ

Q: When constructing my own client class from several base classes, I get the following error: TypeError: Cannot create a consistent method resolution order (MRO) for bases X, Y, Z. What causes this and how can I solve it?

Pydle's use of class inheritance as a feature model may cause method resolution order conflicts if a feature inherits from a different feature, while a class inherits from both the original feature and the inheriting feature. To solve such problem, pydle offers a featurize function that will automatically put all classes in the right order and create an appropriate base class:

# Purposely mis-ordered base classes, as SASLSupport inherits from CapabilityNegotiationSupport, but everything works fine.
MyBase = pydle.featurize(pydle.features.CapabilityNegotiationSupport, pydle.features.SASLSupport)
class Client(MyBase):
    pass

Q: How do I...?

Stop! Read the documentation first. If you're still in need of support, join us on IRC! We hang at #pydle on irc.libera.chat. If someone is around, they'll most likely gladly help you.

License

Pydle is licensed under the 3-clause BSD license. See LICENSE.md for details.

pydle's People

Contributors

bernardosulzbach avatar bigfoot547 avatar danigm avatar enkrypt avatar felixonmars avatar harmon758 avatar hburn7 avatar heufneutje avatar hogklint avatar kenneaal avatar liranuna avatar marksteward avatar nitori avatar polsaker avatar rixxan avatar shakedunay avatar shizmob avatar theunkn0wn1 avatar txtsd avatar yay295 avatar zeroknight 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

pydle's Issues

Possible to create users that never get cleaned up

Currently, members of self.users are primarily only destroyed when Pydle or the user in question leaves a channel. However, there are numerous events that call _sync_user, which will create the user in question if they don't already exist -- including receiving a NOTICE or PRIVMSG from another user.

Since these users are not necessarily in the same channel, Pydle will never see them leaving the channel and thus never know to clean them up. This can cause the users dict to become bloated over time.

test issue

testing issue announces on IRC channel

[asyncio] ClientPool() example in README throws ValueError

Running the example with pydle.ClientPool in the README throws a ValueError:

Traceback (most recent call last):
  File "bot.py", line 14, in <module>
    pool.connect(client, 'irc.rizon.net', 6697, tls=True, tls_verify=False)
  File "/usr/local/lib/python3.5/dist-packages/pydle/client.py", line 462, in connect
    client.connect(*args, eventloop=self.eventloop, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/pydle/features/tls.py", line 37, in connect
    return super().connect(hostname, port, tls=tls, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/pydle/features/rfc1459/client.py", line 190, in connect
    super().connect(hostname, port, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/pydle/client.py", line 104, in connect
    self._connect(hostname=hostname, port=port, reconnect=reconnect, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/pydle/features/tls.py", line 56, in _connect
    self.connection.connect()
  File "/usr/local/lib/python3.5/dist-packages/pydle/connection.py", line 74, in connect
    self.setup_tls()
  File "/usr/local/lib/python3.5/dist-packages/pydle/connection.py", line 148, in setup_tls
    server_hostname=self.hostname if ssl.HAS_SNI else None)
  File "/usr/lib/python3.5/ssl.py", line 377, in wrap_socket
    _context=self)
  File "/usr/lib/python3.5/ssl.py", line 752, in __init__
    self.do_handshake()
  File "/usr/lib/python3.5/ssl.py", line 988, in do_handshake
    self._sslobj.do_handshake()
  File "/usr/lib/python3.5/ssl.py", line 633, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:645)
Exception ignored in: <bound method EventLoop.__del__ of <pydle.async.EventLoop object at 0x7f4793dcd710>>
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/pydle/async.py", line 113, in __del__
  File "/usr/local/lib/python3.5/dist-packages/tornado/ioloop.py", line 713, in close
  File "/usr/local/lib/python3.5/dist-packages/tornado/platform/posix.py", line 48, in fileno
ValueError: I/O operation on closed file

CTCP not according to specifcation?

https://github.com/Shizmob/pydle/blob/60ede96669d77e86b8ee264ebc21ab669418fb7b/pydle/features/ctcp.py#L102

I think, there may be cases where CTCP is not correctly recognized. More specifically, if the CTCP message follows a normal text message (or is embedded in it).

see example 3 in http://www.irchelp.org/protocol/ctcpspec.html


The text part of a PRIVMSG or NOTICE might contain zero or more
extended messages, intermixed with zero or more chunks of non-extended
data.
https://github.com/irchelp/wio/blame/gh-pages/protocol/ctcpspec.md#L189

Furthermore, it should be possible to send multiple CTCP messages (chained together). A check for CTCP should therefore
(1) check for CTCP_DELIMITER and if found
(2) check/extract all CTCP messages.
(3) handle CTCP messages/handle remaining text messages (if available)


I'm not sure how CTCP (aside from DCC) occurs in the wild but the current approach may not work for all cases.

Failure to reconnect

I'm using client.run in the asyncio branch, and after a short period of being connected, I'm encountering:

Encountered error on socket.
TimeoutError: Ping timeout: no data received from server in 180 seconds.
Unexpected disconnect. Attempting to reconnect.

after which the memory for the process jumps from ~15 MB to ~2 GB.
This seems to be because on_data is triggered constantly with empty bytestrings. It's possible this is a result of handle_forever continuing after the connection is disconnected.
I'm not sure what's causing the initial ping timeout though. I'm using a program that was running properly with the master branch, and just converted it by adding async's and await's to overrides and calls of functions that were converted into coroutines and by using client.run instead of client.connect and client.handle_forever

Typo in ircv3_1

File "/home/rfw/pydle/pydle/features/ircv3_1.py", line 86, in on_raw_join
  fakemsg = self._construct_message('JOIN', channels, source=message.source)

_construct_message should be _create_message.

TypeError on connect

Running with or without pool both result in errors while connection still seems to be succesful. Probably should handle somehow?

ERROR:tornado.application:Exception in callback functools.partial(<function wrap.<locals>.wrapped at 0xb618fd68>, <pydle.features.rfc1459.parsing.RFC1459Message object at 0xb619e3f0>)
Traceback (most recent call last):
  File "/usr/lib/python3.3/site-packages/tornado/ioloop.py", line 477, in _run_callback
    callback()
  File "/usr/lib/python3.3/site-packages/tornado/stack_context.py", line 331, in wrapped
    raise_exc_info(exc)
  File "<string>", line 3, in raise_exc_info
  File "/usr/lib/python3.3/site-packages/tornado/stack_context.py", line 302, in wrapped
    ret = fn(*args, **kwargs)
  File "/usr/lib/python3.3/site-packages/pydle-0.7.1-py3.3.egg/pydle/features/ctcp.py", line 81, in on_raw_notice
    nick, metadata = self._parse_user(message.source)
  File "/usr/lib/python3.3/site-packages/pydle-0.7.1-py3.3.egg/pydle/features/rfc1459/client.py", line 109, in _parse_user
    nickname, username, host = parsing.parse_user(data)
  File "/usr/lib/python3.3/site-packages/pydle-0.7.1-py3.3.egg/pydle/features/rfc1459/parsing.py", line 191, in parse_user
    if protocol.HOST_SEPARATOR in raw:
TypeError: argument of type 'NoneType' is not iterable
ERROR:tornado.application:Exception in callback functools.partial(<function wrap.<locals>.wrapped at 0xb62474b0>, <pydle.features.rfc1459.parsing.RFC1459Message object at 0xb619e5f0>)
Traceback (most recent call last):
  File "/usr/lib/python3.3/site-packages/tornado/ioloop.py", line 477, in _run_callback
    callback()
  File "/usr/lib/python3.3/site-packages/tornado/stack_context.py", line 331, in wrapped
    raise_exc_info(exc)
  File "<string>", line 3, in raise_exc_info
  File "/usr/lib/python3.3/site-packages/tornado/stack_context.py", line 302, in wrapped
    ret = fn(*args, **kwargs)
  File "/usr/lib/python3.3/site-packages/pydle-0.7.1-py3.3.egg/pydle/features/ctcp.py", line 81, in on_raw_notice
    nick, metadata = self._parse_user(message.source)
  File "/usr/lib/python3.3/site-packages/pydle-0.7.1-py3.3.egg/pydle/features/rfc1459/client.py", line 109, in _parse_user
    nickname, username, host = parsing.parse_user(data)
  File "/usr/lib/python3.3/site-packages/pydle-0.7.1-py3.3.egg/pydle/features/rfc1459/parsing.py", line 191, in parse_user
    if protocol.HOST_SEPARATOR in raw:
TypeError: argument of type 'NoneType' is not iterable
ERROR:tornado.application:Exception in callback functools.partial(<function wrap.<locals>.wrapped at 0xb6247468>, <pydle.features.rfc1459.parsing.RFC1459Message object at 0xb619e7f0>)
Traceback (most recent call last):
  File "/usr/lib/python3.3/site-packages/tornado/ioloop.py", line 477, in _run_callback
    callback()
  File "/usr/lib/python3.3/site-packages/tornado/stack_context.py", line 331, in wrapped
    raise_exc_info(exc)
  File "<string>", line 3, in raise_exc_info
  File "/usr/lib/python3.3/site-packages/tornado/stack_context.py", line 302, in wrapped
    ret = fn(*args, **kwargs)
  File "/usr/lib/python3.3/site-packages/pydle-0.7.1-py3.3.egg/pydle/features/ctcp.py", line 81, in on_raw_notice
    nick, metadata = self._parse_user(message.source)
  File "/usr/lib/python3.3/site-packages/pydle-0.7.1-py3.3.egg/pydle/features/rfc1459/client.py", line 109, in _parse_user
    nickname, username, host = parsing.parse_user(data)
  File "/usr/lib/python3.3/site-packages/pydle-0.7.1-py3.3.egg/pydle/features/rfc1459/parsing.py", line 191, in parse_user
    if protocol.HOST_SEPARATOR in raw:
TypeError: argument of type 'NoneType' is not iterable

Flood model needs some re-thinking

Currently, pydle's flood model is very limited in its possibilites:

  • It follows a burst -> delay -> burst -> delay model, which is not how IRC servers expect to receive messages. Typically, a burst -> delay -> message -> delay -> message is folllowed in actual client implementations.
  • It fails to properly take floating point delays into account.
  • It is globally configured as part of the (undocumented) pydle.connection module, and should be configurable per-client.
  • The current code in pydle.connection.Connection._on_write is messy.

Timeouts handlers are not getting called

Read this along with UPDATE below for full issue description.

I am using an instance of pydle.Client with a few callback methods overridden.

When I disconnect from my network, the client instance continues to run as though it were still listening for data from socket. Assuming maybe the timeout checker/scheduler got delayed or held back by other resource intensive tasks, I gave it 5 minutes but this did not create any change.
Reconnecting to network doesn't trigger a change either even though the IRC server has dropped that client's connection long ago.

In the course of attempting to debug by myself, I have discovered that the on_data_error() inside _check_ping_timeout on this line does not fire as it should. Therefore by extension, the BasicClient.disconnect() and BasicClient.on_disconnect() functions aren't called either.

Could this have something to do with removing client side pinging in #20?
This is similar to #13

Pydle can't keep track of accounts on networks using Atheme.

Currently, pydle assumes that users are logged out when they change nicks, but this only happens in networks using Anope (as far as I know).

This breaks account tracking in freenode, espernet and some other networks. A solution could be to not assume that users are logged out when they change nicks and instead depend on account-notify or to add an option to tell pydle when it shouldn't assume that users are logged out when they change nicks.

Attempting to 'pip install pydle' fails if tornado isn't already installed

This is due to setup.py importing pydle, which tries to import tornado before pip can actually set anything up.

$ pip install pydle
Downloading/unpacking pydle
  Downloading pydle-0.8.0.tar.gz
  Running setup.py (path:/home/...../venv/build/pydle/setup.py) egg_info for package pydle
    Traceback (most recent call last):
      File "<string>", line 17, in <module>
      File "/home/...../venv/build/pydle/setup.py", line 2, in <module>
        import pydle
      File "/home/...../venv/build/pydle/pydle/__init__.py", line 1, in <module>
        from . import async, connection, protocol, client, features
      File "/home/...../venv/build/pydle/pydle/async.py", line 10, in <module>
        import tornado.concurrent
    ImportError: No module named 'tornado'
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):

  File "<string>", line 17, in <module>

  File "/home/...../venv/build/pydle/setup.py", line 2, in <module>

    import pydle

  File "/home/...../venv/build/pydle/pydle/__init__.py", line 1, in <module>

    from . import async, connection, protocol, client, features

  File "/home/...../venv/build/pydle/pydle/async.py", line 10, in <module>

    import tornado.concurrent

ImportError: No module named 'tornado'

----------------------------------------
Cleaning up...

It looks like you solved this in 902d6e6, but there hasn't been a PyPI release since then, so pip is still trying to grab a broken version.

Any chance you could push a new release?

Can't connect to ZNC - no way to send server passwords

So I'm trying to connect pydle to a ZNC server, but there doesn't seem to be a way to send server passwords. Unfortunately TLS cert auth also won't work because ZNC still requires a password to be sent, even if it's just a random string or blank.

Unknown command: [irc.znc.in] 464 ['username/servername:password', 'Password required']

Tor support

I need to use pydle with Tor, so i did a dirty modification in connection.py:

import socks
import socket
socks.set_default_proxy(socks.SOCKS5, "localhost", 9050)
socket.socket = socks.socksocket

Do you think it could be a feature to add in a proper way?
If so I would be glad to help.

AttributeError: module 'tornado.concurrent' has no attribute 'TracebackFuture'

import pydle
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.6/site-packages/pydle/init.py", line 1, in
from . import async, connection, protocol, client, features
File "/usr/lib/python3.6/site-packages/pydle/async.py", line 17, in
class Future(tornado.concurrent.TracebackFuture):
AttributeError: module 'tornado.concurrent' has no attribute 'TracebackFuture'

SSL errors on Linux

I'm attempting to run a client pool with 2 clients. This runs fine on Windows, but on Linux it seems to give me the following error if I enable TLS and connect to my server's SSL port:
ValueError: non-zero flags not allowed in calls to recv() on <class 'ssl.SSLSocket'>

When connecting to a regular port and having TLS disabled it gives me this:
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:598)

On Windows I ran Python 3.4.1. My Linux server runs 3.4.0.

Asynchronous futures for WHOIS

WHOIS/WHO/whatever should be implemented at some point but, due to their asynchronous nature, can't return a result immediately.

A sketch for implementing this might be using concurrent.futures and returning a Future from whois/who/etc. When issuing a WHOIS, a dictionary of Futures can be maintained and then dispatched later when the server finishes with WHOIS information.

Implement user/channel objects

TODO list:

Channels

Data members

Base implementation

  • users: List[str]
  • name: str

rfc 1459

  • modes: Set
  • topic: str
  • topic_by: str
  • created: ???
  • password: str
  • ban_list: List[???]
  • public: bool

Isupport (optionals)

  • exceptionlist : List[???]
  • inviteexceptlist: List[???]

Methods

TBD

Users

data members

Base

  • nickname: str
  • username: str
  • realname: str
  • hostname: str

RFC 1459

  • away: bool
  • away_message: Optional[str]

Account support

  • account: Optional[str]
  • identified: bool

methods

TBD

Original message is as follows:


Currently, users and channels are dicts โ€“ they would be better off and less gross as objects.

[asyncio] Client disconnects from server without pinging it.

Some servers base sending PING messages on the last time the client sent data to the server, causing the client to thing that it has disconnected from not receiving data. Instead, the client should PING the server to check if it is still connected.

Reconnect functionality does not appear to work on passworded servers.

I'm currently connecting a bot to ZNC (which requires a password to be passed to client.connect) and the initial connection works correctly. However, every once in a while this happens:

TimeoutError: Ping timeout: no data received from server in 300 seconds.
ERROR:IRCBot:(redacted):Unexpected disconnect. Attempting to reconnect.
WARNING:IRCBot:(redacted):Unknown command: [irc.znc.in] 464 ['(redacted)', 'Password required']

The reconnect-fail process repeats itself a few times until finally this exception happens and the bot dies:

ERROR:tornado.application:Exception in callback functools.partial(<function wrap.<locals>.null_wrapper at 0x10a8f2840>)
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/tornado/ioloop.py", line 605, in _run_callback
    ret = callback()
  File "/usr/local/lib/python3.6/site-packages/tornado/stack_context.py", line 277, in null_wrapper
    return fn(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/pydle/features/tls.py", line 37, in connect
    return super().connect(hostname, port, tls=tls, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/pydle/features/rfc1459/client.py", line 196, in connect
    self._register()
  File "/usr/local/lib/python3.6/site-packages/pydle/features/ircv3/cap.py", line 40, in _register
    super()._register()
  File "/usr/local/lib/python3.6/site-packages/pydle/features/rfc1459/client.py", line 213, in _register
    self.set_nickname(self._attempt_nicknames.pop(0))
IndexError: pop from empty list

I haven't looked into it properly but when this function is called during a reconnect, 'password' is always None even if one was initially passed when calling connect() the first time:
https://github.com/Shizmob/pydle/blob/3c1a6d11e949f0f06f4f3e059f859f34e149b4a2/pydle/features/rfc1459/client.py#L188-L196
I'm assuming the password is not being passed along with the rest of the parameters somewhere else in the code.

ValueError thrown when handling numeric 301

DEBUG:Donger:lizardirc:<< [jasper.lizardirc.org] 301 ['testdong', 'JB555|Server', 'AFK/Sleeping']
DEBUG:Donger:lizardirc:<< [jasper.lizardirc.org] 330 ['testdong', 'JB555|Server', 'JB555', 'is logged in as']
DEBUG:Donger:lizardirc:<< [jasper.lizardirc.org] 671 ['testdong', 'JB555|Server', 'is using a secure connection']
DEBUG:Donger:lizardirc:<< [jasper.lizardirc.org] 318 ['testdong', 'JB555|Server', 'End of /WHOIS list.']
ERROR:tornado.application:Exception in callback functools.partial(<function wrap..null_wrapper at 0x7f9c4153e400>, <pydle.features.rfc1459.parsing.RFC1459Message object at 0x7f9c41544208>)
Traceback (most recent call last):
File "/usr/local/lib/python3.4/dist-packages/tornado/ioloop.py", line 604, in _run_callback
ret = callback()
File "/usr/local/lib/python3.4/dist-packages/tornado/stack_context.py", line 275, in null_wrapper
return fn(_args, *_kwargs)
File "/usr/local/lib/python3.4/dist-packages/pydle/features/rfc1459/client.py", line 770, in on_raw_301
nickname, message = message.params[0]
ValueError: too many values to unpack (expected 2)

ValueError thrown when using disconnect()

ERROR:tornado.application:Exception in callback functools.partial(<function wrap..null_wrapper at 0x7fd97c7ed1e0>, True)
Traceback (most recent call last):
File "/usr/local/lib/python3.4/dist-packages/tornado/ioloop.py", line 604, in _run_callback
ret = callback()
File "/usr/local/lib/python3.4/dist-packages/tornado/stack_context.py", line 275, in null_wrapper
return fn(_args, *_kwargs)
File "/usr/local/lib/python3.4/dist-packages/pydle/client.py", line 122, in _disconnect
self.connection.off('read', self.on_data)
File "/usr/local/lib/python3.4/dist-packages/pydle/connection.py", line 295, in off
self.handlers[method].remove(callback)
ValueError: list.remove(x): x not in list

Timeout handler waits for too long

Coming from issue #37 - Read it for the train of discovery leading to this issue.

According to this line in client.py it will check for timeout every PING_TIMEOUT / 2 seconds. But the second time that it checks for timeout, the current time elapsed will be at the same number of seconds as PING_TIMEOUT and thus will not trigger a timeout. So the checking function will have to run another time for the timeout to register.
Meaning that the actual client will have to run for 1.5 times the seconds specified by PING_TIMEOUT before it can timeout.

I have no qualms with this approach but since the default value for PING_TIMEOUT is set to 720 seconds or 12 minutes, this means that the program will run for 18 minutes total before timing out. This is simply way too long.

I propose two solutions : Either change the default value of PING_TIMEOUT to 120 seconds. (I've tested this to be the best value along multiple servers).
Or make the timeout register with an equal to or less than comparison so that the checker does not need to run a third time. This should be used in combination with a lower PING_TIMEOUT value as well to something like 180 seconds, because the default value of 12 minutes is still too much.

errors when user quits

I keep getting this kind of error when a user quits (on master):

ERROR:tornado.application:Exception in callback functools.partial(<function wrap.<locals>.null_wrapper at 0xb6c87e84>, <pydle.features.rfc1459.parsing.RFC1459Message object at 0xb6cad56c>)
Traceback (most recent call last):
  File "/home/flavi0/.local/lib/python3.4/site-packages/tornado/ioloop.py", line 600, in _run_callback
    ret = callback()
  File "/home/flavi0/.local/lib/python3.4/site-packages/tornado/stack_context.py", line 275, in null_wrapper
    return fn(*args, **kwargs)
  File "/home/flavi0/.local/lib/python3.4/site-packages/pydle-0.8.0-py3.4.egg/pydle/features/rfc1459/client.py", line 719, in on_raw_quit
    self._destroy_user(nick)
TypeError: _destroy_user() missing 1 required positional argument: 'channel'

Can't seem to find /names functionality

hello there,

I've been testing this library for a bit now and it seems to be great. though i am trying to find a way to trigger the /names function to get the current list of users of a channel.
I'm aware of

channels['#channel']['users'] 

though it is not updated once a new users joins a channel- is there any alternative that i might have overlooked?

thanks!

How to access tags (ircv3.TaggedMessageSupport)

I am interested in accessing the tags of private messages. Currently I do this in the following fashion:

class PrivMessageTagSupport(pydle.features.ircv3.TaggedMessageSupport):
  def on_raw_privmsg(self, message):
    """ PRIVMSG command. """
    nick, metadata = self._parse_user(message.source)
    tags = message.tags
    target, message = message.params

    self._sync_user(nick, metadata)

    self.on_message(target, nick, message, tags)
    if self.is_channel(target):
        self.on_channel_message(target, nick, message, tags)
    else:
        self.on_private_message(nick, message, tags)

Which is mostly a copy-paste of the on_raw_privmsg method of RFC1459Support and feels kind of messy. Is this the recommended way of handling tagged messages? Or do you have any plans to make access of tags easier in the library?

Thanks for the great work btw!

RFC1459Support does not handle on_raw_301 (/whois user is away) correctly

The current code for RFC1459Support's on_raw_301 method looks like this:

def on_raw_301 (self, message):
    """ User is away. """
    nickname, message = message.params[0]
    # [...]

However, message.params[0] is not unpackable and corresponds to the target of the whois query. It should probably read as:
target, nickname, message = message.params
or
nickname, message = message.params[1:]

Exceptions in coroutines never retrieved

When an exception is thrown inside a coroutine event, the exception doesn't make it to stdout. The exception just seems to be silently dropped, and the coroutine doesn't continue execution for that event.
Sometimes, on ending the program, there'll be an error like
ERROR:tornado.application:Future <pydle.async.Future object at 0x02FB3B30> exception was never retrieved
which includes the traceback and exception that was thrown.

ClientPool is not robust

If any connection in the pool dies or is otherwise invalidated (bad file descriptor, connection reset by peer), the entire client pool dies.

2014-02-04 02:09:49,109 [Client:freenode] WARNING: Unknown command: [None] ERROR ['Closing Link: gefjun.rfw.name (No more connections allowed in your connection class)']
Traceback (most recent call last):
  File "/home/rfw/.virtualenvs/kochira/bin/kochira", line 9, in <module>
    load_entry_point('kochira==0.0', 'console_scripts', 'kochira')()
  File "/home/rfw/kochira/kochira/__init__.py", line 164, in main
    bot.run()
  File "/home/rfw/kochira/kochira/__init__.py", line 42, in run
    self._connect_to_irc()
  File "/home/rfw/kochira/kochira/__init__.py", line 78, in _connect_to_irc
    self.pool.handle_forever()
  File "/home/rfw/pydle/pydle/client.py", line 973, in handle_forever
    self.wait_for_message()
  File "/home/rfw/pydle/pydle/client.py", line 977, in wait_for_message
    return self.connpool.wait_for_message()
  File "/home/rfw/pydle/pydle/connection.py", line 475, in wait_for_message
    readable, writable, error = select.select(sockets.keys(), [], [])
ValueError: file descriptor cannot be a negative integer (-1)

Timeouts for Futures

If a Future never completes, code could be stuck. I don't know important this is but it may be worth looking into it.

Client should not send PINGs

14:19:13 <Shiz>    Servers should not respond to PING commands but rely on PINGs from
14:19:15 <Shiz>    the other end of the connection to indicate the connection is alive.

As discussed, what should ideally happen is:

  • On any read/write from the socket, the timeout, er... timeout, should be cleared and a new one set TIMEOUT_TIME seconds in the future.
  • If we don't receive anything from the server in that time, the timeout will be fired โ€“ the connection should be closed and we should attempt to reestablish the connection.

Any way to handle message formatting? (colors etc.)

Maybe I'm missing something but currently I can't seem to figure out how to get the messages without the leftover from the formatting. All I did was adding a print(message) line to the 'Basic Usage' example's on_message method and enter a channel that's full of formatting. Here's the output:
https://i.imgur.com/kqRVlmG.png
It does leave the color codes in the message. For example the 04 is red etc. What should I do to get only the plain text message without any type of formatting? (colors, bold, italic etc.)

I found an answer elsewhere on how to strip the colors, but I'm not sure where to apply it:
regex = re.compile("\x1f|\x02|\x12|\x0f|\x16|\x03(?:\d{1,2}(?:,\d{1,2})?)?", re.UNICODE)

Thank you.

OSError: [WinError 10038] An operation was attempted on something that is not a socket

Hello, I'm trying to disconnect a client in a pool (from another client in that pool), when I attempt to do so, I get this error, "OSError: [WinError 10038] An operation was attempted on something that is not a socket", presumably because its not removing the socket from the eventloop in time, or something like that. What can I do to prevent this error. (Python 3.5.2, Windows 10) OK, I just tested in Cygwin, and it gives "ValueError: I/O operation on closed file". (Python 3.4.3, Cygwin on Windows 10)
EDIT: I should rephrase, it allows the disconnect, and continues running the function, but after the funtion finishes, it errors.

client.whois() seems case sensitive

If there was a user named "user" on IRC and I used client.whois on them like so:

client.whois("USER")

the whois would never be completed because it seems whois is scanning for whois lines from a user named "USER" not "user".

Main questions:

  • Is this just a problem with how I am using pydle?
  • Is this functionality intentional?
  • Can it be fixed?

>18 lines sent by TLSSupport.message getting lost

Hi, I am running pydle master on our fileserver, which also hosts our IRC server, in order to send status information about raid health/usage etc. into our private discussion channel.

Messages are being lost, if I send more than 18 lines from a single on_message handler. It seems to me that there is some internal buffer or queue overflowing. I tried throttling send rate in my own code, but the messages will only appear if my code finished the on_message handler so that's not helping. Also I'm pretty sure it's not sending rate related, our server is not configured in any way regarding that, and I wrote irssi scripts the other day which quickly generate screens full of text, and that is displayed just fine. I also tried setting self.connection.throttle = True which did not change anything.

I started tracking this down in the pydle code and for now stopped at the point where the asynchronous processing in tornado.ioloop begins. I suspect that either

  • I am using message wrong / at the wrong place, meaning inside the on_message handler (most likely)
  • There is some internal send queue size limitation
  • When pulling messages from the queue there are threading issues / race conditions of some sort

Thanks in advance

Tornado 5.0 broke package

Tornado 5.0 was released three days ago and broke this package.

AttributeError: module 'tornado.concurrent' has no attribute 'TracebackFuture'

As a workaround add tornado==4.5.3 in the top of your own requirements.txt before installing pydle.

For pydle's part, you'd need to set dependencies to less than 5.0.0, or a specific version.

[Asyncio] Test suite is failing

While investigating what it would take to enable 3.7 compatibility, I discovered the test suite is not currently in a passing state and, therefore, it is not possible to reliably prove any fix would take effect without introducing bugs / breaking behaviors.

This is very worrying, as my organization is building a IRC bot using this library that cannot blow up randomly do to an undetected bug in the underlying IRC infrastructure. As the tests are not passing, the stability of this project cannot be reliably proven. While Pydle appears to function as it is documented based on integration tests, It may prove difficult to both maintain the project and upgrade it without passing tests.

Environment:
Windows 10 x64, Linux
python x64 v 3.6.3 and 3.6.6

Test summery:

================================================= test session starts ==================================================
platform linux -- Python 3.6.6, pytest-3.6.3, py-1.5.4, pluggy-0.6.0
rootdir: /pydle, inifile: tox.ini
collected 53 items

tests/test__fixtures.py ...F                                                                                     [  7%]
tests/test__mocks.py FFF.........                                                                                [ 30%]
tests/test_client.py .FF.F.FFFFFF                                                                                [ 52%]
tests/test_client_channels.py ......                                                                             [ 64%]
tests/test_client_users.py ..............                                                                        [ 90%]
tests/test_featurize.py .....                                                                                    [100%]

Full error output: gist

looks like there is an issue somewhere in MockClient._connect, however I have been unable to narrow it down.

My apologies for wasting your time should this already be a known issue, for I am unable to find any reference to tests in recent issue tickets.

[asyncio] Catch ConnectionErrors and force reconnect.

If a connection has a ConnectionError (for example ConnectionResetError), it does not get detected by pydle, and does not reconnect. It also seems that TimeoutErrors are not being caught either, once again causing pydle to not reconnect.

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.