{"id":13468140,"url":"https://github.com/ahawker/ulid","last_synced_at":"2026-01-16T12:22:01.823Z","repository":{"id":40523805,"uuid":"93703838","full_name":"ahawker/ulid","owner":"ahawker","description":"Universally Unique Lexicographically Sortable Identifier (ULID) in Python 3","archived":false,"fork":false,"pushed_at":"2023-03-14T11:26:18.000Z","size":337,"stargazers_count":727,"open_issues_count":8,"forks_count":43,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-09-03T01:35:20.363Z","etag":null,"topics":["python","python3","ulid","uuid"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ahawker.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-06-08T03:30:51.000Z","updated_at":"2025-08-26T13:33:57.000Z","dependencies_parsed_at":"2024-01-15T13:35:54.286Z","dependency_job_id":null,"html_url":"https://github.com/ahawker/ulid","commit_stats":{"total_commits":511,"total_committers":7,"mean_commits":73.0,"dds":0.4794520547945206,"last_synced_commit":"06289583e9de4286b4d80b4ad000d137816502ca"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/ahawker/ulid","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahawker%2Fulid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahawker%2Fulid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahawker%2Fulid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahawker%2Fulid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ahawker","download_url":"https://codeload.github.com/ahawker/ulid/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahawker%2Fulid/sbom","scorecard":{"id":171587,"data":{"date":"2025-08-11","repo":{"name":"github.com/ahawker/ulid","commit":"06289583e9de4286b4d80b4ad000d137816502ca"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"name":"Code-Review","score":3,"reason":"Found 6/19 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":7,"reason":"3 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2025-49 / GHSA-5rjg-fvgr-3xxf","Warn: Project is vulnerable to: GHSA-cx63-2mw6-8hw5","Warn: Project is vulnerable to: PYSEC-2022-43012 / GHSA-r9hx-vwmv-q579"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 25 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-16T16:39:46.125Z","repository_id":40523805,"created_at":"2025-08-16T16:39:46.125Z","updated_at":"2025-08-16T16:39:46.125Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28478570,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["python","python3","ulid","uuid"],"created_at":"2024-07-31T15:01:06.144Z","updated_at":"2026-01-16T12:22:01.803Z","avatar_url":"https://github.com/ahawker.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# ulid\n\n[![Build Status](https://travis-ci.org/ahawker/ulid.svg?branch=master)](https://travis-ci.org/ahawker/ulid)\n[![Build Status](https://ci.appveyor.com/api/projects/status/fy0hufnb8h6gwk4d/branch/master?svg=true)](https://ci.appveyor.com/project/ahawker/ulid/branch/master)\n[![codecov](https://codecov.io/gh/ahawker/ulid/branch/master/graph/badge.svg)](https://codecov.io/gh/ahawker/ulid)\n[![Code Climate](https://codeclimate.com/github/ahawker/ulid/badges/gpa.svg)](https://codeclimate.com/github/ahawker/ulid)\n[![Issue Count](https://codeclimate.com/github/ahawker/ulid/badges/issue_count.svg)](https://codeclimate.com/github/ahawker/ulid)\n\n[![PyPI Version](https://badge.fury.io/py/ulid-py.svg)](https://badge.fury.io/py/ulid-py)\n[![PyPI Versions](https://img.shields.io/pypi/pyversions/ulid-py.svg)](https://pypi.python.org/pypi/ulid-py)\n\n[![Documentation Status](https://readthedocs.org/projects/ulid/badge/?version=latest)](http://ulid.readthedocs.io/en/latest/?badge=latest)\n\n[Universally Unique Lexicographically Sortable Identifier](https://github.com/alizain/ulid) in [Python 3](https://www.python.org/).\n\n### Status\n\nThis project is actively maintained.\n\n### Installation\n\nTo install ulid from [pip](https://pypi.python.org/pypi/pip):\n```bash\n    $ pip install ulid-py\n```\n\nTo install ulid from source:\n```bash\n    $ git clone git@github.com:ahawker/ulid.git\n    $ cd ulid \u0026\u0026 python setup.py install\n```\n\n### Usage\n\nCreate a brand new ULID.\n\nThe timestamp value (48-bits) is from [time.time()](https://docs.python.org/3/library/time.html?highlight=time.time#time.time) with millisecond precision.\n\nThe randomness value (80-bits) is from [os.urandom()](https://docs.python.org/3/library/os.html?highlight=os.urandom#os.urandom).\n\n```python\n\u003e\u003e\u003e import ulid\n\u003e\u003e\u003e ulid.new()\n\u003cULID('01BJQE4QTHMFP0S5J153XCFSP9')\u003e\n```\n\nCreate a new ULID from an existing 128-bit value, such as a [UUID](https://docs.python.org/3/library/uuid.html).\n\nSupports ULID values as `int`, `bytes`, `str`, and `UUID` types.\n\n```python\n\u003e\u003e\u003e import ulid, uuid\n\u003e\u003e\u003e value = uuid.uuid4()\n\u003e\u003e\u003e value\nUUID('0983d0a2-ff15-4d83-8f37-7dd945b5aa39')\n\u003e\u003e\u003e ulid.from_uuid(value)\n\u003cULID('09GF8A5ZRN9P1RYDVXV52VBAHS')\u003e\n```\n\nCreate a new ULID from an existing timestamp value, such as a [datetime](https://docs.python.org/3/library/datetime.html#module-datetime) object.\n\nSupports timestamp values as `int`, `float`, `str`, `bytes`, `bytearray`, `memoryview`, `datetime`, `Timestamp`, and `ULID` types.\n\n```python\n\u003e\u003e\u003e import datetime, ulid\n\u003e\u003e\u003e ulid.from_timestamp(datetime.datetime(1999, 1, 1))\n\u003cULID('00TM9HX0008S220A3PWSFVNFEH')\u003e\n```\n\nCreate a new ULID from an existing randomness value.\n\nSupports randomness values as `int`, `float`, `str`, `bytes`, `bytearray`, `memoryview`, `Randomness`, and `ULID` types.\n\n```python\n\u003e\u003e\u003e import os, ulid\n\u003e\u003e\u003e randomness = os.urandom(10)\n\u003e\u003e\u003e ulid.from_randomness(randomness)\n\u003e\u003e\u003e \u003cULID('01BJQHX2XEDK0VN0GMYWT9JN8S')\u003e\n```\n\nFor cases when you don't necessarily control the data type (input from external system), you can use the `parse` method\nwhich will attempt to make the correct determination for you. Please note that this will be slightly slower than creating\nthe instance from the respective `from_*` method as it needs to make a number of type/conditional checks.\n\nSupports values as `int`, `float`, `str`, `bytes`, `bytearray`, `memoryview`, `uuid.UUID`, and `ULID` types.\n\n```python\n\u003e\u003e\u003e import ulid\n\u003e\u003e\u003e value = db.model.get_id()  ## Unsure about datatype -- Could be int, UUID, or string?\n\u003e\u003e\u003e ulid.parse(value)\n\u003e\u003e\u003e \u003cULID('0K0EDFETFM8SH912DBBD4ABXSZ')\u003e\n```\n\nOnce you have a ULID object, there are a number of ways to interact with it.\n\nThe `timestamp` method will give you a snapshot view of the first 48-bits of the ULID while the `randomness` method\nwill give you a snapshot of the last 80-bits.\n\n```python\n\u003e\u003e\u003e import ulid\n\u003e\u003e\u003e u = ulid.new()\n\u003e\u003e\u003e u\n\u003cULID('01BJQM7SC7D5VVTG3J68ABFQ3N')\u003e\n\u003e\u003e\u003e u.timestamp()\n\u003cTimestamp('01BJQM7SC7')\u003e\n\u003e\u003e\u003e u.randomness()\n\u003cRandomness('D5VVTG3J68ABFQ3N')\u003e\n```\n\nThe `ULID`, `Timestamp`, and `Randomness` classes all derive from the same base class, a `MemoryView`.\n\nA `MemoryView` provides the `bin`, `bytes`, `hex`, `int`, `oct`, and `str`, methods for changing any values representation.\n\n```python\n\u003e\u003e\u003e import ulid\n\u003e\u003e\u003e u = ulid.new()\n\u003e\u003e\u003e u\n\u003cULID('01BJQMF54D093DXEAWZ6JYRPAQ')\u003e\n\u003e\u003e\u003e u.timestamp()\n\u003cTimestamp('01BJQMF54D')\u003e\n\u003e\u003e\u003e u.timestamp().int\n1497589322893\n\u003e\u003e\u003e u.timestamp().bytes\nb'\\x01\\\\\\xafG\\x94\\x8d'\n\u003e\u003e\u003e u.timestamp().datetime\ndatetime.datetime(2017, 6, 16, 5, 2, 2, 893000, tzinfo=datetime.timezone.utc)\n\u003e\u003e\u003e u.randomness().bytes\nb'\\x02F\\xde\\xb9\\\\\\xf9\\xa5\\xecYW'\n\u003e\u003e\u003e u.bytes[6:] == u.randomness().bytes\nTrue\n\u003e\u003e\u003e u.str\n'01BJQMF54D093DXEAWZ6JYRPAQ'\n\u003e\u003e\u003e u.int\n1810474399624548315999517391436142935\n\u003e\u003e\u003e u.bin\n'0b1010111001010111101000111100101001000110100000010010001101101111010111001010111001111100110100101111011000101100101010111'\n\u003e\u003e\u003e u.hex\n'0x015caf47948d0246deb95cf9a5ec5957'\n\u003e\u003e\u003e u.oct\n'0o12712750745106402215572712717464573054527'\n```\n\nA `MemoryView` also provides rich comparison functionality.\n\n```python\n\u003e\u003e\u003e import datetime, time, ulid\n\u003e\u003e\u003e u1 = ulid.new()\n\u003e\u003e\u003e time.sleep(5)\n\u003e\u003e\u003e u2 = ulid.new()\n\u003e\u003e\u003e u1 \u003c u2\nTrue\n\u003e\u003e\u003e u3 = ulid.from_timestamp(datetime.datetime(2039, 1, 1))\n\u003e\u003e\u003e u1 \u003c u2 \u003c u3\nTrue\n\u003e\u003e\u003e [u.timestamp().datetime for u in sorted([u2, u3, u1])]\n[datetime.datetime(2017, 6, 16, 5, 7, 14, 847000, tzinfo=datetime.timezone.utc), datetime.datetime(2017, 6, 16, 5, 7, 26, 775000, tzinfo=datetime.timezone.utc), datetime.datetime(2039, 1, 1, 8, 0, tzinfo=datetime.timezone.utc)]\n```\n\n### Monotonic Support\n\nThis library supports two implementations for stronger guarantees of monotonically increasing randomness.\n\nTo use these implementations, simply import and alias it as `ulid`. They supports an identical interface as `ulid`, so no additional changes should be necessary.\n\n### Thread lock\n\nThe \"thread lock\" implementation is a simple implementation that follows that of the `ulid/spec`. When two or more identifiers are created with the same millisecond, the subsequent identifiers use the previous identifiers randomness value + 1. See [PR 473](https://github.com/ahawker/ulid/pull/473) for more details.\n\n```python\n\u003e\u003e\u003e import time\n\u003e\u003e\u003e from ulid import monotonic as ulid\n\n\u003e\u003e\u003e ts = time.time()\n\u003e\u003e\u003e ulid.from_timestamp(ts)\n\u003cULID('01EFZ62V7VTEQR4Q788PSBBQP8')\u003e\n\u003e\u003e\u003e ulid.from_timestamp(ts)\n\u003cULID('01EFZ62V7VTEQR4Q788PSBBQP9')\u003e\n\u003e\u003e\u003e ulid.from_timestamp(ts)\n\u003cULID('01EFZ62V7VTEQR4Q788PSBBQPA')\u003e\n```\n\n### Microsecond\n\nThe \"microsecond\" implementation is not defined in the `ulid/spec`. It uses a microsecond clock and uses those additional 10-bits into the first two bytes of the randomness value. This means that two identifiers generated within the same millisecond will be monotonically ordered. If two identifiers are generated within the same microsecond, they are ordered entirely by the randomness bytes. See [PR 476](https://github.com/ahawker/ulid/pull/476) for more details.\n\n```python\n\u003e\u003e\u003e from ulid import microsecond as ulid\n\u003e\u003e\u003e ulid.new()\n\u003cULID('01EH0VVVEC0BKJHF0370TNGQ4Z')\u003e\n\u003e\u003e\u003e ulid.new()\n\u003cULID('01EH0VVWPG0C6VDD0529CAHPNJ')\u003e\n\u003e\u003e\u003e ulid.new()\n\u003cULID('01EH0VVX8R0AN45DBYZZYMXVKT')\u003e\n\u003e\u003e\u003e ulid.new()\n\u003cULID('01EH0VVYA406BDKKRVCDJQZHYQ')\u003e\n```\n\n### Contributing\n\nIf you would like to contribute, simply fork the repository, push your changes and send a pull request.\nPull 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.\n\n### License\n\n[Apache 2.0](LICENSE)\n\n## Why not UUID?\n\nUUID can be suboptimal for many uses-cases because:\n\n* It isn't the most character efficient way of encoding 128 bits of randomness\n* UUID v1/v2 is impractical in many environments, as it requires access to a unique, stable MAC address\n* UUID v3/v5 requires a unique seed and produces randomly distributed IDs, which can cause fragmentation in many data structures\n* UUID v4 provides no other information than randomness which can cause fragmentation in many data structures\n\nULID provides:\n\n* 128-bit compatibility with UUID\n* 1.21e+24 unique ULIDs per millisecond\n* Lexicographically sortable!\n* Canonically encoded as a 26 character string, as opposed to the 36 character UUID\n* Uses Crockford's base32 for better efficiency and readability (5 bits per character)\n* Case insensitive\n* No special characters (URL safe)\n\n## Specification\n\nBelow is the current specification of ULID as implemented in this repository.\n\nThe binary format is implemented.\n\n```\n 01AN4Z07BY      79KA1307SR9X4MV3\n\n|----------|    |----------------|\n Timestamp          Randomness\n  10chars            16chars\n   48bits             80bits\n```\n\n### Components\n\n**Timestamp**\n* 48 bit integer\n* UNIX-time in milliseconds\n* Won't run out of space till the year 10895 AD.\n\n**Randomness**\n* 80 bits\n* Cryptographically secure source of randomness, if possible\n\n### Sorting\n\nThe left-most character must be sorted first, and the right-most character sorted last (lexical order).\nThe default ASCII character set must be used. Within the same millisecond, sort order is not guaranteed\n\n### Encoding\n\nCrockford's Base32 is used as shown. This alphabet excludes the letters I, L, O, and U to avoid confusion and abuse.\n\n```\n0123456789ABCDEFGHJKMNPQRSTVWXYZ\n```\n\n### Binary Layout and Byte Order\n\nThe components are encoded as 16 octets. Each component is encoded with the Most Significant Byte first (network byte order).\n\n```\n0                   1                   2                   3\n 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\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n|                      32_bit_uint_time_high                    |\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n|     16_bit_uint_time_low      |       16_bit_uint_random      |\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n|                       32_bit_uint_random                      |\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n|                       32_bit_uint_random                      |\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n```\n\n### String Representation\n\n```\nttttttttttrrrrrrrrrrrrrrrr\n\nwhere\nt is Timestamp\nr is Randomness\n```\n\n### Links\n\n* [Original Implementation (Javascript)](https://github.com/alizain/ulid)\n* [ulid (python)](https://github.com/mdipierro/ulid)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fahawker%2Fulid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fahawker%2Fulid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fahawker%2Fulid/lists"}