1
0
Fork
You've already forked python
0
Pretty cool IDs for your API
  • Python 100%
Find a file
Ale d7d60f792c
All checks were successful
Publish / run (push) Successful in 1m50s
Merge pull request 'Allow custom alphabets for encoding' ( #4 ) from feature/encoding-custom-alphabet into master
Reviewed-on: #4 
2026年04月18日 13:44:31 +02:00
.forgejo/workflows chore(ci): skip Python 3.13 for main test run 2026年04月18日 13:41:43 +02:00
pretty_id Allow custom alphabets for encoding 2026年04月18日 13:41:43 +02:00
tests Allow custom alphabets for encoding 2026年04月18日 13:41:43 +02:00
.editorconfig add tests and CI 2026年04月15日 13:48:56 +05:00
.gitignore initial commit 2024年08月21日 20:48:34 +07:00
LICENSE.md initial commit 2024年08月21日 20:48:34 +07:00
pyproject.toml 0.3.6 2026年04月18日 16:43:44 +05:00
README.md feature: add SQLAlchemy support 2024年08月21日 22:50:12 +07:00
setup.cfg initial commit 2024年08月21日 20:48:34 +07:00
uv.lock 0.3.6 2026年04月18日 16:43:44 +05:00

PrettyId

Pretty cool IDs for your APIs.

poetry add prettyid

Synopsis

Generate prefixed IDs, like Stripe does:

>>> from pretty_id import PrettyId
>>> pid = PrettyId.random("task")
PrettyId("task_068n34jrjdth1fqr2nm9a0sh50")
>>> pid.type, pid.id
('task', '068n34jrjdth1fqr2nm9a0sh50')
>>> pid.bytes
b'...'

Backwards compatible with UUID:

>>> pid = PrettyId.from_uuid("1d4e2ea4-c1ab-4a98-8eeb-898051ef0f71", type="task")
PrettyId("task_3n72x961nd59h3qbh6053vrfe4")
>>> pid.uuid
UUID('1d4e2ea4-c1ab-4a98-8eeb-898051ef0f71')

Works with Pydantic and FastAPI:

@app.route("/tasks/{id}")
def get_task_by_id(id: FriendlyId):
 if id.type != "task":
 raise HTTPException(status_code=400, detail="ID should start with 'task_'")
 return {
 "id": id,
 "title": "TODO",
 }

And with SQLAlchemy:

from pretty_id.ext.sqlalchemy import PrettyIdBinaryType
class TaskModel(Base):
 id: Mapped[PrettyId] = mapped_column(
 PrettyIdBinaryType("task"),
 index=True,
 unique=True,
 primary_key=True,
 default=partial(PrettyId.random, "task")
 )
 title: Mapped[str]
# Pass PrettyId instance or just string
select(TaskModel).filter(
 TaskModel.id == "task_068n34jrjdth1fqr2nm9a0sh50"
)

Design

Generated IDs use UUIDv7 underneath:

>>> u = UUID(bytes=pid.bytes)
UUID('01917192-7b9b-7b10-bf5b-15ec95039128')
>>> u.version
7

This means they inherit some useful properties:

  • Natural Sorting: UUIDv7 values are time-sortable, which means you can sort them in increasing order based on when they were generated. Databases often require additional timestamp columns to sort records based on creation time. With PrettyId, you can achieve this sorting using the ID itself, eliminating the need for extra columns.

  • Optimized Indexing: Since UUIDv7 is time-sortable, database indexing mechanisms can better optimize the storage and retrieval processes, leading to faster query times especially for time-based queries.

  • Concurrency and Distribution: In distributed systems, generating unique, sequential IDs can be a challenge. UUIDv7 can be generated concurrently across multiple nodes without the risk of collisions, making it suitable for distributed architectures.

IDs are encoded as lowercase Base32 using Douglas Crockford’s alphabet. This makes them compact, readable, and case-insensitive.

In database, IDs are stored without prefix using a native UUID type or BINARY(16). (We assume that the prefix can be determined from the table name.)