#π What does it mean when I get the error "function was never awaited"
172 messages Β· Page 1 of 1 (latest)
@ocean pike
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.
it returns a task object which needs to be awaited iirc
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.
I thought create_task would just run the function in the background while the code continues to run?
It's not a thread. Async tasks and functions are run by the event loop.
await asyncio.create_task(function())
its almost the same as,
t = asyncio.create_task(function())
await t
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.
Possibly the event loop was closed when you created your task
Can you show your code?
Probably you want to make a TaskGroup. Add the task to it. At the end, await the group. Tidies it all up.
!e
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
see! if there's no running loop then you can get a never awaited warning
you collect them with pytest filterwarnings=error and unraisablehook
I can't await anything because main.py is not an async function or something
You can start an event loop in main.
Something like:
with asyncio.Runner() as runner:
do async stuff in here ...
ooh should avoid runner
This should start an event loop
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
Feel free to make a better suggestion. The OP has a sync main, and wants to do aomse async stuff inside it.
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())
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
It's way too big π
!paste
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.
Okay... Uh.. I'm sorry if the code is too long and messy, I haven't had the time to sort everything out nicely
A Thread would do this for you.
Threads sound so complicated...
probably a thread is the way to go
It's very much like a task.
I thought it would be simpler to just use asyncio
well with asyncio you can't have something in the background and something in the foreground unless everything is async
Really??
or you use a thread
from threading import Thread
T = Thread(target=function) # note: no () there
T.start()
I have no idea how threading works and the documentation looked more incomprehensible than asyncio's documentation..
possibly it's easier to manage threads with asyncio
It's as easy as the above.
once we'be seen the code we can diagnose a solution
Could I just do Thread().start()?
Yeah, like:
Thread(target=function).start()
but we need to see the code can't really tell what's happening
oh you're doing a discord bot?
Yeah but that's not the main point here-
that means you have to use asyncio
you can't use requests etc
https://paste.pythondiscord.com/PQVA#2L285-L285 you know you can link to a line?
just click the line number
I don't, no
so what do you want to run concurrently with what?
I want to run line 285
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()?
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
show your new code
New code..?
That's a top level line. What if it's inside the on-ready function?
I didn't do anything
oh
I want the task to be created only once though
(I'm assuming on_ready is run just once when the bot starts.
I wish
Ah ok. Is there something which is called just once?
you probably want it run each time the bot is started
Aye, that.
Do bots have an async startup method?
Why do we have to do this through discord.py? Can't I just run this on main.py outside it?
there is setup_hook
in discord.py specifically
Why is that?
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"
Oh
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()
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
Hmm. Is the bot itself made inside a runner? You could give MyBot an __init__ which started the task.
Does this matter? Genuine question.
What's the downside to starting the task yourself?
Somehow putting the create_task inside the setup_hook worked..?
I honestly don't understand why
because it's in the event loop
Well you're inside an event loop then. It's allowed.
but you loose any exceptions if you don't await it
It'll be fine I think
GCd?
garbage collected
Wait really?
No references to it, so garbage collection like other obejcts.
basically don't use create_task unless you're making a TaskGroup
So if I create a task and just leave it, it may be gone?
yep you need a TaskGroup
This isn't good..
Just stash the class on MyBot: self.the_task = create_task(....)
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
No I want it to run in the background
don't make it recursive or you'll run out of stack
discord has a tool for running async functions in a loop
I just want JavaScript's equivalent of setInterval π
I don't know why that's a lot to ask of Python
from discord.ext import tasks
Huh?
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()
people don't use setInterval in JS anymore - they use a while loop
Why?
i have very little idea of your problem but answering from js setInterval could be programmed like this in python
import threading
def set_interval(func, sec):
def func_wrapper():
set_interval(func, sec)
func()
t = threading.Timer(sec, func_wrapper)
t.start()
return t
Hey @frozen galleon!
Add a py after the three backticks.
```py
print('Hello, world!')
```
This will result in the following:
print('Hello, world!')```
my mistake gng
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
Oh, huh
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.
const sleep = async (ms) => await { then(cb) { setTimeout(cb, ms) };
async function setInterval(cb, interval) {
while (true) {
cb();
await sleep(interval);
}
}
^^ the JS version
Sorry I'm really tired, I haven't slept all night π
TypeError: MyBot.prompt_handler() takes 5 positional arguments but 6 were given
Although I gave it 5..
self.prompt_handler.start(PROMPT_LIST, tools, all_chat_sessions, DEBUG_MODE, TOKEN_LIMIT)
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.
can you show your new code
So the 3 argument call ends up as 4 at the method itself, the first being self
like this ^
Why π
Probably because discord's decorator doesn't pass any when it calls this on your behalf.
@tasks.loop(seconds=0.25)
async def prompt_handlerer(self):
await functions.prompt_handler(PROMPT_LIST, tools, all_chat_sessions, DEBUG_MODE, TOKEN_LIMIT)
So the magic method takes no args, but it calls your operation with whatever args are needed.
TypeError: MyBot.prompt_handlerer() takes 0 positional arguments but 1 was given
show your code
You need to define it with a (self) param.
missing self https://paste.pythondiscord.com/U6LQ#1L361-L361
Oh..
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.
I see :o
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.