How to test Fastapi Exception Handler - python

I created a custom exception handler and wanted to write test cases for it.
This is my Testcase:
def test_is_exception_raised(app_client):
exception = CustomException(InvalidSQLStatement())
with pytest.raises(exception):
raise exception
try:
raise exception
except Exception as e:
assert e.message
assert e.status_code
This is the error I get:
My Code looks like this:
main.py
#app.exception_handler(CustomException)
async def custom_exception_handler(request: Request, exc: CustomException):
log.error(f"{exc}")
return JSONResponse(
status_code=exc.status_code_number,
content=jsonable_encoder({exc.status_code_number: exc.message}),
)
exceptions.py
class CustomException(Exception):
"""
All Custom Exceptions are defined in xyz\exceptions.py
"""
def __init__(self, exception):
if not check_if_exception_exists(exception):
raise KeyError(f"Custom Exception: {exception.__class__.__name__} does not exist.")
self.message = exception.message
self.status_code_number = exception.status_code_number

You need to use raises in the class, like this:
with pytest.raises(CustomException):
Also, you declare status_code_number (in exceptions.py), but use status_code in test case.

Related

Pytest raises not working for custom exception

I have the following defined in an exceptions.py file:
class Error(Exception):
"""Base exception raised by api wrapper"""
def __init__(self, message: str):
self.message = message
super().__init__(self.message)
# HTTP response exceptions
class ApiBadRequestError(Error):
"""Bad Request –- Incorrect parameters."""
def __init__(self, message: str):
self.message = message
super().__init__(self.message)
I then have a function that correctly raises an ApiBadRequestError exception.
In pytest I'm doing the following:
def test_handle_request_response_raises_correct_exception_for_response_code(
self, status_code, exception_type, client, create_response
):
response = create_response(status_code=status_code)
with pytest.raises(ApiBadRequestError) as e:
a = client._check_response_codes(response)
which is failing the test because inside pytest.raises it's doing isintance(e, ApiBadRequestError) which is returning False. If I however change the test to the following:
def test_handle_request_response_raises_correct_exception_for_response_code(
self, status_code, exception_type, client, create_response
):
response = create_response(status_code=status_code)
with pytest.raises(Exception) as e:
a = client._check_response_codes(response)
it passes as the raised exception is seen as an instance of Exception even though it's an ApiBadRequestError
Any help would be really appreciated as I'm completely stumped here.

inner function raise in Django rest API

How can I catch a 4XX series raise in inner function of an API in Django rest framework?
from rest_framework.exceptions import ValidationError
class DummyView(APIView):
def get(self, request, id):
if id==something:
dummy_function_1(id)
else:
dummy_function_2(id)
return Response()
def dummy_function_1():
try:
validate_1(id)
except ValidationError:
raise ValidationError()
#do something with id
return id
When I send a HTTP GET request, I receive a 5XX series error if exception occurs. I want to get 400 Bad Request error in response.
After lots of effort and I don't know why,
If I specify the exception type of inner function, I will get 5XX series error.
so in dummy function I just wrote :
def dummy_function_1():
try:
validate_1(id)
except Exception: # just exception, Not ValidationError or other exception
raise ValidationError()
I could get 4XX series error
Try this:
def dummy_function_1():
try:
validate_1(id)
except Exception: # just exception, Not ValidationError or other exceptions
raise ValidationError()

Exception passing in python flask app inside a POST request handler

I have a python flask app, pseudocode shown below.
#app.route('/predict', methods=['POST'])
def transformation():
try:
var1 = function_1()
# do something with var1
var2 = function_2()
except Exception as e:
return jsonify({'message': '{}: {}'.format(type(e).__name__, e)}), 500
As you see, the POST call handler returns a generic exception message back to the client. But I want to customize those exception messages based on whether they are coming from function_1 or function_2
I looked into this thread and understand that it is possible to do below -
try:
#something1
#something2
except ExceptionType1:
#return xyz
except ExceptionType2:
#return abc
But how would it know that ExceptionType1 is coming from function_1() or function_2(). How should I pass exception from function_1() or function_2() to be caught in the main try-except block?

How to create a custom Exception with error message and status code in python3

I am trying to create the following exception and call it in another function:
### The exception
class GoogleAuthError(Exception):
def __init__(self, message, code=403):
self.code = code
self.message = message
### Generating the exception
raise GoogleAuthError(message="There was an error authenticating")
### printing the exception
try:
do_something()
except GoogleAuthError as e:
print(e.message)
Basically, I want it to print "There was an error authenticating". How would I do this properly, or is the above the correct way to do it?
Remove the code argument from your __init__. You aren't using it.
You can also delegate the handling of the error message to the parent Exception class, which already knows about messages
class GoogleAuthError(Exception):
def __init__(self, message):
super().__init__(message)
self.code = 403
try:
raise GoogleAuthError('There was an error authenticating')
except GoogleAuthError as e:
print(e)
# There was an error authenticating

Bottle middleware to catch exceptions of a certain type?

Given this simple Bottle code:
def bar(i):
if i%2 == 0:
return i
raise MyError
#route('/foo')
def foo():
try:
return bar()
except MyError as e:
response.status_code = e.pop('status_code')
return e
How would one write Bottle middleware so the same exception handling is done implicitly, so that code like this can work identically to above:
#route('/foo')
def foo():
return bar()
You can do this elegantly with a plugin leveraging abort:
from bottle import abort
def error_translation(func):
def wrapper(*args,**kwargs):
try:
func(*args,**kwargs)
except ValueError as e:
abort(400, e.message)
return wrapper
app.install(error_translation)
Bottle respect the wsgi spec. You can use a classic wsgi middleware
from bottle import route, default_app, run, request
# push an application in the AppStack
default_app.push()
#route('/foo')
def foo():
raise KeyError()
# error view
#route('/error')
def error():
return 'Sorry an error occured %(myapp.error)r' % request.environ
# get the bottle application. can be a Bottle() instance too
app = default_app.pop()
app.catchall = False
def error_catcher(environ, start_response):
# maybe better to fake the start_response callable but this work
try:
return app.wsgi(environ, start_response)
except Exception as e:
# redirect to the error view if an exception is raised
environ['PATH_INFO'] = '/error'
environ['myapp.error'] = e
return app.wsgi(environ, start_response)
# serve the middleware instead of the applicatio
run(app=error_catcher)
You can use this instead:
from bottle import error, run, route
#error(500)
def error_handler_500(error):
return json.dumps({"status": "error", "message": str(error.exception)})
#route("/")
def index():
a = {}
a['aaa']
run()

Categories

Resources