I had written a piece of code where I'm using traceback to return the exception stacktrace. But I forgot to import traceback.
Filename - trial_main.py
from fastapi import FastAPI
from pydantic import BaseModel
import uvicorn
app = FastAPI()
class RequestJson(BaseModel):
data: str
@app.post("/trial", status_code=200)
async def trial(req:RequestJson):
try:
status = "default"
resp = {
"status": status,
"reason": "default reason"
}
# error point
a = 10/0
status = "complete"
reason = "Finished converting from base64 to image"
resp = {
"status": status,
"reason": reason
}
except Exception as e:
status = "incomplete"
resp = {
"status": status,
"reason": traceback.format_exc(),
}
finally:
return resp
if __name__ == '__main__':
uvicorn.run("trial_main:app", host="0.0.0.0", port=5001, log_level="info")
What's confusing me is why isn't the code exiting with an exception since traceback module is not found. Rather it returns the default response that was set earlier.
This is the API response that I'm getting -
{
"status": "default",
"reason": "default reason"
}
And this is the output on the terminal where I run the uvicorn server -
INFO: Started server process [14744]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:5001 (Press CTRL+C to quit)
INFO: 127.0.0.1:61809 - "POST /trial HTTP/1.1" 200 OK
Api endpoint -
[POST] http://127.0.0.1:5001/trial
Input to re-create the situation -
{"data": "randomString"}
No mystery is happens here.
In the try block, you successfully assign value to resp
variable, then Exception is raised and execution goes to except block. There you're trying to assign new value to resp
, but ImportError happens in the right part of statement, so resp
still contains old value, which would returned in the finally block. Exception is not propagated further because there is return
in the finally block, it's just suppress exception.
To not get distracted by fastapi boilerplate all of this could be illustrated with more simple example
def always_return():
"""return 1"""
try:
res = 1
raise Exception()
except Exception:
res = 1 / 0
finally:
return res
def never_return():
"""raises ZeroDivisionError"""
try:
res = 1
raise Exception()
except Exception:
res = 1 / 0
finally:
print("finally block exists, but no return here")
return res
>>> print(always_return())
1
>>> print(never_return())
finally block exists, but no return here
ZeroDivisionError: division by zero... traceback
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.