Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blueprint exceptions are sometimes handled by other blueprint's exception handlers #2242

Closed
prryplatypus opened this issue Sep 17, 2021 · 2 comments · Fixed by #2246
Closed

Comments

@prryplatypus
Copy link
Member

Describe the bug
Exceptions thrown from within one blueprint are sometimes handled by the exception handler of another, unrelated blueprint instead of by its own. I have not had time to check whether this happens all the time or only if specific conditions are met, but I have attached a code snippet with which the issue can be reproduced.

Code snippet

from sanic import Blueprint, HTTPResponse, Request, Sanic
from sanic.exceptions import SanicException
from sanic.response import text


class BaseException(SanicException):
    code: int
    description: str
    status_code: int
    headers: dict = {}


class ExceptionA(BaseException):
    error: str


class ExceptionB(BaseException):
    code = 0
    status_code = 400


class ExceptionBA(ExceptionB, ExceptionA):
    error = "foo"
    description = "Bar!"


app = Sanic("my_app")
bp1 = Blueprint("auth", url_prefix="/auth")
bp2 = Blueprint("token")


@bp1.route("/network", version=1)
async def error_bp1(_: Request):
    raise ExceptionBA()


@bp2.route("/token")
async def hello_bp2(_: Request):
    return text("P3rry7hePl4typu5")


bpg1 = Blueprint.group(bp1, version_prefix="/api/v")
bpg2 = Blueprint.group(bp2, url_prefix="/api/oauth2")


for bp in bpg1.blueprints:
    @bp.exception(BaseException)
    async def _(_, ex: BaseException) -> HTTPResponse:
        return text("BPG1_BaseException")

    @bp.exception(Exception)
    async def _(request: Request, ex: Exception) -> HTTPResponse:
        return text("BPG1_Exception")


for bp in bpg2.blueprints:
    @bp.exception(ExceptionA)
    async def _(_, ex: ExceptionA):
        return text("BPG2_ExceptionA")

    @bp.exception(Exception)
    async def _(request: Request, ex: Exception):
        return text("BPG2_Exception")


bpg_all = Blueprint.group(bpg1, bpg2)
app.blueprint(bpg_all)


if __name__ == "__main__":
    app.run(debug=True)

Expected behavior
When accessing /api/v1/auth/network, an exception is raised, which is captured by the bpg1 exception handler; rendering a final response which displays the string BPG1_BaseException.

Actual behavior
When accessing /api/v1/auth/network, an exception is raised, which is (somehow) captured by the bpg2 exception handler; rendering a final response which displays the string BPG2_ExceptionA.

Environment (please complete the following information):

  • OS: Windows 10 Pro; 21H1; Compilation 19043.1165.
  • Versions: Sanic 21.6.2; Routing 0.7.1
@komar007
Copy link

This seems to be related to #2202. With the fix for #2202, sanic produces the expected behavior.

@ahopkins
Copy link
Member

See #2246

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants