Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion requirements-testing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ socksio
httpcore[http2]
setuptools
Brotli
docker
docker
1 change: 1 addition & 0 deletions scripts/populate_tox/tox.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ deps =
# Quart
quart: quart-auth
quart: pytest-asyncio
quart-{v0.19,latest}: quart-flask-patch
quart-v0.16: blinker<1.6
quart-v0.16: jinja2<3.1.0
quart-v0.16: Werkzeug<2.1.0
Expand Down
12 changes: 12 additions & 0 deletions sentry_sdk/integrations/flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,18 @@ def __init__(
@staticmethod
def setup_once():
# type: () -> None
try:
from quart import Quart # type: ignore

if Flask == Quart:
# This is Quart masquerading as Flask, don't enable the Flask
# integration. See https://github.com/getsentry/sentry-python/issues/2709
raise DidNotEnable(
"This is not a Flask app but rather Quart pretending to be Flask"
)
except ImportError:
pass

version = package_version("flask")
_check_minimum_version(FlaskIntegration, version)

Expand Down
67 changes: 56 additions & 11 deletions tests/integrations/quart/test_quart.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import importlib
import json
import threading
from unittest import mock
Expand All @@ -13,22 +14,22 @@
from sentry_sdk.integrations.logging import LoggingIntegration
import sentry_sdk.integrations.quart as quart_sentry

from quart import Quart, Response, abort, stream_with_context
from quart.views import View

from quart_auth import AuthUser, login_user

try:
from quart_auth import QuartAuth
def quart_app_factory():
# These imports are inlined because the `test_quart_flask_patch` testcase
# tests behavior that is triggered by importing a package before any Quart
# imports happen, so we can't have these on the module level
from quart import Quart

auth_manager = QuartAuth()
except ImportError:
from quart_auth import AuthManager
try:
from quart_auth import QuartAuth

auth_manager = AuthManager()
auth_manager = QuartAuth()
except ImportError:
from quart_auth import AuthManager

auth_manager = AuthManager()

def quart_app_factory():
app = Quart(__name__)
app.debug = False
app.config["TESTING"] = False
Expand Down Expand Up @@ -71,6 +72,42 @@ def integration_enabled_params(request):
raise ValueError(request.param)


@pytest.mark.asyncio
@pytest.mark.forked
@pytest.mark.skipif(
not importlib.util.find_spec("quart_flask_patch"),
reason="requires quart_flask_patch",
)
async def test_quart_flask_patch(sentry_init, capture_events, reset_integrations):
# This testcase is forked because `import quart_flask_patch` needs to run
# before anything else Quart-related is imported (since it monkeypatches
# some things) and we don't want this to affect other testcases.
#
# It's also important this testcase be run before any other testcase
# that uses `quart_app_factory`.
import quart_flask_patch # noqa: F401

app = quart_app_factory()
sentry_init(
integrations=[quart_sentry.QuartIntegration()],
)

@app.route("/")
async def index():
1 / 0

events = capture_events()

client = app.test_client()
try:
await client.get("/")
except ZeroDivisionError:
pass

(event,) = events
assert event["exception"]["values"][0]["mechanism"]["type"] == "quart"


@pytest.mark.asyncio
async def test_has_context(sentry_init, capture_events):
sentry_init(integrations=[quart_sentry.QuartIntegration()])
Expand Down Expand Up @@ -213,6 +250,8 @@ async def test_quart_auth_configured(
monkeypatch,
integration_enabled_params,
):
from quart_auth import AuthUser, login_user

sentry_init(send_default_pii=send_default_pii, **integration_enabled_params)
app = quart_app_factory()

Expand Down Expand Up @@ -368,6 +407,8 @@ async def error_handler(err):

@pytest.mark.asyncio
async def test_bad_request_not_captured(sentry_init, capture_events):
from quart import abort

sentry_init(integrations=[quart_sentry.QuartIntegration()])
app = quart_app_factory()
events = capture_events()
Expand All @@ -385,6 +426,8 @@ async def index():

@pytest.mark.asyncio
async def test_does_not_leak_scope(sentry_init, capture_events):
from quart import Response, stream_with_context

sentry_init(integrations=[quart_sentry.QuartIntegration()])
app = quart_app_factory()
events = capture_events()
Expand Down Expand Up @@ -514,6 +557,8 @@ async def error():

@pytest.mark.asyncio
async def test_class_based_views(sentry_init, capture_events):
from quart.views import View

sentry_init(integrations=[quart_sentry.QuartIntegration()])
app = quart_app_factory()
events = capture_events()
Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ deps =
# Quart
quart: quart-auth
quart: pytest-asyncio
quart-{v0.19,latest}: quart-flask-patch
quart-v0.16: blinker<1.6
quart-v0.16: jinja2<3.1.0
quart-v0.16: Werkzeug<2.1.0
Expand Down
Loading