Skip to content

Commit 159de61

Browse files
committed
Merge remote-tracking branch 'origin/master' into kmclb-add-pytest-watch
2 parents aa70c54 + 377f71a commit 159de61

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1806
-264
lines changed

.travis.yml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ python:
1616
- "3.6"
1717
- "3.7"
1818
- "3.8"
19-
- "3.9-dev"
19+
- "3.9"
2020

2121
env:
2222
- SENTRY_PYTHON_TEST_POSTGRES_USER=postgres SENTRY_PYTHON_TEST_POSTGRES_NAME=travis_ci_test
@@ -31,21 +31,19 @@ branches:
3131
- /^release\/.+$/
3232

3333
jobs:
34-
allow_failures:
35-
- python: "3.9-dev"
3634
include:
3735
- name: Linting
38-
python: "3.8"
36+
python: "3.9"
3937
install:
4038
- pip install tox
4139
script: tox -e linters
4240

43-
- python: "3.8"
41+
- python: "3.9"
4442
name: Distribution packages
4543
install: []
4644
script: make travis-upload-dist
4745

48-
- python: "3.8"
46+
- python: "3.9"
4947
name: Build documentation
5048
install: []
5149
script: make travis-upload-docs

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"python.pythonPath": ".venv/bin/python"
3+
}

CHANGES.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@ sentry-sdk==0.10.1
2727

2828
A major release `N` implies the previous release `N-1` will no longer receive updates. We generally do not backport bugfixes to older versions unless they are security relevant. However, feel free to ask for backports of specific commits on the bugtracker.
2929

30+
## 0.19.2
31+
32+
* Added support for automatic release and environment configuration for some common situations.
33+
34+
## 0.19.1
35+
36+
* Fix dependency check for `blinker` fixes #858
37+
* Fix incorrect timeout warnings in AWS Lambda and GCP integrations #854
38+
39+
## 0.19.0
40+
41+
* Removed `_experiments.auto_enabling_integrations` in favor of just `auto_enabling_integrations` which is now enabled by default.
42+
3043
## 0.18.0
3144

3245
* **Breaking change**: The `no_proxy` environment variable is now honored when inferring proxy settings from the system. Thanks Xavier Fernandez!

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
copyright = u"2019, Sentry Team and Contributors"
2323
author = u"Sentry Team and Contributors"
2424

25-
release = "0.18.0"
25+
release = "0.19.1"
2626
version = ".".join(release.split(".")[:2]) # The short X.Y version.
2727

2828

mypy.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ ignore_missing_imports = True
5454
ignore_missing_imports = True
5555
[mypy-pure_eval.*]
5656
ignore_missing_imports = True
57-
57+
[mypy-blinker.*]
58+
ignore_missing_imports = True
5859
[mypy-sentry_sdk._queue]
5960
ignore_missing_imports = True
6061
disallow_untyped_defs = False

pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
DJANGO_SETTINGS_MODULE = tests.integrations.django.myapp.settings
33
addopts = --tb=short
44
markers =
5-
tests_internal_exceptions
5+
tests_internal_exceptions: Handle internal exceptions just as the SDK does, to test it. (Otherwise internal exceptions are recorded and reraised.)
66
only: A temporary marker, to make pytest only run the tests with the mark, similar to jest's `it.only`. To use, run `pytest -v -m only`.
77
88
[pytest-watch]

sentry_sdk/__init__.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,33 @@
44
from sentry_sdk.client import Client
55

66
from sentry_sdk.api import * # noqa
7-
from sentry_sdk.api import __all__ as api_all
87

98
from sentry_sdk.consts import VERSION # noqa
109

11-
__all__ = api_all + [ # noqa
10+
__all__ = [ # noqa
1211
"Hub",
1312
"Scope",
1413
"Client",
1514
"Transport",
1615
"HttpTransport",
1716
"init",
1817
"integrations",
18+
# From sentry_sdk.api
19+
"capture_event",
20+
"capture_message",
21+
"capture_exception",
22+
"add_breadcrumb",
23+
"configure_scope",
24+
"push_scope",
25+
"flush",
26+
"last_event_id",
27+
"start_span",
28+
"start_transaction",
29+
"set_tag",
30+
"set_context",
31+
"set_extra",
32+
"set_user",
33+
"set_level",
1934
]
2035

2136
# Initialize the debug support after everything is loaded

sentry_sdk/_types.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55

66

77
if MYPY:
8+
from numbers import Real
89
from types import TracebackType
910
from typing import Any
1011
from typing import Callable
1112
from typing import Dict
1213
from typing import Optional
1314
from typing import Tuple
1415
from typing import Type
16+
from typing import Union
1517
from typing_extensions import Literal
1618

1719
ExcInfo = Tuple[
@@ -24,10 +26,14 @@
2426
Breadcrumb = Dict[str, Any]
2527
BreadcrumbHint = Dict[str, Any]
2628

29+
SamplingContext = Dict[str, Any]
30+
2731
EventProcessor = Callable[[Event, Hint], Optional[Event]]
2832
ErrorProcessor = Callable[[Event, ExcInfo], Optional[Event]]
2933
BreadcrumbProcessor = Callable[[Breadcrumb, BreadcrumbHint], Optional[Breadcrumb]]
3034

35+
TracesSampler = Callable[[SamplingContext], Union[Real, bool]]
36+
3137
# https://github.com/python/mypy/issues/5710
3238
NotImplementedType = Any
3339

sentry_sdk/api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def overload(x):
2727
return x
2828

2929

30+
# When changing this, update __all__ in __init__.py too
3031
__all__ = [
3132
"capture_event",
3233
"capture_message",

sentry_sdk/attachments.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import os
2+
import mimetypes
3+
4+
from sentry_sdk._types import MYPY
5+
from sentry_sdk.envelope import Item, PayloadRef
6+
7+
if MYPY:
8+
from typing import Optional, Union, Callable
9+
10+
11+
class Attachment(object):
12+
def __init__(
13+
self,
14+
bytes=None, # type: Union[None, bytes, Callable[[], bytes]]
15+
filename=None, # type: Optional[str]
16+
path=None, # type: Optional[str]
17+
content_type=None, # type: Optional[str]
18+
add_to_transactions=False, # type: bool
19+
):
20+
# type: (...) -> None
21+
if bytes is None and path is None:
22+
raise TypeError("path or raw bytes required for attachment")
23+
if filename is None and path is not None:
24+
filename = os.path.basename(path)
25+
if filename is None:
26+
raise TypeError("filename is required for attachment")
27+
if content_type is None:
28+
content_type = mimetypes.guess_type(filename)[0]
29+
self.bytes = bytes
30+
self.filename = filename
31+
self.path = path
32+
self.content_type = content_type
33+
self.add_to_transactions = add_to_transactions
34+
35+
def to_envelope_item(self):
36+
# type: () -> Item
37+
"""Returns an envelope item for this attachment."""
38+
payload = None # type: Union[None, PayloadRef, bytes]
39+
if self.bytes is not None:
40+
if callable(self.bytes):
41+
payload = self.bytes()
42+
else:
43+
payload = self.bytes
44+
else:
45+
payload = PayloadRef(path=self.path)
46+
return Item(
47+
payload=payload,
48+
type="attachment",
49+
content_type=self.content_type,
50+
filename=self.filename,
51+
)
52+
53+
def __repr__(self):
54+
# type: () -> str
55+
return "<Attachment %r>" % (self.filename,)

sentry_sdk/client.py

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
disable_capture_event,
1313
format_timestamp,
1414
get_type_name,
15+
get_default_release,
16+
get_default_environment,
1517
handle_in_app,
1618
logger,
1719
)
@@ -21,7 +23,7 @@
2123
from sentry_sdk.integrations import setup_integrations
2224
from sentry_sdk.utils import ContextVar
2325
from sentry_sdk.sessions import SessionFlusher
24-
from sentry_sdk.envelope import Envelope, Item, PayloadRef
26+
from sentry_sdk.envelope import Envelope
2527

2628
from sentry_sdk._types import MYPY
2729

@@ -62,10 +64,10 @@ def _get_options(*args, **kwargs):
6264
rv["dsn"] = os.environ.get("SENTRY_DSN")
6365

6466
if rv["release"] is None:
65-
rv["release"] = os.environ.get("SENTRY_RELEASE")
67+
rv["release"] = get_default_release()
6668

6769
if rv["environment"] is None:
68-
rv["environment"] = os.environ.get("SENTRY_ENVIRONMENT")
70+
rv["environment"] = get_default_environment(rv["release"])
6971

7072
if rv["server_name"] is None and hasattr(socket, "gethostname"):
7173
rv["server_name"] = socket.gethostname()
@@ -128,9 +130,9 @@ def _send_sessions(sessions):
128130
self.integrations = setup_integrations(
129131
self.options["integrations"],
130132
with_defaults=self.options["default_integrations"],
131-
with_auto_enabling_integrations=self.options["_experiments"].get(
132-
"auto_enabling_integrations", False
133-
),
133+
with_auto_enabling_integrations=self.options[
134+
"auto_enabling_integrations"
135+
],
134136
)
135137
finally:
136138
_client_init_debug.set(old_debug)
@@ -144,16 +146,14 @@ def dsn(self):
144146
def _prepare_event(
145147
self,
146148
event, # type: Event
147-
hint, # type: Optional[Hint]
149+
hint, # type: Hint
148150
scope, # type: Optional[Scope]
149151
):
150152
# type: (...) -> Optional[Event]
151153

152154
if event.get("timestamp") is None:
153155
event["timestamp"] = datetime.utcnow()
154156

155-
hint = dict(hint or ()) # type: Hint
156-
157157
if scope is not None:
158158
event_ = scope.apply_to_event(event, hint)
159159
if event_ is None:
@@ -320,10 +320,13 @@ def capture_event(
320320
if hint is None:
321321
hint = {}
322322
event_id = event.get("event_id")
323+
hint = dict(hint or ()) # type: Hint
324+
323325
if event_id is None:
324326
event["event_id"] = event_id = uuid.uuid4().hex
325327
if not self._should_capture(event, hint, scope):
326328
return None
329+
327330
event_opt = self._prepare_event(event, hint, scope)
328331
if event_opt is None:
329332
return None
@@ -334,19 +337,27 @@ def capture_event(
334337
if session:
335338
self._update_session_from_event(session, event)
336339

337-
if event_opt.get("type") == "transaction":
338-
# Transactions should go to the /envelope/ endpoint.
339-
self.transport.capture_envelope(
340-
Envelope(
341-
headers={
342-
"event_id": event_opt["event_id"],
343-
"sent_at": format_timestamp(datetime.utcnow()),
344-
},
345-
items=[
346-
Item(payload=PayloadRef(json=event_opt), type="transaction"),
347-
],
348-
)
340+
attachments = hint.get("attachments")
341+
is_transaction = event_opt.get("type") == "transaction"
342+
343+
if is_transaction or attachments:
344+
# Transactions or events with attachments should go to the
345+
# /envelope/ endpoint.
346+
envelope = Envelope(
347+
headers={
348+
"event_id": event_opt["event_id"],
349+
"sent_at": format_timestamp(datetime.utcnow()),
350+
}
349351
)
352+
353+
if is_transaction:
354+
envelope.add_transaction(event_opt)
355+
else:
356+
envelope.add_event(event_opt)
357+
358+
for attachment in attachments or ():
359+
envelope.add_item(attachment.to_envelope_item())
360+
self.transport.capture_envelope(envelope)
350361
else:
351362
# All other events go to the /store/ endpoint.
352363
self.transport.capture_event(event_opt)

sentry_sdk/consts.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@
1414
from sentry_sdk.transport import Transport
1515
from sentry_sdk.integrations import Integration
1616

17-
from sentry_sdk._types import Event, EventProcessor, BreadcrumbProcessor
17+
from sentry_sdk._types import (
18+
BreadcrumbProcessor,
19+
Event,
20+
EventProcessor,
21+
TracesSampler,
22+
)
1823

1924
# Experiments are feature flags to enable and disable certain unstable SDK
2025
# functionality. Changing them from the defaults (`None`) in production
@@ -25,13 +30,14 @@
2530
{
2631
"max_spans": Optional[int],
2732
"record_sql_params": Optional[bool],
28-
"auto_enabling_integrations": Optional[bool],
2933
"auto_session_tracking": Optional[bool],
3034
"smart_transaction_trimming": Optional[bool],
3135
},
3236
total=False,
3337
)
3438

39+
DEFAULT_MAX_BREADCRUMBS = 100
40+
3541

3642
# This type exists to trick mypy and PyCharm into thinking `init` and `Client`
3743
# take these arguments (even though they take opaque **kwargs)
@@ -40,7 +46,7 @@ def __init__(
4046
self,
4147
dsn=None, # type: Optional[str]
4248
with_locals=True, # type: bool
43-
max_breadcrumbs=100, # type: int
49+
max_breadcrumbs=DEFAULT_MAX_BREADCRUMBS, # type: int
4450
release=None, # type: Optional[str]
4551
environment=None, # type: Optional[str]
4652
server_name=None, # type: Optional[str]
@@ -63,7 +69,9 @@ def __init__(
6369
attach_stacktrace=False, # type: bool
6470
ca_certs=None, # type: Optional[str]
6571
propagate_traces=True, # type: bool
66-
traces_sample_rate=0.0, # type: float
72+
traces_sample_rate=None, # type: Optional[float]
73+
traces_sampler=None, # type: Optional[TracesSampler]
74+
auto_enabling_integrations=True, # type: bool
6775
_experiments={}, # type: Experiments # noqa: B006
6876
):
6977
# type: (...) -> None
@@ -88,7 +96,7 @@ def _get_default_options():
8896
del _get_default_options
8997

9098

91-
VERSION = "0.18.0"
99+
VERSION = "0.19.1"
92100
SDK_INFO = {
93101
"name": "sentry.python",
94102
"version": VERSION,

0 commit comments

Comments
 (0)