Code Monkey home page Code Monkey logo

uuid6-python's Introduction

uuid6

New time-based UUID formats which are suited for use as a database key.

CI codecov PyPI status Python versions supported Code style: black

This module extends immutable UUID objects (the UUID class) with the functions uuid6(), uuid7(), and uuid8() from the IETF draft.

Install

pip install uuid6

Usage

import uuid6

my_uuid = uuid6.uuid6()
print(my_uuid)
assert my_uuid < uuid6.uuid6()

my_uuid = uuid6.uuid7()
print(my_uuid)
assert my_uuid < uuid6.uuid7()

my_uuid = uuid6.uuid8()
print(my_uuid)
assert my_uuid < uuid6.uuid8()

import uuid

my_uuid = uuid.UUID(hex="C232AB00-9414-11EC-B3C8-9E6BDECED846")
assert uuid6.uuid1_to_uuid6(my_uuid) == uuid.UUID(hex="1EC9414C-232A-6B00-B3C8-9E6BDECED846")

Which UUID version should I use?

Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible.

UUID version 7 features a time-ordered value field derived from the widely implemented and well known Unix Epoch timestamp source, the number of milliseconds since midnight 1 Jan 1970 UTC, leap seconds excluded. As well as improved entropy characteristics over versions 1 or 6.

If your use case requires greater granularity than UUID version 7 can provide, you might consider UUID version 8. UUID version 8 doesn't provide as good entropy characteristics as UUID version 7, but it utilizes timestamp with nanosecond level of precision.

Functions

uuid6.uuid1_to_uuid6(uuid1)

Generate a UUID version 6 object from a UUID version 1 object.

uuid6.uuid6(node=None, clock_seq=None)

Generate a UUID from a host ID, sequence number, and the current time. If node is not given, a random 48-bit number is chosen. If clock_seq is given, it is used as the sequence number; otherwise a random 14-bit sequence number is chosen.

uuid6.uuid7()

Generate a UUID from a random number, and the current time.

uuid6.uuid8()

Generate a UUID from a random number, and the current time.

UUID Version 6

UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. Systems that do not involve legacy UUIDv1 SHOULD use UUIDv7 instead.

UUIDv6 Field and Bit Layout

        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                           time_high                           |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |           time_mid            |  ver  |       time_low        |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |var|         clock_seq         |             node              |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                              node                             |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

UUID Version 7

UUID version 7 features a time-ordered value field derived from the widely implemented and well known Unix Epoch timestamp source, the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. UUID version 7 also has improved entropy characteristics over versions 1 or 6.

UUIDv7 Field and Bit Layout

        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                           unix_ts_ms                          |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |          unix_ts_ms           |  ver  |       rand_a          |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |var|                        rand_b                             |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                            rand_b                             |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

UUID Version 8

UUID version 8 provides an RFC-compatible format for experimental or vendor-specific use cases.

This implementation of uuid8() sacrifices some entropy for granularity compared to uuid7(), while being otherwise compatible.

UUIDv8 Field and Bit Layout

        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                           unix_ts_ms                          |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |          unix_ts_ms           |  ver  |      subsec_a         |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |var|   subsec_b    |         rand                              |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                             rand                              |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • unix_ts_ms: 48 bit big-endian unsigned number of Unix epoch timestamp with millisecond level of precision
  • ver: The 4 bit UUIDv8 version (1000)
  • subsec_a: 12 bits allocated to sub-second precision values
  • var: 2 bit UUID variant (10)
  • subsec_b: 8 bits allocated to sub-second precision values
  • rand: The remaining 54 bits are filled with cryptographically strong random data

20 extra bits dedicated to sub-second precision provide nanosecond resolution. The unix_ts_ms, subsec_a, and subsec_b fields guarantee the order of UUIDs generated within the same nanosecond by monotonically incrementing the timer.

Performance

Run the shell script bench.sh to test on your own machine.

Results

MacBook Air 2020

Python 3.10.4
Mean +- std dev: 870 ns +- 11 ns
Mean +- std dev: 1.17 us +- 0.01 us
Mean +- std dev: 2.18 us +- 0.02 us
Mean +- std dev: 1.60 us +- 0.02 us
Mean +- std dev: 1.78 us +- 0.02 us
+-----------+--------+-----------------------+-----------------------+-----------------------+-----------------------+
| Benchmark | uuid1  | uuid4                 | uuid6                 | uuid7                 | uuid8                 |
+===========+========+=======================+=======================+=======================+=======================+
| timeit    | 870 ns | 1.17 us: 1.35x slower | 2.18 us: 2.51x slower | 1.60 us: 1.84x slower | 1.78 us: 2.04x slower |
+-----------+--------+-----------------------+-----------------------+-----------------------+-----------------------+

uuid6-python's People

Contributors

0xflotus avatar dependabot[bot] avatar oittaa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

uuid6-python's Issues

Max UUID

The draft specifies a max UUID of FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF. Do you think you need this special UUID as a feature in this library?

Bildschirmfoto 2022-11-15 um 23 36 30

Thread Safety?

Since this package is on PyPI and shows up in search engine results, I just wanted to point out that it does not appear to be threadsafe.

The global variable _last_v7_timestamp is getting modified but does not have a lock around it.

python 3.10, ubuntu 18.04 cannot pass test

I saw that OS Independent written in setup.py, and I was working on adding an OS other than ubuntu to the action.

But uuid_7 cannot pass a single testing; function test_time of class UUIDTests in test/test_uuid6.py

Is it critically big difference? or is it safe enough?

....F............
======================================================================
FAIL: test_time (test.test_uuid6.UUIDTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/me/work/uuid6-python/uuid6-python/test/test_uuid6.py", line 102, in test_time
    self.assertAlmostEqual(uuid_6.time / 10**7, uuid_1.time / 10**7, 3)
AssertionError: 13869195802.594696 != 13869195802.591389 within 3 places (0.003307342529296875 difference)

----------------------------------------------------------------------
Ran 17 tests in 0.592s

FAILED (failures=1)

JS implementation for UUIDv7

I had a frontend that I wanted to sometimes generate an ID, and since I'm already playing with using UUIDv7 in my (Python) backend, I thought I'd just figure out how to use that in JS as well.

Anyway, I don't know where it should live, but since it's almost a direct translation of the code in this repo, I thought I'd just post it back here in case someone else finds it useful: https://gist.github.com/jcary741/8b27e5bb821e65457c06e5b6160837dd

@oittaa Thank you so much for creating this great python library! I'm so excited about the new UUID versions, but wouldn't have been able to even try them out without your work to implement them in Python.

Different .time granularity on different platforms?

First of all, thank you for the package!

I've used UUID7 from your package as an ID (token) for user session - I want to use time stored in the token as a creation timestamp directly. And I want to invalidate the token after some time (a day). So what I did was to fetch .time from the UUID and compare it to current time.timestamp. Problem is - on different platforms UUID.time returns different order of values. As a workaround I have to divide by certain value to make it possible to compare.

Final function currently looks like this:

def check_token_expired(uuid: UUID, session_timeout_seconds: int) -> bool:
    """Check if session has expired by uuid v7 timestamp. Returns True if session IS expired."""
    assert isinstance(uuid, UUID)
    now_unix = datetime.now().timestamp()
    uuid_time = uuid.time
    if os.name == 'posix':
        uuid_time = uuid_time / 1000
    if os.name == 'nt':
        uuid_time = uuid_time / 1000000000
    return (now_unix - uuid_time) > session_timeout_seconds

Those os.name == ... comparissons look wrong to me. And it looks like the difference comes from uuid.time, not from datetime.now().timestamp(). Could you help checking this please?

Platforms I've tested on are Windows 10 and WSL with Ubuntu.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.