From e7dcaa29f664f67d52f9c2d9124c361a142693b7 Mon Sep 17 00:00:00 2001 From: Amin Alaee Date: Fri, 14 Jun 2024 11:20:30 +0200 Subject: [PATCH] update --- .github/workflows/ci.yml | 9 ++- Makefile | 13 +++- README.md | 30 +++++----- benchmarks/bench_generator.py | 8 +-- docs/api.md | 27 +++++++++ docs/index.md | 105 +++++++++++++++++++++++++++++++++ mkdocs.yml | 45 ++++++++++++++ python/uuid_utils/__init__.pyi | 9 ++- requirements.txt | 2 + 9 files changed, 223 insertions(+), 25 deletions(-) create mode 100644 docs/api.md create mode 100644 docs/index.md create mode 100644 mkdocs.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59e16fe..a2326a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,8 +26,9 @@ jobs: - name: Install dependencies run: pip install -r requirements.txt - name: Check code - run: | - make lint + run: make lint + - name: Check docs + run: make docs_build linux: name: "Linux: ${{ matrix.target }}" @@ -251,6 +252,10 @@ jobs: - uses: actions/download-artifact@v3 with: name: wheels + - name: Build and publish docs + run: | + pip install -r requirements.txt + make docs_build && make docs_deploy - name: Publish to PyPI uses: PyO3/maturin-action@v1 env: diff --git a/Makefile b/Makefile index e086b31..cd778dc 100644 --- a/Makefile +++ b/Makefile @@ -19,10 +19,21 @@ lint: test: pytest tests -vvv - .PHONY: bench bench: richbench benchmarks/ +.PHONY: docs_build +docs_build: + mkdocs build + +.PHONY: docs_serve +docs_serve: + mkdocs serve --dev-addr localhost:8080 + +.PHONY: docs_deploy +docs_deploy: + mkdocs gh-deploy --force + .PHONY: all all: format build lint test diff --git a/README.md b/README.md index 0266dd0..8db3afc 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ Python UUID implementation using Rust's UUID library. This will make `uuid4` function around 10x faster. This package can be a drop-in replacement to the standard library UUID -which implements existing UUID versions like V4 in Rust -and also adds draft UUID versions like V6. +which implements existing UUID versions like v4 in Rust +and also adds draft UUID versions like v6. Avaialble UUID versions: @@ -63,12 +63,12 @@ UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') ``` -## Compat module +## Compatibility -In some cases you might need `UUID` instances to be returned +In some cases, for example if you are using `Django`, you might need `UUID` instances to be returned from the standrad-library `uuid`, not a custom `UUID` class. In that case you can use the `uuid_utils.compat` which comes with a performance penalty -in comparison with the `uuid_utils` default behaviour, but still faster than the standard-library. +in comparison with the `uuid_utils` default behaviour, but is still faster than the standard-library. ```py >>> import uuid_utils.compat as uuid @@ -80,16 +80,16 @@ UUID('ffe95fcc-b818-4aca-a350-e0a35b9de6ec') ## Benchmarks -| Benchmark | Min | Max | Mean | Min (+) | Max (+) | Mean (+) | -|-----------------|---------|---------|---------|-----------------|-----------------|-----------------| -| UUID V1 | 0.058 | 0.059 | 0.058 | 0.005 (12.0x) | 0.005 (11.9x) | 0.005 (12.0x) | -| UUID V3 | 0.063 | 0.064 | 0.063 | 0.008 (7.9x) | 0.008 (8.1x) | 0.008 (8.0x) | -| UUID V4 | 0.041 | 0.041 | 0.041 | 0.004 (11.1x) | 0.004 (10.8x) | 0.004 (10.9x) | -| UUID V5 | 0.064 | 0.066 | 0.065 | 0.008 (8.1x) | 0.008 (8.1x) | 0.008 (8.1x) | -| UUID from hex | 0.024 | 0.025 | 0.024 | 0.004 (6.7x) | 0.004 (6.6x) | 0.004 (6.6x) | -| UUID from bytes | 0.024 | 0.025 | 0.024 | 0.004 (6.7x) | 0.004 (6.6x) | 0.004 (6.7x) | -| UUID from int | 0.024 | 0.025 | 0.024 | 0.004 (6.6x) | 0.004 (6.7x) | 0.004 (6.6x) | -| UUID from fields | 0.028 | 0.028 | 0.028 | 0.009 (3.1x) | 0.009 (3.1x) | 0.009 (3.1x) | +| Benchmark | Min | Max | Mean | Min (+) | Max (+) | Mean (+) | +| ---------------- | ----- | ----- | ----- | ------------- | ------------- | ------------- | +| UUID v1 | 0.058 | 0.059 | 0.058 | 0.005 (12.0x) | 0.005 (11.9x) | 0.005 (12.0x) | +| UUID v3 | 0.063 | 0.064 | 0.063 | 0.008 (7.9x) | 0.008 (8.1x) | 0.008 (8.0x) | +| UUID v4 | 0.041 | 0.041 | 0.041 | 0.004 (11.1x) | 0.004 (10.8x) | 0.004 (10.9x) | +| UUID v5 | 0.064 | 0.066 | 0.065 | 0.008 (8.1x) | 0.008 (8.1x) | 0.008 (8.1x) | +| UUID from hex | 0.024 | 0.025 | 0.024 | 0.004 (6.7x) | 0.004 (6.6x) | 0.004 (6.6x) | +| UUID from bytes | 0.024 | 0.025 | 0.024 | 0.004 (6.7x) | 0.004 (6.6x) | 0.004 (6.7x) | +| UUID from int | 0.024 | 0.025 | 0.024 | 0.004 (6.6x) | 0.004 (6.7x) | 0.004 (6.6x) | +| UUID from fields | 0.028 | 0.028 | 0.028 | 0.009 (3.1x) | 0.009 (3.1x) | 0.009 (3.1x) | ## How to develop locally diff --git a/benchmarks/bench_generator.py b/benchmarks/bench_generator.py index e028127..1c662d8 100644 --- a/benchmarks/bench_generator.py +++ b/benchmarks/bench_generator.py @@ -46,8 +46,8 @@ def uuid_utils_uuid5() -> None: __benchmarks__ = [ - (uuid_uuid1, uuid_utils_uuid1, "UUID V1"), - (uuid_uuid3, uuid_utils_uuid3, "UUID V3"), - (uuid_uuid4, uuid_utils_uuid4, "UUID V4"), - (uuid_uuid5, uuid_utils_uuid5, "UUID V5"), + (uuid_uuid1, uuid_utils_uuid1, "UUID v1"), + (uuid_uuid3, uuid_utils_uuid3, "UUID v3"), + (uuid_uuid4, uuid_utils_uuid4, "UUID v4"), + (uuid_uuid5, uuid_utils_uuid5, "UUID v5"), ] diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..31d1407 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,27 @@ +class `uuid_utils.UUID` + +| Property | Description | +| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | +| `bytes` | the UUID as a 16-byte string (containing the six integer fields in big-endian byte order) | +| `bytes_le` | the UUID as a 16-byte string (with time_low, time_mid, and time_hi_version in little-endian byte order) | +| `fields` | a tuple of the six integer fields of the UUID, which are also available as six individual attributes and two derived attributes | +| `hex` | the UUID as a 32-character hexadecimal string | +| `int` | the UUID as a 128-bit integer | +| `urn` | the UUID as a URN as specified in RFC 4122 | +| `variant` | the UUID variant (one of the constants RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE) | +| `version` | the UUID version number | +| `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)` | +| `timestamp` | The timestamp of the UUID in milliseconds since epoch. Only works for UUID versions 1, 6 and 7, otherwise raises `ValueError`. | + +module `uuid_utils` + +| Function | Description | +| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `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. | +| `uuid3` | Generate a UUID from the MD5 hash of a namespace UUID and a name. | +| `uuid4` | Generate a random UUID. | +| `uuid5` | Generate a UUID from the SHA-1 hash of a namespace UUID and a name. | +| `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. | +| `uuid7` | Generate a version 7 UUID using a time value and random bytes. | +| `uuid8` | Generate a custom UUID comprised almost entirely of user-supplied bytes. | +| `getnode` | Get the hardware address as a 48-bit positive integer. | \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..8db3afc --- /dev/null +++ b/docs/index.md @@ -0,0 +1,105 @@ +# Python UUID Utils + +

+ + Package version + + + Supported Python versions + +

+ +--- + +Python UUID implementation using Rust's UUID library. +This will make `uuid4` function around 10x faster. + +This package can be a drop-in replacement to the standard library UUID +which implements existing UUID versions like v4 in Rust +and also adds draft UUID versions like v6. + +Avaialble UUID versions: + +- `uuid1` - Version 1 UUIDs using a timestamp and monotonic counter. +- `uuid3` - Version 3 UUIDs based on the MD5 hash of some data. +- `uuid4` - Version 4 UUIDs with random data. +- `uuid5` - Version 5 UUIDs based on the SHA1 hash of some data. +- `uuid6` - Version 6 UUIDs using a timestamp and monotonic counter. +- `uuid7` - Version 7 UUIDs using a Unix timestamp ordered by time. +- `uuid8` - Version 8 UUIDs using user-defined data. + +Please note that UUID versions 6, 7 and 8 are still in draft RFC.
+ +## Installation +Using `pip`: +```shell +$ pip install uuid-utils +``` +or, using `conda`: + +```shell +$ conda install -c conda-forge uuid-utils +``` + +## Example + +```shell +>>> import uuid_utils as uuid + +>>> # make a random UUID +>>> uuid.uuid4() +UUID('ffe95fcc-b818-4aca-a350-e0a35b9de6ec') + +>>> # make a random UUID using a Unix timestamp which is time-ordered. +>>> uuid.uuid7() +UUID('018afa4a-0d21-7e6c-b857-012bc678552b') + +>>> # make a UUID using a SHA-1 hash of a namespace UUID and a name +>>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') +UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') + +>>> # make a UUID using an MD5 hash of a namespace UUID and a name +>>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') +UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') +``` + +## Compatibility + +In some cases, for example if you are using `Django`, you might need `UUID` instances to be returned +from the standrad-library `uuid`, not a custom `UUID` class. +In that case you can use the `uuid_utils.compat` which comes with a performance penalty +in comparison with the `uuid_utils` default behaviour, but is still faster than the standard-library. + +```py +>>> import uuid_utils.compat as uuid + +>>> # make a random UUID +>>> uuid.uuid4() +UUID('ffe95fcc-b818-4aca-a350-e0a35b9de6ec') +``` + +## Benchmarks + +| Benchmark | Min | Max | Mean | Min (+) | Max (+) | Mean (+) | +| ---------------- | ----- | ----- | ----- | ------------- | ------------- | ------------- | +| UUID v1 | 0.058 | 0.059 | 0.058 | 0.005 (12.0x) | 0.005 (11.9x) | 0.005 (12.0x) | +| UUID v3 | 0.063 | 0.064 | 0.063 | 0.008 (7.9x) | 0.008 (8.1x) | 0.008 (8.0x) | +| UUID v4 | 0.041 | 0.041 | 0.041 | 0.004 (11.1x) | 0.004 (10.8x) | 0.004 (10.9x) | +| UUID v5 | 0.064 | 0.066 | 0.065 | 0.008 (8.1x) | 0.008 (8.1x) | 0.008 (8.1x) | +| UUID from hex | 0.024 | 0.025 | 0.024 | 0.004 (6.7x) | 0.004 (6.6x) | 0.004 (6.6x) | +| UUID from bytes | 0.024 | 0.025 | 0.024 | 0.004 (6.7x) | 0.004 (6.6x) | 0.004 (6.7x) | +| UUID from int | 0.024 | 0.025 | 0.024 | 0.004 (6.6x) | 0.004 (6.7x) | 0.004 (6.6x) | +| UUID from fields | 0.028 | 0.028 | 0.028 | 0.009 (3.1x) | 0.009 (3.1x) | 0.009 (3.1x) | + +## How to develop locally + +```shell +$ make build +$ make test +``` + +Or: + +```shell +$ RUSTFLAGS="--cfg uuid_unstable" maturin develop --release +``` diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..b925e8d --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,45 @@ +site_name: UUID-Utils +site_description: Python bindings to Rust UUID +site_url: https://aminalaee.dev/uuid-utils + +theme: + name: "material" + palette: + primary: white + features: + - content.code.copy + +repo_name: aminalaee/uuid-utils +repo_url: https://github.com/aminalaee/uuid-utils +edit_uri: "" + +nav: + - Introduction: "index.md" + - API: "api.md" + +markdown_extensions: + - markdown.extensions.codehilite: + guess_lang: false + - tables + - pymdownx.details + - pymdownx.highlight + - pymdownx.tabbed + - pymdownx.superfences + +watch: + - python/ + +plugins: + - search + +extra: + analytics: + provider: google + property: G-MV427T1Z9X + social: + - icon: fontawesome/brands/github + link: https://github.com/aminalaee + - icon: fontawesome/brands/twitter + link: https://twitter.com/aminalaee + - icon: fontawesome/brands/linkedin + link: https://www.linkedin.com/in/amin-alaee \ No newline at end of file diff --git a/python/uuid_utils/__init__.pyi b/python/uuid_utils/__init__.pyi index 20c6076..4fd8f49 100644 --- a/python/uuid_utils/__init__.pyi +++ b/python/uuid_utils/__init__.pyi @@ -60,12 +60,15 @@ class UUID: variant the UUID variant (one of the constants RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE) - version the UUID version number (1 through 5, meaningful only - when the variant is RFC_4122) + version the UUID version number 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). + + timestamp The timestamp of the UUID in milliseconds since epoch. + Only works for UUID versions 1, 6 and 7, + otherwise raises ValueError. """ def __init__( @@ -165,7 +168,7 @@ def uuid7(timestamp: _Int | None = None, nanos: _Int | None = None) -> UUID: ... def uuid8(bytes: _Bytes) -> UUID: - """Generate a custom UUID comprised almost entirely of user-supplied bytes..""" + """Generate a custom UUID comprised almost entirely of user-supplied bytes.""" ... NAMESPACE_DNS: UUID diff --git a/requirements.txt b/requirements.txt index 9ad53b0..23b6c41 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ +mkdocs==1.6.0 +mkdocs-material==9.5.26 mypy==1.10.0 pytest==8.2.0 ruff==0.4.8