I am currently working on asyncio with python 3.7.x not sure about the exact version, right now I am trying to schedule a task. And I am unable to get an output, even when running the thing forever. Here is the code I currently have
import asyncio
async def print_now():
print("Hi there")
loop = asyncio.get_event_loop()
loop.call_later(print_now())
loop.run_until_complete(asyncio.sleep(1))
This gives the following error:
Traceback (most recent call last):
File "D:\Coding\python\async\main.py", line 7, in <module>
loop.call_later(print_now())
TypeError: call_later() missing 1 required positional argument: 'callback'
The call back in call_later() is print_now I've tried just print_now and print_now()
I have also tried using loop.run_forever() instead of loop.run_until_complete() and so far I didn't get anything
Sometimes I get either no output or a different error.
First, yes, you're missing a delay argument . First one is supposed to be the delay while the second one is a callback (docs).
loop.call_later(delay, callback, *args, context=None)
Second, the callback is supposed to be a function. What you're passing is print_now() which is gonna evaluate to None. You might find out that
'NoneType' object is not callable
So you're gonna need to pass print_now — without parentheses — as a callback. This way you're passing a function instead of the result of its application.
Third, async functions are supposed to be awaited on. Your scenario doesn't seem to need that, so just drop the async keyword.
When you call an awaitable function, you create a new coroutine object. The code inside the function won't run until you then await on the function or run it as a task
From this post. You might want to check out
Related
im using pyttsx3 for my telegram bot. i have this code.
def TTSBot(message):
print("TTS")
Engine.save_to_file(message.text, "Voice.mp3")
Engine.runAndWait()
FBot.send_audio(message.chat.id, open("Voice.mp3", "rb"), reply_to_message_id=message.id)
print("done")
this executes when the command is called but it sends the previous command. it dosnt wait for Engine to finish it's work. how do i make it wait?
i tried using Engine.runAndWain() inside the send_audio bot it dosnt return the Voice file.
also if you know a way to not save the file and just directly input it into the commands let me know.
Please specify your operating system next time you deal with audio in case you are on linux and you simply need to install a few packages to fix this.
Now, the problem you requested is not regarding pyttsx3 but regarding FBot.
I assume you are using python-telegram bot because the API looks alike. Within its docs the function bot.send_audio is async which means you must mark your function as asynchronous to await the function FBot.send_audio().
You can, of course, put the event loop inside TTSBot() but it's better to put it in their caller.
This is the complete code for reference.
import asyncio
# import other libraries
# other code
async def TTSBot(message):
# print("TTS") (it is not advised to put simple messages like this, instead use a logger)
Engine.save_to_file(message.text, "Voice.mp3")
Engine.runAndWait()
await FBot.send_audio(message.chat.id, open("Voice.mp3", "rb"), reply_to_message_id=message.id)
#print("done") (it is not advised to put simple messages like this, instead use a logger)
def caller(): # put real function
# other code
asyncio.run(TTSBot(msg))
# if you are using Python3.6 or lower, comment the previous line and uncomment the following lines
# loop = asyncio.get_event_loop()
# loop.run_until_complete(TTSBot(msg))
# loop.close()
# other code
UPDATE
Since you are using pytelegrambotapi, in its documention the audio file shall not be of type str but of type telebot.types.InputFile. Thus, you must pass it using that class.
def TTSBot(message):
Engine.save_to_file(message.text, "Voice.mp3")
Engine.runAndWait()
FBot.send_audio(message.chat.id, InputFile("Voice.mp3"), reply_to_message_id=message.id)
And there's no need to modify the caller now.
Also I don't know how your caller works but I'd also like to give you a note that the function send_audio returns the message.
I have a python program using eel library to build a nice GUI.
In the GUI I have a variable within a JS function that I need to pass to Python to store in a variable.
Any ideas why this is?
You can read the below Github article. Maybe this will help.
https://github.com/samuelhwilliams/Eel
Return values
While we want to think of our code as comprising a single application, the Python interpreter and the browser window run in separate processes. This can make communicating back and forth between them a bit of a mess, especially if we always had to explicitly send values from one side to the other.
Eel supports two ways of retrieving return values from the other side of the app, which helps keep the code concise.
To prevent hanging forever on the Python side, a timeout has been put in place for trying to retrieve values from the JavaScript side, which defaults to 10000 milliseconds (10 seconds). This can be changed with the _js_result_timeout parameter to eel.init. There is no corresponding timeout on the JavaScript side.
Callbacks
When you call an exposed function, you can immediately pass a callback function afterward. This callback will automatically be called asynchronously with the return value when the function has finished executing on the other side.
For example, if we have the following function defined and exposed in Javascript:
eel.expose(js_random);
function js_random() {
return Math.random();
}
Then in Python, we can retrieve random values from the Javascript side like so:
def print_num(n):
print('Got this from Javascript:', n)
# Call Javascript function, and pass explicit callback function
eel.js_random()(print_num)
# Do the same with an inline lambda as callback
eel.js_random()(lambda n: print('Got this from Javascript:', n))
(It works exactly the same the other way around).
Synchronous returns
In most situations, the calls to the other side are to quickly retrieve some piece of data, such as the state of a widget or contents of an input field. In these cases it is more convenient to just synchronously wait a few milliseconds then continue with your code, rather than breaking the whole thing up into callbacks.
To synchronously retrieve the return value, simply pass nothing to the second set of brackets. So in Python we would write:
n = eel.js_random()() # This immediately returns the value
print('Got this from Javascript:', n)
You can only perform synchronous returns after the browser window has started (after calling eel.start()), otherwise obviously the call with hang.
In Javascript, the language doesn't allow us to block while we wait for a callback, except by using await from inside an async function. So the equivalent code from the Javascript side would be:
async function run() {
// Inside a function marked 'async' we can use the 'await' keyword.
let n = await eel.py_random()(); // Must prefix call with 'await', otherwise it's the same syntax
console.log("Got this from Python: " + n);
}
run();
i am scraping one website, there is audio playing from the webpage, i want to know when will the audio finish playing, so i add event listener to the audio webElement to monitor 'onEnded' event to fire, and i want to get noticed from the callback() function within driver.execute_async_script.
but i always get error
TypeError: <function MissionContentItemHelper.audio_play_end at 0x10f3b7b70> is not JSON serializable.
my questions are:
1.does arguments[arguments.length - 1] refer to self.audio_play_end ?
2.why the error output is about 'MissionContentItemHelper.audio_play_end is not JSON serializable'? i can't see any clue between MissionContentItemHelper.audio_play_end and JSON.
3.is the way calling audio_play_end correct?
class MissionContentItemHelper:
def sleep(self):
audio = self.browser.find_element_by_css_selector('#audio')
self.browser.execute_async_script("""
var audio = arguments[0];
callback = arguments[arguments.length - 1];
audio.addEventListener("ended", function(_event) {
callback();
}
""", audio, self.audio_play_end)
#staticmethod
def audio_play_end():
print('the audio finished playing...')
execute_async_script's name confuses many people. It doesn't executes the script asynchronously from your test code, it only allows you to execute a script which runs asynchronously from the browser's main thread, like AJAX calls and JavaScript setTimeout.
These JavaScript functions and alike themselves return almost immediately, but they take a (JavaScript) function argument that is executed when the asynchronous operation completes. What execute_async_script does is exactly like execute_script, but instead of returning when the function itself returns (which is almost immediately) it provides its own callback JavaScript function (which it passes as the last argument, that's why the arguments[arguments.length - 1] is needed), that you can use in the JavaScript code you're passing into execute_async_script, to pass it on to the asynchronous function as the callback. execute_async_script returns only when this callback is called, instead of returning immediately.
For example, in the following code, the call to execute_async_script acts like a delay of 2 seconds:
browser.execute_async_script("setTimeout(arguments[0], 2000)")
Note that because I didn't pass any additional arguments to the script, then arguments[0] is actually the last argument.
In your case, you don't have to pass self.audio_play_end, but you have to call audio.play() inside your JavaScript snippet to start the audio. execute_async_script should return only when the audio is finished playing.
Usage works as following:
# driver allready i initialised
js = """
var done = arguments[0];
// my_async_acript here ..
.then(value=>done(value)
"""
value = driver.execute_async_script(js)
Call javascript function done(value) with the value you want to return.
Note: If you're getting a timeout-exception, check the developer-console for errors
This actually is a dublicate I think reference
It's important to know that the last argument passed is the promise resolver. That means:
self.browser.execute_async_script("""
let [element, resolve] = arguments
element.addEventListener("ended", resolve)
""", audio)
Was working on a simple timer function, but hit a wall. Code in question is:
#!/usr/bin/python3
import threading
Timer = threading.Timer()
def hello():
print "hello, world"
t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
Code is a direct copy of the one in https://docs.python.org/2/library/threading.html#timer-objects
Since the function hello takes no args I don't understand the error output of:
File "timer_test.py", line 3, in <module>
Timer = threading.Timer()
File "C:\Python27\lib\threading.py", line 1047, in Timer
return _Timer(*args, **kwargs)
TypeError: __init__() takes at least 3 arguments (1 given)
Does the Timer require another argument other then the time itself and the function to be executed? Shouldn't the args/kwargs not need to be passed since the function hello takes none? I tried passing arbitrary arguments such as None or [] but it changed nothing.
I know it's probably a stupid problem, but since the documentation doesn't answer me, and I couldn't find an answer already on here I decided to post this.
Thank you for your time/help
It is not a direct copy. It has an extra line:
Timer = threading.Timer()
In this line, you try to create a time, but do not pass the delay and function arguments.
More on that, if that would work, you override the class name Timer with an object of the timer, and try to create another timer, but from an instance, not from the class. That will never work.
Remove that line, and make it exactly as in the docs.
I have been using Python coroutines instead of threading with some success. It occurred to me that I might have a use for a coroutine that knows about itself, so it can send itself something. I found that this is not possible (in Python 3.3.3 anyway). To test, I wrote the following code:
def recursive_coroutine():
rc = (yield)
rc.send(rc)
reco = recursive_coroutine()
next(reco)
reco.send(reco)
This raises an exception:
Traceback (most recent call last):
File "rc.py", line 7, in <module>
reco.send(reco)
File "rc.py", line 3, in recursive_coroutine
rc.send(rc)
ValueError: generator already executing
Although the error is clear, it feels like this should be possible. I never got as far as to come up with a useful, realistic application of a recursive coroutine, so I'm not looking for an answer to a specific problem. Is there a reason, other than perhaps implementation difficulty, that this is not possible?
This isn't possible because for send to work, the coroutine has to be waiting for input. yield pauses a coroutine, and send and next unpause it. If the generator is calling send, it can't simultaneously be paused and waiting for input.
If you could send to an unpaused coroutine, the semantics would get really weird. Suppose that rc.send(rc) line worked. Then send would continue the execution of the coroutine from where it left off, which is the send call... but there is no value for send to return, because we didn't hit a yield.
Suppose we return some dummy value and continue. Then the coroutine would execute until the next yield. At that point, what happens? Does execution rewind so send can return the yielded value? Does the yield discard the value? Where does control flow go? There's no good answer.