sentry-relay 0.5.13__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.
@@ -1,10 +1,10 @@
1
- Metadata-Version: 1.0
1
+ Metadata-Version: 2.1
2
2
  Name: sentry-relay
3
- Version: 0.5.13
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: BSL-1.1
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 PY2, 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 "<%s %r>" % (self.__class__.__name__, text_type(self))
50
+ return f"<{self.__class__.__name__} {str(self)!r}>"
54
51
 
55
52
 
56
53
  class SecretKey(RustObject):
@@ -67,16 +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=(",", ":"))
71
- if not PY2:
72
- packed = packed.encode("utf8")
67
+ packed = json.dumps(data, separators=(",", ":")).encode("utf8")
73
68
  return packed, self.sign(packed)
74
69
 
75
70
  def __str__(self):
76
71
  return decode_str(self._methodcall(lib.relay_secretkey_to_string), free=True)
77
72
 
78
73
  def __repr__(self):
79
- return "<%s %r>" % (self.__class__.__name__, text_type(self))
74
+ return f"<{self.__class__.__name__} {str(self)!r}>"
80
75
 
81
76
 
82
77
  def generate_key_pair():
@@ -91,39 +86,38 @@ def generate_relay_id():
91
86
  return decode_uuid(rustcall(lib.relay_generate_relay_id))
92
87
 
93
88
 
94
- def create_register_challenge(data, signature, max_age=60 * 15):
89
+ def create_register_challenge(data, signature, secret, max_age=60):
95
90
  challenge_json = rustcall(
96
91
  lib.relay_create_register_challenge,
97
92
  make_buf(data),
98
93
  encode_str(signature),
94
+ encode_str(secret),
99
95
  max_age,
100
96
  )
101
97
 
102
98
  challenge = json.loads(decode_str(challenge_json, free=True))
103
99
  return {
104
100
  "relay_id": uuid.UUID(challenge["relay_id"]),
105
- "public_key": PublicKey.parse(challenge["public_key"]),
106
101
  "token": challenge["token"],
107
102
  }
108
103
 
109
104
 
110
- def get_register_response_relay_id(data):
111
- return decode_uuid(
112
- rustcall(lib.relay_get_register_response_relay_id, make_buf(data))
113
- )
114
-
115
-
116
- def validate_register_response(public_key, data, signature, max_age=60 * 15):
105
+ def validate_register_response(data, signature, secret, max_age=60):
117
106
  response_json = rustcall(
118
107
  lib.relay_validate_register_response,
119
- public_key._objptr,
120
108
  make_buf(data),
121
109
  encode_str(signature),
110
+ encode_str(secret),
122
111
  max_age,
123
112
  )
124
113
 
125
114
  response = json.loads(decode_str(response_json, free=True))
126
- return {"relay_id": uuid.UUID(response["relay_id"]), "token": response["token"]}
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
+ }
127
121
 
128
122
 
129
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
- _make_data_categories(locals())
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 sentry_relay._compat import implements_to_string
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 u"%s\n\n%s" % (rv, self.rust_info)
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
- VALID_PLATFORMS = frozenset()
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
- VALID_PLATFORMS = frozenset(valid_platforms)
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, encode_str(string), encode_str(json.dumps(remarks)),
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 iteritems(meta):
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, string_types):
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, text_type):
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 %r>" % (self._path,)
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, text_type):
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, text_type):
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, string_types)
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(with_metaclass(_NoDict)):
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 u""
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, text_type):
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*$(?m)')
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", "rb") as f:
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
- version = _version_re.search(f.read()).group(1)
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 (IOError, OSError):
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/relay-cabi"
69
+ rust_path = scratchpad + "/rustsrc"
68
70
  else:
69
- rust_path = "../relay-cabi"
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=lambda: build.find_dylib("relay", in_path="target/%s" % target),
81
- header_filename=lambda: build.find_header("relay.h", in_path="include"),
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="BSL-1.1",
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
- install_requires=['enum34>=1.1.6,<1.2.0;python_version<"3.4"', "milksnake>=0.1.2"],
99
- setup_requires=["milksnake>=0.1.2"],
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
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", (), {})
@@ -1 +0,0 @@
1
- 0.5.13
File without changes