diff --git a/python/uuid_utils/__init__.py b/python/uuid_utils/__init__.py index 761eaee..4eec8c4 100644 --- a/python/uuid_utils/__init__.py +++ b/python/uuid_utils/__init__.py @@ -1,3 +1,5 @@ +from uuid import SafeUUID + from ._uuid_utils import ( NAMESPACE_DNS, NAMESPACE_OID, @@ -29,6 +31,7 @@ "RESERVED_NCS", "RFC_4122", "UUID", + "SafeUUID", "__version__", "getnode", "uuid1", diff --git a/python/uuid_utils/__init__.pyi b/python/uuid_utils/__init__.pyi index e49fe40..1bbdfdb 100644 --- a/python/uuid_utils/__init__.pyi +++ b/python/uuid_utils/__init__.pyi @@ -1,6 +1,6 @@ import builtins import sys -from enum import Enum +from uuid import SafeUUID from typing_extensions import TypeAlias @@ -9,11 +9,6 @@ _FieldsType: TypeAlias = tuple[int, int, int, int, int, int] __version__: str -class SafeUUID(Enum): - safe: int - unsafe: int - unknown: None - class UUID: """Instances of the UUID class represent UUIDs as specified in RFC 4122. UUID objects are immutable, hashable, and usable as dictionary keys. @@ -182,3 +177,25 @@ RESERVED_NCS: str RFC_4122: str RESERVED_MICROSOFT: str RESERVED_FUTURE: str + +__all__ = [ + "NAMESPACE_DNS", + "NAMESPACE_OID", + "NAMESPACE_URL", + "NAMESPACE_X500", + "RESERVED_FUTURE", + "RESERVED_MICROSOFT", + "RESERVED_NCS", + "RFC_4122", + "UUID", + "SafeUUID", + "__version__", + "getnode", + "uuid1", + "uuid3", + "uuid4", + "uuid5", + "uuid6", + "uuid7", + "uuid8", +] diff --git a/src/lib.rs b/src/lib.rs index fa6fa4a..052e53e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,18 @@ use mac_address::get_mac_address; use pyo3::{ exceptions::{PyTypeError, PyValueError}, + ffi, prelude::*, pyclass::CompareOp, types::{PyBytes, PyDict}, }; use rand::RngCore; -use std::hash::Hasher; -use std::sync::atomic::{AtomicU64, Ordering}; use std::{collections::hash_map::DefaultHasher, hash::Hash}; +use std::{hash::Hasher, sync::atomic::AtomicPtr}; +use std::{ + ptr::null_mut, + sync::atomic::{AtomicU64, Ordering}, +}; use uuid::{Builder, Bytes, Context, Timestamp, Uuid, Variant, Version}; static NODE: AtomicU64 = AtomicU64::new(0); @@ -306,6 +310,11 @@ impl UUID { uuid: Uuid::from_u128(int), }) } + + #[getter] + fn is_safe(&self) -> *mut ffi::PyObject { + return SAFE_UUID_UNKNOWN.load(Ordering::Relaxed); + } } #[pyfunction] @@ -429,6 +438,9 @@ fn _getnode() -> u64 { node } +// ptr to python stdlib uuid.SafeUUID.unknown +static SAFE_UUID_UNKNOWN: AtomicPtr = AtomicPtr::new(null_mut()); + #[pyfunction] fn getnode() -> PyResult { Ok(_getnode()) @@ -436,6 +448,18 @@ fn getnode() -> PyResult { #[pymodule] fn _uuid_utils(m: &Bound<'_, PyModule>) -> PyResult<()> { + let safe_uuid_unknown = Python::with_gil(|py| { + return PyModule::import_bound(py, "uuid") + .unwrap() + .getattr("SafeUUID") + .unwrap() + .getattr("unknown") + .unwrap() + .unbind(); + }); + + SAFE_UUID_UNKNOWN.store(safe_uuid_unknown.into_ptr(), Ordering::Relaxed); + m.add("__version__", env!("CARGO_PKG_VERSION"))?; m.add_class::()?; m.add_function(wrap_pyfunction!(uuid1, m)?)?; diff --git a/tests/test_uuid.py b/tests/test_uuid.py index f023845..b33e988 100644 --- a/tests/test_uuid.py +++ b/tests/test_uuid.py @@ -2,7 +2,7 @@ import pickle import sys from datetime import datetime -from uuid import UUID, getnode +from uuid import UUID, SafeUUID, getnode import pytest import uuid_utils @@ -200,6 +200,11 @@ def test_copy() -> None: assert copy.deepcopy(uuid) == uuid +def test_is_safe() -> None: + assert uuid_utils.uuid1().is_safe is SafeUUID.unknown + assert uuid_utils.uuid4().is_safe is SafeUUID.unknown + + @pytest.mark.xfail(sys.platform == "linux", reason="Might fail in Github Actions") def test_getnode() -> None: assert uuid_utils.getnode() == getnode()