ulid-transform 0.10.1__pp310-pypy310_pp73-macosx_14_0_arm64.whl

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.
@@ -0,0 +1,41 @@
1
+ # distutils: language = c++
2
+ from libcpp.string cimport string
3
+
4
+ from time import time
5
+ from typing import Optional
6
+
7
+ import cython
8
+
9
+
10
+ cdef extern from "ulid_wrapper.h":
11
+ string _cpp_ulid_at_time(double timestamp)
12
+ string _cpp_ulid_to_bytes(const char * ulid_string)
13
+ string _cpp_ulid()
14
+ string _cpp_bytes_to_ulid(string ulid_bytes)
15
+
16
+
17
+ def _ulid_now() -> str:
18
+ return _cpp_ulid().decode("ascii")
19
+
20
+ def _ulid_at_time(_time: float) -> str:
21
+ return _cpp_ulid_at_time(_time).decode("ascii")
22
+
23
+ def _ulid_to_bytes(ulid_str: str) -> bytes:
24
+ if len(ulid_str) != 26:
25
+ raise ValueError(f"ULID must be a 26 character string: {ulid_str}")
26
+ return _cpp_ulid_to_bytes(ulid_str.encode("ascii"))
27
+
28
+ def _bytes_to_ulid(ulid_bytes: bytes) -> str:
29
+ if len(ulid_bytes) != 16:
30
+ raise ValueError(f"ULID bytes be 16 bytes: {ulid_bytes}")
31
+ return _cpp_bytes_to_ulid(ulid_bytes).decode("ascii")
32
+
33
+ def _ulid_to_bytes_or_none(ulid_str: Optional[str]) -> Optional[bytes]:
34
+ if ulid_str is None or len(ulid_str) != 26:
35
+ return None
36
+ return _cpp_ulid_to_bytes(ulid_str.encode("ascii"))
37
+
38
+ def _bytes_to_ulid_or_none(ulid_bytes: Optional[bytes]) -> Optional[str]:
39
+ if ulid_bytes is None or len(ulid_bytes) != 16:
40
+ return None
41
+ return _cpp_bytes_to_ulid(ulid_bytes).decode("ascii")
File without changes
ulid_transform/ulid.hh ADDED
@@ -0,0 +1,17 @@
1
+ // Originally from https://github.com/suyash/ulid
2
+
3
+ #ifndef ULID_HH
4
+ #define ULID_HH
5
+
6
+ // http://stackoverflow.com/a/23981011
7
+ #ifdef __SIZEOF_INT128__
8
+ #define ULIDUINT128
9
+ #endif
10
+
11
+ #ifdef ULIDUINT128
12
+ #include "ulid_uint128.hh"
13
+ #else
14
+ #include "ulid_struct.hh"
15
+ #endif // ULIDUINT128
16
+
17
+ #endif // ULID_HH
@@ -0,0 +1,453 @@
1
+ import array
2
+ from random import getrandbits
3
+ from time import time
4
+
5
+ # From https://github.com/ahawker/ulid/blob/06289583e9de4286b4d80b4ad000d137816502ca/ulid/base32.py#L102
6
+ #: Array that maps encoded string char byte values to enable O(1) lookups.
7
+ _DECODE = array.array(
8
+ "B",
9
+ (
10
+ 0xFF,
11
+ 0xFF,
12
+ 0xFF,
13
+ 0xFF,
14
+ 0xFF,
15
+ 0xFF,
16
+ 0xFF,
17
+ 0xFF,
18
+ 0xFF,
19
+ 0xFF,
20
+ 0xFF,
21
+ 0xFF,
22
+ 0xFF,
23
+ 0xFF,
24
+ 0xFF,
25
+ 0xFF,
26
+ 0xFF,
27
+ 0xFF,
28
+ 0xFF,
29
+ 0xFF,
30
+ 0xFF,
31
+ 0xFF,
32
+ 0xFF,
33
+ 0xFF,
34
+ 0xFF,
35
+ 0xFF,
36
+ 0xFF,
37
+ 0xFF,
38
+ 0xFF,
39
+ 0xFF,
40
+ 0xFF,
41
+ 0xFF,
42
+ 0xFF,
43
+ 0xFF,
44
+ 0xFF,
45
+ 0xFF,
46
+ 0xFF,
47
+ 0xFF,
48
+ 0xFF,
49
+ 0xFF,
50
+ 0xFF,
51
+ 0xFF,
52
+ 0xFF,
53
+ 0xFF,
54
+ 0xFF,
55
+ 0xFF,
56
+ 0xFF,
57
+ 0xFF,
58
+ 0x00,
59
+ 0x01,
60
+ 0x02,
61
+ 0x03,
62
+ 0x04,
63
+ 0x05,
64
+ 0x06,
65
+ 0x07,
66
+ 0x08,
67
+ 0x09,
68
+ 0xFF,
69
+ 0xFF,
70
+ 0xFF,
71
+ 0xFF,
72
+ 0xFF,
73
+ 0xFF,
74
+ 0xFF,
75
+ 0x0A,
76
+ 0x0B,
77
+ 0x0C,
78
+ 0x0D,
79
+ 0x0E,
80
+ 0x0F,
81
+ 0x10,
82
+ 0x11,
83
+ 0x01,
84
+ 0x12,
85
+ 0x13,
86
+ 0x01,
87
+ 0x14,
88
+ 0x15,
89
+ 0x00,
90
+ 0x16,
91
+ 0x17,
92
+ 0x18,
93
+ 0x19,
94
+ 0x1A,
95
+ 0xFF,
96
+ 0x1B,
97
+ 0x1C,
98
+ 0x1D,
99
+ 0x1E,
100
+ 0x1F,
101
+ 0xFF,
102
+ 0xFF,
103
+ 0xFF,
104
+ 0xFF,
105
+ 0xFF,
106
+ 0xFF,
107
+ 0x0A,
108
+ 0x0B,
109
+ 0x0C,
110
+ 0x0D,
111
+ 0x0E,
112
+ 0x0F,
113
+ 0x10,
114
+ 0x11,
115
+ 0x01,
116
+ 0x12,
117
+ 0x13,
118
+ 0x01,
119
+ 0x14,
120
+ 0x15,
121
+ 0x00,
122
+ 0x16,
123
+ 0x17,
124
+ 0x18,
125
+ 0x19,
126
+ 0x1A,
127
+ 0xFF,
128
+ 0x1B,
129
+ 0x1C,
130
+ 0x1D,
131
+ 0x1E,
132
+ 0x1F,
133
+ 0xFF,
134
+ 0xFF,
135
+ 0xFF,
136
+ 0xFF,
137
+ 0xFF,
138
+ 0xFF,
139
+ 0xFF,
140
+ 0xFF,
141
+ 0xFF,
142
+ 0xFF,
143
+ 0xFF,
144
+ 0xFF,
145
+ 0xFF,
146
+ 0xFF,
147
+ 0xFF,
148
+ 0xFF,
149
+ 0xFF,
150
+ 0xFF,
151
+ 0xFF,
152
+ 0xFF,
153
+ 0xFF,
154
+ 0xFF,
155
+ 0xFF,
156
+ 0xFF,
157
+ 0xFF,
158
+ 0xFF,
159
+ 0xFF,
160
+ 0xFF,
161
+ 0xFF,
162
+ 0xFF,
163
+ 0xFF,
164
+ 0xFF,
165
+ 0xFF,
166
+ 0xFF,
167
+ 0xFF,
168
+ 0xFF,
169
+ 0xFF,
170
+ 0xFF,
171
+ 0xFF,
172
+ 0xFF,
173
+ 0xFF,
174
+ 0xFF,
175
+ 0xFF,
176
+ 0xFF,
177
+ 0xFF,
178
+ 0xFF,
179
+ 0xFF,
180
+ 0xFF,
181
+ 0xFF,
182
+ 0xFF,
183
+ 0xFF,
184
+ 0xFF,
185
+ 0xFF,
186
+ 0xFF,
187
+ 0xFF,
188
+ 0xFF,
189
+ 0xFF,
190
+ 0xFF,
191
+ 0xFF,
192
+ 0xFF,
193
+ 0xFF,
194
+ 0xFF,
195
+ 0xFF,
196
+ 0xFF,
197
+ 0xFF,
198
+ 0xFF,
199
+ 0xFF,
200
+ 0xFF,
201
+ 0xFF,
202
+ 0xFF,
203
+ 0xFF,
204
+ 0xFF,
205
+ 0xFF,
206
+ 0xFF,
207
+ 0xFF,
208
+ 0xFF,
209
+ 0xFF,
210
+ 0xFF,
211
+ 0xFF,
212
+ 0xFF,
213
+ 0xFF,
214
+ 0xFF,
215
+ 0xFF,
216
+ 0xFF,
217
+ 0xFF,
218
+ 0xFF,
219
+ 0xFF,
220
+ 0xFF,
221
+ 0xFF,
222
+ 0xFF,
223
+ 0xFF,
224
+ 0xFF,
225
+ 0xFF,
226
+ 0xFF,
227
+ 0xFF,
228
+ 0xFF,
229
+ 0xFF,
230
+ 0xFF,
231
+ 0xFF,
232
+ 0xFF,
233
+ 0xFF,
234
+ 0xFF,
235
+ 0xFF,
236
+ 0xFF,
237
+ 0xFF,
238
+ 0xFF,
239
+ 0xFF,
240
+ 0xFF,
241
+ 0xFF,
242
+ 0xFF,
243
+ 0xFF,
244
+ 0xFF,
245
+ 0xFF,
246
+ 0xFF,
247
+ 0xFF,
248
+ 0xFF,
249
+ 0xFF,
250
+ 0xFF,
251
+ 0xFF,
252
+ 0xFF,
253
+ 0xFF,
254
+ 0xFF,
255
+ 0xFF,
256
+ 0xFF,
257
+ 0xFF,
258
+ 0xFF,
259
+ 0xFF,
260
+ 0xFF,
261
+ 0xFF,
262
+ 0xFF,
263
+ 0xFF,
264
+ 0xFF,
265
+ 0xFF,
266
+ ),
267
+ )
268
+
269
+
270
+ def ulid_hex() -> str:
271
+ """Generate a ULID in lowercase hex that will work for a UUID.
272
+
273
+ This ulid should not be used for cryptographically secure
274
+ operations.
275
+
276
+ This string can be converted with https://github.com/ahawker/ulid
277
+
278
+ ulid.from_uuid(uuid.UUID(ulid_hex))
279
+ """
280
+ return f"{int(time()*1000):012x}{getrandbits(80):020x}"
281
+
282
+
283
+ def ulid_now() -> str:
284
+ """Generate a ULID."""
285
+ return ulid_at_time(time())
286
+
287
+
288
+ def ulid_at_time(timestamp: float) -> str:
289
+ """Generate a ULID.
290
+
291
+ This ulid should not be used for cryptographically secure
292
+ operations.
293
+
294
+ 01AN4Z07BY 79KA1307SR9X4MV3
295
+ |----------| |----------------|
296
+ Timestamp Randomness
297
+ 48bits 80bits
298
+
299
+ This string can be loaded directly with https://github.com/ahawker/ulid
300
+
301
+ import ulid_transform as ulid_util
302
+ import ulid
303
+ ulid.parse(ulid_util.ulid())
304
+ """
305
+ return _encode(
306
+ int((timestamp) * 1000).to_bytes(6, byteorder="big")
307
+ + int(getrandbits(80)).to_bytes(10, byteorder="big")
308
+ )
309
+
310
+
311
+ def _encode(ulid_bytes: bytes) -> str:
312
+ # This is base32 crockford encoding with the loop unrolled for performance
313
+ #
314
+ # This code is adapted from:
315
+ # https://github.com/ahawker/ulid/blob/06289583e9de4286b4d80b4ad000d137816502ca/ulid/base32.py#L102
316
+ #
317
+ enc = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
318
+ return (
319
+ enc[(ulid_bytes[0] & 224) >> 5]
320
+ + enc[ulid_bytes[0] & 31]
321
+ + enc[(ulid_bytes[1] & 248) >> 3]
322
+ + enc[((ulid_bytes[1] & 7) << 2) | ((ulid_bytes[2] & 192) >> 6)]
323
+ + enc[((ulid_bytes[2] & 62) >> 1)]
324
+ + enc[((ulid_bytes[2] & 1) << 4) | ((ulid_bytes[3] & 240) >> 4)]
325
+ + enc[((ulid_bytes[3] & 15) << 1) | ((ulid_bytes[4] & 128) >> 7)]
326
+ + enc[(ulid_bytes[4] & 124) >> 2]
327
+ + enc[((ulid_bytes[4] & 3) << 3) | ((ulid_bytes[5] & 224) >> 5)]
328
+ + enc[ulid_bytes[5] & 31]
329
+ + enc[(ulid_bytes[6] & 248) >> 3]
330
+ + enc[((ulid_bytes[6] & 7) << 2) | ((ulid_bytes[7] & 192) >> 6)]
331
+ + enc[(ulid_bytes[7] & 62) >> 1]
332
+ + enc[((ulid_bytes[7] & 1) << 4) | ((ulid_bytes[8] & 240) >> 4)]
333
+ + enc[((ulid_bytes[8] & 15) << 1) | ((ulid_bytes[9] & 128) >> 7)]
334
+ + enc[(ulid_bytes[9] & 124) >> 2]
335
+ + enc[((ulid_bytes[9] & 3) << 3) | ((ulid_bytes[10] & 224) >> 5)]
336
+ + enc[ulid_bytes[10] & 31]
337
+ + enc[(ulid_bytes[11] & 248) >> 3]
338
+ + enc[((ulid_bytes[11] & 7) << 2) | ((ulid_bytes[12] & 192) >> 6)]
339
+ + enc[(ulid_bytes[12] & 62) >> 1]
340
+ + enc[((ulid_bytes[12] & 1) << 4) | ((ulid_bytes[13] & 240) >> 4)]
341
+ + enc[((ulid_bytes[13] & 15) << 1) | ((ulid_bytes[14] & 128) >> 7)]
342
+ + enc[(ulid_bytes[14] & 124) >> 2]
343
+ + enc[((ulid_bytes[14] & 3) << 3) | ((ulid_bytes[15] & 224) >> 5)]
344
+ + enc[ulid_bytes[15] & 31]
345
+ )
346
+
347
+
348
+ def ulid_to_bytes(value: str) -> bytes:
349
+ """Decode a ulid to bytes."""
350
+ if len(value) != 26:
351
+ raise ValueError(f"ULID must be a 26 character string: {value}")
352
+ encoded = value.encode("ascii")
353
+ decoding = _DECODE
354
+ return bytes(
355
+ (
356
+ ((decoding[encoded[0]] << 5) | decoding[encoded[1]]) & 0xFF,
357
+ ((decoding[encoded[2]] << 3) | (decoding[encoded[3]] >> 2)) & 0xFF,
358
+ (
359
+ (decoding[encoded[3]] << 6)
360
+ | (decoding[encoded[4]] << 1)
361
+ | (decoding[encoded[5]] >> 4)
362
+ )
363
+ & 0xFF,
364
+ ((decoding[encoded[5]] << 4) | (decoding[encoded[6]] >> 1)) & 0xFF,
365
+ (
366
+ (decoding[encoded[6]] << 7)
367
+ | (decoding[encoded[7]] << 2)
368
+ | (decoding[encoded[8]] >> 3)
369
+ )
370
+ & 0xFF,
371
+ ((decoding[encoded[8]] << 5) | (decoding[encoded[9]])) & 0xFF,
372
+ ((decoding[encoded[10]] << 3) | (decoding[encoded[11]] >> 2)) & 0xFF,
373
+ (
374
+ (decoding[encoded[11]] << 6)
375
+ | (decoding[encoded[12]] << 1)
376
+ | (decoding[encoded[13]] >> 4)
377
+ )
378
+ & 0xFF,
379
+ ((decoding[encoded[13]] << 4) | (decoding[encoded[14]] >> 1)) & 0xFF,
380
+ (
381
+ (decoding[encoded[14]] << 7)
382
+ | (decoding[encoded[15]] << 2)
383
+ | (decoding[encoded[16]] >> 3)
384
+ )
385
+ & 0xFF,
386
+ ((decoding[encoded[16]] << 5) | (decoding[encoded[17]])) & 0xFF,
387
+ ((decoding[encoded[18]] << 3) | (decoding[encoded[19]] >> 2)) & 0xFF,
388
+ (
389
+ (decoding[encoded[19]] << 6)
390
+ | (decoding[encoded[20]] << 1)
391
+ | (decoding[encoded[21]] >> 4)
392
+ )
393
+ & 0xFF,
394
+ ((decoding[encoded[21]] << 4) | (decoding[encoded[22]] >> 1)) & 0xFF,
395
+ (
396
+ (decoding[encoded[22]] << 7)
397
+ | (decoding[encoded[23]] << 2)
398
+ | (decoding[encoded[24]] >> 3)
399
+ )
400
+ & 0xFF,
401
+ ((decoding[encoded[24]] << 5) | (decoding[encoded[25]])) & 0xFF,
402
+ )
403
+ )
404
+
405
+
406
+ def bytes_to_ulid(value: bytes) -> str:
407
+ """Encode bytes to a ulid."""
408
+ if len(value) != 16:
409
+ raise ValueError(f"ULID bytes must be 16 bytes: {value!r}")
410
+ return _encode(value)
411
+
412
+
413
+ def ulid_to_bytes_or_none(ulid: str | None) -> bytes | None:
414
+ """Convert an ulid to bytes."""
415
+ if ulid is None:
416
+ return None
417
+ try:
418
+ return ulid_to_bytes(ulid)
419
+ except ValueError:
420
+ return None
421
+
422
+
423
+ def bytes_to_ulid_or_none(_bytes: bytes | None) -> str | None:
424
+ """Convert bytes to a ulid."""
425
+ if _bytes is None:
426
+ return None
427
+ try:
428
+ return bytes_to_ulid(_bytes)
429
+ except ValueError:
430
+ return None
431
+
432
+
433
+ try:
434
+ from ._ulid_impl import ( # type: ignore[no-redef] # noqa: F811 F401 # pragma: no cover
435
+ _bytes_to_ulid as bytes_to_ulid,
436
+ )
437
+ from ._ulid_impl import ( # type: ignore[no-redef] # noqa: F811 F401 # pragma: no cover
438
+ _bytes_to_ulid_or_none as bytes_to_ulid_or_none,
439
+ )
440
+ from ._ulid_impl import ( # type: ignore[no-redef] # noqa: F811 F401 # pragma: no cover
441
+ _ulid_at_time as ulid_at_time,
442
+ )
443
+ from ._ulid_impl import ( # type: ignore[no-redef] # noqa: F811 F401 # pragma: no cover
444
+ _ulid_now as ulid_now,
445
+ )
446
+ from ._ulid_impl import ( # type: ignore[no-redef] # noqa: F811 F401 # pragma: no cover
447
+ _ulid_to_bytes as ulid_to_bytes,
448
+ )
449
+ from ._ulid_impl import ( # type: ignore[no-redef] # noqa: F811 F401 # pragma: no cover
450
+ _ulid_to_bytes_or_none as ulid_to_bytes_or_none,
451
+ )
452
+ except ImportError: # pragma: no cover
453
+ pass # pragma: no cover