Catch mako runtime errors using Bottle - python

I'm looking for a way to catch mako runtime errors using Bottle.
Runtime errors in python are catched using the following code:
# main.py
from lib import errors
import bottle
app = bottle.app()
app.error_handler = errors.handler
...
# lib/errors.py
from bottle import mako_template as template
def custom500(error):
return template('error/500')
handler = {
500: custom500
}
This works flawlessly, as exceptions are turned into 500 Internal Server Error.
I'd like to catch the mako runtime errors in a similar fashion, does anyone have a clue of how to achieve this?

You want to catch mako.exceptions.SyntaxException.
This code works for me:
#bottle.route('/hello')
def hello():
try:
return bottle.mako_template('hello')
except mako.exceptions.SyntaxException as exx:
return 'mako exception: {}\n'.format(exx)
EDIT: Per your comment, here are some pointers on how to install this globally. Install a bottle plugin that wraps your functions in the mako.exceptions.SyntaxException try block.
Something along these lines:
#bottle.route('/hello')
def hello():
return bottle.mako_template('hello')
def catch_mako_errors(callback):
def wrapper(*args, **kwargs):
try:
return callback(*args, **kwargs)
except mako.exceptions.SyntaxException as exx:
return 'mako exception: {}\n'.format(exx)
return wrapper
bottle.install(catch_mako_errors)

Related

Mocking gRPC status code ('RpcError' object has no attribute 'code') in Flask App

I have to create a unittest that should mock a specific grpc status code (in my case I need NOT_FOUND status).
This is what i want to mock:
try:
# my mocked function
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
# do something
My unittest until now looks like this:
def mock_function_which_raise_RpcError():
e = grpc.RpcError(grpc.StatusCode.NOT_FOUND)
raise e
class MyTestCase(BaseViewTestCase):
#property
def base_url(self):
return '/myurl'
#mock.patch('my_func', mock_function_which_raise_RpcError)
def test_service_config_with_grpc_status_error(self):
# some code
assert resp.status_code == 404
First thing first, when I run my flask app and make a request to a URL with a specific body which should raise that RpcError, everything works just fine. e.code() is recognized. On the other hand, when i want to run that unittest, I get AttributeError: 'RpcError' object has no attribute 'code'.
Any thoughts?
Looks like you cannot construct a valid RpcError object from Python the same way it is created in the grpc code (which is written in C). You can, however, emulate the behavior by using:
def mock_function_which_raise_RpcError():
e = grpc.RpcError()
e.code = lambda: grpc.StatusCode.NOT_FOUND
raise e
Alternatively, you can derive your own exception:
class MyRpcError(grpc.RpcError):
def __init__(self, code):
self._code = code
def code(self):
return self._code
def mock_function_which_raise_RpcError():
raise MyRpcError(grpc.StatusCode.NOT_FOUND)
Update:
Added missing code method as mentioned by Martin Grůber in the comments.

How to do post-mortem debugging within Django's runserver?

I am currently debugging a Django project which results in an exception. I would like to enter the ipdb post-mortem debugger. I've tried invoking ipdb as a script (cf. https://docs.python.org/3/library/pdb.html), but this just enters me to the first line of code:
> python -m ipdb manage.py runserver
> /Users/kurtpeek/myproject/manage.py(2)<module>()
1 #!/usr/bin/env python
----> 2 import os
3 import sys
ipdb>
If I press c to continue, I just run into the error, with no possibility to drop into the debugger post-mortem. Presumably I could press n (next) until I get the error, but that would be quite cumbersome.
Is there a way to run python manage.py runserver with post-mortem debugging?
If you know of a line that causes the exception, but don't know how "deep" inside it the exception is caused, you can get a post-mortem debugger for it by catching the exception and calling ipdb.post_mortem() in the exception handler.
For example, change your code from this:
def index(request):
output = function_that_causes_some_exception()
return HttpResponse(output)
To this:
def index(request):
try:
output = function_that_causes_some_exception()
except:
import ipdb
ipdb.post_mortem()
# Let the framework handle the exception as usual:
raise
return HttpResponse(output)
By the way, for server frameworks that could be spewing stuff in the console from other threads I highly recommend wdb, so that you can debug your django app from the comfort of a browser:
def index(request):
try:
output = function_that_causes_some_exception()
except:
import wdb
wdb.post_mortem()
# Let the framework handle the exception as usual:
raise
return HttpResponse(output)

What's the best way to display Exception in Flask?

I'm a newbie in Flask and I am trying to display the Built-In Exceptions in python but I can't seem to have them display on my end.
NOTE:
set FLASK_DEBUG = 0
CODE:
def do_something:
try:
doing_something()
except Exception as err:
return f"{err}"
Expectation:
It will display one of the built-in exceptions:
KeyError
IndexError
NameError
Etc.
Reality:
It will return the line of code that didn't worked which is more ambiguous to the end user.
Also:
I have no problem seeing the errors when the debug mode is ON but that's not something that I want to do if I open them in public
Flask supplies you with a function that enables you to register an error handler throughout your entire app; you can do something as shown below:
def handle_exceptions(e):
# Log exception in your logs
# get traceback and sys exception info and log as required
# app.logger.error(getattr(e, 'description', str(e)))
# Print traceback
# return your response using getattr(e, 'code', 500) etc.
# Exception is used to catch all exceptions
app.register_error_handler(Exception, handle_exceptions)
In my honest opinion, this is the way to go. - Following the structure found in werkzeug.exceptions.HTTPException as an example is a solid foundation.
Having a unified exception handler that will standardise your Exception handling, visualisation and logging will make your life a tad better. :)
Try with this:
def do_something:
try:
doing_something()
except Exception as err:
return f"{err.__class__.__name__}: {err}"

Twisted deferToThread, not working with Mock.patch()

I have 2 functions both wrapped with #defer.inlineCallbacks decorator.
For tests, I'm mocking various things, including the save_to_db() function.
logic.py
#defer.inlineCallbacks
def save_to_db(obj): # mocked for test.
raise Exception('Oh Noe!')
#defer.inlineCallbacks
def create_contact():
xero = yield get_xero_client()
data = {
# <contact info>
}
# Create a new contact
response = yield deferToThread(xero.contacts.put, data)
obj = {
# some data extracted from response
}
yield save_to_db(obj)
tests.py
import mock
from twisted.internet import defer
from twisted.trial import unittest
from .logic import create_contact
class TestContactCreation(unittest.TestCase):
#mock.patch('logic.save_to_db')
#mock.patch('logic.get_xero_client')
#defer.inlineCallbacks
def test_get_xero_client_is_called(self, mocked_xero_client, mocked_save_method):
yield create_contact()
mocked_get_xero_client.assert_called()
However when I run:
$ trial tests.TestContactCreation
save_to_db() is actually called and as expected its raises an Exception.
Traceback (most recent call last):
File "<file_path>/logic.py", line 93, in save_to_db
raise Exception('Oh Noe!')
exceptions.Exception: Oh Noe!
And I'm not sure why! I tried to debug using pdb.
import pdb; pdb.set_trace()
It looks like save_to_db() is mocked correctly before we use deferToThread()
(Pdb) save_to_db
<MagicMock name='save_to_db' id='4404276240'>
However after the line where I've used deferToThread()
(Pdb) save_to_db
<function save_to_db at 0x111c6f488>
save_to_db() is no longer mocked! Only way I can get around this is if I also mock deferToThread()
Is there a better option? Any tips will be appreciated. Many Thanks.
I encountered the same issue; the #mock.patch(...) decorator doesn't work (i.e., it doesn't actually mock the desired thing) when used in conjunction with the #inlineCallbacks decorator.
What did work for me was to mock via context manager:
#defer.inlineCallbacks
def test_get_xero_client_is_called(self):
with mock.patch('logic.save_to_db') as mocked_save_method, \
mock.patch('logic.get_xero_client') as mocked_xero_client:
yield create_contact()
mocked_get_xero_client.assert_called()
Does that work for you?

Skipping an exception in all Python tests

I'm using Python's unittest with pytest for integration testing a library against a third-party API.
Some of the API calls are temporarily returning an error which raises a specific exception in my code. This behaviour is fine in the code.
However, rather than having the tests fail, I'd rather skip these temporary errors.
I have over 150 tests. Rather than rewriting each and every test like this:
class TestMyLibrary(unittest.TestCase):
def test_some_test(self):
try:
// run the test as normal
// assert the normal behaviour
except SomeException:
// skip the test
def test_some_other_test(self):
try:
// run the test as normal
// assert the normal behaviour
except SomeException:
// skip the test
Can I rather wrap them all somehow at the class level, or similar?
If you expect this exception why don't you check its raised when it should?
You can use :
pytest.raises(Exceptiontype, Foo())
This can be done with a decorator. For example:
def handle_lastfm_exceptions(f):
def wrapper(*args, **kw):
try:
return f(*args, **kw)
except pylast.WSError as e:
if (str(e) == "Invalid Method - "
"No method with that name in this package"):
msg = "Ignore broken Last.fm API: " + str(e)
print(msg)
pytest.skip(msg)
else:
raise(e)
return wrapper
And then decorate the problematic functions:
class TestMyLibrary(unittest.TestCase):
#handle_lastfm_exceptions
def test_some_bad_test(self):
// run the test as normal
// assert the normal behaviour
def test_some_good_test(self):
// run the test as normal
// assert the normal behaviour
had the same problem (instable 3rd party library, waiting for fix...). ended up with something like this:
def pytest_runtest_makereport(item, call):
from _pytest.runner import pytest_runtest_makereport as orig_pytest_runtest_makereport
tr = orig_pytest_runtest_makereport(item, call)
if call.excinfo is not None:
if call.excinfo.type == SomeExceptionFromLibrary:
tr.outcome = 'skipped'
tr.wasxfail = "reason: SomeExceptionFromLibrary. shame on them..."
return tr
works like a charm

Categories

Resources