Skip to content

Commit

Permalink
Make uuid3 and uuid5 compatible with Python 3.12 (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
aminalaee committed Jun 15, 2024
1 parent 063eec8 commit 2c2161f
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 28 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,17 @@ jobs:
run: make docs_build

linux:
name: "Linux: ${{ matrix.target }}"
name: "Linux: ${{ matrix.target }} Python ${{ matrix.python-version }}"
runs-on: ubuntu-latest
strategy:
matrix:
target: [x86_64, i686]
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "${{ matrix.python-version }}"
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
Expand Down
22 changes: 16 additions & 6 deletions python/uuid_utils/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -142,17 +142,27 @@ def uuid1(node: _Int | None = None, clock_seq: _Int | None = None) -> UUID:
otherwise a random 14-bit sequence number is chosen."""
...

def uuid3(namespace: UUID, name: str) -> UUID:
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
...
if sys.version_info >= (3, 12):
def uuid3(namespace: UUID, name: str | bytes) -> UUID:
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
...
else:
def uuid3(namespace: UUID, name: str) -> UUID:
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
...

def uuid4() -> UUID:
"""Generate a random UUID."""
...

def uuid5(namespace: UUID, name: str) -> UUID:
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
...
if sys.version_info >= (3, 12):
def uuid5(namespace: UUID, name: str | bytes) -> UUID:
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
...
else:
def uuid5(namespace: UUID, name: str) -> UUID:
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
...

def uuid6(
node: _Int | None = None, timestamp: _Int | None = None, nanos: _Int | None = None
Expand Down
24 changes: 18 additions & 6 deletions python/uuid_utils/compat/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
from uuid import (
NAMESPACE_DNS,
NAMESPACE_OID,
Expand Down Expand Up @@ -39,17 +40,28 @@ def uuid1(node: _Int | None = None, clock_seq: _Int | None = None) -> UUID:
otherwise a random 14-bit sequence number is chosen."""
...

def uuid3(namespace: UUID, name: str) -> UUID:
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
...
if sys.version_info >= (3, 12):
def uuid3(namespace: UUID, name: str | bytes) -> UUID:
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
...

else:
def uuid3(namespace: UUID, name: str) -> UUID:
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
...

def uuid4() -> UUID:
"""Generate a random UUID."""
...

def uuid5(namespace: UUID, name: str) -> UUID:
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
...
if sys.version_info >= (3, 12):
def uuid5(namespace: UUID, name: str | bytes) -> UUID:
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
...
else:
def uuid5(namespace: UUID, name: str) -> UUID:
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
...

def uuid6(node: _Int | None = None, timestamp: _Int | None = None) -> UUID:
"""Generate a version 6 UUID using the given timestamp and a host ID.
Expand Down
40 changes: 30 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ pub const RFC_4122: &str = "specified in RFC 4122";
pub const RESERVED_MICROSOFT: &str = "reserved for Microsoft compatibility";
pub const RESERVED_FUTURE: &str = "reserved for future definition";

#[derive(FromPyObject)]
enum StringOrBytes {
#[pyo3(transparent, annotation = "str")]
String(String),
#[pyo3(transparent, annotation = "bytes")]
Bytes(Vec<u8>),
}

#[pyclass(subclass, module = "uuid_utils")]
#[derive(Clone, Debug)]
struct UUID {
Expand Down Expand Up @@ -317,10 +325,15 @@ fn uuid1(node: Option<u64>, clock_seq: Option<u64>) -> PyResult<UUID> {
}

#[pyfunction]
fn uuid3(namespace: UUID, name: &str) -> PyResult<UUID> {
Ok(UUID {
uuid: Uuid::new_v3(&namespace.uuid, name.as_bytes()),
})
fn uuid3(namespace: UUID, name: StringOrBytes) -> PyResult<UUID> {
match name {
StringOrBytes::String(name) => Ok(UUID {
uuid: Uuid::new_v3(&namespace.uuid, name.as_bytes()),
}),
StringOrBytes::Bytes(name) => Ok(UUID {
uuid: Uuid::new_v3(&namespace.uuid, &name),
}),
}
}

#[pyfunction]
Expand All @@ -331,10 +344,15 @@ fn uuid4() -> PyResult<UUID> {
}

#[pyfunction]
fn uuid5(namespace: &UUID, name: &str) -> PyResult<UUID> {
Ok(UUID {
uuid: Uuid::new_v5(&namespace.uuid, name.as_bytes()),
})
fn uuid5(namespace: &UUID, name: StringOrBytes) -> PyResult<UUID> {
match name {
StringOrBytes::String(name) => Ok(UUID {
uuid: Uuid::new_v5(&namespace.uuid, name.as_bytes()),
}),
StringOrBytes::Bytes(name) => Ok(UUID {
uuid: Uuid::new_v5(&namespace.uuid, &name),
}),
}
}

#[pyfunction]
Expand All @@ -347,7 +365,8 @@ fn uuid6(node: Option<u64>, timestamp: Option<u64>, nanos: Option<u32>) -> PyRes

let uuid = match timestamp {
Some(timestamp) => {
let timestamp = Timestamp::from_unix(&Context::new_random(), timestamp, nanos.unwrap_or(0));
let timestamp =
Timestamp::from_unix(&Context::new_random(), timestamp, nanos.unwrap_or(0));
return Ok(UUID {
uuid: Uuid::new_v6(timestamp, node),
});
Expand All @@ -361,7 +380,8 @@ fn uuid6(node: Option<u64>, timestamp: Option<u64>, nanos: Option<u32>) -> PyRes
fn uuid7(timestamp: Option<u64>, nanos: Option<u32>) -> PyResult<UUID> {
let uuid = match timestamp {
Some(timestamp) => {
let timestamp = Timestamp::from_unix(&Context::new_random(), timestamp, nanos.unwrap_or(0));
let timestamp =
Timestamp::from_unix(&Context::new_random(), timestamp, nanos.unwrap_or(0));
return Ok(UUID {
uuid: Uuid::new_v7(timestamp),
});
Expand Down
10 changes: 6 additions & 4 deletions tests/test_uuid.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ def test_uuid1() -> None:
assert isinstance(uuid, uuid_utils.UUID)


def test_uuid3() -> None:
uuid = uuid_utils.uuid3(namespace=uuid_utils.NAMESPACE_DNS, name="python.org")
@pytest.mark.parametrize("name", ["python.org", b"python.org"])
def test_uuid3(name: str) -> None:
uuid = uuid_utils.uuid3(namespace=uuid_utils.NAMESPACE_DNS, name=name)
assert isinstance(uuid, uuid_utils.UUID)


Expand All @@ -83,8 +84,9 @@ def test_uuid4() -> None:
assert isinstance(uuid, uuid_utils.UUID)


def test_uuid5() -> None:
uuid = uuid_utils.uuid5(namespace=uuid_utils.NAMESPACE_DNS, name="python.org")
@pytest.mark.parametrize("name", ["python.org", b"python.org"])
def test_uuid5(name: str) -> None:
uuid = uuid_utils.uuid5(namespace=uuid_utils.NAMESPACE_DNS, name=name)
assert isinstance(uuid, uuid_utils.UUID)


Expand Down

0 comments on commit 2c2161f

Please sign in to comment.