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

ref: Event Type #2753

Merged
merged 70 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
1e5db1a
Event type WIP
szokeasaurusrex Feb 21, 2024
01d74ce
Merge branch 'master' into szokeasaurusrex/event-type
szokeasaurusrex Feb 27, 2024
8f06af8
Sort Event TypedDict keys
szokeasaurusrex Feb 27, 2024
524312a
Add some more keys, switch to class syntax
szokeasaurusrex Feb 27, 2024
3a9485f
Add `errors` key
szokeasaurusrex Feb 27, 2024
432fa27
Move `event_types` code to `_types`
szokeasaurusrex Feb 27, 2024
5d0ecf3
Add `request` key
szokeasaurusrex Feb 27, 2024
cda5591
Add breadcrumbs and user keys
szokeasaurusrex Feb 27, 2024
899b6d5
Fix `iter_event_frames` and `iter_event_stacktraces` typing
szokeasaurusrex Feb 27, 2024
3ec19ff
Added `exception`, `stacktrace`, `threads` types
szokeasaurusrex Feb 27, 2024
7b42284
Add required items to Event when generated
szokeasaurusrex Feb 27, 2024
411e9e7
Put required items first
szokeasaurusrex Feb 27, 2024
1ba2e93
more keys
szokeasaurusrex Feb 27, 2024
b772d54
measurements and _metrics_summary keys
szokeasaurusrex Feb 27, 2024
62d3c18
all event keys not required
szokeasaurusrex Mar 4, 2024
3bbc809
Revert "Add required items to Event when generated"
szokeasaurusrex Mar 4, 2024
adbf110
Fix capture_message typing
szokeasaurusrex Mar 4, 2024
aade728
Fix scope.py errors
szokeasaurusrex Mar 4, 2024
b9d6900
Fix tracing.py errors
szokeasaurusrex Mar 4, 2024
4626adc
Fix typing in client.py
szokeasaurusrex Mar 4, 2024
ce6a977
Fix `set_level` type
szokeasaurusrex Mar 4, 2024
9baa93a
Fix typing in logging integration
szokeasaurusrex Mar 4, 2024
cbb28d6
Fix checkin typing
szokeasaurusrex Mar 4, 2024
88be616
Use alternative `TypedDict` syntax
szokeasaurusrex Mar 8, 2024
8bda2f1
Remove future import
szokeasaurusrex Mar 8, 2024
1cc4497
Fix type errors
szokeasaurusrex Mar 8, 2024
0abf4d1
Fix wsgi typing
szokeasaurusrex Mar 8, 2024
e3783da
Fix modules integration typing
szokeasaurusrex Mar 8, 2024
64b3f78
Use `Any` type for expandable keys
szokeasaurusrex Mar 8, 2024
712dd46
GNU backtrace type fix
szokeasaurusrex Mar 8, 2024
03a54cf
fix types spark_worker
szokeasaurusrex Mar 8, 2024
cc20306
Fix _wsgi_common typing
szokeasaurusrex Mar 8, 2024
7eb0c15
Fix tornado typing
szokeasaurusrex Mar 8, 2024
6948eb3
Fix rq typing
szokeasaurusrex Mar 8, 2024
56c71e4
Fix aiohttp typing
szokeasaurusrex Mar 8, 2024
a93a5d2
fix pyramid typing
szokeasaurusrex Mar 8, 2024
9e2b5e2
fix types flask integration
szokeasaurusrex Mar 8, 2024
c6267fe
fix falcon integration typing
szokeasaurusrex Mar 8, 2024
91c99af
fix typing bottle
szokeasaurusrex Mar 8, 2024
aa93c5b
fix starlette typing
szokeasaurusrex Mar 8, 2024
bea4112
fix quart typing
szokeasaurusrex Mar 8, 2024
92f8c13
fix ariadne typing
szokeasaurusrex Mar 8, 2024
f585a70
fix django typing
szokeasaurusrex Mar 8, 2024
e979b8a
fix fastapi typing
szokeasaurusrex Mar 8, 2024
ab07457
fix graphene typing
szokeasaurusrex Mar 8, 2024
797e010
fix strawberry typing
szokeasaurusrex Mar 8, 2024
cc1341c
fix gql typing
szokeasaurusrex Mar 8, 2024
301bbf6
Handle span_processor type error
szokeasaurusrex Mar 8, 2024
06552aa
fix tornado typing
szokeasaurusrex Mar 8, 2024
03b423b
refactor strawberry.py so mypy understands it is type safe
szokeasaurusrex Mar 8, 2024
3174215
`rq.py` refactor for mypy to see type safety
szokeasaurusrex Mar 8, 2024
756f488
fix mypy in starlite.py
szokeasaurusrex Mar 8, 2024
cfd1b6f
Fix import that broke all tests
szokeasaurusrex Mar 8, 2024
e1fbd75
Fix 2.7
szokeasaurusrex Mar 8, 2024
1fffb30
Don't use LogLevelStr in code
szokeasaurusrex Mar 8, 2024
2a6d909
Don't use Literal and cast in code
szokeasaurusrex Mar 8, 2024
21a0250
Attempt to remove circular import
szokeasaurusrex Mar 8, 2024
52357ec
2nd attempt fix circular import
szokeasaurusrex Mar 8, 2024
ebed669
Fix circular import
szokeasaurusrex Mar 11, 2024
dc01e58
Merge branch 'master' into szokeasaurusrex/event-type
szokeasaurusrex Mar 11, 2024
19b20d1
Merge branch 'master' into szokeasaurusrex/event-type
szokeasaurusrex Mar 11, 2024
25a1a46
Check if profile is Profile
szokeasaurusrex Mar 11, 2024
e8f688a
Allow "critical" event level
szokeasaurusrex Mar 11, 2024
9bb882f
Merge branch 'master' into szokeasaurusrex/event-type
szokeasaurusrex Mar 11, 2024
01f5239
"start_timestamp" type
szokeasaurusrex Mar 12, 2024
5612f13
fix `contexts` typing
szokeasaurusrex Mar 12, 2024
6caa037
Remove unnecessary `capture_internal_exceptions`
szokeasaurusrex Mar 12, 2024
8e4b828
fix mypy
szokeasaurusrex Mar 12, 2024
f24557c
Merge branch 'master' into szokeasaurusrex/event-type
antonpirker Mar 12, 2024
c513394
Merge branch 'master' into szokeasaurusrex/event-type
szokeasaurusrex Mar 12, 2024
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
63 changes: 61 additions & 2 deletions sentry_sdk/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@


if TYPE_CHECKING:
from collections.abc import MutableMapping

from datetime import datetime

from types import TracebackType
from typing import Any
from typing import Callable
Expand All @@ -19,13 +23,68 @@
from typing import Tuple
from typing import Type
from typing import Union
from typing_extensions import Literal
from typing_extensions import Literal, TypedDict

LogLevelStr = Literal["fatal", "error", "warning", "info", "debug"]

Event = TypedDict(
"Event",
{
"breadcrumbs": dict[
Literal["values"], list[dict[str, Any]]
], # TODO: We can expand on this type
"check_in_id": str,
"contexts": dict[str, object],
"dist": str,
"duration": Optional[float],
"environment": str,
"errors": list[dict[str, Any]], # TODO: We can expand on this type
"event_id": str,
"exception": dict[
Literal["values"], list[dict[str, Any]]
], # TODO: We can expand on this type
"extra": MutableMapping[str, object],
"fingerprint": list[str],
"level": LogLevelStr,
"logentry": Mapping[str, object],
"logger": str,
"measurements": dict[str, object],
"message": str,
"modules": dict[str, str],
"monitor_config": Mapping[str, object],
"monitor_slug": Optional[str],
"platform": Literal["python"],
"profile": object, # Should be sentry_sdk.profiler.Profile, but we can't import that here due to circular imports
"release": str,
"request": dict[str, object],
"sdk": Mapping[str, object],
"server_name": str,
"spans": list[dict[str, object]],
"stacktrace": dict[
str, object
], # We access this key in the code, but I am unsure whether we ever set it
"start_timestamp": Union[datetime, int],
szokeasaurusrex marked this conversation as resolved.
Show resolved Hide resolved
"status": Optional[str],
"tags": MutableMapping[
str, str
antonpirker marked this conversation as resolved.
Show resolved Hide resolved
], # Tags must be less than 200 characters each
"threads": dict[
Literal["values"], list[dict[str, Any]]
], # TODO: We can expand on this type
"timestamp": Optional[datetime], # Must be set before sending the event
"transaction": str,
"transaction_info": Mapping[str, Any], # TODO: We can expand on this type
"type": Literal["check_in", "transaction"],
"user": dict[str, object],
"_metrics_summary": dict[str, object],
},
total=False,
)

ExcInfo = Tuple[
Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]
]

Event = Dict[str, Any]
Hint = Dict[str, Any]

Breadcrumb = Dict[str, Any]
Expand Down
5 changes: 3 additions & 2 deletions sentry_sdk/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
BreadcrumbHint,
ExcInfo,
MeasurementUnit,
LogLevelStr,
)
from sentry_sdk.tracing import Span

Expand Down Expand Up @@ -91,7 +92,7 @@ def capture_event(
@hubmethod
def capture_message(
message, # type: str
level=None, # type: Optional[str]
level=None, # type: Optional[LogLevelStr]
scope=None, # type: Optional[Any]
**scope_kwargs # type: Any
):
Expand Down Expand Up @@ -189,7 +190,7 @@ def set_user(value):

@scopemethod
def set_level(value):
# type: (str) -> None
# type: (LogLevelStr) -> None
return Hub.current.scope.set_level(value)


Expand Down
18 changes: 13 additions & 5 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
try:
from collections.abc import Mapping, MutableMapping
except ImportError:
from collections import Mapping, MutableMapping # type: ignore[attr-defined]

Check warning on line 4 in sentry_sdk/client.py

View check run for this annotation

Codecov / codecov/patch

sentry_sdk/client.py#L3-L4

Added lines #L3 - L4 were not covered by tests

from importlib import import_module
import os
import uuid
Expand Down Expand Up @@ -38,7 +43,7 @@
from sentry_sdk.utils import ContextVar
from sentry_sdk.sessions import SessionFlusher
from sentry_sdk.envelope import Envelope
from sentry_sdk.profiler import has_profiling_enabled, setup_profiler
from sentry_sdk.profiler import has_profiling_enabled, Profile, setup_profiler
from sentry_sdk.scrubber import EventScrubber
from sentry_sdk.monitor import Monitor
from sentry_sdk.spotlight import setup_spotlight
Expand Down Expand Up @@ -393,7 +398,7 @@

for key in "release", "environment", "server_name", "dist":
if event.get(key) is None and self.options[key] is not None:
event[key] = text_type(self.options[key]).strip()
event[key] = text_type(self.options[key]).strip() # type: ignore[literal-required]
if event.get("sdk") is None:
sdk_info = dict(SDK_INFO)
sdk_info["integrations"] = sorted(self.integrations.keys())
Expand Down Expand Up @@ -567,7 +572,7 @@
errored = True
for error in exceptions:
mechanism = error.get("mechanism")
if mechanism and mechanism.get("handled") is False:
if isinstance(mechanism, Mapping) and mechanism.get("handled") is False:
crashed = True
break

Expand Down Expand Up @@ -644,7 +649,10 @@
attachments = hint.get("attachments")

trace_context = event_opt.get("contexts", {}).get("trace") or {}
dynamic_sampling_context = trace_context.pop("dynamic_sampling_context", {})
if isinstance(trace_context, MutableMapping):
dynamic_sampling_context = trace_context.pop("dynamic_sampling_context", {})
else:
dynamic_sampling_context = {}

Check warning on line 655 in sentry_sdk/client.py

View check run for this annotation

Codecov / codecov/patch

sentry_sdk/client.py#L655

Added line #L655 was not covered by tests
szokeasaurusrex marked this conversation as resolved.
Show resolved Hide resolved

# If tracing is enabled all events should go to /envelope endpoint.
# If no tracing is enabled only transactions, events with attachments, and checkins should go to the /envelope endpoint.
Expand All @@ -667,7 +675,7 @@
envelope = Envelope(headers=headers)

if is_transaction:
if profile is not None:
if isinstance(profile, Profile):
antonpirker marked this conversation as resolved.
Show resolved Hide resolved
envelope.add_profile(profile.to_json(event_opt, self.options))
envelope.add_transaction(event_opt)
elif is_checkin:
Expand Down
5 changes: 3 additions & 2 deletions sentry_sdk/crons/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

if TYPE_CHECKING:
from typing import Any, Dict, Optional
from sentry_sdk._types import Event

Check warning on line 9 in sentry_sdk/crons/api.py

View check run for this annotation

Codecov / codecov/patch

sentry_sdk/crons/api.py#L9

Added line #L9 was not covered by tests


def _create_check_in_event(
Expand All @@ -15,7 +16,7 @@
duration_s=None,
monitor_config=None,
):
# type: (Optional[str], Optional[str], Optional[str], Optional[float], Optional[Dict[str, Any]]) -> Dict[str, Any]
# type: (Optional[str], Optional[str], Optional[str], Optional[float], Optional[Dict[str, Any]]) -> Event
options = Hub.current.client.options if Hub.current.client else {}
check_in_id = check_in_id or uuid.uuid4().hex # type: str

Expand All @@ -27,7 +28,7 @@
"duration": duration_s,
"environment": options.get("environment", None),
"release": options.get("release", None),
}
} # type: Event

if monitor_config:
check_in["monitor_config"] = monitor_config
Expand Down
3 changes: 2 additions & 1 deletion sentry_sdk/hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
Breadcrumb,
BreadcrumbHint,
ExcInfo,
LogLevelStr,
)
from sentry_sdk.consts import ClientConstructor

Expand Down Expand Up @@ -335,7 +336,7 @@ def capture_event(self, event, hint=None, scope=None, **scope_kwargs):
return last_event_id

def capture_message(self, message, level=None, scope=None, **scope_kwargs):
# type: (str, Optional[str], Optional[Scope], Any) -> Optional[str]
# type: (str, Optional[LogLevelStr], Optional[Scope], Any) -> Optional[str]
"""
Captures a message.

Expand Down
3 changes: 2 additions & 1 deletion sentry_sdk/integrations/_wsgi_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from typing import Dict
from typing import Optional
from typing import Union
from sentry_sdk._types import Event

Check warning on line 25 in sentry_sdk/integrations/_wsgi_common.py

View check run for this annotation

Codecov / codecov/patch

sentry_sdk/integrations/_wsgi_common.py#L25

Added line #L25 was not covered by tests


SENSITIVE_ENV_KEYS = (
Expand Down Expand Up @@ -59,7 +60,7 @@
self.request = request

def extract_into_event(self, event):
# type: (Dict[str, Any]) -> None
# type: (Event) -> None
client = Hub.current.client
if client is None:
return
Expand Down
9 changes: 4 additions & 5 deletions sentry_sdk/integrations/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,12 @@
from aiohttp import TraceRequestStartParams, TraceRequestEndParams
from types import SimpleNamespace
from typing import Any
from typing import Dict
from typing import Optional
from typing import Tuple
from typing import Union

from sentry_sdk.utils import ExcInfo
from sentry_sdk._types import EventProcessor
from sentry_sdk._types import Event, EventProcessor

Check warning on line 56 in sentry_sdk/integrations/aiohttp.py

View check run for this annotation

Codecov / codecov/patch

sentry_sdk/integrations/aiohttp.py#L56

Added line #L56 was not covered by tests


TRANSACTION_STYLE_VALUES = ("handler_name", "method_and_path_pattern")
Expand Down Expand Up @@ -256,10 +255,10 @@
def _make_request_processor(weak_request):
# type: (weakref.ReferenceType[Request]) -> EventProcessor
def aiohttp_processor(
event, # type: Dict[str, Any]
hint, # type: Dict[str, Tuple[type, BaseException, Any]]
event, # type: Event
hint, # type: dict[str, Tuple[type, BaseException, Any]]
):
# type: (...) -> Dict[str, Any]
# type: (...) -> Event
request = weak_request()
if request is None:
return event
Expand Down
6 changes: 3 additions & 3 deletions sentry_sdk/integrations/ariadne.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from typing import Any, Dict, List, Optional
from ariadne.types import GraphQLError, GraphQLResult, GraphQLSchema, QueryParser # type: ignore
from graphql.language.ast import DocumentNode # type: ignore
from sentry_sdk._types import EventProcessor
from sentry_sdk._types import Event, EventProcessor

Check warning on line 26 in sentry_sdk/integrations/ariadne.py

View check run for this annotation

Codecov / codecov/patch

sentry_sdk/integrations/ariadne.py#L26

Added line #L26 was not covered by tests


class AriadneIntegration(Integration):
Expand Down Expand Up @@ -131,7 +131,7 @@
"""Add request data and api_target to events."""

def inner(event, hint):
# type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
# type: (Event, dict[str, Any]) -> Event
if not isinstance(data, dict):
return event

Expand Down Expand Up @@ -163,7 +163,7 @@
"""Add response data to the event's response context."""

def inner(event, hint):
# type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
# type: (Event, dict[str, Any]) -> Event
with capture_internal_exceptions():
if _should_send_default_pii() and response.get("errors"):
contexts = event.setdefault("contexts", {})
Expand Down
2 changes: 1 addition & 1 deletion sentry_sdk/integrations/bottle.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def _make_request_event_processor(app, request, integration):
# type: (Bottle, LocalRequest, BottleIntegration) -> EventProcessor

def event_processor(event, hint):
# type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
# type: (Event, dict[str, Any]) -> Event
_set_transaction_name_and_source(event, integration.transaction_style, request)

with capture_internal_exceptions():
Expand Down
4 changes: 2 additions & 2 deletions sentry_sdk/integrations/django/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ def sentry_patched_get_response(self, request):
def _make_wsgi_request_event_processor(weak_request, integration):
# type: (Callable[[], WSGIRequest], DjangoIntegration) -> EventProcessor
def wsgi_request_event_processor(event, hint):
# type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
# type: (Event, dict[str, Any]) -> Event
# if the request is gone we are fine not logging the data from
# it. This might happen if the processor is pushed away to
# another thread.
Expand Down Expand Up @@ -570,7 +570,7 @@ def parsed_body(self):


def _set_user_info(request, event):
# type: (WSGIRequest, Dict[str, Any]) -> None
# type: (WSGIRequest, Event) -> None
user_info = event.setdefault("user", {})

user = getattr(request, "user", None)
Expand Down
4 changes: 2 additions & 2 deletions sentry_sdk/integrations/django/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@
from django.core.handlers.asgi import ASGIRequest
from django.http.response import HttpResponse

from sentry_sdk._types import EventProcessor
from sentry_sdk._types import Event, EventProcessor

Check warning on line 29 in sentry_sdk/integrations/django/asgi.py

View check run for this annotation

Codecov / codecov/patch

sentry_sdk/integrations/django/asgi.py#L29

Added line #L29 was not covered by tests


def _make_asgi_request_event_processor(request):
# type: (ASGIRequest) -> EventProcessor
def asgi_request_event_processor(event, hint):
# type: (dict[str, Any], dict[str, Any]) -> dict[str, Any]
# type: (Event, dict[str, Any]) -> Event
# if the request is gone we are fine not logging the data from
# it. This might happen if the processor is pushed away to
# another thread.
Expand Down
6 changes: 3 additions & 3 deletions sentry_sdk/integrations/falcon.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from typing import Dict
from typing import Optional

from sentry_sdk._types import EventProcessor
from sentry_sdk._types import Event, EventProcessor

Check warning on line 21 in sentry_sdk/integrations/falcon.py

View check run for this annotation

Codecov / codecov/patch

sentry_sdk/integrations/falcon.py#L21

Added line #L21 was not covered by tests

# In Falcon 3.0 `falcon.api_helpers` is renamed to `falcon.app_helpers`
# and `falcon.API` to `falcon.App`
Expand Down Expand Up @@ -258,7 +258,7 @@


def _set_transaction_name_and_source(event, transaction_style, request):
# type: (Dict[str, Any], str, falcon.Request) -> None
# type: (Event, str, falcon.Request) -> None
name_for_style = {
"uri_template": request.uri_template,
"path": request.path,
Expand All @@ -271,7 +271,7 @@
# type: (falcon.Request, FalconIntegration) -> EventProcessor

def event_processor(event, hint):
# type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
# type: (Event, dict[str, Any]) -> Event
_set_transaction_name_and_source(event, integration.transaction_style, req)

with capture_internal_exceptions():
Expand Down
5 changes: 3 additions & 2 deletions sentry_sdk/integrations/fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
if TYPE_CHECKING:
from typing import Any, Callable, Dict
from sentry_sdk.scope import Scope
from sentry_sdk._types import Event

Check warning on line 14 in sentry_sdk/integrations/fastapi.py

View check run for this annotation

Codecov / codecov/patch

sentry_sdk/integrations/fastapi.py#L14

Added line #L14 was not covered by tests

try:
from sentry_sdk.integrations.starlette import (
Expand Down Expand Up @@ -111,9 +112,9 @@
info = await extractor.extract_request_info()

def _make_request_event_processor(req, integration):
# type: (Any, Any) -> Callable[[Dict[str, Any], Dict[str, Any]], Dict[str, Any]]
# type: (Any, Any) -> Callable[[Event, Dict[str, Any]], Event]
def event_processor(event, hint):
# type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
# type: (Event, Dict[str, Any]) -> Event

# Extract information from request
request_info = event.get("request", {})
Expand Down
6 changes: 3 additions & 3 deletions sentry_sdk/integrations/flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
if TYPE_CHECKING:
from typing import Any, Callable, Dict, Union

from sentry_sdk._types import EventProcessor
from sentry_sdk._types import Event, EventProcessor

Check warning on line 19 in sentry_sdk/integrations/flask.py

View check run for this annotation

Codecov / codecov/patch

sentry_sdk/integrations/flask.py#L19

Added line #L19 was not covered by tests
from sentry_sdk.integrations.wsgi import _ScopedResponse
from werkzeug.datastructures import FileStorage, ImmutableMultiDict

Expand Down Expand Up @@ -172,7 +172,7 @@
# type: (Flask, Callable[[], Request], FlaskIntegration) -> EventProcessor

def inner(event, hint):
# type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
# type: (Event, dict[str, Any]) -> Event

# if the request is gone we are fine not logging the data from
# it. This might happen if the processor is pushed away to
Expand Down Expand Up @@ -211,7 +211,7 @@


def _add_user_to_event(event):
# type: (Dict[str, Any]) -> None
# type: (Event) -> None
if flask_login is None:
return

Expand Down
Loading
Loading