Is it possible to create a function to shortcut module functions? - python

#BOT.message_handler(commands=['drink'])
def drink(message):
try:
BOT.send_message(message.chat.id, f'I added {message.text.split(" ", 2)[1]} to your daily intake for today, {fecha_excel}!')
except IndexError:
BOT.send_message(message.chat.id, 'IndexError')
I basically want to create a function to shorten the "BOT.send_message(message.chat.id," part, since it will always be the same (at least for this project)
I tried creating this function inside the (handler? method? the # thingy):
def send(message): BOT.send_message(message.chat.id, message)
And then in the drink() function, change it to:
#BOT.message_handler(commands=['drink'])
def drink(message):
try:
send(f'I added {message.text.split(" ", 2)[1]} to your daily intake for today, {fecha_excel}!')
except IndexError:
send('IndexError')
That doesn't work because it doesn't need a string but a "chat" object (if I understood correctly the error message), but is there any way to make it work?
This project should be fairly simple and short, so I won't lose too much time typing "BOT.send_message(message.chat.id,", but in the future it might save me some time :)

You can't avoid using message or message.chat.id completely. The best (shortest) you can do is:
def respond(message, text):
BOT.send_message(message.chat.id, text)
#BOT.message_handler(commands=['drink'])
def drink(message):
try:
respond(message, f'I added {message.text.split(" ", 2)[1]} to your daily intake for today, {fecha_excel}!')
except IndexError:
respond(message, 'IndexError')
Although, doesn't Message have .reply_text(text)?

You can modify the helper function to take two arguments, chat_id and text :
def send(chat_id, text):
BOT.send_message(chat_id, text)
Then in the drink function, change it to:
#BOT.message_handler(commands=['drink'])
def drink(message):
try:
send(message.chat.id, f'I added {message.text.split(" ", 2)[1]} to your daily intake for today, {fecha_excel}!')
except IndexError:
send(message.chat.id, 'IndexError')
Now use the helper function send to send messages to the chat with a given chat id and text.

Related

Need telegram bot to edit a function from another file

As the title says. I need my telegram bot to take user input, and use that to change some values on another function from another file. I already got the file to be successfully run from the bot, but I can't figure out how to change values first. I am using Python-Telegram-bot.
here is the code I need to edit that is in a separate file (call.py)
call = client.calls.create(
machine_detection='Enable',
url='https://ngrok.io/main',
to='',
from_=''
)
I need to edit the "to" and "from" field(s) in this code above.
The code I use to run this from my bot is as follows:
def update(update, context):
update.message.reply_text('Enter number :\n'
'e.g. 18004585478\n')
update.message.reply_text('Calling...')
exec(open("call.py").read())
I am pretty new to all this so I know the code is not good at all. I have read that I should be using ConversationHandler or CommandHandler but I honestly am not sure how to implement it.
I edited the code based on what Alexey suggested and now am stuck on a similar issue.
def update(update, context):
update.message.reply_text('Enter number:\n'
'e.g. 18004585478\n'
'Number Must begin with 1')
from_number = update.message.text
update.message.reply_text('Enter number:\n'
'e.g. 18004585478\n'
'Number Must begin with 1')
to_number = update.message.text
update.message.reply_text('Calling...')
call_state = call.make_call(to_number, from_number)
The Telegram bot just runs all the code at once, it doesn't stop and wait for any input from the number fields. How do I go about implementing MessageHandler to make the bot stop and accept input to pass along to call_state, then execute call_state at the end?
You don't need to change the code, you need to use arguments to pass the data you wanted to.
In call.py you can make a funciton
def make_call(to_number, from_number):
call = client.calls.create(
machine_detection='Enable',
url='https://ngrok.io/main',
to=to_number,
from=from_number,
)
return call
In your update function just use the function by giving it the necessary values
import call
def update(update, context):
update.message.reply_text('Enter number :\n'
'e.g. 18004585478\n')
update.message.reply_text('Calling...')
call_state = call.make_call(to_number='0123456789', from_number='9876543210')
# use call_state ...
What Alexey stated ended up working with very slight modifications.
I took what Alexey posted and deleted the numbers and turned them into a variable I could edit from my other script.
def make_call(to_number, from_number):
call = client.calls.create(
machine_detection='Enable',
url='https:snip/main',
to=to_number,
from_=from_number
)
print(call.sid)
Then in the other file I defined the variables and executed them by importing the file I needed to edit by using user_data[FROM] = update.message.text and user_data[TO] = update.message.text.
then calling the funciton.
call_state = call.make_call({user_data[TO]}, {user_data[FROM]})
Dont forget to add user_data = {} at the top of your code.

How do I make a python bot with selenium that checks when a new message has arrived from a Telegram channel?

I should start off mentioning I am pretty new to python and selenium, so I don't really know much about either of them.
what I am trying to do:
Check every second if a telegram channel I follow has sent out a new message. I have telegram web opened on a browser opened with custom flags so that I don't need to log in with telegram every single time.
So far what I did is see the class that has all the message's text inside of it
im_message_text, and get the last of them in the list.
Source Code
NOTE The "strong" tag is simply where the title is stored in side the text message, which is what i'm using to compare everything:
def getItemsInfo1(self):
try:
iteminfo1 = WebDriverWait(self.driver, 4).until(
EC.presence_of_element_located((By.CLASS_NAME, 'im_message_text')))
list3 = self.driver.find_elements_by_class_name("im_message_text")
list33 = list3[-1]
list4 = list33.find_element_by_tag_name("strong")
list4txt = list4.text
return list4txt
except:
print("Nothing is found")
What I do from here is I make another identical code which has a time.sleep(1) at the start to give the message time to appear, and i compare the 2 using the following while loop:
while Main.getItemsInfo1() == Main.getItemsInfo2():
print("No new messages. Try number ", count)
print(Main.getItemsInfo1(), Main.getItemsInfo2())
count += 1
So far, whilst as soon as there is a new message the code output highlights that the 2 methods have different text, it still does not end the while loop and it continues to say that there aren't any new messages.
Does anyone know how to help?
while Main.getItemsInfo1() == Main.getItemsInfo2():
print("No new messages. Try number ", count)
print(Main.getItemsInfo1(), Main.getItemsInfo2())
count += 1
When you call getItemsInfo1() you are calling the method again , so there is no guarantee that the value is get in print statement is same as what is there in while so use something like:
info1= Main.getItemsInfo1()
info2= Main.getItemsInfo2()
while info == Info2:
print("No new messages. Try number ", count)
info1= Main.getItemsInfo1()
info2= Main.getItemsInfo2()
print(info1,info2)
count += 1
The above code will make sure you are having same value, as you are storing the value to a variable and then validating it .
You don't even need to use telegram web or selenuim either, let's make it much more easier:
‍
from telethon import TelegramClient, events
client = TelegramClient(PHONE_NUMBER, API_ID, API_HASH)
#client.on(events.NewMessage("chanel name"))
def new_message_listener(event):
new_message = event.message.message
media_status = event.message.media
## DO what you like with new_messsage
Just remember to change the variables in the TelegramClient, You can receive API_ID, API_HASH from Telegram website.
They should be like this:
api_id = 1027347
api_hash = "c0e2cfefac982659a52da625b81e2a99"

Not receiving a return message in python 2 code

I'm pretty new to python and just learning to ropes. In the code bellow I have a function taking several inputs from a json string. I'm attempting to have a return output in the specified strings. Problem? when I run the file I get nothing... I'm sure I'm missing something incredibly simply, but for the life of me I can't figure out what. I've attempted to use return as well as print at the end of the function. No cheese.
Help?
Here's what I've got so far:
import datetime, json
def jeeves(request): #defines the function
message=''
if request['type']=='maintainance':
message='Thank you tenant at unit'+str(request['unit'])+', your request for maintenance to deal with '+'"'+str(request['issue'])+'"'+' has been received #2 input'
elif request['type']=='purchase':
message='Thank you tenant at unit'+str(request['unit'])+'your request to purchase a'+str(request['commodity'])+ ' has been received'
elif request['type']=='reservation':
startTime=request['date'].split(" ")[1]
startTime=startTime.split('')
time=0;
num=[]
for item in startTime:
if isdigit(item):
num.append(item)
for index in range(len(num)):
time+=num[index]*10**(len(num)-index)
endTime=0
daySplit=''.join(startTime[-2:])
if time+int(request['duration'].split(' ')[0])>12:
endTime=time+int(request['duration'].split(' ')[0])-12
if daySplit=='AM':
endTime=str(endTime)+'PM'
else:
endTime=str(endTime)+'AM'
else:
endTime=endTime+int(request['duration'].split(' ')[0])
endTime=str(endTime)+daySplit
message='Thank you tenant at unit'+str(request['unit'])+'your request to reserve our '+str(request['location'])+' on '+str(request['date'].split(' ')[0])+' from '+str(request['date'].split(' ')[1])+' to '+ endTime+' has been received'
elif request['type']=='complaint':
message='Thank you tenant at unit'+str(request['unit'])+' we will have someone follow up on '+'"'+request['issue']+'"'+' in regards to our '+request['location']
return message
print message
json.dumps(jeeves({"type":"maintenance", "unit":221, "issue":"Air filter needs replacing"}))
ps: I'm new to coding in general. If there is a better, more productive way for me to ask questions, I'm open to feedback. Thank you in advanced.
You have to put return before the print function because when you use return it ends a function. You might also want to check out what return actually does here

asterisk ari calling stuck in ringing with python

I'm quite new with ARI scripting for Asterisk, and I've been trying to make some script to handle a 1 to 1 communication with ari-py in python. I've been following the example that provided in the asterisk wiki and so far so good. But when I try to create a call, the recipient always keep ringing, even if I have answered it. Is there something wrong with how I handle the call? Here's my script
def stasis_start_cb(self, channel, ev):
"""Handler for StasisStart event"""
chan = channel.get('channel')
chan.answer()
print "Channel %s has entered the application" % chan.json.get('name')
outgoing = client.channels.originate(endpoint="SIP/1002", extension='1002', callerId='Tes', app='channel-dump', appArgs='dialed')
I tried using OOP to simplify the function usage, are there anything wrong with that script? And here's another script trying to make a call by using a bridge:
def outgoing_call(self,channel):
try:
outgoing = client.channels.originate(endpoint="SIP/1002", app='channel-dump', appArgs='dialed')
except requests.HTTPError:
channel.hangup()
return
def outgoing_start(self, bri, channel):
channel.answer()
self.addChan(channel, bridge)
def stasis_start(self, channel, ev):
chan = channel.get('channel')
name = chan.json.get('name')
"""ars = ev.get('args')
if not ars:
print "Error: {} didn't provide any arguments!".format(name)
return
if ars and ars[0] != 'inbound':
return
if len(ars) != 2:
print "Error: {} didn't tell us who to dial".format(name)
chan.hangup()"""
print "Channel {} entered the application".format(name)
chan.ring()
self.outgoing_call(chan)
self.outgoing_start(bridge, chan)
Both the client is able to be added in the bridge, and I can make a call, but the problem still persist, the recipient keep saying they are ringing despite I have answered the call
Turns out, the problem is in here
def outgoing_call(self,channel):
try:
outgoing = client.channels.originate(endpoint="SIP/1002", app='channel-dump', appArgs='dialed')
except requests.HTTPError:
channel.hangup()
return
As the dialed number answer the call, they uses the same script, so they ended up calling themselves again. A simple if condition to make the dialed number not call to itself again is all that is needed

Python: Break-up large function into segments

I am creating a Bot for Reddit. I currently only have 1 very large function and I am looking to create sub-functions to make it more readable.
Here is a rough break-down of what it does
def replybot():
submissions = reversed(list(subreddit.get_new(limit=MAXPOSTS)))
for post in submissions:
try:
author = post.author.name
except AttributeError:
print "AttributeError: Author is deleted"
continue # Author is deleted. We don't care about this post.
# DOES PID EXIST IN DB? IF NOT ADD IT
cur.execute('SELECT * FROM oldposts WHERE ID=?', [pid])
sql.commit()
if cur.fetchone(): # Post is already in the database
continue
cur.execute('INSERT INTO oldposts VALUES(?)', [pid])
sql.commit()
...
I am looking to break the code up into segments i.e. put
try:
author = post.author.name
except AttributeError:
print "AttributeError: Author is deleted"
continue # Author is deleted. We don't care about this post.
in it's own function and call it from within replybot() but I run into the issue of calling continue. I get SyntaxError: 'continue' not properly in loop
Is there a way for me to do this?
If you take the inner part of a loop and convert it to its own function, it's no longer in a loop. The equivalent of continue in a loop, for a function, is return (i.e. terminate this iteration (which is now a function call) early).
Raise the error again instead of trying to continue. Either simply let it bubble to the main loop, or if you need better error handling, make your own custom error. For instance:
class MyNotFatalError(Exception):
pass
def do_something():
try:
a, b, c = 1, 2
except ValueError:
raise MyNotFatalError('Something went wrong')
# In your main function
for post in submissions:
try:
do_something()
do_some_other_thing()
do_some_more()
except MyNotFatalError as err:
continue # we could print out the error text here
do_some_last_thing()
It is probably better that way because you only catch errors you know you want to catch, and still let the program crash when there are actual bugs.
If you had simply caught ValueError that would also intercept and hide all other possible sources of the same kind of error.
as Claudiu said, when you broke inner commands into it's own function; It's not no longer in the loop and your code will be look like this:
def isNotAuthorDeleted(post):
try:
author = post.author.name
return author
except AttributeError:
print "AttributeError: Author is deleted"
return false
and your loop will be:
for post in submissions:
if not isNotAuthorDeleted(post):
continue

Categories

Resources