%global _empty_manifest_terminate_build 0 Name: python-ulid-py Version: 1.1.0 Release: 1 Summary: Universally Unique Lexicographically Sortable Identifier License: Apache 2.0 URL: https://github.com/ahawker/ulid Source0: https://mirrors.nju.edu.cn/pypi/web/packages/3b/53/d14a8ec344048e21431821cb49e9a6722384f982b889c2dd449428dbdcc1/ulid-py-1.1.0.tar.gz BuildArch: noarch %description # ulid [![Build Status](https://travis-ci.org/ahawker/ulid.svg?branch=master)](https://travis-ci.org/ahawker/ulid) [![Build Status](https://ci.appveyor.com/api/projects/status/fy0hufnb8h6gwk4d/branch/master?svg=true)](https://ci.appveyor.com/project/ahawker/ulid/branch/master) [![codecov](https://codecov.io/gh/ahawker/ulid/branch/master/graph/badge.svg)](https://codecov.io/gh/ahawker/ulid) [![Code Climate](https://codeclimate.com/github/ahawker/ulid/badges/gpa.svg)](https://codeclimate.com/github/ahawker/ulid) [![Issue Count](https://codeclimate.com/github/ahawker/ulid/badges/issue_count.svg)](https://codeclimate.com/github/ahawker/ulid) [![PyPI Version](https://badge.fury.io/py/ulid-py.svg)](https://badge.fury.io/py/ulid-py) [![PyPI Versions](https://img.shields.io/pypi/pyversions/ulid-py.svg)](https://pypi.python.org/pypi/ulid-py) [![Updates](https://pyup.io/repos/github/ahawker/ulid/shield.svg)](https://pyup.io/repos/github/ahawker/ulid/) [![Documentation Status](https://readthedocs.org/projects/ulid/badge/?version=latest)](http://ulid.readthedocs.io/en/latest/?badge=latest) [Universally Unique Lexicographically Sortable Identifier](https://github.com/alizain/ulid) in [Python 3](https://www.python.org/). ### Status This project is actively maintained. ### Installation To install ulid from [pip](https://pypi.python.org/pypi/pip): ```bash $ pip install ulid-py ``` To install ulid from source: ```bash $ git clone git@github.com:ahawker/ulid.git $ cd ulid && python setup.py install ``` ### Usage Create a brand new ULID. The timestamp value (48-bits) is from [time.time()](https://docs.python.org/3/library/time.html?highlight=time.time#time.time) with millisecond precision. The randomness value (80-bits) is from [os.urandom()](https://docs.python.org/3/library/os.html?highlight=os.urandom#os.urandom). ```python >>> import ulid >>> ulid.new() ``` Create a new ULID from an existing 128-bit value, such as a [UUID](https://docs.python.org/3/library/uuid.html). Supports ULID values as `int`, `bytes`, `str`, and `UUID` types. ```python >>> import ulid, uuid >>> value = uuid.uuid4() >>> value UUID('0983d0a2-ff15-4d83-8f37-7dd945b5aa39') >>> ulid.from_uuid(value) ``` Create a new ULID from an existing timestamp value, such as a [datetime](https://docs.python.org/3/library/datetime.html#module-datetime) object. Supports timestamp values as `int`, `float`, `str`, `bytes`, `bytearray`, `memoryview`, `datetime`, `Timestamp`, and `ULID` types. ```python >>> import datetime, ulid >>> ulid.from_timestamp(datetime.datetime(1999, 1, 1)) ``` Create a new ULID from an existing randomness value. Supports randomness values as `int`, `float`, `str`, `bytes`, `bytearray`, `memoryview`, `Randomness`, and `ULID` types. ```python >>> import os, ulid >>> randomness = os.urandom(10) >>> ulid.from_randomness(randomness) >>> ``` For cases when you don't necessarily control the data type (input from external system), you can use the `parse` method which will attempt to make the correct determination for you. Please note that this will be slightly slower than creating the instance from the respective `from_*` method as it needs to make a number of type/conditional checks. Supports values as `int`, `float`, `str`, `bytes`, `bytearray`, `memoryview`, `uuid.UUID`, and `ULID` types. ```python >>> import ulid >>> value = db.model.get_id() ## Unsure about datatype -- Could be int, UUID, or string? >>> ulid.parse(value) >>> ``` Once you have a ULID object, there are a number of ways to interact with it. The `timestamp` method will give you a snapshot view of the first 48-bits of the ULID while the `randomness` method will give you a snapshot of the last 80-bits. ```python >>> import ulid >>> u = ulid.new() >>> u >>> u.timestamp() >>> u.randomness() ``` The `ULID`, `Timestamp`, and `Randomness` classes all derive from the same base class, a `MemoryView`. A `MemoryView` provides the `bin`, `bytes`, `hex`, `int`, `oct`, and `str`, methods for changing any values representation. ```python >>> import ulid >>> u = ulid.new() >>> u >>> u.timestamp() >>> u.timestamp().int 1497589322893 >>> u.timestamp().bytes b'\x01\\\xafG\x94\x8d' >>> u.timestamp().datetime datetime.datetime(2017, 6, 16, 5, 2, 2, 893000) >>> u.randomness().bytes b'\x02F\xde\xb9\\\xf9\xa5\xecYW' >>> u.bytes[6:] == u.randomness().bytes True >>> u.str '01BJQMF54D093DXEAWZ6JYRPAQ' >>> u.int 1810474399624548315999517391436142935 >>> u.bin '0b1010111001010111101000111100101001000110100000010010001101101111010111001010111001111100110100101111011000101100101010111' >>> u.hex '0x15caf47948d0246deb95cf9a5ec5957' >>> u.oct '0o12712750745106402215572712717464573054527' ``` A `MemoryView` also provides rich comparison functionality. ```python >>> import datetime, time, ulid >>> u1 = ulid.new() >>> time.sleep(5) >>> u2 = ulid.new() >>> u1 < u2 True >>> u3 = ulid.from_timestamp(datetime.datetime(2039, 1, 1)) >>> u1 < u2 < u3 True >>> [u.timestamp().datetime for u in sorted([u2, u3, u1])] [datetime.datetime(2017, 6, 16, 5, 7, 14, 847000), datetime.datetime(2017, 6, 16, 5, 7, 26, 775000), datetime.datetime(2039, 1, 1, 8, 0)] ``` ### Future Items * Collection of benchmarks to track performance. * Backport to Python 2.7? * See [Github Issues](https://github.com/ahawker/ulid/issues) for more! ### Goals A fast implementation in pure python of the spec with binary format support. ### Contributing If you would like to contribute, simply fork the repository, push your changes and send a pull request. Pull requests will be brought into the `master` branch via a rebase and fast-forward merge with the goal of having a linear branch history with no merge commits. ### License [Apache 2.0](LICENSE) ## Why not UUID? UUID can be suboptimal for many uses-cases because: * It isn't the most character efficient way of encoding 128 bits of randomness * UUID v1/v2 is impractical in many environments, as it requires access to a unique, stable MAC address * UUID v3/v5 requires a unique seed and produces randomly distributed IDs, which can cause fragmentation in many data structures * UUID v4 provides no other information than randomness which can cause fragmentation in many data structures ULID provides: * 128-bit compatibility with UUID * 1.21e+24 unique ULIDs per millisecond * Lexicographically sortable! * Canonically encoded as a 26 character string, as opposed to the 36 character UUID * Uses Crockford's base32 for better efficiency and readability (5 bits per character) * Case insensitive * No special characters (URL safe) ## Specification Below is the current specification of ULID as implemented in this repository. The binary format is implemented. ``` 01AN4Z07BY 79KA1307SR9X4MV3 |----------| |----------------| Timestamp Randomness 10chars 16chars 48bits 80bits ``` ### Components **Timestamp** * 48 bit integer * UNIX-time in milliseconds * Won't run out of space till the year 10895 AD. **Randomness** * 80 bits * Cryptographically secure source of randomness, if possible ### Sorting The left-most character must be sorted first, and the right-most character sorted last (lexical order). The default ASCII character set must be used. Within the same millisecond, sort order is not guaranteed ### Encoding Crockford's Base32 is used as shown. This alphabet excludes the letters I, L, O, and U to avoid confusion and abuse. ``` 0123456789ABCDEFGHJKMNPQRSTVWXYZ ``` ### Binary Layout and Byte Order The components are encoded as 16 octets. Each component is encoded with the Most Significant Byte first (network byte order). ``` 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 32_bit_uint_time_high | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 16_bit_uint_time_low | 16_bit_uint_random | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 32_bit_uint_random | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 32_bit_uint_random | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ``` ### String Representation ``` ttttttttttrrrrrrrrrrrrrrrr where t is Timestamp r is Randomness ``` ### Links * [Original Implementation (Javascript)](https://github.com/alizain/ulid) * [ulid (python)](https://github.com/mdipierro/ulid) %package -n python3-ulid-py Summary: Universally Unique Lexicographically Sortable Identifier Provides: python-ulid-py BuildRequires: python3-devel BuildRequires: python3-setuptools BuildRequires: python3-pip %description -n python3-ulid-py # ulid [![Build Status](https://travis-ci.org/ahawker/ulid.svg?branch=master)](https://travis-ci.org/ahawker/ulid) [![Build Status](https://ci.appveyor.com/api/projects/status/fy0hufnb8h6gwk4d/branch/master?svg=true)](https://ci.appveyor.com/project/ahawker/ulid/branch/master) [![codecov](https://codecov.io/gh/ahawker/ulid/branch/master/graph/badge.svg)](https://codecov.io/gh/ahawker/ulid) [![Code Climate](https://codeclimate.com/github/ahawker/ulid/badges/gpa.svg)](https://codeclimate.com/github/ahawker/ulid) [![Issue Count](https://codeclimate.com/github/ahawker/ulid/badges/issue_count.svg)](https://codeclimate.com/github/ahawker/ulid) [![PyPI Version](https://badge.fury.io/py/ulid-py.svg)](https://badge.fury.io/py/ulid-py) [![PyPI Versions](https://img.shields.io/pypi/pyversions/ulid-py.svg)](https://pypi.python.org/pypi/ulid-py) [![Updates](https://pyup.io/repos/github/ahawker/ulid/shield.svg)](https://pyup.io/repos/github/ahawker/ulid/) [![Documentation Status](https://readthedocs.org/projects/ulid/badge/?version=latest)](http://ulid.readthedocs.io/en/latest/?badge=latest) [Universally Unique Lexicographically Sortable Identifier](https://github.com/alizain/ulid) in [Python 3](https://www.python.org/). ### Status This project is actively maintained. ### Installation To install ulid from [pip](https://pypi.python.org/pypi/pip): ```bash $ pip install ulid-py ``` To install ulid from source: ```bash $ git clone git@github.com:ahawker/ulid.git $ cd ulid && python setup.py install ``` ### Usage Create a brand new ULID. The timestamp value (48-bits) is from [time.time()](https://docs.python.org/3/library/time.html?highlight=time.time#time.time) with millisecond precision. The randomness value (80-bits) is from [os.urandom()](https://docs.python.org/3/library/os.html?highlight=os.urandom#os.urandom). ```python >>> import ulid >>> ulid.new() ``` Create a new ULID from an existing 128-bit value, such as a [UUID](https://docs.python.org/3/library/uuid.html). Supports ULID values as `int`, `bytes`, `str`, and `UUID` types. ```python >>> import ulid, uuid >>> value = uuid.uuid4() >>> value UUID('0983d0a2-ff15-4d83-8f37-7dd945b5aa39') >>> ulid.from_uuid(value) ``` Create a new ULID from an existing timestamp value, such as a [datetime](https://docs.python.org/3/library/datetime.html#module-datetime) object. Supports timestamp values as `int`, `float`, `str`, `bytes`, `bytearray`, `memoryview`, `datetime`, `Timestamp`, and `ULID` types. ```python >>> import datetime, ulid >>> ulid.from_timestamp(datetime.datetime(1999, 1, 1)) ``` Create a new ULID from an existing randomness value. Supports randomness values as `int`, `float`, `str`, `bytes`, `bytearray`, `memoryview`, `Randomness`, and `ULID` types. ```python >>> import os, ulid >>> randomness = os.urandom(10) >>> ulid.from_randomness(randomness) >>> ``` For cases when you don't necessarily control the data type (input from external system), you can use the `parse` method which will attempt to make the correct determination for you. Please note that this will be slightly slower than creating the instance from the respective `from_*` method as it needs to make a number of type/conditional checks. Supports values as `int`, `float`, `str`, `bytes`, `bytearray`, `memoryview`, `uuid.UUID`, and `ULID` types. ```python >>> import ulid >>> value = db.model.get_id() ## Unsure about datatype -- Could be int, UUID, or string? >>> ulid.parse(value) >>> ``` Once you have a ULID object, there are a number of ways to interact with it. The `timestamp` method will give you a snapshot view of the first 48-bits of the ULID while the `randomness` method will give you a snapshot of the last 80-bits. ```python >>> import ulid >>> u = ulid.new() >>> u >>> u.timestamp() >>> u.randomness() ``` The `ULID`, `Timestamp`, and `Randomness` classes all derive from the same base class, a `MemoryView`. A `MemoryView` provides the `bin`, `bytes`, `hex`, `int`, `oct`, and `str`, methods for changing any values representation. ```python >>> import ulid >>> u = ulid.new() >>> u >>> u.timestamp() >>> u.timestamp().int 1497589322893 >>> u.timestamp().bytes b'\x01\\\xafG\x94\x8d' >>> u.timestamp().datetime datetime.datetime(2017, 6, 16, 5, 2, 2, 893000) >>> u.randomness().bytes b'\x02F\xde\xb9\\\xf9\xa5\xecYW' >>> u.bytes[6:] == u.randomness().bytes True >>> u.str '01BJQMF54D093DXEAWZ6JYRPAQ' >>> u.int 1810474399624548315999517391436142935 >>> u.bin '0b1010111001010111101000111100101001000110100000010010001101101111010111001010111001111100110100101111011000101100101010111' >>> u.hex '0x15caf47948d0246deb95cf9a5ec5957' >>> u.oct '0o12712750745106402215572712717464573054527' ``` A `MemoryView` also provides rich comparison functionality. ```python >>> import datetime, time, ulid >>> u1 = ulid.new() >>> time.sleep(5) >>> u2 = ulid.new() >>> u1 < u2 True >>> u3 = ulid.from_timestamp(datetime.datetime(2039, 1, 1)) >>> u1 < u2 < u3 True >>> [u.timestamp().datetime for u in sorted([u2, u3, u1])] [datetime.datetime(2017, 6, 16, 5, 7, 14, 847000), datetime.datetime(2017, 6, 16, 5, 7, 26, 775000), datetime.datetime(2039, 1, 1, 8, 0)] ``` ### Future Items * Collection of benchmarks to track performance. * Backport to Python 2.7? * See [Github Issues](https://github.com/ahawker/ulid/issues) for more! ### Goals A fast implementation in pure python of the spec with binary format support. ### Contributing If you would like to contribute, simply fork the repository, push your changes and send a pull request. Pull requests will be brought into the `master` branch via a rebase and fast-forward merge with the goal of having a linear branch history with no merge commits. ### License [Apache 2.0](LICENSE) ## Why not UUID? UUID can be suboptimal for many uses-cases because: * It isn't the most character efficient way of encoding 128 bits of randomness * UUID v1/v2 is impractical in many environments, as it requires access to a unique, stable MAC address * UUID v3/v5 requires a unique seed and produces randomly distributed IDs, which can cause fragmentation in many data structures * UUID v4 provides no other information than randomness which can cause fragmentation in many data structures ULID provides: * 128-bit compatibility with UUID * 1.21e+24 unique ULIDs per millisecond * Lexicographically sortable! * Canonically encoded as a 26 character string, as opposed to the 36 character UUID * Uses Crockford's base32 for better efficiency and readability (5 bits per character) * Case insensitive * No special characters (URL safe) ## Specification Below is the current specification of ULID as implemented in this repository. The binary format is implemented. ``` 01AN4Z07BY 79KA1307SR9X4MV3 |----------| |----------------| Timestamp Randomness 10chars 16chars 48bits 80bits ``` ### Components **Timestamp** * 48 bit integer * UNIX-time in milliseconds * Won't run out of space till the year 10895 AD. **Randomness** * 80 bits * Cryptographically secure source of randomness, if possible ### Sorting The left-most character must be sorted first, and the right-most character sorted last (lexical order). The default ASCII character set must be used. Within the same millisecond, sort order is not guaranteed ### Encoding Crockford's Base32 is used as shown. This alphabet excludes the letters I, L, O, and U to avoid confusion and abuse. ``` 0123456789ABCDEFGHJKMNPQRSTVWXYZ ``` ### Binary Layout and Byte Order The components are encoded as 16 octets. Each component is encoded with the Most Significant Byte first (network byte order). ``` 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 32_bit_uint_time_high | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 16_bit_uint_time_low | 16_bit_uint_random | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 32_bit_uint_random | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 32_bit_uint_random | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ``` ### String Representation ``` ttttttttttrrrrrrrrrrrrrrrr where t is Timestamp r is Randomness ``` ### Links * [Original Implementation (Javascript)](https://github.com/alizain/ulid) * [ulid (python)](https://github.com/mdipierro/ulid) %package help Summary: Development documents and examples for ulid-py Provides: python3-ulid-py-doc %description help # ulid [![Build Status](https://travis-ci.org/ahawker/ulid.svg?branch=master)](https://travis-ci.org/ahawker/ulid) [![Build Status](https://ci.appveyor.com/api/projects/status/fy0hufnb8h6gwk4d/branch/master?svg=true)](https://ci.appveyor.com/project/ahawker/ulid/branch/master) [![codecov](https://codecov.io/gh/ahawker/ulid/branch/master/graph/badge.svg)](https://codecov.io/gh/ahawker/ulid) [![Code Climate](https://codeclimate.com/github/ahawker/ulid/badges/gpa.svg)](https://codeclimate.com/github/ahawker/ulid) [![Issue Count](https://codeclimate.com/github/ahawker/ulid/badges/issue_count.svg)](https://codeclimate.com/github/ahawker/ulid) [![PyPI Version](https://badge.fury.io/py/ulid-py.svg)](https://badge.fury.io/py/ulid-py) [![PyPI Versions](https://img.shields.io/pypi/pyversions/ulid-py.svg)](https://pypi.python.org/pypi/ulid-py) [![Updates](https://pyup.io/repos/github/ahawker/ulid/shield.svg)](https://pyup.io/repos/github/ahawker/ulid/) [![Documentation Status](https://readthedocs.org/projects/ulid/badge/?version=latest)](http://ulid.readthedocs.io/en/latest/?badge=latest) [Universally Unique Lexicographically Sortable Identifier](https://github.com/alizain/ulid) in [Python 3](https://www.python.org/). ### Status This project is actively maintained. ### Installation To install ulid from [pip](https://pypi.python.org/pypi/pip): ```bash $ pip install ulid-py ``` To install ulid from source: ```bash $ git clone git@github.com:ahawker/ulid.git $ cd ulid && python setup.py install ``` ### Usage Create a brand new ULID. The timestamp value (48-bits) is from [time.time()](https://docs.python.org/3/library/time.html?highlight=time.time#time.time) with millisecond precision. The randomness value (80-bits) is from [os.urandom()](https://docs.python.org/3/library/os.html?highlight=os.urandom#os.urandom). ```python >>> import ulid >>> ulid.new() ``` Create a new ULID from an existing 128-bit value, such as a [UUID](https://docs.python.org/3/library/uuid.html). Supports ULID values as `int`, `bytes`, `str`, and `UUID` types. ```python >>> import ulid, uuid >>> value = uuid.uuid4() >>> value UUID('0983d0a2-ff15-4d83-8f37-7dd945b5aa39') >>> ulid.from_uuid(value) ``` Create a new ULID from an existing timestamp value, such as a [datetime](https://docs.python.org/3/library/datetime.html#module-datetime) object. Supports timestamp values as `int`, `float`, `str`, `bytes`, `bytearray`, `memoryview`, `datetime`, `Timestamp`, and `ULID` types. ```python >>> import datetime, ulid >>> ulid.from_timestamp(datetime.datetime(1999, 1, 1)) ``` Create a new ULID from an existing randomness value. Supports randomness values as `int`, `float`, `str`, `bytes`, `bytearray`, `memoryview`, `Randomness`, and `ULID` types. ```python >>> import os, ulid >>> randomness = os.urandom(10) >>> ulid.from_randomness(randomness) >>> ``` For cases when you don't necessarily control the data type (input from external system), you can use the `parse` method which will attempt to make the correct determination for you. Please note that this will be slightly slower than creating the instance from the respective `from_*` method as it needs to make a number of type/conditional checks. Supports values as `int`, `float`, `str`, `bytes`, `bytearray`, `memoryview`, `uuid.UUID`, and `ULID` types. ```python >>> import ulid >>> value = db.model.get_id() ## Unsure about datatype -- Could be int, UUID, or string? >>> ulid.parse(value) >>> ``` Once you have a ULID object, there are a number of ways to interact with it. The `timestamp` method will give you a snapshot view of the first 48-bits of the ULID while the `randomness` method will give you a snapshot of the last 80-bits. ```python >>> import ulid >>> u = ulid.new() >>> u >>> u.timestamp() >>> u.randomness() ``` The `ULID`, `Timestamp`, and `Randomness` classes all derive from the same base class, a `MemoryView`. A `MemoryView` provides the `bin`, `bytes`, `hex`, `int`, `oct`, and `str`, methods for changing any values representation. ```python >>> import ulid >>> u = ulid.new() >>> u >>> u.timestamp() >>> u.timestamp().int 1497589322893 >>> u.timestamp().bytes b'\x01\\\xafG\x94\x8d' >>> u.timestamp().datetime datetime.datetime(2017, 6, 16, 5, 2, 2, 893000) >>> u.randomness().bytes b'\x02F\xde\xb9\\\xf9\xa5\xecYW' >>> u.bytes[6:] == u.randomness().bytes True >>> u.str '01BJQMF54D093DXEAWZ6JYRPAQ' >>> u.int 1810474399624548315999517391436142935 >>> u.bin '0b1010111001010111101000111100101001000110100000010010001101101111010111001010111001111100110100101111011000101100101010111' >>> u.hex '0x15caf47948d0246deb95cf9a5ec5957' >>> u.oct '0o12712750745106402215572712717464573054527' ``` A `MemoryView` also provides rich comparison functionality. ```python >>> import datetime, time, ulid >>> u1 = ulid.new() >>> time.sleep(5) >>> u2 = ulid.new() >>> u1 < u2 True >>> u3 = ulid.from_timestamp(datetime.datetime(2039, 1, 1)) >>> u1 < u2 < u3 True >>> [u.timestamp().datetime for u in sorted([u2, u3, u1])] [datetime.datetime(2017, 6, 16, 5, 7, 14, 847000), datetime.datetime(2017, 6, 16, 5, 7, 26, 775000), datetime.datetime(2039, 1, 1, 8, 0)] ``` ### Future Items * Collection of benchmarks to track performance. * Backport to Python 2.7? * See [Github Issues](https://github.com/ahawker/ulid/issues) for more! ### Goals A fast implementation in pure python of the spec with binary format support. ### Contributing If you would like to contribute, simply fork the repository, push your changes and send a pull request. Pull requests will be brought into the `master` branch via a rebase and fast-forward merge with the goal of having a linear branch history with no merge commits. ### License [Apache 2.0](LICENSE) ## Why not UUID? UUID can be suboptimal for many uses-cases because: * It isn't the most character efficient way of encoding 128 bits of randomness * UUID v1/v2 is impractical in many environments, as it requires access to a unique, stable MAC address * UUID v3/v5 requires a unique seed and produces randomly distributed IDs, which can cause fragmentation in many data structures * UUID v4 provides no other information than randomness which can cause fragmentation in many data structures ULID provides: * 128-bit compatibility with UUID * 1.21e+24 unique ULIDs per millisecond * Lexicographically sortable! * Canonically encoded as a 26 character string, as opposed to the 36 character UUID * Uses Crockford's base32 for better efficiency and readability (5 bits per character) * Case insensitive * No special characters (URL safe) ## Specification Below is the current specification of ULID as implemented in this repository. The binary format is implemented. ``` 01AN4Z07BY 79KA1307SR9X4MV3 |----------| |----------------| Timestamp Randomness 10chars 16chars 48bits 80bits ``` ### Components **Timestamp** * 48 bit integer * UNIX-time in milliseconds * Won't run out of space till the year 10895 AD. **Randomness** * 80 bits * Cryptographically secure source of randomness, if possible ### Sorting The left-most character must be sorted first, and the right-most character sorted last (lexical order). The default ASCII character set must be used. Within the same millisecond, sort order is not guaranteed ### Encoding Crockford's Base32 is used as shown. This alphabet excludes the letters I, L, O, and U to avoid confusion and abuse. ``` 0123456789ABCDEFGHJKMNPQRSTVWXYZ ``` ### Binary Layout and Byte Order The components are encoded as 16 octets. Each component is encoded with the Most Significant Byte first (network byte order). ``` 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 32_bit_uint_time_high | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 16_bit_uint_time_low | 16_bit_uint_random | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 32_bit_uint_random | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 32_bit_uint_random | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ``` ### String Representation ``` ttttttttttrrrrrrrrrrrrrrrr where t is Timestamp r is Randomness ``` ### Links * [Original Implementation (Javascript)](https://github.com/alizain/ulid) * [ulid (python)](https://github.com/mdipierro/ulid) %prep %autosetup -n ulid-py-1.1.0 %build %py3_build %install %py3_install install -d -m755 %{buildroot}/%{_pkgdocdir} if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi pushd %{buildroot} if [ -d usr/lib ]; then find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/lib64 ]; then find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/bin ]; then find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/sbin ]; then find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst fi touch doclist.lst if [ -d usr/share/man ]; then find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst fi popd mv %{buildroot}/filelist.lst . mv %{buildroot}/doclist.lst . %files -n python3-ulid-py -f filelist.lst %dir %{python3_sitelib}/* %files help -f doclist.lst %{_docdir}/* %changelog * Fri Apr 21 2023 Python_Bot - 1.1.0-1 - Package Spec generated