I am developing a telegram bot, and I have many handlers for responses from the user.
Since there are many handlers and many different dialogs are also possible. I moved some of the handlers into different classes (Dialogs)
import telebot
bot = telebot.TeleBot(tg_api_key)
#bot.message_handler(commands=['buy_something'])
def buy(message):
from dialogs.buy_something
import Buy_Dialog
w = Buy_Dialog(bot, message)
and:
#bot.message_handler(commands=['sell_something'])
def sell(message):
from dialogs.sell_something
import Sell_Dialog
w = Sell_Dialog(bot, message)
Inside the dialog classes I can send questions to the user and get answers from them by using:
self.m = self.bot.send_message(message.chat.id, "Some question")
self.bot.register_next_step_handler(self.m, self.enter_your_name)
But now I need to get from user callback from button click:
#bot.callback_query_handler(func=lambda call: True)
def button_click_yes_or_no(self, call):
So I can catch them only from main.py, not inside the dialog.
How to redesign code to get clear logic and code with the ability to catch button_callback?
maybe the function can't see your variable try to make your variable global in the beginning of the code :
global your variable, another variable
You cannot catch callbacks from inside the class instance.
But you can follow the same logic as for commands: create a decorated general function for catch all calls and pass each one to proper class instance based on call's content (call.data or call.message.chat.id).
Related
I've created a GUI that ask the user an User/Password. The class that creates the GUI calls another class that creates a web browser and try to login in a website using a method of the same class. If the login is successful, a variable of the GUI's object becomes 'True'
My main file is the next one :
from AskUserPassword import AskGUI
from MainInterfaceGUI import MainGUI
Ask = AskGUI()
Ask = Ask.show()
MainInterface = MainGUI()
if Ask.LoginSuccesful == True:
Ask.close()
MainInterface.show()
If the login is successful, I would like to hide the User/Password GUI and show the main GUI. The code above clearly doesn't work.
How can I make Python to wait until some condition of this type is met ?
Instead of constantly checking for the condition to be met, why not supply what you want upon login to do as a callback to your AskGUI object, and then have the AskGUI object call the callback when login is attempted? Something like:
def on_login(ask_gui):
if ask_gui.LoginSuccesful:
ask_gui.close()
MainInterface.show()
Ask = AskGUI()
Ask.login_callback = on_login
Then, in AskGUI, when the login button is clicked and you check the credentials, you do:
def on_login_click(self):
...
# Check login credentials.
self.LoginSuccessful = True
# Try to get self.login_callback, return None if it doesn't exist.
callback_function = getattr(self, 'login_callback', None)
if callback_function is not None:
callback_function(self)
Re.
I prefer to have all the structure in the main file. This is a reduced example but If I start to trigger from a method inside a class that is also inside another class... it's going to be hard to understand
I recommend this way because all the code to handle something that happens upon login is included in the class that needs to do the logging in. The code to handle which UI elements to display (on_login()) is included in the class that handles that.
You don't need anything in the background that keeps checking to see if Ask.LoginSuccessful has changed.
When you use a decent IDE, it's pretty easy to keep track of where each function is defined.
I am new to pyhton APIs. I can not get the script to return a value. Could anyone give me a direction please. I can not get the lambda function to work properly. I am trying to save the streamed data into variables to use with a set of operations.
from tda.auth import easy_client
from tda.client import Client
from tda.streaming import StreamClient
import asyncio
import json
import config
import pathlib
import math
import pandas as pd
client = easy_client(
api_key=config.API_KEY,
redirect_uri=config.REDIRECT_URI,
token_path=config.TOKEN_PATH)
stream_client = StreamClient(client, account_id=config.ACCOUNT_ID)
async def read_stream():
login = asyncio.create_task(stream_client.login())
await login
service = asyncio.create_task(stream_client.quality_of_service(StreamClient.QOSLevel.EXPRESS))
await service
book_snapshots = {}
def my_nasdaq_book_handler(msg):
book_snapshots.update(msg)
stream_client.add_nasdaq_book_handler(my_nasdaq_book_handler)
stream = stream_client.nasdaq_book_subs(['GOOG','AAPL','FB'])
await stream
while True:
await stream_client.handle_message()
print(book_snapshots)
asyncio.run(read_stream())
Callbacks
This (wrong) assumption
stream_client.add_nasdaq_book_handler() contains all the trade data.
shows difficulties in understanding the callback concept. Typically the naming pattern add handler indicates that this concept is being used. There is also the comment in the boiler plate code from the Streaming Client docs
# Always add handlers before subscribing because many streams start sending
# data immediately after success, and messages with no handlers are dropped.
that consistently talks about subscribing - also this word is a strong indicator.
The basic principle of a callback is that instead you pull the information from a service (and being blocked until it's available), you enable that service to push that information to you when it's available. You do this typically be first registering one (or more) interest(s) with the service and after then wait for the things to come.
In section Handling Messages they give an example for function (to provide by you) as follows:
def sample_handler(msg):
print(json.dumps(msg, indent=4))
which takes a str argument which is dumped in JSON format to the console. The lambda in your example does exactly the same.
Lambdas
it's not possible to return a value from a lambda function because it is anonymous
This is not correct. If lambda functions wouldn't be able to return values, they wouldn't play such an important role. See 4.7.6. Lambda Expressions in the Python 3 docs.
The problem in your case is that both functions don't do anything you want, both just print to console. Now you need to get into these functions to tell what to do.
Control
Actually, your program runs within this loop
while True:
await stream_client.handle_message()
each stream_client.handle_message() call finally causes a call to the function you registered by calling stream_client.add_nasdaq_book_handler. So that's the point: your script defines what to do when messages arrive before it gets waiting.
For example, your function could just collect the arriving messages:
book_snapshots = []
def my_nasdaq_book_handler(msg):
book_snapshots.append(msg)
A global object book_snapshots is used in the implementation. You may expand/change this function at will (of course translating the information into JSON format will help you accessing it in a structured way). This line will register your function:
stream_client.add_nasdaq_book_handler(my_nasdaq_book_handler)
I am trying to gather the files: output.xml, report.html and log.html when the whole execution ends.
I can use a listener for this purpose but I want to avoid write a line like:
robot --listener "SomeListener.py" YourTestSuite.robot
Then, I looked at the documentation and I found that I can use a Test Library as a Listener and import it in my Test Suite, for example:
class SomeLibrary(object):
ROBOT_LISTENER_API_VERSION = 2 # or 3
ROBOT_LIBRARY_SCOPE = "GLOBAL" # or TEST SUITE
def __init__(self):
self.ROBOT_LIBRARY_LISTENER = self
def start_suite(self, data, result):
pass
def close(self):
pass
My problem is that the close method is called when the library goes out of the scope. So, I cannot gather the report files because they don't exist in that moment and I receive an Error. I also tried with the method:
def report_file(self, path):
pass
But, nothing happens, I guess that it could be because a Library as a Listener cannot use this methods from the Listener API or because the file is still not created.
Any idea about How can I gather those files using a library as a Listener?
I am open to ideas or suggestions.
Thanks.
The Listener specification actually specifies three methods that are triggered when the three files are generated:
startSuite
endSuite
startTest
endTest
startKeyword
endKeyword
logMessage
message
outputFile
logFile
reportFile
debugFile
Have a look at the last 4 ones, which should be helpful. For more details look at the listener API specification. 4.3.3 Listener interface methods
I am not skilled in Gtk programming and I am trying to modify some existing code so that the gobject.timeout_add() callback function can use data from another thread.
The existing code creates a GUI for displaying a DOT graph by periodically reading a file but I want the DOT data to be read from a string that can be obtained from a subscriber defined as follows:
import rospy
from std_msgs.msg import String
rospy.Subscriber('/dot_string', String, self.update_dot_graph)
def update_dot_graph(self, msg)
self.dot_string = msg.data
The rospy.Subscriber runs in its own thread and so it is unclear to me how to get access to self.dot_string when the Gtk.main() function appears to block any other code from running.
The existing GUI code defines the following callback for gobject.timeout_add():
def update(self):
if self.openfilename is not None:
current_mtime = os.stat(self.openfilename).st_mtime
if current_mtime != self.last_mtime:
self.last_mtime = current_mtime
self.reload()
return True
Here you can see that the DOT code is read from a file if it has changed since the last read and then the GUI window is reloaded. I would like instead to use the data in self.dot_string from the other thread to be used in this update function. Alternatively, I would like to trigger the data update and reload() directly in the update_dot_graph() callback that is attached to the other thread.
Please let me know if more details are needed for this to make sense.
So I have a small python program that is spread out across a few classes. In my main class, I tell my title screen class to display and then wait for input. If the input it gets is 'q' it calls back to my main class telling it to set it's stop flag to true. Otherwise, it just loops.
This is the callback I give to my title screen:
def quit():
stopped = True
stopped is set to False outside of the callback. The callback is registered fine, and goes off no problem, but it seems to set stopped to true locally in titlescreen, and not in main. I can fix this by creating a class stopFlag and doing the exact same thing, except in the object.
My question is why do I need to make a new class to do this? Is there a way I can set a global flag in main which is just a boolean without making an object out of it? How can I have the callback reference that boolean?
Edit:
I declare stopped like this:
stopped = False
Here is the quit callback register call:
titleScreen.registerCallbackQuit(quit)
Which looks like:
def registerCallbackQuit(self, callback):
self.callbackQuit = callback
And it calls quit if it gets a in the user input.
global stopped would work (probably). People use classes to avoid globals (among other things). If 'stopped' is spread out over many files, you would need to import it.