lastuuid 0.4.2__cp313-cp313-win_arm64.whl

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.
lastuuid/__init__.py ADDED
@@ -0,0 +1,9 @@
1
+ """
2
+ lastuuid API.
3
+ """
4
+ from .lastuuid import uuid7, uuid7_to_datetime
5
+
6
+ __all__ = [
7
+ "uuid7",
8
+ "uuid7_to_datetime",
9
+ ]
lastuuid/dummies.py ADDED
@@ -0,0 +1,106 @@
1
+ """
2
+ A dummy uuid usefull for unit testing purpose.
3
+
4
+ UUID generated here are full of 0, they does not respect any kind of UUID version,
5
+ they remove a bit of cognitive load while testing.
6
+ """
7
+
8
+ from collections.abc import Callable
9
+ from typing import Iterator
10
+ from uuid import UUID
11
+
12
+ from lastuuid.factories import LastUUIDFactory
13
+
14
+ __all__ = ["uuidgen", "uuid7gen"]
15
+
16
+
17
+ def gen_id() -> Iterator[int]:
18
+ num = 0
19
+ while True:
20
+ num += 1
21
+ yield num
22
+
23
+
24
+ next_id = gen_id()
25
+
26
+
27
+ def _uuidgen(i: int = 0, j: int = 0, k: int = 0, x: int = 0, y: int = 0) -> UUID:
28
+ if i == 0 and y == 0:
29
+ y = next(next_id)
30
+ return UUID(f"{i:0>8}-{j:0>4}-{k:0>4}-{x:0>4}-{y:0>12}")
31
+
32
+
33
+ uuidgen: Callable[..., UUID] = LastUUIDFactory[None](None, _uuidgen) # type: ignore
34
+ """
35
+ A UUID generator that makes UUIDs more readable for humans.
36
+
37
+ # Generate autoincrement UUID that you need to predict
38
+
39
+ Sometime you prepare fixtures with well known UUID and you want to repeat them,
40
+
41
+ uuidgen(1) is more readable that UUID('00000001-0000-0000-0000-000000000000'),
42
+ this is why this function is made for.
43
+ Every section of the uuid can be filled out using `i`, `j`, `k`, `x`, `y` but,
44
+ I personnaly never use more than `i` and `j`.
45
+
46
+ ```python
47
+ >>> from lastuuid.dummies import uuidgen
48
+ >>> uuidgen(1)
49
+ UUID('00000001-0000-0000-0000-000000000000')
50
+ >>> uuidgen(1, 2)
51
+ UUID('00000001-0002-0000-0000-000000000000')
52
+ >>> uuidgen(1, 2, 3, 4, 5)
53
+ UUID('00000001-0002-0003-0004-000000000005')
54
+ ```
55
+
56
+ ```{tip}
57
+ if you don't want a dependency for that, the standard library let you write
58
+ UUID(int=1) which produce UUID('00000000-0000-0000-0000-000000000001').
59
+ ```
60
+
61
+ # Generate autoincrement UUID that you don't need to predict
62
+
63
+ Without any parameter, it will generate UUID where the last bits are incremented.
64
+ It also keep the 10 lasts created values.
65
+
66
+ ```python
67
+ >>> from lastuuid.dummies import uuidgen
68
+ >>> uuidgen()
69
+ UUID('00000000-0000-0000-0000-000000000001')
70
+ >>> uuidgen.last
71
+ UUID('00000000-0000-0000-0000-000000000001')
72
+ >>> uuidgen()
73
+ UUID('00000000-0000-0000-0000-000000000002')
74
+ >>> uuidgen.last
75
+ UUID('00000000-0000-0000-0000-000000000002')
76
+ >>> uuidgen.lasts[1]
77
+ UUID('00000000-0000-0000-0000-000000000001')
78
+ ```
79
+
80
+ """
81
+
82
+ uuid7gen: Callable[..., UUID] = LastUUIDFactory[None](None) # type: ignore
83
+ """
84
+ Generate uuid7 and store the last generated values to get them
85
+ using last and lasts property.
86
+
87
+ ```python
88
+ >>> from lastuuid.dummies import uuid7gen
89
+ >>> uuid7gen()
90
+ UUID('019b5cb2-2fea-7572-8fc6-84fc550278e8')
91
+ >>> uuid7gen.last
92
+ UUID('019b5cb2-2fea-7572-8fc6-84fc550278e8')
93
+ >>> uuid7gen.lasts
94
+ [UUID('019b5cb2-2fea-7572-8fc6-84fc550278e8')]
95
+ >>> uuid7gen()
96
+ UUID('019b5cb2-82e5-709d-a24d-7dba31eb3e82')
97
+ >>> uuid7gen.last
98
+ UUID('019b5cb2-82e5-709d-a24d-7dba31eb3e82')
99
+ >>> uuid7gen.last[0]
100
+ UUID('019b5cb2-82e5-709d-a24d-7dba31eb3e82')
101
+ >>> uuid7gen.lasts[1]
102
+ UUID('019b5cb2-2fea-7572-8fc6-84fc550278e8')
103
+ ```
104
+
105
+ See also {class}`lastuuid.factories.LastUUIDFactory`.
106
+ """
lastuuid/factories.py ADDED
@@ -0,0 +1,104 @@
1
+ """
2
+ Factories for new types.
3
+ """
4
+
5
+ from collections import deque
6
+ from collections.abc import Callable
7
+ from typing import Any, Deque, Generic, TypeVar
8
+ from uuid import UUID
9
+
10
+ from .lastuuid import uuid7
11
+
12
+ __all__ = [
13
+ "NewTypeFactory",
14
+ "LastUUIDFactory",
15
+ ]
16
+
17
+
18
+ T = TypeVar("T", bound=UUID)
19
+
20
+
21
+ class NewTypeFactory(Generic[T]):
22
+ """
23
+ Factory for NewType UUIDs
24
+ """
25
+
26
+ def __init__(self, newtype: Any, id_factory: Callable[[], UUID] = uuid7):
27
+ """
28
+ Create a factory of type that store the last instances.
29
+
30
+ :param newtype: the type to be used
31
+ :param id_factory: the factory to use, uuid7 by default.
32
+ """
33
+ self._newtype = newtype
34
+ self._id_factory = id_factory
35
+
36
+ def __call__(self, *args: Any, **kwargs: Any) -> T:
37
+ """Generate a new value."""
38
+ val = self._id_factory(*args, **kwargs) # type: ignore
39
+ if self._newtype:
40
+ val: T = self._newtype(val) # cast to NewType
41
+ return val
42
+
43
+
44
+ class LastUUIDFactory(NewTypeFactory[T]):
45
+ """
46
+ Keep last UUID generated.
47
+
48
+ ```python
49
+ >>> from typing import NewType
50
+ >>> from uuid import UUID
51
+ >>> from lastuuid.utils import LastUUIDFactory
52
+ >>> ClientId = NewType("ClientId", UUID)
53
+ >>> client_id_factory = LastUUIDFactory[ClientId](ClientId)
54
+ >>> client_id_factory()
55
+ UUID('019b4f7d-f9d1-7d46-922a-7b83c4462366')
56
+ >>> client_id_factory()
57
+ UUID('019b4f7d-f9d2-7471-b6bb-c48f31146c56')
58
+ >>> client_id_factory()
59
+ UUID('019b4f7d-f9d2-7471-b6bb-c490f5b50e3a')
60
+ >>> client_id_factory.last
61
+ UUID('019b4f7d-f9d2-7471-b6bb-c490f5b50e3a')
62
+ >>> client_id_factory.lasts[0]
63
+ UUID('019b4f7d-f9d2-7471-b6bb-c490f5b50e3a')
64
+ >>> client_id_factory.lasts[1]
65
+ UUID('019b4f7d-f9d2-7471-b6bb-c48f31146c56')
66
+ >>> client_id_factory.lasts[2]
67
+ UUID('019b4f7d-f9d1-7d46-922a-7b83c4462366')
68
+ ```
69
+ """
70
+ def __init__(
71
+ self,
72
+ newtype: Any,
73
+ id_factory: Callable[[], UUID] = uuid7,
74
+ cache_size: int = 10,
75
+ ):
76
+ """
77
+ Create a factory of type that store the last instances.
78
+
79
+ :param newtype: the type to be used
80
+ :param cache_size: size of the queue that saved the last uuids
81
+ """
82
+ super().__init__(newtype, id_factory)
83
+ self._cache: Deque[T] = deque(maxlen=cache_size)
84
+
85
+ def __call__(self, *args: Any, **kwargs: Any) -> T:
86
+ """Generate the id and cache it."""
87
+ val = super().__call__(*args, **kwargs)
88
+ self._cache.append(val)
89
+ return val
90
+
91
+ @property
92
+ def last(self) -> T:
93
+ """Most recently generated UUID-NewType instance."""
94
+ return self._cache[-1]
95
+
96
+ @property
97
+ def lasts(self) -> list[T]:
98
+ """
99
+ Returns a list of the last N generated UUID-NewType instances.
100
+
101
+ The list is ordered from most recent to oldest.
102
+ The most recent value is accessible via `last`.
103
+ """
104
+ return list(reversed(self._cache))
Binary file
lastuuid/lastuuid.pyi ADDED
@@ -0,0 +1,14 @@
1
+ """Pyo3 binding interface definition."""
2
+
3
+ from uuid import UUID
4
+ from datetime import datetime, timezone
5
+
6
+
7
+ def uuid7() -> UUID:
8
+ """
9
+ Generate an uuid using uuidv7 format, the best format that feet in a BTree.
10
+ """
11
+
12
+
13
+ def uuid7_to_datetime(uuid7: UUID, tz=timezone.utc) -> datetime:
14
+ """Extract the datetime part of an uuid 7."""
lastuuid/py.typed ADDED
File without changes
lastuuid/utils.py ADDED
@@ -0,0 +1,72 @@
1
+ """
2
+ Utilities methods that may be used for database querying purpose.
3
+
4
+ Because UUIDv7 are timestamped ordered and monotonically increasing,
5
+ there are a good solution for generating primary keys.
6
+
7
+ The design of UUIDv7 feet well with the design of BTree.
8
+
9
+ Because they contains a date time, a UUID range can be compute
10
+ in order to retrieve UUIDs generated at a given time.
11
+
12
+ """
13
+
14
+ from datetime import UTC, date, datetime, time, timedelta
15
+ from uuid import UUID
16
+
17
+ __all__ = [
18
+ "uuid7_bounds_from_datetime",
19
+ "uuid7_bounds_from_date",
20
+ ]
21
+
22
+
23
+ def _datetime_to_uuid7_lowest(dt: datetime) -> UUID:
24
+ unix_ts_ms = int(dt.timestamp() * 1000)
25
+ version = 0x07
26
+ var = 2
27
+ final_bytes = unix_ts_ms.to_bytes(6)
28
+ final_bytes += (version << 12).to_bytes(2)
29
+ final_bytes += ((var << 62) + 0x3000000000000000).to_bytes(8)
30
+ return UUID(bytes=final_bytes)
31
+
32
+
33
+ def uuid7_bounds_from_datetime(
34
+ dt_lower: datetime,
35
+ dt_upper: datetime | None = None,
36
+ ) -> tuple[UUID, UUID]:
37
+ """
38
+ Get uuid bound for a half-open interval.
39
+
40
+ This function can be usefull to search for any rows based on a uuid7 in a sql query.
41
+ If one parameter is set, then the search is based on a millisecond, because uuid7
42
+ are only millisecond precision.
43
+
44
+ The returned bound are half open, so the upper bound, from the ``dt_upper`` will
45
+ not include in the result, only the first value to be excluded.
46
+
47
+ If the the second parameter is ommited, then the bound only contains a millisecond,
48
+ of dt_lower.
49
+
50
+ :param dt_lower: the included left bound of the range.
51
+ :param dt_upper: the excluded right bound of the range.
52
+ """
53
+ return _datetime_to_uuid7_lowest(dt_lower), _datetime_to_uuid7_lowest(
54
+ dt_upper or (dt_lower + timedelta(milliseconds=1))
55
+ )
56
+
57
+
58
+ def uuid7_bounds_from_date(dt: date, tz=UTC) -> tuple[UUID, UUID]:
59
+ """
60
+ Get uuid bound for a particular day.
61
+
62
+ This function can be usefull to search for any rows based on a uuid7 in a sql query.
63
+ The right bound return is the first uuid of the next day that should be excluded.
64
+
65
+ :param dt: the included left bound of the range.
66
+ :param tz: the timezone used to compute the UUID, it should always be ommited.
67
+ """
68
+ return _datetime_to_uuid7_lowest(
69
+ datetime.combine(dt, time=time(tzinfo=tz))
70
+ ), _datetime_to_uuid7_lowest(
71
+ datetime.combine(dt + timedelta(days=1), time=time(tzinfo=tz))
72
+ )
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: lastuuid
3
+ Version: 0.4.2
4
+ Classifier: License :: OSI Approved :: MIT License
5
+ Classifier: Programming Language :: Python :: 3
6
+ Classifier: Programming Language :: Rust
7
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
8
+ Classifier: Typing :: Typed
9
+ Requires-Dist: furo>=2024.5.6 ; extra == 'docs'
10
+ Requires-Dist: linkify-it-py>=2.0.3,<3 ; extra == 'docs'
11
+ Requires-Dist: myst-parser>=3.0.0,<4 ; python_full_version < '3.10' and extra == 'docs'
12
+ Requires-Dist: myst-parser>=4.0.0,<5 ; python_full_version >= '3.10' and extra == 'docs'
13
+ Requires-Dist: sphinx>=7.0.1,<8 ; extra == 'docs'
14
+ Requires-Dist: sphinx-autodoc2>=0.5.0,<1 ; extra == 'docs'
15
+ Provides-Extra: docs
16
+ Summary: Fast UUIDv7 Compatible with standard library type, and utils.
17
+ Keywords: uuid,UUIDv7
18
+ Author-email: Guillaume Gauvrit <guillaume@gauvr.it>
19
+ License: MIT License
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
22
+ Project-URL: Homepage, https://github.com/mardiros/lastuuid
23
+ Project-URL: Documentation, https://mardiros.github.io/lastuuid/
24
+ Project-URL: Repository, https://github.com/mardiros/lastuuid.git
25
+ Project-URL: Issues, https://github.com/mardiros/lastuuid/issues
26
+ Project-URL: Changelog, https://mardiros.github.io/lastuuid/changelog.html
27
+
28
+ # lastuuid - yet another uuid library
29
+
30
+ [![Documentation](https://github.com/mardiros/lastuuid/actions/workflows/publish-doc.yml/badge.svg)](https://mardiros.github.io/lastuuid/)
31
+ [![Continuous Integration](https://github.com/mardiros/lastuuid/actions/workflows/tests.yml/badge.svg)](https://github.com/mardiros/lastuuid/actions/workflows/tests.yml)
32
+
33
+ UUID type is awesome, but, at the moment, the UUID type in the standard library
34
+ does not support the uuid7 format.
35
+
36
+ **lastuuid** provide **fast UUIDv7 generation** made by the
37
+ [rust crate uuid7](https://crates.io/crates/uuid7) **compatible with Pydantic**.
38
+
39
+ It has additional features that may helps for testing or inspecting UUIDv7.
40
+
41
+ ```{note}
42
+ lastuuid is a developer joke based on the nature of UUIDv7,
43
+
44
+ where the most recently generated UUID is always the last one when sorted.
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ ### UUID7
50
+
51
+ ```python
52
+ >>> from lastuuid import uuid7
53
+ >>> uuid7()
54
+ UUID('019316cc-f99a-77b3-89d5-ed8c3cf1f50e')
55
+ ```
56
+
57
+ There is no parameter here, the uuid is generated from the current time.
58
+
59
+ The implementation of uuid7 algorithm is made in the uuid7 rust crate.
60
+
61
+ #### Pydantic
62
+
63
+ This lib has been created because all the other library that implement uuid7
64
+ create there own UUID type, so its not easy to use with pydantic.
65
+
66
+ ```python
67
+ from uuid import UUID
68
+ from pydantic import BaseModel, Field
69
+
70
+ from lastuuid import uuid7
71
+
72
+
73
+ class Event(BaseModel):
74
+ id: UUID = Field(default_factory=uuid7)
75
+
76
+ ```
77
+
78
+ #### NewType
79
+
80
+
81
+ The NewTypeFactory will generate an uuid7 for a new defined type.
82
+
83
+ ```python
84
+ from typing import NewType
85
+
86
+ from uuid import UUID
87
+ from pydantic import BaseModel, Field
88
+
89
+ from lastuuid.utils import NewTypeFactory
90
+
91
+
92
+ MessageID = NewType("MessageID", UUID)
93
+ message_id = NewTypeFactory[MessageID](MessageID)
94
+
95
+
96
+ class Message(BaseModel):
97
+ id: UUID = Field(default_factory=message_id)
98
+
99
+ ```
100
+
101
+ The message_id here will generate a uuid7 typed MessageID,
102
+
103
+ this avoid to write `MessageID(uuid7())` to have a MessageID typed uuid.
104
+
105
+
106
+ #### Performance
107
+
108
+ On my machine the uuid7 is as fast (or slow) as the native uuid4.
109
+
110
+ ```bash
111
+ $ python -m timeit "from lastuuid import uuid7; uuid7()"
112
+ 200000 loops, best of 5: 1.8 usec per loop
113
+
114
+ $ python -m timeit "from uuid import uuid4; uuid4()"
115
+ 200000 loops, best of 5: 1.82 usec per loop
116
+ ```
117
+
118
+ ### Read More
119
+
120
+ There are other usefull function in the library that cab be found in the
121
+ [API documentation](https://mardiros.github.io/lastuuid/).
122
+
123
+ https://mardiros.github.io/lastuuid/
124
+
@@ -0,0 +1,10 @@
1
+ lastuuid-0.4.2.dist-info/METADATA,sha256=Q8jchvK6MUmSgQdwuaEz4DNpQR39AjrS8OyQyvZyzjQ,3843
2
+ lastuuid-0.4.2.dist-info/WHEEL,sha256=J5COssFJIeAczlAAep7Aav_aPF47wuQgCP8ZUSEsJZE,97
3
+ lastuuid/__init__.py,sha256=yW5FLV4ITqTqPOxW-_Lha9ge5jjAfDUz2auXqboXnYU,131
4
+ lastuuid/dummies.py,sha256=q1HKwlKsf0UDvI_Z9mksxstaksIGTwv4DyXvTAqKJ4Y,3018
5
+ lastuuid/factories.py,sha256=-VhQkx5wMJgdB8i8F22uqE8p4O3qu6Qfwefs-ElGUg8,3062
6
+ lastuuid/lastuuid.cp313-win_arm64.pyd,sha256=pnzsiJY3CsoieSqN9EQ6fS7BqnJdKoWlwz2PJc847H0,216064
7
+ lastuuid/lastuuid.pyi,sha256=hu4g_4eOmq8ixpQ2E3FhjD1xfdtPqNRJI4iFm6mMCTU,354
8
+ lastuuid/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ lastuuid/utils.py,sha256=s0jFEy6bb022FAX8hjchSPFaRKErN_KggvCWN989-6M,2479
10
+ lastuuid-0.4.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.10.2)
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-cp313-win_arm64