shizmob / pydle

An IRCv3-compliant Python 3 IRC library.
BSD 3-Clause "New" or "Revised" License
154 stars 48 forks source link

Error connecting to a channel without a topic #158

Closed ghost closed 2 years ago

ghost commented 3 years ago

I've just started tinkering with pydle, and I encountered this error when attempting to connect to my local IRC server and join a channel without a topic.

I think the error occurred because there is no on_raw_331 function to handle the 331 response (RPL_NOTOPIC). Also, I'm not very good with asyncio, and I don't really understand the mentions of it in the error. Would this be the expected handling of an error, or have I made some mistake with asyncio in my initial setup?

Setup

import pydle
import asyncio

class Me(pydle.Client):
    async def on_connect(self):
        await super().on_connect()
        await self.join("#home")

async def test():
    client = Me("justme")
    await client.connect('<local server>', port=6667, tls=True)
    return client

async def connect():
    client = await test()
    await client.handle_forever()

asyncio.run(connect())

Error

Task exception was never retrieved
future: <Task finished name='Task-2' coro=<BasicClient.handle_forever() done, defined at /home/user/.local/lib/python3.9/site-packages/pydle/client.py:363> exception=RuntimeError('readuntil() called while another coroutine is already waiting for incoming data')>
Traceback (most recent call last):
  File "/home/user/.local/lib/python3.9/site-packages/pydle/client.py", line 367, in handle_forever
    data = await self.connection.recv(timeout=self.READ_TIMEOUT)
  File "/home/user/.local/lib/python3.9/site-packages/pydle/connection.py", line 115, in recv
    return await asyncio.wait_for(self.reader.readline(), timeout=timeout)
  File "/usr/lib/python3.9/asyncio/tasks.py", line 481, in wait_for
    return fut.result()
  File "/usr/lib/python3.9/asyncio/streams.py", line 540, in readline
    line = await self.readuntil(sep)
  File "/usr/lib/python3.9/asyncio/streams.py", line 632, in readuntil
    await self._wait_for_data('readuntil')
  File "/usr/lib/python3.9/asyncio/streams.py", line 503, in _wait_for_data
    raise RuntimeError(
RuntimeError: readuntil() called while another coroutine is already waiting for incoming data
Unknown command: [irc-5887d475f-8f8z4] 331 ['justme', '#home', 'No topic is set']

Environment

IRC Server

$ miniircd --version
2.1

Local

$ python --version
Python 3.9.6
$ pip show pydle | grep Version
Version: 0.9.4
theunkn0wn1 commented 2 years ago

This is a usage error.

pydle.Client.connect schedules pydle.Client.handle_forever for execution via asyncio.create_task. calling it a second time results in the above exception.

see https://github.com/Shizmob/pydle/blob/c0c0d619c1ae29f2a5e205252dd5efbc504468b8/pydle/client.py#L130

import pydle
import asyncio

class Me(pydle.Client):
    async def on_connect(self):
        await super().on_connect()
        await self.join("#home")

async def main():
    client = client = Me("justme")
    await client.connect('localhost', tls=True, tls_verify=False)

if __name__ == "__main__":
    loop.run_until_complete(main())
    loop.run_forever()