I'm coding a bot using the discord.py api, was trying to simulate switch/cases for different commands to the bot
I read online that I can use switcher = { *some value* : *function* } to simulate switch/cases, but on specific values, its runs every function instead of the appropriate one
async def command_switcher(argument, message, parameters):
switcher= {
">autovc": await autovc_command_switcher(parameters[1], message,
parameters) if (len(parameters) > 1) else await
autovc_invalid(message),
">help": await default_help(message),
">vcgroup": await autovc_invalid(message)
}
return switcher.get(argument, "Invalid")
I call the command_switcher and pass in an argument, if the argument is ">help", then it properly only runs the default_help() function, but if I pass in ">autovc" it runs all 3 functions
Edit: also, if I switch the order of the entries, it still has the same result: ">help" still only runs itself, and ">autovc" still runs all 3
Edit 2: Solved thanks for the comments, while trying to create a proper MCVE as advised, and seeing the comment that dict values are the function objects, I figured out I was incorrectly calling the functions as opposed to referencing the function object itself. I was also having some issues with async/await, but the comment linking me to https://xinhuang.github.io/posts/2017-07-31-common-mistakes-using-python3-asyncio.html cleared that up for me as well
Related
I'm newbie in the world of python and have been trying to solve the following for last 3 days on my own. I read many articles online none of them address my problem or I seem to been missing something so I decided to post my question here.
Purpose:-
I'm trying to connect realtime data from my broker to a charting library via 'socketio python' websocket which I host locally and runs on an ASGI server. Broker has provided following two sync functions which I've wrapped inside an async fuction SubAdd but couldn't get an output from
#sio.event
async def SubAdd(sid,data): #event that handles subscribe requests from library for realtime data
def socket(access_token): #This funtion gets the data from broker
data_type = "symbolData"
symbol =["NSE:NIFTYBANK-INDEX"]
fs = ws.FyersSocket(access_token=access_token,run_background=False,log_path="/home/log/")
fs.websocket_data = custom_message
fs.subscribe(symbol=symbol,data_type=data_type)
fs.keep_running()
def custom_message(msg):# Function that returns fetched data
print (f"Custom:{msg}")
socket(access_token)
A thing that confused me the most is at the line 4 of socket i.e.fs.websocket_data = custom_message. Normally, if we write A=B then left side of assignment operator gets assigned the value of right side i.e. A is getting value from B But something else is happening here I dont know what?
Thing I've tried:
making both socket and custome_message an async fuction and then yielding sio.emit from inside async custom_message
making both socket and custome_message an async fuction and then awiting/yielding to the append msg to another list and then using async for on that list and then await sio.emit
Both of above gave an error RuntimeWarning: coroutine 'SubAdd.<locals>.socket' was never awaited which clearly means I'm heading in the wrong direction.
So my question is how do I wrap these two sync functions inside an async function and get an awaitable output from custom_message. If you could directly answer the question its well and good but even if you point me to the a link to a resource or even a keyword to search, which you think would answer my question is greatly appreciated. Thank you.
Is there a Function that runs before the bot gets closed
Ex.
#bot.event()
async def on_close(ctx):
export_files()
I'm making a bot that reads all the new messages and adds them to the author's list of words and when the command .get_word_count gets called all of the words that the author has sent will be shown
im: 98
under: 1
the: 1
water: 1
please: 1
help: 1
me: 1
test: 124136624745687697698608
the reason I'm storing the data is that it's more efficient to store and start a new read rather than going through all of the channels and get the word counts
The on_disconnect event. However, do note that it might trigger when no connection was already established, if establishing one fails.
Hoewever I haven't really understood what your use case is and what you need on_disconnect for. There might be a better way.
The best way I have found yet is to subclass commands.Bot and override the close method
class MyBot(commands.Bot):
async def close(self):
pass # you can also use attributes (even custom ones) using self.attr
bot = MyBot(command_prefix="!")
This would be well suited if you need a coroutine
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)
Is it possible to return from a function and continue executing code from just under the function. I know that may sound vague but here is an example:
def sayhi():
print("hi")
continue_function() #makes this function continue below in stead of return
#the code continues here with execution and will print hey
print("hey")
sayhi()
when executing this the code should do this:
it prints "hey"
it calls the sayhi() function
it prints "hi"
it calls a function to make it continue after the function (in theory similar behavour could be achieve by using decorators)
it prints "hey" again
it calls sayhi() again
etc
i am fully aware of the fact that similar behaviour can be achieved by just using for loops but for the project i am working on this functionality is required and not achievable by using looping.
some solutions i have thought of (but i have no clue how i could execute them) are:
somehow clearing the stack python uses to return from one function to another
changing return values
changing python itself (just to make clear: it would solve the problem but it is something i do not want to do beacuse the project must be usable on non-altered versions of python
using some c extension to change python's behaviour from within python itself
Repetition without loops can be done with recursion:
def sayhi():
print("hey")
print("hi")
sayhi()
sayhi()
I assume you have some terminating condition to insert. If not, this code will give a RecursionError.