I'm fairly new to Python, but not new to programming. Basically, I'm trying to call certain functions/procedures to simulate keyboard/mouse based on user input from an IRC channel.
I am running an IRC bot on twitch like a twitch plays sort of thing. I know how to simulate keyboard and mouse input, but I'm having trouble figuring out how to do this efficiently.
I have a class for the bot and it starts like:
class bot:
def __init__(self):
...
login stuff
...
self.options = {'!test': self.command_test,
'q': self.quickSave,
'f': self.forward,
'ff': self.forward2,
'fff': self.forward3
}
...
and then the functions are called while the bot parses IRC chat input like so:
def parse_message(self, msg):
if len(msg) >= 1:
msg = msg.split(' ')
if msg[0] in self.options:
self.options[msg[0]]()
I have a load of functions that are basically the same only repeated. (forward, forward2, forward3, left, left2, left3, etc). It really makes no sense to repeat the same function over and over. I cannot figure out how to efficiently call these functions like forward(1), forward(2), forward(3), etc.
I would like my code to look like this:
def forward(self, num):
for x in range(1, num):
#Simulate walking forward
I just cant figure out how to add arguments to forward() using simple text input. This is hard for me to explain, just imagine a hundred people voting to move/aim in a video game in an IRC channel.
Again, I'm not asking for help emulating mouse/keyboard input. I just need advice about how to use text to call functions.
if it help you understand, i'm attempting to croudplay fallout 4
So, each command is actually one symbol, and repeating a symbol n times means calling the associated function the same amount of times, right?
Assuming command is a string of symbols without spaces, it could be done like that:
command = #get command
for char in command:
your_dict[char]()
BTW, it's not really needed to check whether the dictionary contains the specified command. Just wrap the calling into a try/except block:
try
your_dict[char]()
except KeyError:
# this is OK, tell the user that it's an error
except:
# this means that some of the functions has raised an error
Related
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 am relatively new to coding and to python. I am trying to make a telegram bot using telebot.
I have a flow in which I have to go. eg: after /start, I should get a text. So I created a running_work_list in which my workflow is arranged in order and after completion, I delete the index 0 elements. 'start' is the first element in the array.
So I tried to implement something like this so that I can comfortably code each step rather than looking at input and deciding.
But despite putting inside an if statement, '#bot.message_handler()' is running even if the condition fails.
if running_work_list[0]=='start':
print('inside if')
#bot.message_handler(commands=['start','new test'])
def start(message):
print('user sent start')
bot.send_message(message.chat.id,welcome_message)
running_work_list.pop(0)
print(f'work flow deciding list {running_work_list}')
#bot.message_handler(content_types=['text','photo','poll'])
def bot_intro(message):
print('here')
print(f'user sent {message.text}')
bot.send_message(message.chat.id,BOT_INTRO_MSG)
Below are the outputs I got. The user had sent /start first and then some other random text.
inside if
user sent start
work flow deciding list ['test_name', 'test_description', 'test_time', 'test_image', 'test_poll']
here
user sent fdf
Is it like the '#bot.message_handler()' will run even if we put it inside an if statement?
Executing #bot.message_handler decorator marks the function to be called when the message matches the filters that you've passed as arguments (content_types or commands). They are called by the telebot library directly and do not execute the if statement after they have been registered.
The proper way to do this is to invert the logic: define the message handler functions at the top level of the program and decide what you should do in the if within the function.
This is the code I want to implement. Simply stated, it is a small chat bot that connects to a server and joins room testroom1 with credentials user and pass. Using a library, an event is called every time somebody enters a message into the chatroom, and this bot will print their message, with formatting:
import ch
class bot(ch.RoomManager):
for x in range(0, 3):
def onMessage(self, room, user, message):
print("[{0}] {1}: {2}".format(room.name, user.name.title(), message.body))
rooms = ["testroom1"]
username = "user"
password = "pass"
bot.easy_start(rooms,username,password)
However, the key problem is this:
for x in range(0, 3):
I only want the "onMessage" function to be accessed 3 times then to not print any more messages. This doesn't seem to work, and it continues to print messages until I exit it.
If possible, I would like to limit the onMessage function with while loops further in my program, and to use it in several different cases to parse messages at different times.
The source of the ch library and basis for my simple code is here
Any insight on this issue is appreciated.
I think you have misunderstood the Python syntax slightly. The for loop in your class will define the same onMessagemethod three times, with each new iteration replacing the old one. This would be apparent if you tried to use the x (or rather self.x) within your function.
What you want, is a counter within the method or class, that is incremented with each call and then, when the max count is reached you could just have the onMessagemethod do nothing.
Try the following code, which I think does what you want:
import ch
class bot(ch.RoomManager):
messages_left = 3
def onMessage(self, room, user, message):
if self.messages_left > 0:
print("[{0}] {1}: {2}".format(room.name, user.name.title(), message.body))
self.messages_left -=1
rooms = ["testroom1"]
username = "user"
password = "pass"
bot.easy_start(rooms,username,password)
What I have done here, is to add an initializing function that defines an object variable messages_left that is decremented in the onMessagecall, until it hits zero. Further, I have added a class parameter, which allows you to control how many times you want onMessage to format the message.
I'm creating an instant messenger program for my school's common drive. I have everything working except for on small detail. In the code below it checks for a new message from a friend and prints the last message they sent. If there are no messages it says so. The problem is when it moves to the next step of the code it waits for the user to put in an input. Until you give an input it won't let you receive any more messages because the program stops reading and searching the while loop and gets caught on the input statement. I want to know if there is anyway to make an input statement optional. To say that it doesn't require an input but if there is an input it will send it and do it's thing. I just can't seem to figure out a way to make the input statement optional. Any ideas or working code would be greatly appreciated. If you need the entire code I don't have a problem with sending it to you or posting it. This is the only bit of code that should really matter for this problem though.
LastMessage = ""
while Message:
Path = "Message"+SendTo+"-"+UserName+".txt"
if path.isfile(Path):
LoadMessage = open(Path, "rb")
NewMessage = pickle.load(LoadMessage)
LoadMessage.close()
else:
NewMessage = "Sorry, No messages found"
if LastMessage != NewMessage:
LastMessage = NewMessage
print(NewMessage)
print("")
SendMessage = raw_input() #--- This is where it gets caught up! ---
Save = open("Message"+UserName+"-"+SendTo+".txt", "wb")
pickle.dump(SendMessage, Save)
Save.close()
You have two main options as I see it:
Simultaneous input and checking (various options, search for e.g. threading or multiprocessing from the standard library); or
Input with timeout and loop (see e.g. How to set time limit on raw_input).
So it sounds like you want to do two separate things at the same time - look for input from a user and poll for new messages from other users. Jonrsharpe gives threading as his first option to solve this and I agree its the most straightforward. What you need to do is something like this:
import threading
class InputMessageThread(threading.Thread):
def run(self):
SendMessage = raw_input() # This thread will hang here for input but thats
# OK as original thread will keep going
Save = open("Message"+UserName+"-"+SendTo+".txt", "wb")
pickle.dump(SendMessage, Save)
Save.close()
inputthread = InputMessageThread()
inputthread.start()
# rest of your code here
While you are at it though you might want to look at some other issues. For example if I understand what you are trying to do correctly you are going to have a file containing a message from a source user to a destination user. But if the source user sends a second message before this file gets processed then the first message will be overwritten. In practice you may never see this but some sort of handshaking to make sure the message has actually been sent before you allow the next to be written would be a more robust approach.
I've set up a irc bot using socket. I've added a few commands , but I'd like to add a "poll" function.
Ideally, the bot would get a command with this format:
!poll <name> <opt1> <opt2> <opt3> <time>
How would I go about checking user who voted and ending the poll after a certain time?
Thanks in advance,
Desperate Python Beginner.
EDIT: Thanks a lot for the responses guys, I went with using global vars ( I know, I know ) because I couldn't figure out how to do it otherwise. Again, thanks a lot!
Well, I'm starting to get a little rusty with my Python but I think I can answer that - It may not be the best answer, though.
If you plan to have many polls going at once, you could implement a dictionary containing multiple instances of a custom class like Poll.. Here's a possible solution:
class PollVotes(object):
def __init__(self):
self.votes = []
self.stoptime = "some date/time" #I can't remember how to do this bit ;)
def add_vote(self, vote_value):
self.votes.append(vote_value);
def tally_votes(self):
return self.votes.size()
def has_closed(self):
if time_now >= self.stoptime: # I forget how you'd do this exactly, but it's for sake of example
return True
else:
return False
#then use it something like this
poll_list = {}
#irc processing...
if got_vote_command:
if poll_list["channel_or_poll_name"].has_ended():
send("You can no longer vote.")
else:
poll_list["channel_or_poll_name"].add_vote(persons_vote)
#send the tally
send("%d people have now voted!" % poll_list["channel_or_poll_name"].tally_votes())
Of course, you'd have to edit the poll class to fit your needs, i.e. to allow multiple values in a vote, to record who is voting what (if you want that), etc.
As for checking if the poll has ended, you could edit the poll class to have the stop time, and have a function that returns True/False whether that time has passed or not. Possibly look at the docs for the datetime module...?
Anyway, hope this helps.