Question about getting asyncmongo query result in Tornado web - python

Hi
I know this is a common issue for user who is not familiar with async method....
i want to query db with user id using asyncmongo to check if the user log on, but obviously this doesn't work and i don't want to use self.render in call back.
Thanks for your help.
class MainPage(BaseHandler):
def get(self):
if not self.current_user:
#### get no result here
.............
get_current_user function using asyncmongo method:
def get_current_user(self):
user_id = self.get_secure_cookie("user")
if not user_id: return None
self.db.users.find({'user_id': bson.ObjectId(str(user_id))}, limit=1, callback=self._on_response)
def _on_response(self, response, error):
if error:
raise tornado.web.HTTPError(500)
how to return the value of response instead of self.render('template',response) ?

see Tornado Asynchronous Handler

def _on_response(self, response, error):
if error:
raise tornado.web.HTTPError(500)
self.render(str(response))

Related

How to restrict the acess to a few users in pyTelegramBotAPI?

I'm using telebot (https://github.com/eternnoir/pyTelegramBotAPI) to create a bot to send photos to its users. The point is I didn't see a way to restrict the access to this bot as I intend to share private images through this bot.
I read in this forum that through python-telegram-bot there is a way to limit the access from the sender's message (How To Limit Access To A Telegram Bot), but I didn't know if via pyTelegramBotAPI it is possible.
Do you know how can I solve it?
A bit late tot the party - perhaps for future post readers. You can wrap the function to disallow access.
An example below:
from functools import wraps
def is_known_username(username):
'''
Returns a boolean if the username is known in the user-list.
'''
known_usernames = ['username1', 'username2']
return username in known_usernames
def private_access():
"""
Restrict access to the command to users allowed by the is_known_username function.
"""
def deco_restrict(f):
#wraps(f)
def f_restrict(message, *args, **kwargs):
username = message.from_user.username
if is_known_username(username):
return f(message, *args, **kwargs)
else:
bot.reply_to(message, text='Who are you? Keep on walking...')
return f_restrict # true decorator
return deco_restrict
Then where you are handling commands you can restrict access to the command like this:
#bot.message_handler(commands=['start'])
#private_access()
def send_welcome(message):
bot.reply_to(message, "Hi and welcome")
Keep in mind, order matters. First the message-handler and then your custom decorator - or it will not work.
The easiest way is probably a hard coded check on the user id.
# The allowed user id
my_user_id = '12345678'
# Handle command
#bot.message_handler(commands=['picture'])
def send_picture(message):
# Get user id from message
to_check_id = message.message_id
if my_user_id = to_check_id:
response_message = 'Pretty picture'
else:
response_message = 'Sorry, this is a private bot!'
# Send response message
bot.reply_to(message, response_message)

Raising a server error to the client with grpc

Let's consider a simple service:
service Something {
rpc Do(Request) returns Response;
}
message Request {
string field = 1;
}
message Response {
string response = 1;
}
Assume I have to do some checking on the Request.field, I want to raise a client error if the field is invalid:
class MyService(proto_pb2.SomethingServicer):
def Do(self, request, context):
if not is_valid_field(request.field):
raise ValueError("Damn!") # Or something like that
return proto_pb2.Response(response="Yeah!")
With the following client:
channel = grpc.insecure_channel(...)
stub = proto_pb2.SomethingStub(channel)
try:
response = stub.Do(proto_pb2.Request(field="invalid"))
except grpc.RpcError as e:
print(e)
<_Rendezvous of RPC that terminated with (StatusCode.UNKNOWN, Exception calling application: Damn!)>
So I can technically handle errors. My issue is... is there a better way? Is there a good way to change the message description? Can we change the status code?
Yes, there is a better way. You may change the status details using the ServicerContext.set_details method and you may change the status code using the ServicerContext.set_code method. I suspect that your servicer will look something like
class MyService(proto_pb2.SomethingServicer):
def Do(self, request, context):
if not is_valid_field(request.field):
context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
context.set_details('Consarnit!')
return proto_pb2.Response()
return proto_pb2.Response(response='Yeah!')
.
There's a new method for this too, context.abort() - it'll actually raise an exception to terminate the RPC call:
grpc.ServicerContext.abort()
So at gRPC side someone can abort context using:
grpc.ServicerContext.abort()
At client side (python):
try:
result = {'msg', 'success'}
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.INVALID_ARGUMENT:
result = {'msg', 'invalid arg error'}
elif e.code() == grpc.StatusCode.ALREADY_EXISTS:
result = {'msg', 'already exists error'}

Give Flask error handler access to request

I'm trying to make a custom error page in Flask, and I'd like to give the error handler access to the request that generated the API call that caused the error so that the error page it returns can change depend on the circumstances. For instance, say there are two endpoints:
(1) #app.route('/get_item')
(2) #app.route('/submit_item')
If an error occurs during a call to get_item, I want to display a certain error page ("Sorry, an error occurred...") however, if an error occurs during a call to submit_item, I want it to say something more informative, like:
"An error occured! Please contact us.
Your user id: request.json['userid']
Your submission id: request.json['submission']"
Is it possible to allow the error handler to have access to this, or do I just have to wrap the whole of submit_item in try/except statements?
You can use the request context in the error handler function,
something along those lines:
from flask import request
def exception_handler(*args):
if request.url.endswith('submit_item'):
return "MyMoreDescriptiveErrorMessage", 500
else:
return "Something wrong happened", 500
I would probably create a custom exception and specify an error handler for it similar to this example.
class CustomException(Exception):
def __init__(self, message=None, status_code=None, payload=None):
Exception.__init__(self)
if message is None:
message = "Sorry, an error occurred..."
self.message = message
if status_code is not None:
self.status_code = status_code
self.payload = payload
#app.errorhandler(CustomException)
def handle_custom(error):
response = render_template('error.html', message=error.message)
response.status_code = error.status_code
return response
#app.route('/submit_item')
def submit_item():
message = "An error occured! Userid: %(userid)d, submission: %(submission_id)d"
message = message % (request.json)
raise CustomException(message)

Python twisted irc: Wait for a whois reply inside privmsg method

I'm trying to make an IRC bot using the twisted.words.protocols.irc module.
The bot will parse messages from a channel and parse them for command strings.
Everything works fine except when I need the bot to identify a nick by sending a whois command. The whois reply will not be handled until the privmsg method (the method from which I'm doing the parsing) returns.
example:
from twisted.words.protocols import irc
class MyBot(irc.IRClient):
..........
def privmsg(self, user, channel, msg):
"""This method is called when the client recieves a message"""
if msg.startswith(':whois '):
nick = msg.split()[1]
self.whois(nick)
print(self.whoislist)
def irc_RPL_WHOISCHANNELS(self, prefix, params):
"""This method is called when the client recieves a reply for whois"""
self.whoislist[prefix] = params
Is there a way to somehow make the bot wait for a reply after self.whois(nick)?
Perhaps use a thread (I don't have any experience with those).
Deferred is a core concept in Twisted, you must be familiar with it to use Twisted.
Basically, your whois checking function should return a Deferred that will be fired when you receive whois-reply.
I managed to fix this by running all handler methods as threads, and then setting a field, following
kirelagin's suggestion, before running a whois query, and modifying the method that recieves the data
to change the field when it recieves a reply. Its not the most elegant solution but it works.
Modified code:
class MyBot(irc.IRClient):
..........
def privmsg(self, user, channel, msg):
"""This method is called when the client recieves a message"""
if msg.startswith(':whois '):
nick = msg.split()[1]
self.whois_status = 'REQUEST'
self.whois(nick)
while not self.whois_status == 'ACK':
sleep(1)
print(self.whoislist)
def irc_RPL_WHOISCHANNELS(self, prefix, params):
"""This method is called when the client recieves a reply for whois"""
self.whoislist[prefix] = params
def handleCommand(self, command, prefix, params):
"""Determine the function to call for the given command and call
it with the given arguments.
"""
method = getattr(self, "irc_%s" % command, None)
try:
# all handler methods are now threaded.
if method is not None:
thread.start_new_thread(method, (prefix, params))
else:
thread.start_new_thread(self.irc_unknown, (prefix, command, params))
except:
irc.log.deferr()
def irc_RPL_WHOISCHANNELS(self, prefix, params):
"""docstring for irc_RPL_WHOISCHANNELS"""
self.whoislist[prefix] = params
def irc_RPL_ENDOFWHOIS(self, prefix, params):
self.whois_status = 'ACK'

Tornado, Accessing additional data in callback function?

I have just started a project using Tornado, and asyncmongo.
I have a handler with an async method. Inside I am querying mongo for some words:
#tornado.web.asynchronous
def get(self):
word = self.get_argument('word', None)
if not word:
self.write('{}')
self.finish()
self.db.spanish_dict.find({'$or': [{'word': word}, {'stem': word}]},
callback=self._on_response)
def _on_response(self, response, error):
# need to sort response by relevancy
In my callback method I need the original word to sort the mongo results accurately.
I found this post which uses functools.partial to accomplish this, by allowing me to pass additional parameters to the callback method
I was wondering if there are any adverse affects to setting an instance attribute in the get method and accessing it in _on_response? THank you
#tornado.web.asynchronous
def get(self):
word = self.get_argument('word', None)
if not word:
self.write('{}')
self.finish()
self.word = word
self.db.spanish_dict.find({'$or': [{'word': word}, {'stem': word}]},
callback=self._on_response)
def _on_response(self, response, error):
# need to sort response by relevancy
# will self.word always be accurate?
self.word
Use tornado.gen and you sidestep the problem completely
http://www.tornadoweb.org/documentation/gen.html?highlight=tornado.gen#tornado.gen

Categories