feat: Improve type annotations · bluetech/sentry-python@a6bfc71 · GitHub
Skip to content

Commit a6bfc71

Browse files
committed
feat: Improve type annotations
Enable some more strict mypy options and deal with the fallout.
1 parent c4f53c8 commit a6bfc71

18 files changed

Lines changed: 170 additions & 66 deletions

mypy.ini

Lines changed: 35 additions & 0 deletions

sentry_sdk/api.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@
1010
from typing import Optional
1111
from typing import overload
1212
from typing import Callable
13-
from typing import Dict
13+
from typing import TypeVar
1414
from contextlib import ContextManager
15+
16+
from sentry_sdk.utils import Event, Hint, Breadcrumb, BreadcrumbHint
17+
18+
F = TypeVar("F", bound=Callable[..., Any])
1519
else:
1620

1721
def overload(x):
@@ -31,6 +35,7 @@ def overload(x):
3135

3236

3337
def hubmethod(f):
38+
# type: (F) -> F
3439
f.__doc__ = "%s\n\n%s" % (
3540
"Alias for `Hub.%s`" % f.__name__,
3641
inspect.getdoc(getattr(Hub, f.__name__)),
@@ -40,7 +45,7 @@ def hubmethod(f):
4045

4146
@hubmethod
4247
def capture_event(event, hint=None):
43-
# type: (Dict[str, Any], Dict[str, Any]) -> Optional[str]
48+
# type: (Event, Optional[Hint]) -> Optional[str]
4449
hub = Hub.current
4550
if hub is not None:
4651
return hub.capture_event(event, hint)
@@ -49,7 +54,7 @@ def capture_event(event, hint=None):
4954

5055
@hubmethod
5156
def capture_message(message, level=None):
52-
# type: (str, Optional[Any]) -> Optional[str]
57+
# type: (str, Optional[str]) -> Optional[str]
5358
hub = Hub.current
5459
if hub is not None:
5560
return hub.capture_message(message, level)
@@ -67,7 +72,7 @@ def capture_exception(error=None):
6772

6873
@hubmethod
6974
def add_breadcrumb(crumb=None, hint=None, **kwargs):
70-
# type: (Dict[str, Any], Dict[str, Any], **Any) -> None
75+
# type: (Optional[Breadcrumb], Optional[BreadcrumbHint], **Any) -> None
7176
hub = Hub.current
7277
if hub is not None:
7378
return hub.add_breadcrumb(crumb, hint, **kwargs)

sentry_sdk/client.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def get_options(*args, **kwargs):
4747
for key, value in iteritems(options):
4848
if key not in rv:
4949
raise TypeError("Unknown option %r" % (key,))
50-
rv[key] = value # type: ignore
50+
rv[key] = value
5151

5252
if rv["dsn"] is None:
5353
rv["dsn"] = os.environ.get("SENTRY_DSN")
@@ -108,9 +108,10 @@ def _prepare_event(
108108
hint = dict(hint or ()) # type: Hint
109109

110110
if scope is not None:
111-
event = scope.apply_to_event(event, hint)
112-
if event is None:
113-
return
111+
event_ = scope.apply_to_event(event, hint)
112+
if event_ is None:
113+
return None
114+
event = event_
114115

115116
if (
116117
self.options["attach_stacktrace"]
@@ -178,7 +179,7 @@ def _is_ignored_error(self, event, hint):
178179
if errcls == full_name or errcls == type_name:
179180
return True
180181
else:
181-
if issubclass(exc_info[0], errcls):
182+
if issubclass(exc_info[0], errcls): # type: ignore
182183
return True
183184

184185
return False
@@ -187,7 +188,7 @@ def _should_capture(
187188
self,
188189
event, # type: Event
189190
hint, # type: Hint
190-
scope=None, # type: Scope
191+
scope=None, # type: Optional[Scope]
191192
):
192193
# type: (...) -> bool
193194
if scope is not None and not scope._should_capture:
@@ -205,7 +206,7 @@ def _should_capture(
205206
return True
206207

207208
def capture_event(self, event, hint=None, scope=None):
208-
# type: (Dict[str, Any], Any, Scope) -> Optional[str]
209+
# type: (Dict[str, Any], Optional[Any], Optional[Scope]) -> Optional[str]
209210
"""Captures an event.
210211
211212
This takes the ready made event and an optional hint and scope. The
@@ -225,7 +226,7 @@ def capture_event(self, event, hint=None, scope=None):
225226
event["event_id"] = rv = uuid.uuid4().hex
226227
if not self._should_capture(event, hint, scope):
227228
return None
228-
event = self._prepare_event(event, hint, scope) # type: ignore
229+
event = self._prepare_event(event, hint, scope)
229230
if event is None:
230231
return None
231232
self.transport.capture_event(event)

sentry_sdk/consts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"send_default_pii": bool,
3636
"http_proxy": Optional[str],
3737
"https_proxy": Optional[str],
38-
"ignore_errors": List[type],
38+
"ignore_errors": List[Union[type, str]],
3939
"request_bodies": str,
4040
"before_send": Optional[EventProcessor],
4141
"before_breadcrumb": Optional[BreadcrumbProcessor],

sentry_sdk/debug.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ def filter(self, record):
2020

2121

2222
def init_debug_support():
23+
# type: () -> None
2324
if not logger.handlers:
2425
configure_logger()
2526
configure_debug_hub()
2627

2728

2829
def configure_logger():
30+
# type: () -> None
2931
_handler = logging.StreamHandler(sys.stderr)
3032
_handler.setFormatter(logging.Formatter(" [sentry] %(levelname)s: %(message)s"))
3133
logger.addHandler(_handler)
@@ -34,6 +36,7 @@ def configure_logger():
3436

3537

3638
def configure_debug_hub():
39+
# type: () -> None
3740
def _get_debug_hub():
3841
return Hub.current
3942

sentry_sdk/hub.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
if False:
2020
from contextlib import ContextManager
21+
from sys import _OptExcInfo
2122

2223
from typing import Union
2324
from typing import Any
@@ -26,6 +27,7 @@
2627
from typing import List
2728
from typing import Callable
2829
from typing import Generator
30+
from typing import Type
2931
from typing import overload
3032

3133
from sentry_sdk.integrations import Integration
@@ -36,8 +38,8 @@ def overload(x):
3638
return x
3739

3840

39-
_local = ContextVar("sentry_current_hub")
40-
_initial_client = None
41+
_local = ContextVar("sentry_current_hub") # type: ignore
42+
_initial_client = None # type: Optional[weakref.ReferenceType[Client]]
4143

4244

4345
def _should_send_default_pii():
@@ -50,9 +52,11 @@ def _should_send_default_pii():
5052

5153
class _InitGuard(object):
5254
def __init__(self, client):
55+
# type: (Client) -> None
5356
self._client = client
5457

5558
def __enter__(self):
59+
# type: () -> _InitGuard
5660
return self
5761

5862
def __exit__(self, exc_type, exc_value, tb):
@@ -103,6 +107,7 @@ def __exit__(self, exc_type, exc_value, tb):
103107

104108
class _ScopeManager(object):
105109
def __init__(self, hub):
110+
# type: (Hub) -> None
106111
self._hub = hub
107112
self._original_len = len(hub._stack)
108113
self._layer = hub._stack[-1]
@@ -157,8 +162,13 @@ class Hub(with_metaclass(HubMeta)): # type: ignore
157162

158163
_stack = None # type: List[Tuple[Optional[Client], Scope]]
159164

165+
# Mypy doesn't pick up on the metaclass.
166+
if False:
167+
current = ... # type: Hub
168+
main = ... # type: Hub
169+
160170
def __init__(self, client_or_hub=None, scope=None):
161-
# type: (Union[Hub, Client], Optional[Any]) -> None
171+
# type: (Optional[Union[Hub, Client]], Optional[Any]) -> None
162172
if isinstance(client_or_hub, Hub):
163173
hub = client_or_hub
164174
client, other_scope = hub._stack[-1]
@@ -197,7 +207,7 @@ def run(self, callback):
197207
return callback()
198208

199209
def get_integration(self, name_or_class):
200-
# type: (Union[str, Integration]) -> Any
210+
# type: (Union[str, Type[Integration]]) -> Any
201211
"""Returns the integration for this hub by name or class. If there
202212
is no client bound or the client does not have that integration
203213
then `None` is returned.
@@ -218,9 +228,10 @@ def get_integration(self, name_or_class):
218228
if rv is not None:
219229
return rv
220230

221-
initial_client = _initial_client
222-
if initial_client is not None:
223-
initial_client = initial_client()
231+
if _initial_client is not None:
232+
initial_client = _initial_client()
233+
else:
234+
initial_client = None
224235

225236
if (
226237
initial_client is not None
@@ -254,7 +265,7 @@ def bind_client(self, new):
254265
self._stack[-1] = (new, top[1])
255266

256267
def capture_event(self, event, hint=None):
257-
# type: (Event, Hint) -> Optional[str]
268+
# type: (Event, Optional[Hint]) -> Optional[str]
258269
"""Captures an event. The return value is the ID of the event.
259270
260271
The event is a dictionary following the Sentry v7/v8 protocol
@@ -306,9 +317,10 @@ def capture_exception(self, error=None):
306317
return None
307318

308319
def _capture_internal_exception(self, exc_info):
320+
# type: (_OptExcInfo) -> Any
309321
"""Capture an exception that is likely caused by a bug in the SDK
310322
itself."""
311-
logger.error("Internal error in sentry_sdk", exc_info=exc_info)
323+
logger.error("Internal error in sentry_sdk", exc_info=exc_info) # type: ignore
312324

313325
def add_breadcrumb(self, crumb=None, hint=None, **kwargs):
314326
# type: (Optional[Breadcrumb], Optional[BreadcrumbHint], **Any) -> None

sentry_sdk/integrations/__init__.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ def iter_default_integrations():
3333

3434
if isinstance(iter_default_integrations.__doc__, str):
3535
for import_string in import_strings:
36-
iter_default_integrations.__doc__ += "\n- `{}`".format( # type: ignore
37-
import_string
38-
)
36+
iter_default_integrations.__doc__ += "\n- `{}`".format(import_string)
3937

4038
return iter_default_integrations
4139

@@ -72,7 +70,7 @@ def setup_integrations(integrations, with_defaults=True):
7270
instance = integration_cls()
7371
integrations[instance.identifier] = instance
7472

75-
for identifier, integration in iteritems(integrations):
73+
for identifier, integration in iteritems(integrations): # type: ignore
7674
with _installer_lock:
7775
if identifier not in _installed_integrations:
7876
logger.debug(
@@ -113,6 +111,7 @@ class Integration(object):
113111

114112
@staticmethod
115113
def setup_once():
114+
# type: () -> None
116115
"""
117116
Initialize the integration.
118117

sentry_sdk/integrations/atexit.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def default_callback(pending, timeout):
2020
"""
2121

2222
def echo(msg):
23+
# type: (str) -> None
2324
sys.stderr.write(msg + "\n")
2425

2526
echo("Sentry is attempting to send %i pending error messages" % pending)

sentry_sdk/integrations/aws_lambda.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class AwsLambdaIntegration(Integration):
5555

5656
@staticmethod
5757
def setup_once():
58+
# type: () -> None
5859
import __main__ as lambda_bootstrap # type: ignore
5960

6061
pre_37 = True # Python 3.6 or 2.7

sentry_sdk/integrations/celery.py

Lines changed: 1 addition & 0 deletions

0 commit comments

Comments
 (0)