sentry-relay 0.5.12__zip → 0.5.87__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sentry-relay-0.5.12 → sentry-relay-0.5.87}/PKG-INFO +5 -5
- sentry-relay-0.5.87/rustsrc.zip +0 -0
- {sentry-relay-0.5.12 → sentry-relay-0.5.87}/sentry_relay/auth.py +13 -17
- {sentry-relay-0.5.12 → sentry-relay-0.5.87}/sentry_relay/consts.py +48 -11
- {sentry-relay-0.5.12 → sentry-relay-0.5.87}/sentry_relay/exceptions.py +7 -3
- {sentry-relay-0.5.12 → sentry-relay-0.5.87}/sentry_relay/processing.py +113 -41
- sentry-relay-0.5.87/sentry_relay/py.typed +0 -0
- {sentry-relay-0.5.12 → sentry-relay-0.5.87}/sentry_relay/utils.py +6 -4
- {sentry-relay-0.5.12 → sentry-relay-0.5.87}/setup.py +31 -12
- sentry-relay-0.5.87/version.txt +1 -0
- sentry-relay-0.5.12/rustsrc.zip +0 -0
- sentry-relay-0.5.12/sentry_relay/_compat.py +0 -37
- sentry-relay-0.5.12/version.txt +0 -1
- {sentry-relay-0.5.12 → sentry-relay-0.5.87}/README +0 -0
- {sentry-relay-0.5.12 → sentry-relay-0.5.87}/sentry_relay/__init__.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 1
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: sentry-relay
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.87
|
|
4
4
|
Summary: A python library to access sentry relay functionality.
|
|
5
|
-
Home-page: UNKNOWN
|
|
6
5
|
Author: Sentry
|
|
7
6
|
Author-email: hello@sentry.io
|
|
8
|
-
License:
|
|
9
|
-
Description: UNKNOWN
|
|
7
|
+
License: FSL-1.0-Apache-2.0
|
|
10
8
|
Platform: any
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
Binary file
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import uuid
|
|
3
3
|
from sentry_relay._lowlevel import lib
|
|
4
|
-
from sentry_relay._compat import text_type, implements_to_string
|
|
5
4
|
from sentry_relay.utils import (
|
|
6
5
|
RustObject,
|
|
7
6
|
encode_str,
|
|
@@ -18,13 +17,11 @@ __all__ = [
|
|
|
18
17
|
"SecretKey",
|
|
19
18
|
"generate_key_pair",
|
|
20
19
|
"create_register_challenge",
|
|
21
|
-
"get_register_response_relay_id",
|
|
22
20
|
"validate_register_response",
|
|
23
21
|
"is_version_supported",
|
|
24
22
|
]
|
|
25
23
|
|
|
26
24
|
|
|
27
|
-
@implements_to_string
|
|
28
25
|
class PublicKey(RustObject):
|
|
29
26
|
__dealloc_func__ = lib.relay_publickey_free
|
|
30
27
|
|
|
@@ -50,7 +47,7 @@ class PublicKey(RustObject):
|
|
|
50
47
|
return decode_str(self._methodcall(lib.relay_publickey_to_string), free=True)
|
|
51
48
|
|
|
52
49
|
def __repr__(self):
|
|
53
|
-
return "
|
|
50
|
+
return f"<{self.__class__.__name__} {str(self)!r}>"
|
|
54
51
|
|
|
55
52
|
|
|
56
53
|
class SecretKey(RustObject):
|
|
@@ -67,14 +64,14 @@ class SecretKey(RustObject):
|
|
|
67
64
|
return decode_str(self._methodcall(lib.relay_secretkey_sign, buf), free=True)
|
|
68
65
|
|
|
69
66
|
def pack(self, data):
|
|
70
|
-
packed = json.dumps(data, separators=(",", ":"))
|
|
67
|
+
packed = json.dumps(data, separators=(",", ":")).encode("utf8")
|
|
71
68
|
return packed, self.sign(packed)
|
|
72
69
|
|
|
73
70
|
def __str__(self):
|
|
74
71
|
return decode_str(self._methodcall(lib.relay_secretkey_to_string), free=True)
|
|
75
72
|
|
|
76
73
|
def __repr__(self):
|
|
77
|
-
return "
|
|
74
|
+
return f"<{self.__class__.__name__} {str(self)!r}>"
|
|
78
75
|
|
|
79
76
|
|
|
80
77
|
def generate_key_pair():
|
|
@@ -89,39 +86,38 @@ def generate_relay_id():
|
|
|
89
86
|
return decode_uuid(rustcall(lib.relay_generate_relay_id))
|
|
90
87
|
|
|
91
88
|
|
|
92
|
-
def create_register_challenge(data, signature, max_age=60
|
|
89
|
+
def create_register_challenge(data, signature, secret, max_age=60):
|
|
93
90
|
challenge_json = rustcall(
|
|
94
91
|
lib.relay_create_register_challenge,
|
|
95
92
|
make_buf(data),
|
|
96
93
|
encode_str(signature),
|
|
94
|
+
encode_str(secret),
|
|
97
95
|
max_age,
|
|
98
96
|
)
|
|
99
97
|
|
|
100
98
|
challenge = json.loads(decode_str(challenge_json, free=True))
|
|
101
99
|
return {
|
|
102
100
|
"relay_id": uuid.UUID(challenge["relay_id"]),
|
|
103
|
-
"public_key": PublicKey.parse(challenge["public_key"]),
|
|
104
101
|
"token": challenge["token"],
|
|
105
102
|
}
|
|
106
103
|
|
|
107
104
|
|
|
108
|
-
def
|
|
109
|
-
return decode_uuid(
|
|
110
|
-
rustcall(lib.relay_get_register_response_relay_id, make_buf(data))
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def validate_register_response(public_key, data, signature, max_age=60 * 15):
|
|
105
|
+
def validate_register_response(data, signature, secret, max_age=60):
|
|
115
106
|
response_json = rustcall(
|
|
116
107
|
lib.relay_validate_register_response,
|
|
117
|
-
public_key._objptr,
|
|
118
108
|
make_buf(data),
|
|
119
109
|
encode_str(signature),
|
|
110
|
+
encode_str(secret),
|
|
120
111
|
max_age,
|
|
121
112
|
)
|
|
122
113
|
|
|
123
114
|
response = json.loads(decode_str(response_json, free=True))
|
|
124
|
-
return {
|
|
115
|
+
return {
|
|
116
|
+
"relay_id": uuid.UUID(response["relay_id"]),
|
|
117
|
+
"token": response["token"],
|
|
118
|
+
"public_key": response["public_key"],
|
|
119
|
+
"version": response["version"],
|
|
120
|
+
}
|
|
125
121
|
|
|
126
122
|
|
|
127
123
|
def is_version_supported(version):
|
|
@@ -1,23 +1,36 @@
|
|
|
1
|
+
import sys
|
|
1
2
|
from enum import IntEnum
|
|
2
3
|
|
|
3
4
|
from sentry_relay._lowlevel import lib
|
|
4
5
|
from sentry_relay.utils import decode_str, encode_str
|
|
5
6
|
|
|
6
|
-
|
|
7
7
|
__all__ = ["DataCategory", "SPAN_STATUS_CODE_TO_NAME", "SPAN_STATUS_NAME_TO_CODE"]
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
def _make_data_categories(ns):
|
|
11
|
-
prefix = "RELAY_DATA_CATEGORY_"
|
|
12
|
-
|
|
13
|
-
for attr in dir(lib):
|
|
14
|
-
if attr.startswith(prefix):
|
|
15
|
-
category_name = attr[len(prefix) :]
|
|
16
|
-
ns[category_name] = getattr(lib, attr)
|
|
17
|
-
|
|
18
|
-
|
|
19
10
|
class DataCategory(IntEnum):
|
|
20
|
-
|
|
11
|
+
# begin generated
|
|
12
|
+
DEFAULT = 0
|
|
13
|
+
ERROR = 1
|
|
14
|
+
TRANSACTION = 2
|
|
15
|
+
SECURITY = 3
|
|
16
|
+
ATTACHMENT = 4
|
|
17
|
+
SESSION = 5
|
|
18
|
+
PROFILE = 6
|
|
19
|
+
REPLAY = 7
|
|
20
|
+
TRANSACTION_PROCESSED = 8
|
|
21
|
+
TRANSACTION_INDEXED = 9
|
|
22
|
+
MONITOR = 10
|
|
23
|
+
PROFILE_INDEXED = 11
|
|
24
|
+
SPAN = 12
|
|
25
|
+
MONITOR_SEAT = 13
|
|
26
|
+
USER_REPORT_V2 = 14
|
|
27
|
+
METRIC_BUCKET = 15
|
|
28
|
+
SPAN_INDEXED = 16
|
|
29
|
+
PROFILE_DURATION = 17
|
|
30
|
+
PROFILE_CHUNK = 18
|
|
31
|
+
METRIC_HOUR = 19
|
|
32
|
+
UNKNOWN = -1
|
|
33
|
+
# end generated
|
|
21
34
|
|
|
22
35
|
@classmethod
|
|
23
36
|
def parse(cls, name):
|
|
@@ -47,6 +60,7 @@ class DataCategory(IntEnum):
|
|
|
47
60
|
DataCategory.ERROR,
|
|
48
61
|
DataCategory.TRANSACTION,
|
|
49
62
|
DataCategory.SECURITY,
|
|
63
|
+
DataCategory.USER_REPORT_V2,
|
|
50
64
|
]
|
|
51
65
|
|
|
52
66
|
@classmethod
|
|
@@ -63,6 +77,29 @@ class DataCategory(IntEnum):
|
|
|
63
77
|
return decode_str(lib.relay_data_category_name(self.value), free=True)
|
|
64
78
|
|
|
65
79
|
|
|
80
|
+
def _check_generated():
|
|
81
|
+
prefix = "RELAY_DATA_CATEGORY_"
|
|
82
|
+
|
|
83
|
+
attrs = {}
|
|
84
|
+
for attr in dir(lib):
|
|
85
|
+
if attr.startswith(prefix):
|
|
86
|
+
category_name = attr[len(prefix) :]
|
|
87
|
+
attrs[category_name] = getattr(lib, attr)
|
|
88
|
+
|
|
89
|
+
if attrs != DataCategory.__members__:
|
|
90
|
+
values = sorted(
|
|
91
|
+
attrs.items(), key=lambda kv: sys.maxsize if kv[1] == -1 else kv[1]
|
|
92
|
+
)
|
|
93
|
+
generated = "".join(f" {k} = {v}\n" for k, v in values)
|
|
94
|
+
raise AssertionError(
|
|
95
|
+
f"DataCategory enum does not match source!\n\n"
|
|
96
|
+
f"Paste this into `class DataCategory` in py/sentry_relay/consts.py:\n\n"
|
|
97
|
+
f"{generated}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
_check_generated()
|
|
102
|
+
|
|
66
103
|
SPAN_STATUS_CODE_TO_NAME = {}
|
|
67
104
|
SPAN_STATUS_NAME_TO_CODE = {}
|
|
68
105
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
from
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
2
3
|
from sentry_relay._lowlevel import lib
|
|
3
4
|
|
|
4
5
|
|
|
@@ -6,7 +7,6 @@ __all__ = ["RelayError"]
|
|
|
6
7
|
exceptions_by_code = {}
|
|
7
8
|
|
|
8
9
|
|
|
9
|
-
@implements_to_string
|
|
10
10
|
class RelayError(Exception):
|
|
11
11
|
code = None
|
|
12
12
|
|
|
@@ -18,7 +18,7 @@ class RelayError(Exception):
|
|
|
18
18
|
def __str__(self):
|
|
19
19
|
rv = self.message
|
|
20
20
|
if self.rust_info is not None:
|
|
21
|
-
return
|
|
21
|
+
return f"{rv}\n\n{self.rust_info}"
|
|
22
22
|
return rv
|
|
23
23
|
|
|
24
24
|
|
|
@@ -59,3 +59,7 @@ def _make_exceptions():
|
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
_make_exceptions()
|
|
62
|
+
|
|
63
|
+
if TYPE_CHECKING:
|
|
64
|
+
# treat unknown attribute names as exception types
|
|
65
|
+
def __getattr__(name: str) -> type[RelayError]: ...
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import json
|
|
2
4
|
|
|
3
|
-
from sentry_relay._compat import string_types, iteritems, text_type
|
|
4
5
|
from sentry_relay._lowlevel import lib, ffi
|
|
5
6
|
from sentry_relay.utils import (
|
|
6
7
|
encode_str,
|
|
@@ -17,24 +18,24 @@ __all__ = [
|
|
|
17
18
|
"meta_with_chunks",
|
|
18
19
|
"StoreNormalizer",
|
|
19
20
|
"GeoIpLookup",
|
|
20
|
-
"scrub_event",
|
|
21
21
|
"is_glob_match",
|
|
22
|
+
"is_codeowners_path_match",
|
|
22
23
|
"parse_release",
|
|
24
|
+
"validate_pii_selector",
|
|
23
25
|
"validate_pii_config",
|
|
24
26
|
"convert_datascrubbing_config",
|
|
25
27
|
"pii_strip_event",
|
|
26
|
-
"pii_selectors_from_event",
|
|
27
28
|
"pii_selector_suggestions_from_event",
|
|
28
29
|
"VALID_PLATFORMS",
|
|
30
|
+
"validate_rule_condition",
|
|
31
|
+
"validate_sampling_condition",
|
|
32
|
+
"validate_sampling_configuration",
|
|
33
|
+
"validate_project_config",
|
|
34
|
+
"normalize_global_config",
|
|
29
35
|
]
|
|
30
36
|
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def _init_valid_platforms():
|
|
36
|
-
global VALID_PLATFORMS
|
|
37
|
-
|
|
38
|
+
def _init_valid_platforms() -> frozenset[str]:
|
|
38
39
|
size_out = ffi.new("uintptr_t *")
|
|
39
40
|
strings = rustcall(lib.relay_valid_platforms, size_out)
|
|
40
41
|
|
|
@@ -42,15 +43,17 @@ def _init_valid_platforms():
|
|
|
42
43
|
for i in range(int(size_out[0])):
|
|
43
44
|
valid_platforms.append(decode_str(strings[i], free=True))
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
return frozenset(valid_platforms)
|
|
46
47
|
|
|
47
48
|
|
|
48
|
-
_init_valid_platforms()
|
|
49
|
+
VALID_PLATFORMS = _init_valid_platforms()
|
|
49
50
|
|
|
50
51
|
|
|
51
52
|
def split_chunks(string, remarks):
|
|
52
53
|
json_chunks = rustcall(
|
|
53
|
-
lib.relay_split_chunks,
|
|
54
|
+
lib.relay_split_chunks,
|
|
55
|
+
encode_str(string),
|
|
56
|
+
encode_str(json.dumps(remarks)),
|
|
54
57
|
)
|
|
55
58
|
return json.loads(decode_str(json_chunks, free=True))
|
|
56
59
|
|
|
@@ -60,10 +63,10 @@ def meta_with_chunks(data, meta):
|
|
|
60
63
|
return meta
|
|
61
64
|
|
|
62
65
|
result = {}
|
|
63
|
-
for key, item in
|
|
66
|
+
for key, item in meta.items():
|
|
64
67
|
if key == "" and isinstance(item, dict):
|
|
65
68
|
result[""] = item.copy()
|
|
66
|
-
if item.get("rem") and isinstance(data,
|
|
69
|
+
if item.get("rem") and isinstance(data, str):
|
|
67
70
|
result[""]["chunks"] = split_chunks(data, item["rem"])
|
|
68
71
|
elif isinstance(data, dict):
|
|
69
72
|
result[key] = meta_with_chunks(data.get(key), item)
|
|
@@ -83,14 +86,14 @@ class GeoIpLookup(RustObject):
|
|
|
83
86
|
|
|
84
87
|
@classmethod
|
|
85
88
|
def from_path(cls, path):
|
|
86
|
-
if isinstance(path,
|
|
89
|
+
if isinstance(path, str):
|
|
87
90
|
path = path.encode("utf-8")
|
|
88
91
|
rv = cls._from_objptr(rustcall(lib.relay_geoip_lookup_new, path))
|
|
89
92
|
rv._path = path
|
|
90
93
|
return rv
|
|
91
94
|
|
|
92
95
|
def __repr__(self):
|
|
93
|
-
return "<GeoIpLookup
|
|
96
|
+
return f"<GeoIpLookup {self._path!r}>"
|
|
94
97
|
|
|
95
98
|
|
|
96
99
|
class StoreNormalizer(RustObject):
|
|
@@ -119,7 +122,7 @@ class StoreNormalizer(RustObject):
|
|
|
119
122
|
|
|
120
123
|
def _serialize_event(event):
|
|
121
124
|
raw_event = json.dumps(event, ensure_ascii=False)
|
|
122
|
-
if isinstance(raw_event,
|
|
125
|
+
if isinstance(raw_event, str):
|
|
123
126
|
raw_event = raw_event.encode("utf-8", errors="replace")
|
|
124
127
|
return raw_event
|
|
125
128
|
|
|
@@ -130,19 +133,6 @@ def _encode_raw_event(raw_event):
|
|
|
130
133
|
return event
|
|
131
134
|
|
|
132
135
|
|
|
133
|
-
def scrub_event(config, data):
|
|
134
|
-
if not config:
|
|
135
|
-
return data
|
|
136
|
-
|
|
137
|
-
config = json.dumps(config)
|
|
138
|
-
|
|
139
|
-
raw_event = _serialize_event(data)
|
|
140
|
-
event = _encode_raw_event(raw_event)
|
|
141
|
-
|
|
142
|
-
rv = rustcall(lib.relay_scrub_event, encode_str(config), event)
|
|
143
|
-
return json.loads(decode_str(rv, free=True))
|
|
144
|
-
|
|
145
|
-
|
|
146
136
|
def is_glob_match(
|
|
147
137
|
value,
|
|
148
138
|
pat,
|
|
@@ -165,11 +155,30 @@ def is_glob_match(
|
|
|
165
155
|
if allow_newline:
|
|
166
156
|
flags |= lib.GLOB_FLAGS_ALLOW_NEWLINE
|
|
167
157
|
|
|
168
|
-
if isinstance(value,
|
|
158
|
+
if isinstance(value, str):
|
|
169
159
|
value = value.encode("utf-8")
|
|
170
160
|
return rustcall(lib.relay_is_glob_match, make_buf(value), encode_str(pat), flags)
|
|
171
161
|
|
|
172
162
|
|
|
163
|
+
def is_codeowners_path_match(value, pattern):
|
|
164
|
+
if isinstance(value, str):
|
|
165
|
+
value = value.encode("utf-8")
|
|
166
|
+
return rustcall(
|
|
167
|
+
lib.relay_is_codeowners_path_match, make_buf(value), encode_str(pattern)
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def validate_pii_selector(selector):
|
|
172
|
+
"""
|
|
173
|
+
Validate a PII selector spec. Used to validate datascrubbing safe fields.
|
|
174
|
+
"""
|
|
175
|
+
assert isinstance(selector, str)
|
|
176
|
+
raw_error = rustcall(lib.relay_validate_pii_selector, encode_str(selector))
|
|
177
|
+
error = decode_str(raw_error, free=True)
|
|
178
|
+
if error:
|
|
179
|
+
raise ValueError(error)
|
|
180
|
+
|
|
181
|
+
|
|
173
182
|
def validate_pii_config(config):
|
|
174
183
|
"""
|
|
175
184
|
Validate a PII config against the schema. Used in project options UI.
|
|
@@ -178,7 +187,7 @@ def validate_pii_config(config):
|
|
|
178
187
|
as a string such that line numbers from the error message match with what
|
|
179
188
|
the user typed in.
|
|
180
189
|
"""
|
|
181
|
-
assert isinstance(config,
|
|
190
|
+
assert isinstance(config, str)
|
|
182
191
|
raw_error = rustcall(lib.relay_validate_pii_config, encode_str(config))
|
|
183
192
|
error = decode_str(raw_error, free=True)
|
|
184
193
|
if error:
|
|
@@ -204,15 +213,6 @@ def pii_strip_event(config, event):
|
|
|
204
213
|
return json.loads(decode_str(raw_rv, free=True))
|
|
205
214
|
|
|
206
215
|
|
|
207
|
-
def pii_selectors_from_event(event):
|
|
208
|
-
"""
|
|
209
|
-
DEPRECATED: Use relay_pii_selector_suggestions_from_event
|
|
210
|
-
"""
|
|
211
|
-
raw_event = encode_str(json.dumps(event))
|
|
212
|
-
raw_rv = rustcall(lib.relay_pii_selectors_from_event, raw_event)
|
|
213
|
-
return json.loads(decode_str(raw_rv, free=True))
|
|
214
|
-
|
|
215
|
-
|
|
216
216
|
def pii_selector_suggestions_from_event(event):
|
|
217
217
|
"""
|
|
218
218
|
Walk through the event and collect selectors that can be applied to it in a
|
|
@@ -225,6 +225,78 @@ def pii_selector_suggestions_from_event(event):
|
|
|
225
225
|
|
|
226
226
|
|
|
227
227
|
def parse_release(release):
|
|
228
|
+
"""Parses a release string into a dictionary of its components."""
|
|
228
229
|
return json.loads(
|
|
229
230
|
decode_str(rustcall(lib.relay_parse_release, encode_str(release)), free=True)
|
|
230
231
|
)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def compare_version(a, b):
|
|
235
|
+
"""Compares two versions with each other and returns 1/0/-1."""
|
|
236
|
+
return rustcall(lib.relay_compare_versions, encode_str(a), encode_str(b))
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def validate_sampling_condition(condition):
|
|
240
|
+
"""
|
|
241
|
+
Deprecated legacy alias. Please use ``validate_rule_condition`` instead.
|
|
242
|
+
"""
|
|
243
|
+
return validate_rule_condition(condition)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def validate_rule_condition(condition):
|
|
247
|
+
"""
|
|
248
|
+
Validate a dynamic rule condition. Used by dynamic sampling, metric extraction, and metric
|
|
249
|
+
tagging.
|
|
250
|
+
|
|
251
|
+
:param condition: A string containing the condition encoded as JSON.
|
|
252
|
+
"""
|
|
253
|
+
assert isinstance(condition, str)
|
|
254
|
+
raw_error = rustcall(lib.relay_validate_rule_condition, encode_str(condition))
|
|
255
|
+
error = decode_str(raw_error, free=True)
|
|
256
|
+
if error:
|
|
257
|
+
raise ValueError(error)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def validate_sampling_configuration(condition):
|
|
261
|
+
"""
|
|
262
|
+
Validate the whole sampling configuration. Used in dynamic sampling serializer.
|
|
263
|
+
The parameter is a string containing the rules configuration as JSON.
|
|
264
|
+
"""
|
|
265
|
+
assert isinstance(condition, str)
|
|
266
|
+
raw_error = rustcall(
|
|
267
|
+
lib.relay_validate_sampling_configuration, encode_str(condition)
|
|
268
|
+
)
|
|
269
|
+
error = decode_str(raw_error, free=True)
|
|
270
|
+
if error:
|
|
271
|
+
raise ValueError(error)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def validate_project_config(config, strict: bool):
|
|
275
|
+
"""Validate the whole project config.
|
|
276
|
+
|
|
277
|
+
:param strict: Whether or not to check for unknown fields.
|
|
278
|
+
"""
|
|
279
|
+
assert isinstance(config, str)
|
|
280
|
+
raw_error = rustcall(lib.relay_validate_project_config, encode_str(config), strict)
|
|
281
|
+
error = decode_str(raw_error, free=True)
|
|
282
|
+
if error:
|
|
283
|
+
raise ValueError(error)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def normalize_global_config(config):
|
|
287
|
+
"""Normalize the global config.
|
|
288
|
+
|
|
289
|
+
Normalization consists of deserializing and serializing back the given
|
|
290
|
+
global config. If deserializing fails, throw an exception. Note that even if
|
|
291
|
+
the roundtrip doesn't produce errors, the given config may differ from
|
|
292
|
+
normalized one.
|
|
293
|
+
|
|
294
|
+
:param config: the global config to validate.
|
|
295
|
+
"""
|
|
296
|
+
serialized = json.dumps(config)
|
|
297
|
+
normalized = rustcall(lib.normalize_global_config, encode_str(serialized))
|
|
298
|
+
rv = decode_str(normalized, free=True)
|
|
299
|
+
try:
|
|
300
|
+
return json.loads(rv)
|
|
301
|
+
except json.JSONDecodeError:
|
|
302
|
+
raise ValueError(rv)
|
|
File without changes
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import os
|
|
2
4
|
import uuid
|
|
3
5
|
import weakref
|
|
4
6
|
from sentry_relay._lowlevel import ffi, lib
|
|
5
|
-
from sentry_relay._compat import text_type, with_metaclass
|
|
6
7
|
from sentry_relay.exceptions import exceptions_by_code, RelayError
|
|
7
8
|
|
|
8
9
|
|
|
10
|
+
attached_refs: weakref.WeakKeyDictionary[object, bytes]
|
|
9
11
|
attached_refs = weakref.WeakKeyDictionary()
|
|
10
12
|
|
|
11
13
|
|
|
@@ -35,7 +37,7 @@ def rustcall(func, *args):
|
|
|
35
37
|
raise exc
|
|
36
38
|
|
|
37
39
|
|
|
38
|
-
class RustObject(
|
|
40
|
+
class RustObject(metaclass=_NoDict):
|
|
39
41
|
__slots__ = ["_objptr", "_shared"]
|
|
40
42
|
__dealloc_func__ = None
|
|
41
43
|
|
|
@@ -75,7 +77,7 @@ def decode_str(s, free=False):
|
|
|
75
77
|
"""Decodes a RelayStr"""
|
|
76
78
|
try:
|
|
77
79
|
if s.len == 0:
|
|
78
|
-
return
|
|
80
|
+
return ""
|
|
79
81
|
return ffi.unpack(s.data, s.len).decode("utf-8", "replace")
|
|
80
82
|
finally:
|
|
81
83
|
if free and s.owned:
|
|
@@ -85,7 +87,7 @@ def decode_str(s, free=False):
|
|
|
85
87
|
def encode_str(s, mutable=False):
|
|
86
88
|
"""Encodes a RelayStr"""
|
|
87
89
|
rv = ffi.new("RelayStr *")
|
|
88
|
-
if isinstance(s,
|
|
90
|
+
if isinstance(s, str):
|
|
89
91
|
s = s.encode("utf-8")
|
|
90
92
|
if mutable:
|
|
91
93
|
s = bytearray(s)
|
|
@@ -10,18 +10,20 @@ from setuptools import setup, find_packages
|
|
|
10
10
|
from distutils.command.sdist import sdist
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
_version_re = re.compile(r'^version\s*=\s*"(.*?)"\s*$
|
|
13
|
+
_version_re = re.compile(r'(?m)^version\s*=\s*"(.*?)"\s*$')
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
DEBUG_BUILD = os.environ.get("RELAY_DEBUG") == "1"
|
|
17
17
|
|
|
18
|
-
with open("README", "
|
|
18
|
+
with open("README", encoding="UTF-8") as f:
|
|
19
19
|
readme = f.read()
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
if os.path.isfile("../relay-cabi/Cargo.toml"):
|
|
23
23
|
with open("../relay-cabi/Cargo.toml") as f:
|
|
24
|
-
|
|
24
|
+
match = _version_re.search(f.read())
|
|
25
|
+
assert match is not None
|
|
26
|
+
version = match[1]
|
|
25
27
|
else:
|
|
26
28
|
with open("version.txt") as f:
|
|
27
29
|
version = f.readline().strip()
|
|
@@ -44,7 +46,7 @@ class CustomSDist(sdist):
|
|
|
44
46
|
|
|
45
47
|
|
|
46
48
|
def build_native(spec):
|
|
47
|
-
cmd = ["cargo", "build"]
|
|
49
|
+
cmd = ["cargo", "build", "-p", "relay-cabi"]
|
|
48
50
|
if not DEBUG_BUILD:
|
|
49
51
|
cmd.append("--release")
|
|
50
52
|
target = "release"
|
|
@@ -59,26 +61,40 @@ def build_native(spec):
|
|
|
59
61
|
def delete_scratchpad():
|
|
60
62
|
try:
|
|
61
63
|
shutil.rmtree(scratchpad)
|
|
62
|
-
except
|
|
64
|
+
except OSError:
|
|
63
65
|
pass
|
|
64
66
|
|
|
65
67
|
zf = zipfile.ZipFile("rustsrc.zip")
|
|
66
68
|
zf.extractall(scratchpad)
|
|
67
|
-
rust_path = scratchpad + "/rustsrc
|
|
69
|
+
rust_path = scratchpad + "/rustsrc"
|
|
68
70
|
else:
|
|
69
|
-
rust_path = "
|
|
71
|
+
rust_path = ".."
|
|
70
72
|
scratchpad = None
|
|
71
73
|
|
|
74
|
+
# if the lib already built we replace the command
|
|
75
|
+
if os.environ.get("SKIP_RELAY_LIB_BUILD") is not None:
|
|
76
|
+
cmd = ["echo", "'Use pre-built library.'"]
|
|
77
|
+
|
|
72
78
|
# Step 1: build the rust library
|
|
73
79
|
build = spec.add_external_build(cmd=cmd, path=rust_path)
|
|
74
80
|
|
|
81
|
+
def find_dylib():
|
|
82
|
+
cargo_target = os.environ.get("CARGO_BUILD_TARGET")
|
|
83
|
+
if cargo_target:
|
|
84
|
+
in_path = f"target/{cargo_target}/{target}"
|
|
85
|
+
else:
|
|
86
|
+
in_path = "target/%s" % target
|
|
87
|
+
return build.find_dylib("relay_cabi", in_path=in_path)
|
|
88
|
+
|
|
75
89
|
rtld_flags = ["NOW"]
|
|
76
90
|
if sys.platform == "darwin":
|
|
77
91
|
rtld_flags.append("NODELETE")
|
|
78
92
|
spec.add_cffi_module(
|
|
79
93
|
module_path="sentry_relay._lowlevel",
|
|
80
|
-
dylib=
|
|
81
|
-
header_filename=lambda: build.find_header(
|
|
94
|
+
dylib=find_dylib,
|
|
95
|
+
header_filename=lambda: build.find_header(
|
|
96
|
+
"relay.h", in_path="relay-cabi/include"
|
|
97
|
+
),
|
|
82
98
|
rtld_flags=rtld_flags,
|
|
83
99
|
)
|
|
84
100
|
|
|
@@ -88,15 +104,18 @@ setup(
|
|
|
88
104
|
version=version,
|
|
89
105
|
packages=find_packages(),
|
|
90
106
|
author="Sentry",
|
|
91
|
-
license="
|
|
107
|
+
license="FSL-1.0-Apache-2.0",
|
|
92
108
|
author_email="hello@sentry.io",
|
|
93
109
|
description="A python library to access sentry relay functionality.",
|
|
94
110
|
long_description=readme,
|
|
111
|
+
long_description_content_type="text/markdown",
|
|
95
112
|
include_package_data=True,
|
|
113
|
+
package_data={"sentry_relay": ["py.typed", "_lowlevel.pyi"]},
|
|
96
114
|
zip_safe=False,
|
|
97
115
|
platforms="any",
|
|
98
|
-
|
|
99
|
-
|
|
116
|
+
python_requires=">=3.10",
|
|
117
|
+
install_requires=["milksnake>=0.1.6"],
|
|
118
|
+
setup_requires=["milksnake>=0.1.6"],
|
|
100
119
|
milksnake_tasks=[build_native],
|
|
101
120
|
cmdclass={"sdist": CustomSDist},
|
|
102
121
|
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.5.87
|
sentry-relay-0.5.12/rustsrc.zip
DELETED
|
Binary file
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
PY2 = sys.version_info[0] == 2
|
|
5
|
-
|
|
6
|
-
if PY2:
|
|
7
|
-
text_type = unicode # noqa
|
|
8
|
-
int_types = (int, long) # noqa
|
|
9
|
-
string_types = (str, unicode) # noqa
|
|
10
|
-
range_type = xrange # noqa
|
|
11
|
-
iteritems = lambda x: x.iteritems()
|
|
12
|
-
itervalues = lambda x: x.itervalues()
|
|
13
|
-
NUL = "\x00"
|
|
14
|
-
|
|
15
|
-
def implements_to_string(cls):
|
|
16
|
-
cls.__unicode__ = cls.__str__
|
|
17
|
-
cls.__str__ = lambda x: x.__unicode__().encode("utf-8")
|
|
18
|
-
return cls
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
else:
|
|
22
|
-
text_type = str
|
|
23
|
-
int_types = (int,)
|
|
24
|
-
string_types = (str,)
|
|
25
|
-
range_type = range
|
|
26
|
-
iteritems = lambda x: x.items()
|
|
27
|
-
itervalues = lambda x: x.values()
|
|
28
|
-
NUL = 0
|
|
29
|
-
implements_to_string = lambda x: x
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def with_metaclass(meta, *bases):
|
|
33
|
-
class metaclass(type):
|
|
34
|
-
def __new__(cls, name, this_bases, d):
|
|
35
|
-
return meta(name, bases, d)
|
|
36
|
-
|
|
37
|
-
return type.__new__(metaclass, "temporary_class", (), {})
|
sentry-relay-0.5.12/version.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.5.12
|
|
File without changes
|
|
File without changes
|