#πŸ”’ What does it mean when I get the error "function was never awaited"

172 messages Β· Page 1 of 1 (latest)

ocean pike
#

and it points to the line saying asyncio.create_task(function())? Like, you're not supposed to await a create_task, so I don't understand why the code is upset?

ember reefBOT
#

@ocean pike

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

vivid trench
#

it returns a task object which needs to be awaited iirc

chilly aspen
#

You're meant to wait for completion of any outstanding tasks before ending the event loop.

#

When the event loop exits there's nothing to run any outstanding (incomplete) tasks.

#

You don't await the task when you make it but you need to await it at some point.

ocean pike
#

I thought create_task would just run the function in the background while the code continues to run?

chilly aspen
#

It's not a thread. Async tasks and functions are run by the event loop.

vivid trench
#
await asyncio.create_task(function())

its almost the same as,

t = asyncio.create_task(function())
await t
chilly aspen
#

So when you make a task, that makes an object which the event loop "runs" until it awaits something. So bits of the task get run.

still shuttle
#

Can you show your code?

chilly aspen
#

Probably you want to make a TaskGroup. Add the task to it. At the end, await the group. Tidies it all up.

still shuttle
#

!e

import asyncio

async def foo():
    pass

asyncio.create_task(foo())
ember reefBOT
# still shuttle !e ```python import asyncio async def foo(): pass asyncio.create_task(foo(...

:x: Your 3.12 eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "/home/main.py", line 6, in <module>
003 |     asyncio.create_task(foo())
004 |   File "/snekbin/python/3.12/lib/python3.12/asyncio/tasks.py", line 417, in create_task
005 |     loop = events.get_running_loop()
006 |            ^^^^^^^^^^^^^^^^^^^^^^^^^
007 | RuntimeError: no running event loop
008 | sys:1: RuntimeWarning: coroutine 'foo' was never awaited
still shuttle
#

see! if there's no running loop then you can get a never awaited warning

#

you collect them with pytest filterwarnings=error and unraisablehook

ocean pike
chilly aspen
#

You can start an event loop in main.

#

Something like:

with asyncio.Runner() as runner:
    do async stuff in here ...
still shuttle
#

ooh should avoid runner

chilly aspen
#

This should start an event loop

ocean pike
# still shuttle Can you show your code?

So there is quite a bit of junk in the way but um I have a functions.py file
In main.py I have

import functions
import asyncio

asyncio.create_task(functions.stuff_handler(args))

and in functions.py

async def stuff_handler():
  return
chilly aspen
still shuttle
#

just do

import asyncio
import functions

async def amain():
    await functions.stuff_handler(args)
    return 0

def main():
    return asyncio.run(amain())

if __name__ == "__main__":
    sys.exit(main())
ocean pike
#

All I wanted was, like, to have code running in the background which would process an array every few seconds, one element at a time

still shuttle
#

in the background to what?

#

can you show your whole file

ocean pike
#

It's way too big 😭

still shuttle
#

!paste

ember reefBOT
#
Pasting large amounts of code

If your code is too long to fit in a codeblock in Discord, you can paste your code here:
https://paste.pythondiscord.com/

After pasting your code, save it by clicking the Paste! button in the bottom left, or by pressing CTRL + S. After doing that, you will be navigated to the new paste's page. Copy the URL and post it here so others can see it.

ocean pike
#

Okay... Uh.. I'm sorry if the code is too long and messy, I haven't had the time to sort everything out nicely

still shuttle
#

you don't need to sort it out

#

it just needs to run eh?

chilly aspen
ocean pike
#

Threads sound so complicated...

still shuttle
#

probably a thread is the way to go

chilly aspen
#

It's very much like a task.

ocean pike
#

I thought it would be simpler to just use asyncio

still shuttle
#

well with asyncio you can't have something in the background and something in the foreground unless everything is async

ocean pike
#

Really??

still shuttle
#

or you use a thread

chilly aspen
#
from threading import Thread

T = Thread(target=function) # note: no () there
T.start()
ocean pike
#

I have no idea how threading works and the documentation looked more incomprehensible than asyncio's documentation..

still shuttle
#

possibly it's easier to manage threads with asyncio

still shuttle
#

once we'be seen the code we can diagnose a solution

ocean pike
still shuttle
#

best to use a tpe

#

ThreadPoolExecutor

chilly aspen
#

Yeah, like:

Thread(target=function).start()
still shuttle
#

but we need to see the code can't really tell what's happening

ocean pike
#

I guess I can show the code.. It's a bit embarrassing

still shuttle
#

oh you're doing a discord bot?

ocean pike
#

Yeah but that's not the main point here-

still shuttle
#

that means you have to use asyncio

#

you can't use requests etc

#

just click the line number

ocean pike
#

I don't, no

still shuttle
#

so what do you want to run concurrently with what?

ocean pike
#

I want to run line 285

chilly aspen
#

Looks like this:

asyncio.create_task(functions.prompt_handler(PROMPT_LIST, tools, all_chat_sessions, DEBUG_MODE, TOKEN_LIMIT))

is the only async stuff called outside the event loop (the bot stuff runs inside an event loop - all the funcs are async).

Can you put that line in MyBot.on_ready()?

ocean pike
#

But it gives me this

Traceback (most recent call last):
  File "main.py", line 285, in <module>
    asyncio.create_task(functions.prompt_handler(PROMPT_LIST, tools, all_chat_sessions, DEBUG_MODE, TOKEN_LIMIT))
    ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "AppData\Local\Programs\Python\Python313\Lib\asyncio\tasks.py", line 407, in create_task
    loop = events.get_running_loop()
RuntimeError: no running event loop
<sys>:0: RuntimeWarning: coroutine 'prompt_handler' was never awaited
still shuttle
#

show your new code

ocean pike
#

New code..?

chilly aspen
ocean pike
#

I didn't do anything

still shuttle
#

oh

ocean pike
chilly aspen
#

(I'm assuming on_ready is run just once when the bot starts.

ocean pike
#

I wish

chilly aspen
#

Ah ok. Is there something which is called just once?

still shuttle
#

you probably want it run each time the bot is started

chilly aspen
#

Aye, that.

still shuttle
#

like if it reconnects

#

you still want it run again probably

chilly aspen
#

Do bots have an async startup method?

still shuttle
#

you can read the code of bot.run

#

it's somewhat simple these days

ocean pike
#

Why do we have to do this through discord.py? Can't I just run this on main.py outside it?

still shuttle
#

you could just use asyncio.run here

#

it's a bit unusual

vivid trench
ocean pike
still shuttle
#

having two asyncio.run calls in a prod program is unusual

#

the way I'd do it

#

is have it in on_ready and use a bool for "did run"

ocean pike
still shuttle
#

and do

if self.did_start_promp_handler:
    return
self.did_start_promp_handler = True
await functions.prompt_handler(PROMPT_LIST, tools, all_chat_sessions, DEBUG_MODE, TOKEN_LIMIT)
self.prompt_handler_finished.set()
vivid trench
# ocean pike Oh

yeah and this isn't an event so you could either subclass the commands.Bot and override the setup_hook or do your_bot_instance.setup_hook = your_async_setup_function

chilly aspen
#

Hmm. Is the bot itself made inside a runner? You could give MyBot an __init__ which started the task.

still shuttle
#

nuuu don't create_task

#

await the coro in on_ready let discord start all the tasks

chilly aspen
#

Does this matter? Genuine question.

#

What's the downside to starting the task yourself?

ocean pike
#

Somehow putting the create_task inside the setup_hook worked..?

#

I honestly don't understand why

still shuttle
#

because it's in the event loop

chilly aspen
#

Well you're inside an event loop then. It's allowed.

still shuttle
#

but you loose any exceptions if you don't await it

ocean pike
still shuttle
#

no just await it

#

and your task can get GCd if you don't keep a reference to it

ocean pike
#

GCd?

still shuttle
#

garbage collected

ocean pike
#

Wait really?

chilly aspen
still shuttle
#

basically don't use create_task unless you're making a TaskGroup

ocean pike
#

So if I create a task and just leave it, it may be gone?

still shuttle
#

yep you need a TaskGroup

ocean pike
#

This isn't good..

chilly aspen
#

Just stash the class on MyBot: self.the_task = create_task(....)

still shuttle
#

that helps

#

but you can just await the coro!!

ocean pike
#

All I wanted was to start a function that would await a second at the end and then return itself to start it again, doing this loop forever

still shuttle
#

you don't even need a task

#

you mean a while loop?

ocean pike
#

No I want it to run in the background

still shuttle
#

don't make it recursive or you'll run out of stack

#

discord has a tool for running async functions in a loop

ocean pike
#

I just want JavaScript's equivalent of setInterval 😭

#

I don't know why that's a lot to ask of Python

still shuttle
#

from discord.ext import tasks

ocean pike
#

Huh?

still shuttle
#
class MyBot(...):
    @tasks.loop(seconds=5.0)
    async def handlerer(self):
        await functions.prompt_handler(PROMPT_LIST, tools, all_chat_sessions, DEBUG_MODE, TOKEN_LIMIT)
#

then you do self.handlerer.start()

still shuttle
ocean pike
#

Why?

frozen galleon
ember reefBOT
#

Hey @frozen galleon!

Please edit your message to use a code block

Add a py after the three backticks.

```py
print('Hello, world!')
```

This will result in the following:

print('Hello, world!')```
frozen galleon
#

my mistake gng

chilly aspen
# ocean pike Why?

Browser JS is single threaded, like the asyncio stuff. So setInterval arranged to do this for you.
I gather the JS models' better these days and a while loop presumably does the equivalent of asyncio.sleep().

So the trite example for your task in the background is

async def function(....):
    while True:
        ... do stuff ...
        asyncio.sleep(1.0) # or whatever seconds
ocean pike
#

Oh, huh

chilly aspen
#

The @tasks.loop(seconds=5.0) example graingert gave is some mechanics discord provides for regular calls to a method.

#

Sorry await asyncio.sleep(1.0)

#

The await is the magic glue which yields control when you do a "blocking" thing in async, letting the event loop run something else meanwhile.

still shuttle
#
const sleep = async (ms) => await { then(cb) { setTimeout(cb, ms) };
async function setInterval(cb, interval) {
    while (true) {
        cb();
        await sleep(interval);
    }
}
chilly aspen
#

^^ the JS version

still shuttle
#

you need the await asyncio.sleep(1.0)

#

oh you said

ocean pike
#

Sorry I'm really tired, I haven't slept all night 😭

ocean pike
#

Although I gave it 5..
self.prompt_handler.start(PROMPT_LIST, tools, all_chat_sessions, DEBUG_MODE, TOKEN_LIMIT)

chilly aspen
#

Can you show the definition of the prompt_handler method?

When you call obj.method(a,b,c) the method itself gets calls with (obj,a,b,c), which obj landing as the self parameter.

still shuttle
#

can you show your new code

chilly aspen
#

So the 3 argument call ends up as 4 at the method itself, the first being self

still shuttle
#

you shouldn't pass any arguments to the method

#

and it should be called handlerer

ocean pike
ocean pike
chilly aspen
#

Probably because discord's decorator doesn't pass any when it calls this on your behalf.

still shuttle
#
    @tasks.loop(seconds=0.25)
    async def prompt_handlerer(self):
        await functions.prompt_handler(PROMPT_LIST, tools, all_chat_sessions, DEBUG_MODE, TOKEN_LIMIT)

chilly aspen
#

So the magic method takes no args, but it calls your operation with whatever args are needed.

ocean pike
#

TypeError: MyBot.prompt_handlerer() takes 0 positional arguments but 1 was given

still shuttle
#

show your code

chilly aspen
#

You need to define it with a (self) param.

ocean pike
still shuttle
ocean pike
#

Oh..

chilly aspen
#

Yeah this:

    @tasks.loop(seconds=0.25)
    async def prompt_handlerer():

should be:

    @tasks.loop(seconds=0.25)
    async def prompt_handlerer(self):
#

Discord's got a reference to your bot, let's call it bot. It's calling bot.prompt_handlerer(). Which becomes MyBot.prompt_handlerer(bot), and bot lands as self.

ocean pike
#

I see :o

ocean pike
#

It is working so magnificently well...

#

!close

ember reefBOT
#
Python help channel closed with !close

This help channel has been closed. Feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.