Skip to content

Commit 4acfcb2

Browse files
committed
feat: Add support for DSN paths
Fix getsentry#212
1 parent d2daa00 commit 4acfcb2

File tree

2 files changed

+53
-6
lines changed

2 files changed

+53
-6
lines changed

sentry_sdk/utils.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,18 @@ def __init__(self, value):
8484
self.port = self.scheme == "https" and 443 or 80
8585
self.public_key = parts.username
8686
if not self.public_key:
87-
raise BadDsn("Missig public key")
87+
raise BadDsn("Missing public key")
8888
self.secret_key = parts.password
89-
if not parts.path:
90-
raise BadDsn("Missing project ID in DSN")
89+
90+
path = parts.path.rsplit("/", 1)
91+
9192
try:
92-
self.project_id = text_type(int(parts.path[1:]))
93+
self.project_id = text_type(int(path.pop()))
9394
except (ValueError, TypeError):
9495
raise BadDsn("Invalid project in DSN (%r)" % (parts.path or "")[1:])
9596

97+
self.path = "/".join(path) + "/"
98+
9699
@property
97100
def netloc(self):
98101
"""The netloc part of a DSN."""
@@ -106,18 +109,20 @@ def to_auth(self, client=None):
106109
return Auth(
107110
scheme=self.scheme,
108111
host=self.netloc,
112+
path=self.path,
109113
project_id=self.project_id,
110114
public_key=self.public_key,
111115
secret_key=self.secret_key,
112116
client=client,
113117
)
114118

115119
def __str__(self):
116-
return "%s://%s%s@%s/%s" % (
120+
return "%s://%s%s@%s%s%s" % (
117121
self.scheme,
118122
self.public_key,
119123
self.secret_key and "@" + self.secret_key or "",
120124
self.netloc,
125+
self.path,
121126
self.project_id,
122127
)
123128

@@ -129,6 +134,7 @@ def __init__(
129134
self,
130135
scheme,
131136
host,
137+
path,
132138
project_id,
133139
public_key,
134140
secret_key=None,
@@ -137,6 +143,7 @@ def __init__(
137143
):
138144
self.scheme = scheme
139145
self.host = host
146+
self.path = path
140147
self.project_id = project_id
141148
self.public_key = public_key
142149
self.secret_key = secret_key
@@ -146,7 +153,12 @@ def __init__(
146153
@property
147154
def store_api_url(self):
148155
"""Returns the API url for storing events."""
149-
return "%s://%s/api/%s/store/" % (self.scheme, self.host, self.project_id)
156+
return "%s://%s%sapi/%s/store/" % (
157+
self.scheme,
158+
self.host,
159+
self.path,
160+
self.project_id,
161+
)
150162

151163
def to_header(self, timestamp=None):
152164
"""Returns the auth header a string."""

tests/utils/test_general.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
import hypothesis.strategies as st
99

1010
from sentry_sdk.utils import (
11+
Auth,
12+
BadDsn,
13+
Dsn,
1114
safe_repr,
1215
exceptions_from_error_tuple,
1316
format_and_strip,
@@ -111,3 +114,35 @@ def test_filename():
111114
import sentry_sdk.utils
112115

113116
assert x("sentry_sdk.utils", sentry_sdk.utils.__file__) == "sentry_sdk/utils.py"
117+
118+
119+
@pytest.mark.parametrize(
120+
"given,expected",
121+
[
122+
("https://foobar@sentry.io/123", "https://sentry.io/api/123/store/"),
123+
("https://foobar@sentry.io/bam/123", "https://sentry.io/bam/api/123/store/"),
124+
(
125+
"https://foobar@sentry.io/bam/baz/123",
126+
"https://sentry.io/bam/baz/api/123/store/",
127+
),
128+
],
129+
)
130+
def test_parse_dsn_paths(given, expected):
131+
dsn = Dsn(given)
132+
auth = dsn.to_auth()
133+
assert auth.store_api_url == expected
134+
135+
136+
@pytest.mark.parametrize(
137+
"dsn",
138+
[
139+
"https://foobar@sentry.io"
140+
"https://foobar@sentry.io/"
141+
"https://foobar@sentry.io/asdf"
142+
"https://foobar@sentry.io/asdf/"
143+
"https://foobar@sentry.io/asdf/123/"
144+
],
145+
)
146+
def test_parse_invalid_dsn(dsn):
147+
with pytest.raises(BadDsn):
148+
dsn = Dsn(dsn)

0 commit comments

Comments
 (0)