ulid-transform 0.1.0__tar.gz → 0.2.1__tar.gz

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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ulid-transform
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: Create and transform ULIDs
5
5
  Home-page: https://github.com/bdraco/ulid-transform
6
6
  License: MIT
@@ -16,7 +16,6 @@ Classifier: Programming Language :: Python :: 3
16
16
  Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Topic :: Software Development :: Libraries
19
- Requires-Dist: fast-ulid (>=0.2.0,<0.3.0)
20
19
  Project-URL: Bug Tracker, https://github.com/bdraco/ulid-transform/issues
21
20
  Project-URL: Changelog, https://github.com/bdraco/ulid-transform/blob/main/CHANGELOG.md
22
21
  Project-URL: Repository, https://github.com/bdraco/ulid-transform
@@ -61,6 +60,8 @@ Install this via pip (or your favourite package manager):
61
60
 
62
61
  ## Contributors ✨
63
62
 
63
+ Thanks to https://github.com/suyash/ulid which provides the cython implementation guts.
64
+
64
65
  Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
65
66
 
66
67
  <!-- prettier-ignore-start -->
@@ -37,6 +37,8 @@ Install this via pip (or your favourite package manager):
37
37
 
38
38
  ## Contributors ✨
39
39
 
40
+ Thanks to https://github.com/suyash/ulid which provides the cython implementation guts.
41
+
40
42
  Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
41
43
 
42
44
  <!-- prettier-ignore-start -->
@@ -2,8 +2,23 @@
2
2
 
3
3
  import os
4
4
  from distutils.command.build_ext import build_ext
5
+ from os.path import join
5
6
  from typing import Any
6
7
 
8
+ try:
9
+ from setuptools import Extension
10
+ except ImportError:
11
+ from distutils.core import Extension
12
+
13
+ ulid_module = Extension(
14
+ "ulid_transform._ulid_impl",
15
+ [
16
+ join("src", "ulid_transform", "_ulid_impl.pyx"),
17
+ join("src", "ulid_transform", "ulid_wrapper.cpp"),
18
+ ],
19
+ language="c++",
20
+ )
21
+
7
22
 
8
23
  class BuildExt(build_ext):
9
24
  def build_extensions(self) -> None:
@@ -23,7 +38,7 @@ def build(setup_kwargs: Any) -> None:
23
38
  dict(
24
39
  ext_modules=cythonize(
25
40
  [
26
- "src/ulid_tansform/convert.py",
41
+ ulid_module,
27
42
  ],
28
43
  compiler_directives={"language_level": "3"}, # Python 3
29
44
  ),
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "ulid-transform"
3
- version = "0.1.0"
3
+ version = "0.2.1"
4
4
  description = "Create and transform ULIDs"
5
5
  authors = ["J. Nick Koston <nick@koston.org>"]
6
6
  license = "MIT"
@@ -27,7 +27,6 @@ script = "build_ext.py"
27
27
 
28
28
  [tool.poetry.dependencies]
29
29
  python = "^3.10"
30
- fast-ulid = "^0.2.0"
31
30
 
32
31
  [tool.poetry.group.dev.dependencies]
33
32
  pytest = "^7.0"
@@ -10,14 +10,11 @@ packages = \
10
10
  package_data = \
11
11
  {'': ['*']}
12
12
 
13
- install_requires = \
14
- ['fast-ulid>=0.2.0,<0.3.0']
15
-
16
13
  setup_kwargs = {
17
14
  'name': 'ulid-transform',
18
- 'version': '0.1.0',
15
+ 'version': '0.2.1',
19
16
  'description': 'Create and transform ULIDs',
20
- 'long_description': '# Fast ULID transformations\n\n<p align="center">\n <a href="https://github.com/bdraco/ulid-transform/actions/workflows/ci.yml?query=branch%3Amain">\n <img src="https://img.shields.io/github/actions/workflow/status/bdraco/ulid-transform/ci.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" >\n </a>\n <a href="https://codecov.io/gh/bdraco/ulid-transform">\n <img src="https://img.shields.io/codecov/c/github/bdraco/ulid-transform.svg?logo=codecov&logoColor=fff&style=flat-square" alt="Test coverage percentage">\n </a>\n</p>\n<p align="center">\n <a href="https://python-poetry.org/">\n <img src="https://img.shields.io/badge/packaging-poetry-299bd7?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAASCAYAAABrXO8xAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAJJSURBVHgBfZLPa1NBEMe/s7tNXoxW1KJQKaUHkXhQvHgW6UHQQ09CBS/6V3hKc/AP8CqCrUcpmop3Cx48eDB4yEECjVQrlZb80CRN8t6OM/teagVxYZi38+Yz853dJbzoMV3MM8cJUcLMSUKIE8AzQ2PieZzFxEJOHMOgMQQ+dUgSAckNXhapU/NMhDSWLs1B24A8sO1xrN4NECkcAC9ASkiIJc6k5TRiUDPhnyMMdhKc+Zx19l6SgyeW76BEONY9exVQMzKExGKwwPsCzza7KGSSWRWEQhyEaDXp6ZHEr416ygbiKYOd7TEWvvcQIeusHYMJGhTwF9y7sGnSwaWyFAiyoxzqW0PM/RjghPxF2pWReAowTEXnDh0xgcLs8l2YQmOrj3N7ByiqEoH0cARs4u78WgAVkoEDIDoOi3AkcLOHU60RIg5wC4ZuTC7FaHKQm8Hq1fQuSOBvX/sodmNJSB5geaF5CPIkUeecdMxieoRO5jz9bheL6/tXjrwCyX/UYBUcjCaWHljx1xiX6z9xEjkYAzbGVnB8pvLmyXm9ep+W8CmsSHQQY77Zx1zboxAV0w7ybMhQmfqdmmw3nEp1I0Z+FGO6M8LZdoyZnuzzBdjISicKRnpxzI9fPb+0oYXsNdyi+d3h9bm9MWYHFtPeIZfLwzmFDKy1ai3p+PDls1Llz4yyFpferxjnyjJDSEy9CaCx5m2cJPerq6Xm34eTrZt3PqxYO1XOwDYZrFlH1fWnpU38Y9HRze3lj0vOujZcXKuuXm3jP+s3KbZVra7y2EAAAAAASUVORK5CYII=" alt="Poetry">\n </a>\n <a href="https://github.com/ambv/black">\n <img src="https://img.shields.io/badge/code%20style-black-000000.svg?style=flat-square" alt="black">\n </a>\n <a href="https://github.com/pre-commit/pre-commit">\n <img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square" alt="pre-commit">\n </a>\n</p>\n<p align="center">\n <a href="https://pypi.org/project/ulid-transform/">\n <img src="https://img.shields.io/pypi/v/ulid-transform.svg?logo=python&logoColor=fff&style=flat-square" alt="PyPI Version">\n </a>\n <img src="https://img.shields.io/pypi/pyversions/ulid-transform.svg?style=flat-square&logo=python&amp;logoColor=fff" alt="Supported Python versions">\n <img src="https://img.shields.io/pypi/l/ulid-transform.svg?style=flat-square" alt="License">\n</p>\n\nCreate and transform ULIDs\n\n## Installation\n\nInstall this via pip (or your favourite package manager):\n\n`pip install ulid-transform`\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- prettier-ignore-start -->\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- markdownlint-disable -->\n<!-- markdownlint-enable -->\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n<!-- prettier-ignore-end -->\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n\n## Credits\n\nThis package was created with\n[Copier](https://copier.readthedocs.io/) and the\n[browniebroke/pypackage-template](https://github.com/browniebroke/pypackage-template)\nproject template.\n',
17
+ 'long_description': '# Fast ULID transformations\n\n<p align="center">\n <a href="https://github.com/bdraco/ulid-transform/actions/workflows/ci.yml?query=branch%3Amain">\n <img src="https://img.shields.io/github/actions/workflow/status/bdraco/ulid-transform/ci.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" >\n </a>\n <a href="https://codecov.io/gh/bdraco/ulid-transform">\n <img src="https://img.shields.io/codecov/c/github/bdraco/ulid-transform.svg?logo=codecov&logoColor=fff&style=flat-square" alt="Test coverage percentage">\n </a>\n</p>\n<p align="center">\n <a href="https://python-poetry.org/">\n <img src="https://img.shields.io/badge/packaging-poetry-299bd7?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAASCAYAAABrXO8xAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAJJSURBVHgBfZLPa1NBEMe/s7tNXoxW1KJQKaUHkXhQvHgW6UHQQ09CBS/6V3hKc/AP8CqCrUcpmop3Cx48eDB4yEECjVQrlZb80CRN8t6OM/teagVxYZi38+Yz853dJbzoMV3MM8cJUcLMSUKIE8AzQ2PieZzFxEJOHMOgMQQ+dUgSAckNXhapU/NMhDSWLs1B24A8sO1xrN4NECkcAC9ASkiIJc6k5TRiUDPhnyMMdhKc+Zx19l6SgyeW76BEONY9exVQMzKExGKwwPsCzza7KGSSWRWEQhyEaDXp6ZHEr416ygbiKYOd7TEWvvcQIeusHYMJGhTwF9y7sGnSwaWyFAiyoxzqW0PM/RjghPxF2pWReAowTEXnDh0xgcLs8l2YQmOrj3N7ByiqEoH0cARs4u78WgAVkoEDIDoOi3AkcLOHU60RIg5wC4ZuTC7FaHKQm8Hq1fQuSOBvX/sodmNJSB5geaF5CPIkUeecdMxieoRO5jz9bheL6/tXjrwCyX/UYBUcjCaWHljx1xiX6z9xEjkYAzbGVnB8pvLmyXm9ep+W8CmsSHQQY77Zx1zboxAV0w7ybMhQmfqdmmw3nEp1I0Z+FGO6M8LZdoyZnuzzBdjISicKRnpxzI9fPb+0oYXsNdyi+d3h9bm9MWYHFtPeIZfLwzmFDKy1ai3p+PDls1Llz4yyFpferxjnyjJDSEy9CaCx5m2cJPerq6Xm34eTrZt3PqxYO1XOwDYZrFlH1fWnpU38Y9HRze3lj0vOujZcXKuuXm3jP+s3KbZVra7y2EAAAAAASUVORK5CYII=" alt="Poetry">\n </a>\n <a href="https://github.com/ambv/black">\n <img src="https://img.shields.io/badge/code%20style-black-000000.svg?style=flat-square" alt="black">\n </a>\n <a href="https://github.com/pre-commit/pre-commit">\n <img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square" alt="pre-commit">\n </a>\n</p>\n<p align="center">\n <a href="https://pypi.org/project/ulid-transform/">\n <img src="https://img.shields.io/pypi/v/ulid-transform.svg?logo=python&logoColor=fff&style=flat-square" alt="PyPI Version">\n </a>\n <img src="https://img.shields.io/pypi/pyversions/ulid-transform.svg?style=flat-square&logo=python&amp;logoColor=fff" alt="Supported Python versions">\n <img src="https://img.shields.io/pypi/l/ulid-transform.svg?style=flat-square" alt="License">\n</p>\n\nCreate and transform ULIDs\n\n## Installation\n\nInstall this via pip (or your favourite package manager):\n\n`pip install ulid-transform`\n\n## Contributors ✨\n\nThanks to https://github.com/suyash/ulid which provides the cython implementation guts.\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- prettier-ignore-start -->\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- markdownlint-disable -->\n<!-- markdownlint-enable -->\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n<!-- prettier-ignore-end -->\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n\n## Credits\n\nThis package was created with\n[Copier](https://copier.readthedocs.io/) and the\n[browniebroke/pypackage-template](https://github.com/browniebroke/pypackage-template)\nproject template.\n',
21
18
  'author': 'J. Nick Koston',
22
19
  'author_email': 'nick@koston.org',
23
20
  'maintainer': 'None',
@@ -26,7 +23,6 @@ setup_kwargs = {
26
23
  'package_dir': package_dir,
27
24
  'packages': packages,
28
25
  'package_data': package_data,
29
- 'install_requires': install_requires,
30
26
  'python_requires': '>=3.10,<4.0',
31
27
  }
32
28
  from build_ext import *
@@ -0,0 +1,5 @@
1
+ __version__ = "0.2.1"
2
+
3
+ from .ulid_impl import ulid_at_time, ulid_hex, ulid_now, ulid_to_bytes
4
+
5
+ __all__ = ["ulid_now", "ulid_at_time", "ulid_hex", "ulid_to_bytes"]
@@ -0,0 +1,20 @@
1
+ # distutils: language = c++
2
+ from libcpp.string cimport string
3
+
4
+ import cython
5
+
6
+
7
+ cdef extern from "ulid_wrapper.h":
8
+ string _cpp_ulid()
9
+ string _cpp_ulid_at_time(double timestamp)
10
+ string _cpp_ulid_to_bytes(string ulid)
11
+
12
+
13
+ def _ulid_now() -> str:
14
+ return _cpp_ulid().decode("ascii")
15
+
16
+ def _ulid_at_time(time: float) -> str:
17
+ return _cpp_ulid_at_time(time).decode("ascii")
18
+
19
+ def _ulid_to_bytes(ulid_str: str) -> bytes:
20
+ return _cpp_ulid_to_bytes(ulid_str.encode("ascii"))
@@ -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
@@ -1,4 +1,6 @@
1
1
  import array
2
+ from random import getrandbits
3
+ from time import time
2
4
 
3
5
  # From https://github.com/ahawker/ulid/blob/06289583e9de4286b4d80b4ad000d137816502ca/ulid/base32.py#L102
4
6
  #: Array that maps encoded string char byte values to enable O(1) lookups.
@@ -264,25 +266,87 @@ DECODE = array.array(
264
266
  ),
265
267
  )
266
268
 
267
- HAS_CYTHON = 0
268
- _str = str
269
269
 
270
- try:
271
- import cython
270
+ def ulid_hex() -> str:
271
+ """Generate a ULID in lowercase hex that will work for a UUID.
272
272
 
273
- HAS_CYTHON = 1
274
- except ImportError:
275
- from ._cython_compat import FAKE_CYTHON as cython
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
276
300
 
301
+ import ulid_transform as ulid_util
302
+ import ulid
303
+ ulid.parse(ulid_util.ulid())
304
+ """
305
+ ulid_bytes = int((timestamp) * 1000).to_bytes(6, byteorder="big") + int(
306
+ getrandbits(80)
307
+ ).to_bytes(10, byteorder="big")
277
308
 
278
- def decode_ulid(value: _str) -> bytes:
309
+ # This is base32 crockford encoding with the loop unrolled for performance
310
+ #
311
+ # This code is adapted from:
312
+ # https://github.com/ahawker/ulid/blob/06289583e9de4286b4d80b4ad000d137816502ca/ulid/base32.py#L102
313
+ #
314
+ enc = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
315
+ return (
316
+ enc[(ulid_bytes[0] & 224) >> 5]
317
+ + enc[ulid_bytes[0] & 31]
318
+ + enc[(ulid_bytes[1] & 248) >> 3]
319
+ + enc[((ulid_bytes[1] & 7) << 2) | ((ulid_bytes[2] & 192) >> 6)]
320
+ + enc[((ulid_bytes[2] & 62) >> 1)]
321
+ + enc[((ulid_bytes[2] & 1) << 4) | ((ulid_bytes[3] & 240) >> 4)]
322
+ + enc[((ulid_bytes[3] & 15) << 1) | ((ulid_bytes[4] & 128) >> 7)]
323
+ + enc[(ulid_bytes[4] & 124) >> 2]
324
+ + enc[((ulid_bytes[4] & 3) << 3) | ((ulid_bytes[5] & 224) >> 5)]
325
+ + enc[ulid_bytes[5] & 31]
326
+ + enc[(ulid_bytes[6] & 248) >> 3]
327
+ + enc[((ulid_bytes[6] & 7) << 2) | ((ulid_bytes[7] & 192) >> 6)]
328
+ + enc[(ulid_bytes[7] & 62) >> 1]
329
+ + enc[((ulid_bytes[7] & 1) << 4) | ((ulid_bytes[8] & 240) >> 4)]
330
+ + enc[((ulid_bytes[8] & 15) << 1) | ((ulid_bytes[9] & 128) >> 7)]
331
+ + enc[(ulid_bytes[9] & 124) >> 2]
332
+ + enc[((ulid_bytes[9] & 3) << 3) | ((ulid_bytes[10] & 224) >> 5)]
333
+ + enc[ulid_bytes[10] & 31]
334
+ + enc[(ulid_bytes[11] & 248) >> 3]
335
+ + enc[((ulid_bytes[11] & 7) << 2) | ((ulid_bytes[12] & 192) >> 6)]
336
+ + enc[(ulid_bytes[12] & 62) >> 1]
337
+ + enc[((ulid_bytes[12] & 1) << 4) | ((ulid_bytes[13] & 240) >> 4)]
338
+ + enc[((ulid_bytes[13] & 15) << 1) | ((ulid_bytes[14] & 128) >> 7)]
339
+ + enc[(ulid_bytes[14] & 124) >> 2]
340
+ + enc[((ulid_bytes[14] & 3) << 3) | ((ulid_bytes[15] & 224) >> 5)]
341
+ + enc[ulid_bytes[15] & 31]
342
+ )
343
+
344
+
345
+ def ulid_to_bytes(value: str) -> bytes:
279
346
  """Decode a ulid to bytes."""
280
347
  if len(value) != 26:
281
348
  raise ValueError("ULID must be 26 characters")
282
349
  encoded = value.encode("ascii")
283
- if cython.compiled:
284
- return _decode_ulid(encoded) # type: ignore[name-defined] # noqa: F821
285
-
286
350
  decoding = DECODE
287
351
  return bytes(
288
352
  (
@@ -334,3 +398,17 @@ def decode_ulid(value: _str) -> bytes:
334
398
  ((decoding[encoded[24]] << 5) | (decoding[encoded[25]])) & 0xFF,
335
399
  )
336
400
  )
401
+
402
+
403
+ try:
404
+ from ._ulid_impl import ( # type: ignore[no-redef] # noqa: F811 F401
405
+ _ulid_at_time as ulid_at_time,
406
+ )
407
+ from ._ulid_impl import ( # type: ignore[no-redef] # noqa: F811 F401
408
+ _ulid_now as ulid_now,
409
+ )
410
+ from ._ulid_impl import ( # type: ignore[no-redef] # noqa: F811 F401
411
+ _ulid_to_bytes as ulid_to_bytes,
412
+ )
413
+ except ImportError:
414
+ pass