uuid-utils 0.7.0__tar.gz → 0.8.0__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.
Potentially problematic release.
This version of uuid-utils might be problematic. Click here for more details.
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/.github/workflows/ci.yml +18 -10
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/Cargo.lock +1 -1
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/Cargo.toml +1 -1
- uuid_utils-0.8.0/Makefile +39 -0
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/PKG-INFO +22 -17
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/README.md +21 -16
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/benchmarks/bench_generator.py +4 -4
- uuid_utils-0.8.0/docs/api.md +27 -0
- uuid_utils-0.8.0/docs/index.md +105 -0
- uuid_utils-0.8.0/mkdocs.yml +45 -0
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/pyproject.toml +9 -3
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/python/uuid_utils/__init__.pyi +26 -11
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/python/uuid_utils/compat/__init__.pyi +45 -7
- uuid_utils-0.8.0/requirements.txt +5 -0
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/src/lib.rs +32 -12
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/tests/test_compat/test_compat.py +0 -1
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/tests/test_uuid.py +19 -5
- uuid_utils-0.7.0/Makefile +0 -28
- uuid_utils-0.7.0/requirements.txt +0 -5
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/.gitignore +0 -0
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/LICENSE.md +0 -0
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/benchmarks/README.md +0 -0
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/benchmarks/bench_parser.py +0 -0
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/python/uuid_utils/__init__.py +0 -0
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/python/uuid_utils/compat/__init__.py +0 -0
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/python/uuid_utils/py.typed +0 -0
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/tests/__init__.py +0 -0
- {uuid_utils-0.7.0 → uuid_utils-0.8.0}/tests/test_compat/__init__.py +0 -0
|
@@ -8,9 +8,6 @@ on:
|
|
|
8
8
|
- "*"
|
|
9
9
|
pull_request:
|
|
10
10
|
|
|
11
|
-
permissions:
|
|
12
|
-
contents: read
|
|
13
|
-
|
|
14
11
|
env:
|
|
15
12
|
RUSTFLAGS: "--cfg uuid_unstable"
|
|
16
13
|
|
|
@@ -26,23 +23,22 @@ jobs:
|
|
|
26
23
|
- name: Install dependencies
|
|
27
24
|
run: pip install -r requirements.txt
|
|
28
25
|
- name: Check code
|
|
29
|
-
run:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
mypy .
|
|
33
|
-
ruff .
|
|
26
|
+
run: make lint
|
|
27
|
+
- name: Check docs
|
|
28
|
+
run: make docs_build
|
|
34
29
|
|
|
35
30
|
linux:
|
|
36
|
-
name: "Linux: ${{ matrix.target }}"
|
|
31
|
+
name: "Linux: ${{ matrix.target }} Python ${{ matrix.python-version }}"
|
|
37
32
|
runs-on: ubuntu-latest
|
|
38
33
|
strategy:
|
|
39
34
|
matrix:
|
|
40
35
|
target: [x86_64, i686]
|
|
36
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
41
37
|
steps:
|
|
42
38
|
- uses: actions/checkout@v3
|
|
43
39
|
- uses: actions/setup-python@v4
|
|
44
40
|
with:
|
|
45
|
-
python-version: "
|
|
41
|
+
python-version: "${{ matrix.python-version }}"
|
|
46
42
|
- name: Build wheels
|
|
47
43
|
uses: PyO3/maturin-action@v1
|
|
48
44
|
with:
|
|
@@ -261,3 +257,15 @@ jobs:
|
|
|
261
257
|
with:
|
|
262
258
|
command: upload
|
|
263
259
|
args: --skip-existing *
|
|
260
|
+
|
|
261
|
+
docs:
|
|
262
|
+
name: Publish docs
|
|
263
|
+
runs-on: ubuntu-latest
|
|
264
|
+
if: "startsWith(github.ref, 'refs/tags/')"
|
|
265
|
+
needs: [release]
|
|
266
|
+
steps:
|
|
267
|
+
- uses: actions/checkout@v3
|
|
268
|
+
- name: Build and publish docs
|
|
269
|
+
run: |
|
|
270
|
+
pip install -r requirements.txt
|
|
271
|
+
make docs_build && make docs_deploy
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
.DEFAULT_GOAL := all
|
|
2
|
+
|
|
3
|
+
.PHONY: build
|
|
4
|
+
build:
|
|
5
|
+
RUSTFLAGS="--cfg uuid_unstable" maturin develop --release
|
|
6
|
+
|
|
7
|
+
.PHONY: format
|
|
8
|
+
format:
|
|
9
|
+
ruff check --fix python/ tests/
|
|
10
|
+
ruff format python/ tests/
|
|
11
|
+
cargo fmt
|
|
12
|
+
|
|
13
|
+
.PHONY: lint
|
|
14
|
+
lint:
|
|
15
|
+
ruff check python/ tests/
|
|
16
|
+
ruff format --check --diff python/ tests/
|
|
17
|
+
mypy python/ tests/
|
|
18
|
+
.PHONY: test
|
|
19
|
+
test:
|
|
20
|
+
pytest tests -vvv
|
|
21
|
+
|
|
22
|
+
.PHONY: bench
|
|
23
|
+
bench:
|
|
24
|
+
richbench benchmarks/
|
|
25
|
+
|
|
26
|
+
.PHONY: docs_build
|
|
27
|
+
docs_build:
|
|
28
|
+
mkdocs build
|
|
29
|
+
|
|
30
|
+
.PHONY: docs_serve
|
|
31
|
+
docs_serve:
|
|
32
|
+
mkdocs serve --dev-addr localhost:8080
|
|
33
|
+
|
|
34
|
+
.PHONY: docs_deploy
|
|
35
|
+
docs_deploy:
|
|
36
|
+
mkdocs gh-deploy --force
|
|
37
|
+
|
|
38
|
+
.PHONY: all
|
|
39
|
+
all: format build lint test
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: uuid_utils
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Programming Language :: Python
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -41,8 +41,8 @@ Python UUID implementation using Rust's UUID library.
|
|
|
41
41
|
This will make `uuid4` function around 10x faster.
|
|
42
42
|
|
|
43
43
|
This package can be a drop-in replacement to the standard library UUID
|
|
44
|
-
which implements existing UUID versions like
|
|
45
|
-
and also adds draft UUID versions like
|
|
44
|
+
which implements existing UUID versions like v4 in Rust
|
|
45
|
+
and also adds draft UUID versions like v6.
|
|
46
46
|
|
|
47
47
|
Avaialble UUID versions:
|
|
48
48
|
|
|
@@ -57,10 +57,15 @@ Avaialble UUID versions:
|
|
|
57
57
|
<sup>Please note that UUID versions 6, 7 and 8 are still in draft RFC.</sup><br>
|
|
58
58
|
|
|
59
59
|
## Installation
|
|
60
|
-
|
|
60
|
+
Using `pip`:
|
|
61
61
|
```shell
|
|
62
62
|
$ pip install uuid-utils
|
|
63
63
|
```
|
|
64
|
+
or, using `conda`:
|
|
65
|
+
|
|
66
|
+
```shell
|
|
67
|
+
$ conda install -c conda-forge uuid-utils
|
|
68
|
+
```
|
|
64
69
|
|
|
65
70
|
## Example
|
|
66
71
|
|
|
@@ -84,12 +89,12 @@ UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
|
|
|
84
89
|
UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
|
|
85
90
|
```
|
|
86
91
|
|
|
87
|
-
##
|
|
92
|
+
## Compatibility
|
|
88
93
|
|
|
89
|
-
In some cases you might need `UUID` instances to be returned
|
|
94
|
+
In some cases, for example if you are using `Django`, you might need `UUID` instances to be returned
|
|
90
95
|
from the standrad-library `uuid`, not a custom `UUID` class.
|
|
91
96
|
In that case you can use the `uuid_utils.compat` which comes with a performance penalty
|
|
92
|
-
in comparison with the `uuid_utils` default behaviour, but still faster than the standard-library.
|
|
97
|
+
in comparison with the `uuid_utils` default behaviour, but is still faster than the standard-library.
|
|
93
98
|
|
|
94
99
|
```py
|
|
95
100
|
>>> import uuid_utils.compat as uuid
|
|
@@ -101,16 +106,16 @@ UUID('ffe95fcc-b818-4aca-a350-e0a35b9de6ec')
|
|
|
101
106
|
|
|
102
107
|
## Benchmarks
|
|
103
108
|
|
|
104
|
-
|
|
|
105
|
-
|
|
106
|
-
|
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
| UUID from bytes
|
|
112
|
-
|
|
|
113
|
-
| UUID from fields | 0.028
|
|
109
|
+
| Benchmark | Min | Max | Mean | Min (+) | Max (+) | Mean (+) |
|
|
110
|
+
| ---------------- | ----- | ----- | ----- | ------------- | ------------- | ------------- |
|
|
111
|
+
| UUID v1 | 0.058 | 0.059 | 0.058 | 0.005 (12.0x) | 0.005 (11.9x) | 0.005 (12.0x) |
|
|
112
|
+
| UUID v3 | 0.063 | 0.064 | 0.063 | 0.008 (7.9x) | 0.008 (8.1x) | 0.008 (8.0x) |
|
|
113
|
+
| UUID v4 | 0.041 | 0.041 | 0.041 | 0.004 (11.1x) | 0.004 (10.8x) | 0.004 (10.9x) |
|
|
114
|
+
| UUID v5 | 0.064 | 0.066 | 0.065 | 0.008 (8.1x) | 0.008 (8.1x) | 0.008 (8.1x) |
|
|
115
|
+
| UUID from hex | 0.024 | 0.025 | 0.024 | 0.004 (6.7x) | 0.004 (6.6x) | 0.004 (6.6x) |
|
|
116
|
+
| UUID from bytes | 0.024 | 0.025 | 0.024 | 0.004 (6.7x) | 0.004 (6.6x) | 0.004 (6.7x) |
|
|
117
|
+
| UUID from int | 0.024 | 0.025 | 0.024 | 0.004 (6.6x) | 0.004 (6.7x) | 0.004 (6.6x) |
|
|
118
|
+
| UUID from fields | 0.028 | 0.028 | 0.028 | 0.009 (3.1x) | 0.009 (3.1x) | 0.009 (3.1x) |
|
|
114
119
|
|
|
115
120
|
## How to develop locally
|
|
116
121
|
|
|
@@ -15,8 +15,8 @@ Python UUID implementation using Rust's UUID library.
|
|
|
15
15
|
This will make `uuid4` function around 10x faster.
|
|
16
16
|
|
|
17
17
|
This package can be a drop-in replacement to the standard library UUID
|
|
18
|
-
which implements existing UUID versions like
|
|
19
|
-
and also adds draft UUID versions like
|
|
18
|
+
which implements existing UUID versions like v4 in Rust
|
|
19
|
+
and also adds draft UUID versions like v6.
|
|
20
20
|
|
|
21
21
|
Avaialble UUID versions:
|
|
22
22
|
|
|
@@ -31,10 +31,15 @@ Avaialble UUID versions:
|
|
|
31
31
|
<sup>Please note that UUID versions 6, 7 and 8 are still in draft RFC.</sup><br>
|
|
32
32
|
|
|
33
33
|
## Installation
|
|
34
|
-
|
|
34
|
+
Using `pip`:
|
|
35
35
|
```shell
|
|
36
36
|
$ pip install uuid-utils
|
|
37
37
|
```
|
|
38
|
+
or, using `conda`:
|
|
39
|
+
|
|
40
|
+
```shell
|
|
41
|
+
$ conda install -c conda-forge uuid-utils
|
|
42
|
+
```
|
|
38
43
|
|
|
39
44
|
## Example
|
|
40
45
|
|
|
@@ -58,12 +63,12 @@ UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
|
|
|
58
63
|
UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
|
|
59
64
|
```
|
|
60
65
|
|
|
61
|
-
##
|
|
66
|
+
## Compatibility
|
|
62
67
|
|
|
63
|
-
In some cases you might need `UUID` instances to be returned
|
|
68
|
+
In some cases, for example if you are using `Django`, you might need `UUID` instances to be returned
|
|
64
69
|
from the standrad-library `uuid`, not a custom `UUID` class.
|
|
65
70
|
In that case you can use the `uuid_utils.compat` which comes with a performance penalty
|
|
66
|
-
in comparison with the `uuid_utils` default behaviour, but still faster than the standard-library.
|
|
71
|
+
in comparison with the `uuid_utils` default behaviour, but is still faster than the standard-library.
|
|
67
72
|
|
|
68
73
|
```py
|
|
69
74
|
>>> import uuid_utils.compat as uuid
|
|
@@ -75,16 +80,16 @@ UUID('ffe95fcc-b818-4aca-a350-e0a35b9de6ec')
|
|
|
75
80
|
|
|
76
81
|
## Benchmarks
|
|
77
82
|
|
|
78
|
-
|
|
|
79
|
-
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
83
|
-
|
|
|
84
|
-
|
|
|
85
|
-
| UUID from bytes
|
|
86
|
-
|
|
|
87
|
-
| UUID from fields | 0.028
|
|
83
|
+
| Benchmark | Min | Max | Mean | Min (+) | Max (+) | Mean (+) |
|
|
84
|
+
| ---------------- | ----- | ----- | ----- | ------------- | ------------- | ------------- |
|
|
85
|
+
| UUID v1 | 0.058 | 0.059 | 0.058 | 0.005 (12.0x) | 0.005 (11.9x) | 0.005 (12.0x) |
|
|
86
|
+
| UUID v3 | 0.063 | 0.064 | 0.063 | 0.008 (7.9x) | 0.008 (8.1x) | 0.008 (8.0x) |
|
|
87
|
+
| UUID v4 | 0.041 | 0.041 | 0.041 | 0.004 (11.1x) | 0.004 (10.8x) | 0.004 (10.9x) |
|
|
88
|
+
| UUID v5 | 0.064 | 0.066 | 0.065 | 0.008 (8.1x) | 0.008 (8.1x) | 0.008 (8.1x) |
|
|
89
|
+
| UUID from hex | 0.024 | 0.025 | 0.024 | 0.004 (6.7x) | 0.004 (6.6x) | 0.004 (6.6x) |
|
|
90
|
+
| UUID from bytes | 0.024 | 0.025 | 0.024 | 0.004 (6.7x) | 0.004 (6.6x) | 0.004 (6.7x) |
|
|
91
|
+
| UUID from int | 0.024 | 0.025 | 0.024 | 0.004 (6.6x) | 0.004 (6.7x) | 0.004 (6.6x) |
|
|
92
|
+
| UUID from fields | 0.028 | 0.028 | 0.028 | 0.009 (3.1x) | 0.009 (3.1x) | 0.009 (3.1x) |
|
|
88
93
|
|
|
89
94
|
## How to develop locally
|
|
90
95
|
|
|
@@ -46,8 +46,8 @@ def uuid_utils_uuid5() -> None:
|
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
__benchmarks__ = [
|
|
49
|
-
(uuid_uuid1, uuid_utils_uuid1, "UUID
|
|
50
|
-
(uuid_uuid3, uuid_utils_uuid3, "UUID
|
|
51
|
-
(uuid_uuid4, uuid_utils_uuid4, "UUID
|
|
52
|
-
(uuid_uuid5, uuid_utils_uuid5, "UUID
|
|
49
|
+
(uuid_uuid1, uuid_utils_uuid1, "UUID v1"),
|
|
50
|
+
(uuid_uuid3, uuid_utils_uuid3, "UUID v3"),
|
|
51
|
+
(uuid_uuid4, uuid_utils_uuid4, "UUID v4"),
|
|
52
|
+
(uuid_uuid5, uuid_utils_uuid5, "UUID v5"),
|
|
53
53
|
]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
class `uuid_utils.UUID`
|
|
2
|
+
|
|
3
|
+
| Property | Description |
|
|
4
|
+
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
5
|
+
| `bytes` | the UUID as a 16-byte string (containing the six integer fields in big-endian byte order) |
|
|
6
|
+
| `bytes_le` | the UUID as a 16-byte string (with time_low, time_mid, and time_hi_version in little-endian byte order) |
|
|
7
|
+
| `fields` | a tuple of the six integer fields of the UUID, which are also available as six individual attributes and two derived attributes |
|
|
8
|
+
| `hex` | the UUID as a 32-character hexadecimal string |
|
|
9
|
+
| `int` | the UUID as a 128-bit integer |
|
|
10
|
+
| `urn` | the UUID as a URN as specified in RFC 4122 |
|
|
11
|
+
| `variant` | the UUID variant (one of the constants RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE) |
|
|
12
|
+
| `version` | the UUID version number |
|
|
13
|
+
| `is_safe` | An enum indicating whether the UUID has been generated in a way that is safe for multiprocessing applications, via `uuid_generate_time_safe(3)` |
|
|
14
|
+
| `timestamp` | The timestamp of the UUID in milliseconds since epoch. Only works for UUID versions 1, 6 and 7, otherwise raises `ValueError`. |
|
|
15
|
+
|
|
16
|
+
module `uuid_utils`
|
|
17
|
+
|
|
18
|
+
| Function | Description |
|
|
19
|
+
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
20
|
+
| `uuid1` | Generate a UUID from a host ID, sequence number, and the current time. If `node` is not given, `getnode()` is used to obtain the hardware address. If `clock_seq` is given, it is used as the sequence number; otherwise a random 14-bit sequence number is chosen. |
|
|
21
|
+
| `uuid3` | Generate a UUID from the MD5 hash of a namespace UUID and a name. |
|
|
22
|
+
| `uuid4` | Generate a random UUID. |
|
|
23
|
+
| `uuid5` | Generate a UUID from the SHA-1 hash of a namespace UUID and a name. |
|
|
24
|
+
| `uuid6` | Generate a version 6 UUID using the given timestamp and a host ID. This is similar to version 1 UUIDs, except that it is lexicographically sortable by timestamp. |
|
|
25
|
+
| `uuid7` | Generate a version 7 UUID using a time value and random bytes. |
|
|
26
|
+
| `uuid8` | Generate a custom UUID comprised almost entirely of user-supplied bytes. |
|
|
27
|
+
| `getnode` | Get the hardware address as a 48-bit positive integer. |
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Python UUID Utils
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://pypi.org/project/uuid-utils/">
|
|
5
|
+
<img src="https://badge.fury.io/py/uuid-utils.svg" alt="Package version">
|
|
6
|
+
</a>
|
|
7
|
+
<a href="https://pypi.org/project/uuid-utils" target="_blank">
|
|
8
|
+
<img src="https://img.shields.io/pypi/pyversions/uuid-utils.svg?color=%2334D058" alt="Supported Python versions">
|
|
9
|
+
</a>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
Python UUID implementation using Rust's UUID library.
|
|
15
|
+
This will make `uuid4` function around 10x faster.
|
|
16
|
+
|
|
17
|
+
This package can be a drop-in replacement to the standard library UUID
|
|
18
|
+
which implements existing UUID versions like v4 in Rust
|
|
19
|
+
and also adds draft UUID versions like v6.
|
|
20
|
+
|
|
21
|
+
Avaialble UUID versions:
|
|
22
|
+
|
|
23
|
+
- `uuid1` - Version 1 UUIDs using a timestamp and monotonic counter.
|
|
24
|
+
- `uuid3` - Version 3 UUIDs based on the MD5 hash of some data.
|
|
25
|
+
- `uuid4` - Version 4 UUIDs with random data.
|
|
26
|
+
- `uuid5` - Version 5 UUIDs based on the SHA1 hash of some data.
|
|
27
|
+
- `uuid6` - Version 6 UUIDs using a timestamp and monotonic counter.
|
|
28
|
+
- `uuid7` - Version 7 UUIDs using a Unix timestamp ordered by time.
|
|
29
|
+
- `uuid8` - Version 8 UUIDs using user-defined data.
|
|
30
|
+
|
|
31
|
+
<sup>Please note that UUID versions 6, 7 and 8 are still in draft RFC.</sup><br>
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
Using `pip`:
|
|
35
|
+
```shell
|
|
36
|
+
$ pip install uuid-utils
|
|
37
|
+
```
|
|
38
|
+
or, using `conda`:
|
|
39
|
+
|
|
40
|
+
```shell
|
|
41
|
+
$ conda install -c conda-forge uuid-utils
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Example
|
|
45
|
+
|
|
46
|
+
```shell
|
|
47
|
+
>>> import uuid_utils as uuid
|
|
48
|
+
|
|
49
|
+
>>> # make a random UUID
|
|
50
|
+
>>> uuid.uuid4()
|
|
51
|
+
UUID('ffe95fcc-b818-4aca-a350-e0a35b9de6ec')
|
|
52
|
+
|
|
53
|
+
>>> # make a random UUID using a Unix timestamp which is time-ordered.
|
|
54
|
+
>>> uuid.uuid7()
|
|
55
|
+
UUID('018afa4a-0d21-7e6c-b857-012bc678552b')
|
|
56
|
+
|
|
57
|
+
>>> # make a UUID using a SHA-1 hash of a namespace UUID and a name
|
|
58
|
+
>>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
|
|
59
|
+
UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
|
|
60
|
+
|
|
61
|
+
>>> # make a UUID using an MD5 hash of a namespace UUID and a name
|
|
62
|
+
>>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
|
|
63
|
+
UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Compatibility
|
|
67
|
+
|
|
68
|
+
In some cases, for example if you are using `Django`, you might need `UUID` instances to be returned
|
|
69
|
+
from the standrad-library `uuid`, not a custom `UUID` class.
|
|
70
|
+
In that case you can use the `uuid_utils.compat` which comes with a performance penalty
|
|
71
|
+
in comparison with the `uuid_utils` default behaviour, but is still faster than the standard-library.
|
|
72
|
+
|
|
73
|
+
```py
|
|
74
|
+
>>> import uuid_utils.compat as uuid
|
|
75
|
+
|
|
76
|
+
>>> # make a random UUID
|
|
77
|
+
>>> uuid.uuid4()
|
|
78
|
+
UUID('ffe95fcc-b818-4aca-a350-e0a35b9de6ec')
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Benchmarks
|
|
82
|
+
|
|
83
|
+
| Benchmark | Min | Max | Mean | Min (+) | Max (+) | Mean (+) |
|
|
84
|
+
| ---------------- | ----- | ----- | ----- | ------------- | ------------- | ------------- |
|
|
85
|
+
| UUID v1 | 0.058 | 0.059 | 0.058 | 0.005 (12.0x) | 0.005 (11.9x) | 0.005 (12.0x) |
|
|
86
|
+
| UUID v3 | 0.063 | 0.064 | 0.063 | 0.008 (7.9x) | 0.008 (8.1x) | 0.008 (8.0x) |
|
|
87
|
+
| UUID v4 | 0.041 | 0.041 | 0.041 | 0.004 (11.1x) | 0.004 (10.8x) | 0.004 (10.9x) |
|
|
88
|
+
| UUID v5 | 0.064 | 0.066 | 0.065 | 0.008 (8.1x) | 0.008 (8.1x) | 0.008 (8.1x) |
|
|
89
|
+
| UUID from hex | 0.024 | 0.025 | 0.024 | 0.004 (6.7x) | 0.004 (6.6x) | 0.004 (6.6x) |
|
|
90
|
+
| UUID from bytes | 0.024 | 0.025 | 0.024 | 0.004 (6.7x) | 0.004 (6.6x) | 0.004 (6.7x) |
|
|
91
|
+
| UUID from int | 0.024 | 0.025 | 0.024 | 0.004 (6.6x) | 0.004 (6.7x) | 0.004 (6.6x) |
|
|
92
|
+
| UUID from fields | 0.028 | 0.028 | 0.028 | 0.009 (3.1x) | 0.009 (3.1x) | 0.009 (3.1x) |
|
|
93
|
+
|
|
94
|
+
## How to develop locally
|
|
95
|
+
|
|
96
|
+
```shell
|
|
97
|
+
$ make build
|
|
98
|
+
$ make test
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Or:
|
|
102
|
+
|
|
103
|
+
```shell
|
|
104
|
+
$ RUSTFLAGS="--cfg uuid_unstable" maturin develop --release
|
|
105
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
site_name: UUID-Utils
|
|
2
|
+
site_description: Python bindings to Rust UUID
|
|
3
|
+
site_url: https://aminalaee.dev/uuid-utils
|
|
4
|
+
|
|
5
|
+
theme:
|
|
6
|
+
name: "material"
|
|
7
|
+
palette:
|
|
8
|
+
primary: white
|
|
9
|
+
features:
|
|
10
|
+
- content.code.copy
|
|
11
|
+
|
|
12
|
+
repo_name: aminalaee/uuid-utils
|
|
13
|
+
repo_url: https://github.com/aminalaee/uuid-utils
|
|
14
|
+
edit_uri: ""
|
|
15
|
+
|
|
16
|
+
nav:
|
|
17
|
+
- Introduction: "index.md"
|
|
18
|
+
- API: "api.md"
|
|
19
|
+
|
|
20
|
+
markdown_extensions:
|
|
21
|
+
- markdown.extensions.codehilite:
|
|
22
|
+
guess_lang: false
|
|
23
|
+
- tables
|
|
24
|
+
- pymdownx.details
|
|
25
|
+
- pymdownx.highlight
|
|
26
|
+
- pymdownx.tabbed
|
|
27
|
+
- pymdownx.superfences
|
|
28
|
+
|
|
29
|
+
watch:
|
|
30
|
+
- python/
|
|
31
|
+
|
|
32
|
+
plugins:
|
|
33
|
+
- search
|
|
34
|
+
|
|
35
|
+
extra:
|
|
36
|
+
analytics:
|
|
37
|
+
provider: google
|
|
38
|
+
property: G-MV427T1Z9X
|
|
39
|
+
social:
|
|
40
|
+
- icon: fontawesome/brands/github
|
|
41
|
+
link: https://github.com/aminalaee
|
|
42
|
+
- icon: fontawesome/brands/twitter
|
|
43
|
+
link: https://twitter.com/aminalaee
|
|
44
|
+
- icon: fontawesome/brands/linkedin
|
|
45
|
+
link: https://www.linkedin.com/in/amin-alaee
|
|
@@ -60,12 +60,15 @@ class UUID:
|
|
|
60
60
|
variant the UUID variant (one of the constants RESERVED_NCS,
|
|
61
61
|
RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
|
|
62
62
|
|
|
63
|
-
version the UUID version number
|
|
64
|
-
when the variant is RFC_4122)
|
|
63
|
+
version the UUID version number
|
|
65
64
|
|
|
66
65
|
is_safe An enum indicating whether the UUID has been generated in
|
|
67
66
|
a way that is safe for multiprocessing applications, via
|
|
68
67
|
uuid_generate_time_safe(3).
|
|
68
|
+
|
|
69
|
+
timestamp The timestamp of the UUID in milliseconds since epoch.
|
|
70
|
+
Only works for UUID versions 1, 6 and 7,
|
|
71
|
+
otherwise raises ValueError.
|
|
69
72
|
"""
|
|
70
73
|
|
|
71
74
|
def __init__(
|
|
@@ -139,31 +142,43 @@ def uuid1(node: _Int | None = None, clock_seq: _Int | None = None) -> UUID:
|
|
|
139
142
|
otherwise a random 14-bit sequence number is chosen."""
|
|
140
143
|
...
|
|
141
144
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
+
if sys.version_info >= (3, 12):
|
|
146
|
+
def uuid3(namespace: UUID, name: str | bytes) -> UUID:
|
|
147
|
+
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
|
|
148
|
+
...
|
|
149
|
+
else:
|
|
150
|
+
def uuid3(namespace: UUID, name: str) -> UUID:
|
|
151
|
+
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
|
|
152
|
+
...
|
|
145
153
|
|
|
146
154
|
def uuid4() -> UUID:
|
|
147
155
|
"""Generate a random UUID."""
|
|
148
156
|
...
|
|
149
157
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
158
|
+
if sys.version_info >= (3, 12):
|
|
159
|
+
def uuid5(namespace: UUID, name: str | bytes) -> UUID:
|
|
160
|
+
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
|
|
161
|
+
...
|
|
162
|
+
else:
|
|
163
|
+
def uuid5(namespace: UUID, name: str) -> UUID:
|
|
164
|
+
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
|
|
165
|
+
...
|
|
153
166
|
|
|
154
|
-
def uuid6(
|
|
167
|
+
def uuid6(
|
|
168
|
+
node: _Int | None = None, timestamp: _Int | None = None, nanos: _Int | None = None
|
|
169
|
+
) -> UUID:
|
|
155
170
|
"""Generate a version 6 UUID using the given timestamp and a host ID.
|
|
156
171
|
This is similar to version 1 UUIDs,
|
|
157
172
|
except that it is lexicographically sortable by timestamp.
|
|
158
173
|
"""
|
|
159
174
|
...
|
|
160
175
|
|
|
161
|
-
def uuid7(timestamp: _Int | None = None) -> UUID:
|
|
176
|
+
def uuid7(timestamp: _Int | None = None, nanos: _Int | None = None) -> UUID:
|
|
162
177
|
"""Generate a version 7 UUID using a time value and random bytes."""
|
|
163
178
|
...
|
|
164
179
|
|
|
165
180
|
def uuid8(bytes: _Bytes) -> UUID:
|
|
166
|
-
"""Generate a custom UUID comprised almost entirely of user-supplied bytes
|
|
181
|
+
"""Generate a custom UUID comprised almost entirely of user-supplied bytes."""
|
|
167
182
|
...
|
|
168
183
|
|
|
169
184
|
NAMESPACE_DNS: UUID
|
|
@@ -1,7 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
import sys
|
|
2
|
+
from uuid import (
|
|
3
|
+
NAMESPACE_DNS,
|
|
4
|
+
NAMESPACE_OID,
|
|
5
|
+
NAMESPACE_URL,
|
|
6
|
+
NAMESPACE_X500,
|
|
7
|
+
RESERVED_FUTURE,
|
|
8
|
+
RESERVED_MICROSOFT,
|
|
9
|
+
RESERVED_NCS,
|
|
10
|
+
RFC_4122,
|
|
11
|
+
UUID,
|
|
12
|
+
SafeUUID,
|
|
13
|
+
getnode,
|
|
14
|
+
)
|
|
2
15
|
|
|
3
16
|
from typing_extensions import TypeAlias
|
|
4
17
|
|
|
18
|
+
__all__ = [
|
|
19
|
+
"NAMESPACE_DNS",
|
|
20
|
+
"NAMESPACE_OID",
|
|
21
|
+
"NAMESPACE_URL",
|
|
22
|
+
"NAMESPACE_X500",
|
|
23
|
+
"RESERVED_FUTURE",
|
|
24
|
+
"RESERVED_MICROSOFT",
|
|
25
|
+
"RESERVED_NCS",
|
|
26
|
+
"RFC_4122",
|
|
27
|
+
"UUID",
|
|
28
|
+
"SafeUUID",
|
|
29
|
+
"getnode",
|
|
30
|
+
]
|
|
31
|
+
|
|
5
32
|
# Because UUID has properties called int and bytes we need to rename these temporarily.
|
|
6
33
|
_Int: TypeAlias = int
|
|
7
34
|
_Bytes: TypeAlias = bytes
|
|
@@ -13,17 +40,28 @@ def uuid1(node: _Int | None = None, clock_seq: _Int | None = None) -> UUID:
|
|
|
13
40
|
otherwise a random 14-bit sequence number is chosen."""
|
|
14
41
|
...
|
|
15
42
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
43
|
+
if sys.version_info >= (3, 12):
|
|
44
|
+
def uuid3(namespace: UUID, name: str | bytes) -> UUID:
|
|
45
|
+
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
else:
|
|
49
|
+
def uuid3(namespace: UUID, name: str) -> UUID:
|
|
50
|
+
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
|
|
51
|
+
...
|
|
19
52
|
|
|
20
53
|
def uuid4() -> UUID:
|
|
21
54
|
"""Generate a random UUID."""
|
|
22
55
|
...
|
|
23
56
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
57
|
+
if sys.version_info >= (3, 12):
|
|
58
|
+
def uuid5(namespace: UUID, name: str | bytes) -> UUID:
|
|
59
|
+
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
|
|
60
|
+
...
|
|
61
|
+
else:
|
|
62
|
+
def uuid5(namespace: UUID, name: str) -> UUID:
|
|
63
|
+
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
|
|
64
|
+
...
|
|
27
65
|
|
|
28
66
|
def uuid6(node: _Int | None = None, timestamp: _Int | None = None) -> UUID:
|
|
29
67
|
"""Generate a version 6 UUID using the given timestamp and a host ID.
|
|
@@ -18,6 +18,14 @@ pub const RFC_4122: &str = "specified in RFC 4122";
|
|
|
18
18
|
pub const RESERVED_MICROSOFT: &str = "reserved for Microsoft compatibility";
|
|
19
19
|
pub const RESERVED_FUTURE: &str = "reserved for future definition";
|
|
20
20
|
|
|
21
|
+
#[derive(FromPyObject)]
|
|
22
|
+
enum StringOrBytes {
|
|
23
|
+
#[pyo3(transparent, annotation = "str")]
|
|
24
|
+
String(String),
|
|
25
|
+
#[pyo3(transparent, annotation = "bytes")]
|
|
26
|
+
Bytes(Vec<u8>),
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
#[pyclass(subclass, module = "uuid_utils")]
|
|
22
30
|
#[derive(Clone, Debug)]
|
|
23
31
|
struct UUID {
|
|
@@ -317,10 +325,15 @@ fn uuid1(node: Option<u64>, clock_seq: Option<u64>) -> PyResult<UUID> {
|
|
|
317
325
|
}
|
|
318
326
|
|
|
319
327
|
#[pyfunction]
|
|
320
|
-
fn uuid3(namespace: UUID, name:
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
328
|
+
fn uuid3(namespace: UUID, name: StringOrBytes) -> PyResult<UUID> {
|
|
329
|
+
match name {
|
|
330
|
+
StringOrBytes::String(name) => Ok(UUID {
|
|
331
|
+
uuid: Uuid::new_v3(&namespace.uuid, name.as_bytes()),
|
|
332
|
+
}),
|
|
333
|
+
StringOrBytes::Bytes(name) => Ok(UUID {
|
|
334
|
+
uuid: Uuid::new_v3(&namespace.uuid, &name),
|
|
335
|
+
}),
|
|
336
|
+
}
|
|
324
337
|
}
|
|
325
338
|
|
|
326
339
|
#[pyfunction]
|
|
@@ -331,14 +344,19 @@ fn uuid4() -> PyResult<UUID> {
|
|
|
331
344
|
}
|
|
332
345
|
|
|
333
346
|
#[pyfunction]
|
|
334
|
-
fn uuid5(namespace: &UUID, name:
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
347
|
+
fn uuid5(namespace: &UUID, name: StringOrBytes) -> PyResult<UUID> {
|
|
348
|
+
match name {
|
|
349
|
+
StringOrBytes::String(name) => Ok(UUID {
|
|
350
|
+
uuid: Uuid::new_v5(&namespace.uuid, name.as_bytes()),
|
|
351
|
+
}),
|
|
352
|
+
StringOrBytes::Bytes(name) => Ok(UUID {
|
|
353
|
+
uuid: Uuid::new_v5(&namespace.uuid, &name),
|
|
354
|
+
}),
|
|
355
|
+
}
|
|
338
356
|
}
|
|
339
357
|
|
|
340
358
|
#[pyfunction]
|
|
341
|
-
fn uuid6(node: Option<u64>, timestamp: Option<u64>) -> PyResult<UUID> {
|
|
359
|
+
fn uuid6(node: Option<u64>, timestamp: Option<u64>, nanos: Option<u32>) -> PyResult<UUID> {
|
|
342
360
|
let node = match node {
|
|
343
361
|
Some(node) => node.to_ne_bytes(),
|
|
344
362
|
None => _getnode().to_ne_bytes(),
|
|
@@ -347,7 +365,8 @@ fn uuid6(node: Option<u64>, timestamp: Option<u64>) -> PyResult<UUID> {
|
|
|
347
365
|
|
|
348
366
|
let uuid = match timestamp {
|
|
349
367
|
Some(timestamp) => {
|
|
350
|
-
let timestamp =
|
|
368
|
+
let timestamp =
|
|
369
|
+
Timestamp::from_unix(&Context::new_random(), timestamp, nanos.unwrap_or(0));
|
|
351
370
|
return Ok(UUID {
|
|
352
371
|
uuid: Uuid::new_v6(timestamp, node),
|
|
353
372
|
});
|
|
@@ -358,10 +377,11 @@ fn uuid6(node: Option<u64>, timestamp: Option<u64>) -> PyResult<UUID> {
|
|
|
358
377
|
}
|
|
359
378
|
|
|
360
379
|
#[pyfunction]
|
|
361
|
-
fn uuid7(timestamp: Option<u64>) -> PyResult<UUID> {
|
|
380
|
+
fn uuid7(timestamp: Option<u64>, nanos: Option<u32>) -> PyResult<UUID> {
|
|
362
381
|
let uuid = match timestamp {
|
|
363
382
|
Some(timestamp) => {
|
|
364
|
-
let timestamp =
|
|
383
|
+
let timestamp =
|
|
384
|
+
Timestamp::from_unix(&Context::new_random(), timestamp, nanos.unwrap_or(0));
|
|
365
385
|
return Ok(UUID {
|
|
366
386
|
uuid: Uuid::new_v7(timestamp),
|
|
367
387
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
import pickle
|
|
3
3
|
import sys
|
|
4
|
+
from datetime import datetime
|
|
4
5
|
from uuid import UUID, getnode
|
|
5
6
|
|
|
6
7
|
import pytest
|
|
7
|
-
|
|
8
8
|
import uuid_utils
|
|
9
9
|
|
|
10
10
|
|
|
@@ -73,8 +73,9 @@ def test_uuid1() -> None:
|
|
|
73
73
|
assert isinstance(uuid, uuid_utils.UUID)
|
|
74
74
|
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
@pytest.mark.parametrize("name", ["python.org", b"python.org"])
|
|
77
|
+
def test_uuid3(name: str) -> None:
|
|
78
|
+
uuid = uuid_utils.uuid3(namespace=uuid_utils.NAMESPACE_DNS, name=name)
|
|
78
79
|
assert isinstance(uuid, uuid_utils.UUID)
|
|
79
80
|
|
|
80
81
|
|
|
@@ -83,8 +84,9 @@ def test_uuid4() -> None:
|
|
|
83
84
|
assert isinstance(uuid, uuid_utils.UUID)
|
|
84
85
|
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
@pytest.mark.parametrize("name", ["python.org", b"python.org"])
|
|
88
|
+
def test_uuid5(name: str) -> None:
|
|
89
|
+
uuid = uuid_utils.uuid5(namespace=uuid_utils.NAMESPACE_DNS, name=name)
|
|
88
90
|
assert isinstance(uuid, uuid_utils.UUID)
|
|
89
91
|
|
|
90
92
|
|
|
@@ -92,6 +94,9 @@ def test_uuid6() -> None:
|
|
|
92
94
|
uuid = uuid_utils.uuid6(getnode(), 1679665408)
|
|
93
95
|
assert isinstance(uuid, uuid_utils.UUID)
|
|
94
96
|
|
|
97
|
+
uuid = uuid_utils.uuid6(getnode(), 1679665408, 123)
|
|
98
|
+
assert isinstance(uuid, uuid_utils.UUID)
|
|
99
|
+
|
|
95
100
|
uuid = uuid_utils.uuid6()
|
|
96
101
|
assert isinstance(uuid, uuid_utils.UUID)
|
|
97
102
|
|
|
@@ -100,9 +105,18 @@ def test_uuid7() -> None:
|
|
|
100
105
|
uuid = uuid_utils.uuid7(1679665408)
|
|
101
106
|
assert isinstance(uuid, uuid_utils.UUID)
|
|
102
107
|
|
|
108
|
+
uuid = uuid_utils.uuid7(1679665408, 999)
|
|
109
|
+
assert isinstance(uuid, uuid_utils.UUID)
|
|
110
|
+
|
|
103
111
|
uuid = uuid_utils.uuid7()
|
|
104
112
|
assert isinstance(uuid, uuid_utils.UUID)
|
|
105
113
|
|
|
114
|
+
ts = datetime(
|
|
115
|
+
year=2024, month=1, day=2, hour=3, minute=4, second=5, microsecond=123000
|
|
116
|
+
)
|
|
117
|
+
uuid = uuid_utils.uuid7(int(ts.timestamp()), ts.microsecond * 1_000)
|
|
118
|
+
assert uuid.timestamp == int(ts.timestamp() * 1000)
|
|
119
|
+
|
|
106
120
|
|
|
107
121
|
def test_uuid8() -> None:
|
|
108
122
|
uuid = uuid_utils.uuid8(b"1234567812345678")
|
uuid_utils-0.7.0/Makefile
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
.DEFAULT_GOAL := all
|
|
2
|
-
|
|
3
|
-
.PHONY: build
|
|
4
|
-
build:
|
|
5
|
-
RUSTFLAGS="--cfg uuid_unstable" maturin develop --release
|
|
6
|
-
|
|
7
|
-
.PHONY: format
|
|
8
|
-
format:
|
|
9
|
-
ruff --fix python/ tests/
|
|
10
|
-
black python/ tests/
|
|
11
|
-
cargo fmt
|
|
12
|
-
|
|
13
|
-
.PHONY: lint
|
|
14
|
-
lint:
|
|
15
|
-
ruff python/ tests/
|
|
16
|
-
black --check --diff python/ tests/
|
|
17
|
-
mypy python/ tests/
|
|
18
|
-
.PHONY: test
|
|
19
|
-
test:
|
|
20
|
-
pytest tests -vvv
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
.PHONY: bench
|
|
24
|
-
bench:
|
|
25
|
-
richbench benchmarks/
|
|
26
|
-
|
|
27
|
-
.PHONY: all
|
|
28
|
-
all: format build lint test
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|