Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @svix/Engineering
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: 2
updates:
- package-ecosystem: "uv"
directory: "/"
schedule:
interval: "weekly"
day: "tuesday"
time: "10:00"
timezone: "America/Los_Angeles"
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI
on: [pull_request]
jobs:
lint:
runs-on: ubuntu-latest
strategy:
matrix:
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v5
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python }}
enable-cache: true
- name: Sync lockfile
run: uv sync
- name: Run linting
run: uv run sh ./scripts/lint.sh
prek:
name: Validate prek
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
- uses: j178/prek-action@v1
test:
runs-on: ubuntu-latest
strategy:
matrix:
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v5
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python }}
enable-cache: true
- name: Install deps
run: uv sync
- name: Run linting
run: uv run pytest
build:
runs-on: ubuntu-latest
needs: [prek, lint, test]
steps:
- run: echo "This is a dummy job so that we can only require one job for branch protection"
19 changes: 0 additions & 19 deletions .github/workflows/lint.yml

This file was deleted.

20 changes: 0 additions & 20 deletions .github/workflows/test.yml

This file was deleted.

25 changes: 25 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
repos:
- repo: builtin
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-case-conflict
- id: check-merge-conflict
- id: check-symlinks
- id: check-toml
- id: check-yaml
args: ["--allow-multiple-documents"]
- id: check-json
- repo: https://github.com/google/yamlfmt
rev: v0.20.0
hooks:
- id: yamlfmt
- repo: https://github.com/rhysd/actionlint
rev: v1.7.7
hooks:
- id: actionlint
- repo: https://github.com/crate-ci/typos
rev: v1.42.1
hooks:
- id: typos
exclude: "tests/test_kuids.txt"
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Next
* Changed `KsuidMs` implementation to use the fractional part to have 4ms of precision instead of (1/256)s of precision, aligning its interpretation with [rust-ksuid](https://github.com/svix/rust-ksuid), and with its own docstrings
* Bump minimum Python version to 3.10
* Switch to `uv`, `ruff`, and `ty` for development instead of `pip-tools`, `black`, `flake8`, `isort`, and `mypy`

## Version 0.6.2
* Fix `__str__` implementation for non standard sized ksuids (see #27 for details)
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
THE SOFTWARE.
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
[![Join our slack](https://img.shields.io/badge/Slack-join%20the%20community-blue?logo=slack&style=social)](https://www.svix.com/slack/)

This library is inspired by [Segment's KSUID](https://segment.com/blog/a-brief-history-of-the-uuid/) implementation:
https://github.com/segmentio/ksuid
<https://github.com/segmentio/ksuid>

For the Rust version, please check out https://github.com/svix/rust-ksuid
For the Rust version, please check out <https://github.com/svix/rust-ksuid>

## What is a ksuid?

A ksuid is a K sorted UID. In other words, a KSUID also stores a date component, so that ksuids can be approximately
sorted based on the time they were created.
A ksuid is a K sorted UID. In other words, a KSUID also stores a date component, so that ksuids can be approximately
sorted based on the time they were created.

Read more [here](https://segment.com/blog/a-brief-history-of-the-uuid/).

Expand Down Expand Up @@ -180,3 +180,12 @@ Out[8]: False
### License

ksuid source code is available under an MIT [License](./LICENSE).

### Development

This application uses [`uv`](https://docs.astral.sh/uv/) for virtualenv management by default.

- To lint, use `uv run scripts/lint.sh`
- To run tests, use `uv run pytest`

This repository also has pre-commit hooks set up using [`prek`](https://prek.j178.dev/). They will be checked in CI, but if you'd like to run them locally you can use the `prek` tool.
8 changes: 3 additions & 5 deletions ksuid/ksuid.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,20 @@ class Ksuid:
_uid: bytes

@classmethod
def from_base62(cls: t.Type[SelfT], data: str) -> SelfT:
def from_base62(cls: type[SelfT], data: str) -> SelfT:
"""initializes Ksuid from base62 encoding"""
return cls.from_bytes(int.to_bytes(int(base62.decode(data)), cls.BYTES_LENGTH, "big"))

@classmethod
def from_bytes(cls: t.Type[SelfT], value: bytes) -> SelfT:
def from_bytes(cls: type[SelfT], value: bytes) -> SelfT:
"""initializes Ksuid from bytes"""

if len(value) != cls.TIMESTAMP_LENGTH_IN_BYTES + cls.PAYLOAD_LENGTH_IN_BYTES:
raise ByteArrayLengthException(f"Incorrect value length {len(value)}")

return cls(_raw=value)

def __init__(
self, datetime: t.Optional[datetime] = None, payload: t.Optional[bytes] = None, _raw: t.Optional[bytes] = None
):
def __init__(self, datetime: datetime | None = None, payload: bytes | None = None, _raw: bytes | None = None):
if _raw is not None:
self._uid = _raw
return
Expand Down
63 changes: 55 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,57 @@
[tool.black]
[project]
name = "svix-ksuid"
version = "0.6.2"
description = "A pure-Python KSUID implementation"
authors = [
{ name = "Svix", email = "development@svix.com" }
]
readme = "README.md"
requires-python = ">=3.10"
license = "MIT"
license-files = ["LICENSE"]
dependencies = [
"python-baseconv"
]
keywords = [
"svix",
"ksuid",
]

[project.urls]
Repository = "https://github.com/svix/python-ksuid/"
Issues = "https://github.com/svix/python-ksuid/issues"
Changelog = "https://github.com/svix/python-ksuid/blob/main/ChangeLog.md"

[build-system]
requires = ["hatchling >= 1.26"]
build-backend = "hatchling.build"

[tool.hatch.build]
exclude = [".github/*", "scripts/*", "tests/*", 'uv.lock', "mypy.ini", "/.*"]

[tool.hatch.build.targets.wheel]
packages = ["ksuid"]

[dependency-groups]
dev = [
"pytest>=9.0",
"ty>=0.0.23",
"ruff>=0.15.6",
]

[tool.ruff]
# we're not on VT220's any more
line-length = 120
target-version = "py310"

[tool.isort]
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
line_length = 120
[tool.ruff.lint]
select = [
# pycodestyle
"E",
# Pyflakes
"F",
# pyupgrade
"UP",
# isort
"I",
]
72 changes: 0 additions & 72 deletions requirements-dev.txt

This file was deleted.

1 change: 0 additions & 1 deletion requirements.in/base.txt

This file was deleted.

9 changes: 0 additions & 9 deletions requirements.in/development.txt

This file was deleted.

8 changes: 0 additions & 8 deletions requirements.txt

This file was deleted.

6 changes: 6 additions & 0 deletions scripts/lint-fix.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

set -exu

ruff check --fix ksuid
ruff format ksuid
9 changes: 4 additions & 5 deletions scripts/lint.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#!/usr/bin/env bash

set -ex
set -exu

mypy ksuid
isort --check-only ksuid
black ksuid --check
flake8 ksuid
ty check ksuid
ruff check ksuid
ruff format --check ksuid
Loading