Skip to content

ref: Add typehints #270

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

Merged
merged 12 commits into from
Feb 25, 2019
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ venv
.hypothesis
semaphore
pip-wheel-metadata
.mypy_cache
2 changes: 2 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[mypy]
allow_redefinition = True
19 changes: 16 additions & 3 deletions sentry_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,25 @@
except Exception as e:
sentry_sdk.capture_exception(e)
"""
from sentry_sdk.hub import Hub, init
from sentry_sdk.scope import Scope
from sentry_sdk.transport import Transport, HttpTransport
from sentry_sdk.client import Client

from sentry_sdk.api import * # noqa
from sentry_sdk.api import __all__ # noqa
from sentry_sdk.api import __all__ as api_all

from sentry_sdk.consts import VERSION # noqa

# modules we consider public
__all__.append("integrations")
__all__ = api_all + [ # noqa
"Hub",
"Scope",
"Client",
"Transport",
"HttpTransport",
"init",
"integrations",
]

# Initialize the debug support after everything is loaded
from sentry_sdk.debug import init_debug_support
Expand Down
15 changes: 12 additions & 3 deletions sentry_sdk/_compat.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import sys

if False:
from typing import Optional
from typing import Tuple
from typing import Any
from typing import Type


PY2 = sys.version_info[0] == 2

Expand Down Expand Up @@ -27,8 +33,8 @@ def implements_str(cls):
import queue # noqa

text_type = str
string_types = (text_type,)
number_types = (int, float)
string_types = (text_type,) # type: Tuple[type]
number_types = (int, float) # type: Tuple[type, type]
int_types = (int,) # noqa
iteritems = lambda x: x.items()

Expand All @@ -39,6 +45,8 @@ def implements_str(x):
return x

def reraise(tp, value, tb=None):
# type: (Optional[Type[BaseException]], Optional[BaseException], Optional[Any]) -> None
assert value is not None
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
Expand All @@ -53,8 +61,9 @@ def __new__(cls, name, this_bases, d):


def check_thread_support():
# type: () -> None
try:
from uwsgi import opt
from uwsgi import opt # type: ignore
except ImportError:
return

Expand Down
57 changes: 50 additions & 7 deletions sentry_sdk/api.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import inspect
from contextlib import contextmanager

from sentry_sdk.hub import Hub, init
from sentry_sdk.hub import Hub
from sentry_sdk.scope import Scope
from sentry_sdk.transport import Transport, HttpTransport
from sentry_sdk.client import Client


__all__ = ["Hub", "Scope", "Client", "Transport", "HttpTransport", "init"]
if False:
from typing import Any
from typing import Optional
from typing import overload
from typing import Callable
from contextlib import AbstractContextManager
else:

def overload(x):
return x

_initial_client = None

__all__ = []


def public(f):
Expand All @@ -35,16 +42,20 @@ def capture_event(event, hint=None):

@hubmethod
def capture_message(message, level=None):
# type: (str, Optional[Any]) -> Optional[str]
hub = Hub.current
if hub is not None:
return hub.capture_message(message, level)
return None


@hubmethod
def capture_exception(error=None):
# type: (ValueError) -> Optional[str]
hub = Hub.current
if hub is not None:
return hub.capture_exception(error)
return None


@hubmethod
Expand All @@ -54,7 +65,19 @@ def add_breadcrumb(*args, **kwargs):
return hub.add_breadcrumb(*args, **kwargs)


@hubmethod
@overload # noqa
def configure_scope():
# type: () -> AbstractContextManager
pass


@overload # noqa
def configure_scope(callback):
# type: (Callable) -> None
pass


@hubmethod # noqa
def configure_scope(callback=None):
hub = Hub.current
if hub is not None:
Expand All @@ -66,9 +89,24 @@ def inner():
yield Scope()

return inner()
else:
# returned if user provided callback
return None


@hubmethod
@overload # noqa
def push_scope():
# type: () -> AbstractContextManager
pass


@overload # noqa
def push_scope(callback):
# type: (Callable) -> None
pass


@hubmethod # noqa
def push_scope(callback=None):
hub = Hub.current
if hub is not None:
Expand All @@ -80,6 +118,9 @@ def inner():
yield Scope()

return inner()
else:
# returned if user provided callback
return None


@hubmethod
Expand All @@ -91,6 +132,8 @@ def flush(timeout=None, callback=None):

@hubmethod
def last_event_id():
# type: () -> Optional[str]
hub = Hub.current
if hub is not None:
return hub.last_event_id()
return None
53 changes: 38 additions & 15 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,39 @@
from sentry_sdk.integrations import setup_integrations
from sentry_sdk.utils import ContextVar

if False:
from sentry_sdk.consts import ClientOptions
from sentry_sdk.scope import Scope
from typing import Any
from typing import Dict
from typing import Optional


_client_init_debug = ContextVar("client_init_debug")


def get_options(*args, **kwargs):
# type: (*str, **ClientOptions) -> ClientOptions
if args and (isinstance(args[0], string_types) or args[0] is None):
dsn = args[0]
dsn = args[0] # type: Optional[str]
args = args[1:]
else:
dsn = None

rv = dict(DEFAULT_OPTIONS)
options = dict(*args, **kwargs)
options = dict(*args, **kwargs) # type: ignore
if dsn is not None and options.get("dsn") is None:
options["dsn"] = dsn
options["dsn"] = dsn # type: ignore

for key, value in options.items():
if key not in rv:
raise TypeError("Unknown option %r" % (key,))
rv[key] = value
rv[key] = value # type: ignore

if rv["dsn"] is None:
rv["dsn"] = os.environ.get("SENTRY_DSN")

return rv
return rv # type: ignore


class Client(object):
Expand All @@ -54,6 +62,7 @@ class Client(object):
"""

def __init__(self, *args, **kwargs):
# type: (*str, **ClientOptions) -> None
old_debug = _client_init_debug.get(False)
try:
self.options = options = get_options(*args, **kwargs)
Expand All @@ -79,7 +88,13 @@ def dsn(self):
"""Returns the configured DSN as string."""
return self.options["dsn"]

def _prepare_event(self, event, hint, scope):
def _prepare_event(
self,
event, # type: Dict[str, Any]
hint, # type: Optional[Dict[str, Any]]
scope, # type: Optional[Scope]
):
# type: (...) -> Optional[Dict[str, Any]]
if event.get("timestamp") is None:
event["timestamp"] = datetime.utcnow()

Expand All @@ -104,8 +119,8 @@ def _prepare_event(self, event, hint, scope):
]

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()
if event.get(key) is None and self.options[key] is not None: # type: ignore
event[key] = text_type(self.options[key]).strip() # type: ignore
if event.get("sdk") is None:
sdk_info = dict(SDK_INFO)
sdk_info["integrations"] = sorted(self.integrations.keys())
Expand All @@ -132,11 +147,12 @@ def _prepare_event(self, event, hint, scope):
new_event = before_send(event, hint)
if new_event is None:
logger.info("before send dropped event (%s)", event)
event = new_event
event = new_event # type: ignore

return event

def _is_ignored_error(self, event, hint=None):
def _is_ignored_error(self, event, hint):
# type: (Dict[str, Any], Dict[str, Any]) -> bool
exc_info = hint.get("exc_info")
if exc_info is None:
return False
Expand All @@ -156,7 +172,13 @@ def _is_ignored_error(self, event, hint=None):

return False

def _should_capture(self, event, hint, scope=None):
def _should_capture(
self,
event, # type: Dict[str, Any]
hint, # type: Dict[str, Any]
scope=None, # type: Scope
):
# type: (...) -> bool
if scope is not None and not scope._should_capture:
return False

Expand All @@ -172,6 +194,7 @@ def _should_capture(self, event, hint, scope=None):
return True

def capture_event(self, event, hint=None, scope=None):
# type: (Dict[str, Any], Any, Scope) -> Optional[str]
"""Captures an event.

This takes the ready made event and an optoinal hint and scope. The
Expand All @@ -183,17 +206,17 @@ def capture_event(self, event, hint=None, scope=None):
value of this function will be the ID of the captured event.
"""
if self.transport is None:
return
return None
if hint is None:
hint = {}
rv = event.get("event_id")
if rv is None:
event["event_id"] = rv = uuid.uuid4().hex
if not self._should_capture(event, hint, scope):
return
event = self._prepare_event(event, hint, scope)
return None
event = self._prepare_event(event, hint, scope) # type: ignore
if event is None:
return
return None
self.transport.capture_event(event)
return rv

Expand Down
40 changes: 40 additions & 0 deletions sentry_sdk/consts.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
import socket

if False:
from mypy_extensions import TypedDict
from typing import Optional
from typing import Callable
from typing import Union
from typing import List

from sentry_sdk.transport import Transport
from sentry_sdk.integrations import Integration

ClientOptions = TypedDict(
"ClientOptions",
{
"dsn": Optional[str],
"with_locals": bool,
"max_breadcrumbs": int,
"release": Optional[str],
"environment": Optional[str],
"server_name": Optional[str],
"shutdown_timeout": int,
"integrations": List[Integration],
"in_app_include": List[str],
"in_app_exclude": List[str],
"default_integrations": bool,
"dist": Optional[str],
"transport": Optional[Union[Transport, type, Callable]],
"sample_rate": int,
"send_default_pii": bool,
"http_proxy": Optional[str],
"https_proxy": Optional[str],
"ignore_errors": List[type],
"request_bodies": str,
"before_send": Optional[Callable],
"before_breadcrumb": Optional[Callable],
"debug": bool,
"attach_stacktrace": bool,
"ca_certs": Optional[str],
},
)


VERSION = "0.7.3"
DEFAULT_SERVER_NAME = socket.gethostname() if hasattr(socket, "gethostname") else None
Expand Down
2 changes: 2 additions & 0 deletions sentry_sdk/debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
from sentry_sdk.hub import Hub
from sentry_sdk.utils import logger
from sentry_sdk.client import _client_init_debug
from logging import LogRecord


class _HubBasedClientFilter(logging.Filter):
def filter(self, record):
# type: (LogRecord) -> bool
if _client_init_debug.get(False):
return True
hub = Hub.current
Expand Down
Loading