shizmob / pydle

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

Unexpected keyword argument 'loop' under Python 3.10 #162

Open felixonmars opened 2 years ago

felixonmars commented 2 years ago
    await client.connect(config["irc"]["server"], tls=True, tls_verify=True)
  File "/usr/lib/python3.10/site-packages/pydle/features/tls.py", line 35, in connect
    return await super().connect(hostname, port, tls=tls, **kwargs)
  File "/usr/lib/python3.10/site-packages/pydle/features/rfc1459/client.py", line 190, in connect
    await super().connect(hostname, port, **kwargs)
  File "/usr/lib/python3.10/site-packages/pydle/client.py", line 124, in connect
    await self._connect(hostname=hostname, port=port, reconnect=reconnect, **kwargs)
  File "/usr/lib/python3.10/site-packages/pydle/features/tls.py", line 54, in _connect
    await self.connection.connect()
  File "/usr/lib/python3.10/site-packages/pydle/connection.py", line 48, in connect
    (self.reader, self.writer) = await asyncio.open_connection(
  File "/usr/lib/python3.10/asyncio/streams.py", line 47, in open_connection
    transport, _ = await loop.create_connection(
TypeError: BaseEventLoop.create_connection() got an unexpected keyword argument 'loop'
Rixxan commented 2 years ago

Looking through some of the other open issues, it does not appear Pydle supports Python 3.10 at present (Ref #161, #142) as a few places call asyncio.coroutine which was removed in Python 3.10.

I can't say if this issue is related to that or not, but it might be a contributing factor. Can you provide more information about your environment and the context this code is in to assist in diagnosis?

theunkn0wn1 commented 2 years ago

Dug into this a bit. There are a couple distinct issues

client = Client("MyBot", realname='My Bot')

@client.event async def on_connect(self): await self.join('#bottest')

@client.event 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)

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

if name == "main": asyncio.run(main())

Pydle tries to run on a different event loop than it was called under.
```py
RuntimeError: Task <Task pending name='Task-1' coro=<main() running at test.py:20> cb=[_run_until_complete_cb() at /usr/lib/python3.8/asyncio/base_events.py:184]> got Future <Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.8/asyncio/futures.py:360]> attached to a different loop

The currently "correct" version of the above is:

from pydle import Client
import asyncio

loop = asyncio.get_event_loop()
client = Client("MyBot", realname='My Bot', loop=loop)

@client.event
async def on_connect(self):
    await self.join('#bottest')

@client.event
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)

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

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

The real fix here would be to remove Pydle's internal handling of the event loop object entirely, and instead depend upon the fact that pydle's coroutines will be awaited by downstream code - from a valid event loop. By removing the loop parameter from pydle.Client and all internal logic that uses self.eventloop, we can eliminate this class of issue all together.

Doing so would be a breaking change by semver, as it changes the public api in a backward-incompatible way.

Baughn commented 1 year ago

Is this still a problem on 3.11, or is upgrading Python a potential solution?

Rixxan commented 1 year ago

@Baughn

Pydle is also broken on 3.11. Upgrading is not a fix. See #180 for the current discussion on various potential fixes.

I'll also note for the record that 3.11 removed coroutine as a valid import from asyncio (see: https://docs.python.org/3.11/whatsnew/3.11.html#removed) but Pydle still attempts in some places to import that, so once 3.10 compatibility is confirmed 3.11 will need to have another look.