How can I conduct a poll through an irc bot? - python

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.

Related

trio.Event(): Which is “better”: setting and initializing a new Event or checking if someone is waiting for it beforehand?

import trio
work_available = trio.Event()
async def get_work():
while True:
work = check_for_work()
if not work:
await work_available.wait()
else:
return work
def add_work_to_pile(...):
...
if work_available.statistics().tasks_waiting:
global work_available
work_available.set()
work_available = trio.Event()
In this Python-like code example I get work in bursts via add_work_to_pile(). The workers which get work via get_work() are slow. So most of the time add_work_to_pile() is called there will be no one waiting on work_available.
Which is better/cleaner/simpler/more pythonic/more trionic/more intended by the trio developers?
checking if someone is looking for the Event() via statistics().tasks_waiting, like in the example code, ...or...
unconditionally set() setting the Event() and creating a new one each time? (Most of them in vain.)
Furthermore... the API does not really seem to expect regular code to check if someone is waiting via this statistics() call...
I don’t mind spending a couple more lines to make things clearer. But that goes both ways: a couple CPU cycles more are fine for simpler code...
Creating a new Event is roughly the same cost as creating the _EventStatistics object within the statistics method. You'll need to profile your own code to pick out any small difference in performance. However, although it is safe and performant, the intent of statistics across trio's classes is for debug rather than core logic. Using/discarding many Event instances would be relatively more along the intent of the devs.
A more trionic pattern would be to load each work item into a buffered memory channel in place of your add_work_to_pile() method and then iterate on that in the task that awaits get_work. I feel the amount of code is comparable to your example:
import trio
send_chan, recv_chan = trio.open_memory_channel(float('inf'))
async def task_that_uses_work_items():
# # compare
# while True:
# work = await get_work()
# handle_work(work)
async for work in recv_chan:
handle_work(work)
def add_work_to_pile():
...
for work in new_work_set:
send_chan.send_nowait(work)
# maybe your work is coming in from a thread?
def add_work_from_thread():
...
for work in new_work_set:
trio_token.run_sync_soon(send_chan.send_nowait, work)
Furthermore, it's performant because the work items are efficiently rotated through a deque internally. This code would checkpoint for every work item so you may have to jump through some hoops if you want to avoid that.
I think you might want a trio.ParkingLot. It gives more control over parking (i.e. which is like Event.wait()) and unparking (which is like Event.set() except that it doesn't stop future parkers from waiting). But it doesn't have any notion of being set at all so you would need to store that information separately. If you work is naturally Truety when set (e.g. a non-empty list) then that might be easy anyway. Example:
available_work = []
available_work_pl = trio.ParkingLot()
async def get_work():
while not available_work:
await available_work_pl.park()
result = list(available_work)
available_work.clear()
return result
def add_work_to_pile():
available_work.append(foo)
available_work_pl.unpark()
Edit: Replaced "if" with "while" in get_work(). I think if has a race condition: if there are two parked tasks and then add_work_to_pile() gets called twice, then one get_work() would get both work items but the other would still be unparked and return an empty list. Using while instead will make it loop back around until more data is added.
IMHO you don't want an event in the first place. The combination of an array and something that tells the reader there's work in the array is already available as memory channels. They have the additional advantage that you can tell them how much work to accept before the sender stalls.
send_channel, recv_channel = trio.open_memory_channel(10)
get_work = recv_channel.receive
add_work_to_pile = send_channel.send
# both are async functions or use the _nowait() versions

How to properly use getUpdates method from Telegram API

Let's say I would like to create a simple "listener" bot which will print out the result when I send the message "say *". I would imagine that it should look like this:
import requests
import time
key = 'iknowthatyouarenotsupposedtodoitlikethat'
start_time = time.time()
while True:
result = requests.get(f'https://api.telegram.org/bot{key}/getUpdates?timeout=1').json()
if result['result'][-1]['message']['date'] < start_time: continue # Ignore old messages
message = result['result'][-1]['message']['text'].split()
if message[0] == 'say':
print(' '.join(message[1:]))
break
This is by no means an example of a great approach, but it should work fine :).
The problem here is that the result variable is filled like it is supposed to with messages from the last 24 hours, but starting with the second iteration it only receives the one or two most distant messages, which is super weird. I have found that doing time.sleep(.25) after each iteration seems to fix the issue, but this looks like such a dumb fix which may not be reliable. If this is simply rate limiting, there at least should be some indication of the error, but the code is always 200 and there are no indications of the problem.
The same happens when you try doing the request by directly inserting the link into the browser and start mashing F5, which is obvious, but it is easier to see what I am talking about this way.
After looking into the documentation I have found that this issue may be caused by short polling which is "only recommended for testing purposes", but this should be fixed by the timeout argument which I have.
I don't know how to further approach this issue, so maybe there a solution that I am not seeing?

Python cashier without db

so i have this mission to build a python cashier program using only python. without db use.
i use the dict and keys method to build it.
so i have 2 questions:
can i get an idea how to keep the program running after the moneybalance part, while i'm still saving the current moneybalance status? like, to make it an continuous program and not just one time.
i would like to get overall review on how is the idea for this mission, how it's written, and etc. would you do it in other way? if so i would like to hear how.
remember, my mission is to build python cashier without any outside libraries\db's.
Code:
print('welcome to python cashier')
money = int(input('enter cashier current money\n'))
prices = {"small popcorn" : 3, "medium popcorn" : 5,
"large popcorn" : 8, "small drink" : 1,
"medium drink" : 2, "large drink" : 3 }
def calc(money, prices):
try:
itemchange = pay - itemvalue
except Exception as e:
print(e)
finally:
print(f'change: {itemchange}')
def show(money, prices):
try:
for key,value in prices.items():
print (f'{key}: {value}')
except Exception as e:
print(e)
finally:
return False
show(money, prices)
def start(money, prices):
try:
for key, value in prices.items():
global item
item = str(input('enter what you want to buy:\n'))
if (item in prices.keys()):
global itemvalue
itemvalue = prices.get(item)
print(f'{item}: {itemvalue}')
global pay
pay = float(input('how much costumer pay?\n'))
return calc(money, prices)
else:
print('item not found')
except Exception as e:
print(e)
finally:
moneybalance = money + itemvalue
print(f'moneybalance: {moneybalance}')
start(money, prices)
The real question is if someone asked you to save the information. As you said they asked in the mission to do this without a database I don't think you need to do that. Btw if it's without an actual database you can use just .txt files to save information. Check about the "open" function in Python.
Quick Example:
with open('save.txt', 'w') as file:
file.write(str(cash)) # cash is an integer.
It's an example of writing a file. Btw I don't think they wanted you to save the information. Check it before you're applying something to don't ruin your work :).
I would suggest to put all the declarations of variables at the start of the script and add a "main" function. Call the main function from name == 'main'. Too I recommend you to do a more detailed function names. Try not to use global variables in this small code (you can declare it at the start, it'll be global and more easy to read your code and understand it faster). I think in your first question you thought about making your program run more than one time in any program run? Read about Python Loops if I'm correct :). Too you wrapped your input return with str() and it useless, because the returned value from input is already str (String type).
Quick Example:
# Variables Declaration (Just an example for the structure).
ABC = 0
cash = 1000
# Functions Declaration
def calculate_price(money, prices):
# Code Here.
pass
def main():
# The code of your start function, you don't need and arguments for this.
pass
if __name__ == '__main__':
main() # Call main here.
In this way your code will be readable and comfort to analyze :).
This sounds more like an assignment than an actual problem.
Here is the thing, and this is fundamental software architecture. You only need a database when it is time to persist something. So, what you need os a persistence service. Call it a database if you want, it can be as simple as a text file, as someone sugested.
Ironically the same set of rules that made your life easier as a developer, are making you confused. And questions arise. Specifically the question of what exactly happens when I close the program?
But the answer is dead simple. The requirements made it simple. If you close the application its gone. There is no persistence mechanism. This is actually super safe. No record, no proof. More importantly, its a requirement to be like so.
The problem, therefore, is you. You feel the need for persistence. You see an account and immediately place it in a database somewhere. You do a transaction, you feel the need to store it.
So what exactly happens when you persist something in a program? The program keeps all the information it needs to run. It may have gotten that information from a database, a user, or it may have randomly generated it. Who cares? All the program needs is the information in objects it knows how to use, in classes types and whatever more; in other words, in RAM. So persistence is taking things out of RAM into a less volatile storage.
But the real question is, how exactly does that affect the program? Does that cause any fundamental change?
For one the cashier operations are still the same. Prices must still be calculated, transactions must still be made, and all the rules associated must still be observed.
If something, there is less code involved. There is no solving the persistence problem. The information is volatile. Its a requirement to be so.
This is fundamentally the evolution process of a system under development, or even to some extent in production.
During development I care very little to store anything. What is actually usefull is to have reproucible state of the data. One I can interact with to make tests and verify that the software works (ie. it does not let me buy something if I have no money). This is easier done without any database system, specially the repoducible part.
Sure I can do backups of the data, but is it not easier to just restart the app? And where is the bug exactly if I need a specific database to see it? Is it in the code? Or is it a consistency issue in the database system? Probably the latter. How does that affect the cashier? It doesn't. Its a persistence detail. It has nothing to do with the business of a cashier.
I feel I have way more I could say, but I'm not sure where exactly you expect to get with this question. So I will stop here. Feel free to further inquire on this matter.

Trying to call functions based on IRC user input

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

Python, How to swap between multiple infinite loops?

Could someone please point me in the right direction?
I am trying to swap between multiple infinite control loops within python. I need to kill a loop and then select a different loop upon request from an outside source(hopefully web interface), not based on an internal condition. I understand this is a vague question but I need a general point in the right direction to get me started, I have looked at exceptions, signals and threading but I am struggling to find what would be the "correct" way to do this.
Please note, I work in electronics not programming so sorry if this sounds stupid. Also if this is completely the wrong way to go about the problem could someone advise me on the correct method.
I can provide more info/explanation if someone can help me and post code if needed but I think it's pretty irrelevant at the moment due to the vagueness of the question.
Thanks
I'm guessing you have two (or more) procedures you want to run repeatedly and allow them to be changed when the user selects a new condition. I would take advantage of Python having functions as objects and so something like this:
def f1():
# do something
def f2():
# do something else
func_to_run = {"user_input1": f1, "user_input2": f2}
while True:
user_input = get_any_new_input() # however you want to get your user input
func_to_run[user_input]()
Edit: As Keith mentioned in the comments, get_any_new_input needs to be non-blocking. I would do this via threading. The web interface should be on a separate thread from the loops, but share a control object that the web interface will set. This could be a table in a database if you have that available. It might look something like this if you use your own lock:
L = threading.Lock() # Shared by web ui
user_response = 'data set by web ui'
last_input = 'user_input1'
def get_any_new_input(L, last_input, user_response):
if L.acquire([False]):
last_input = user_response
return last_input
The easiest way is probably just read some file which controls your loops ...
while True:
#loop1
while True:
#do something
with open("some.file") as f:
if f.read() == "loop2":
break
#loop2
while True:
#do something
with open("some.file") as f:
if f.read() == "loop1":
break
then just put which loop you want in "some.file" (however you want ... web interface etc)

Categories

Resources