Skip to content

Development

LazyGreed edited this page Nov 11, 2026 · 3 revisions

Development

Setup

git clone https://github.com/0x1d1e/ocr-foundry.git
cd ocr-foundry

uv sync --extra dev               # installs dev deps (pytest, ruff, ty) - pure Python
uv sync --extra dev --extra rust  # also builds the Rust extension via maturin

uv sync --extra dev installs development tools without requiring a Rust toolchain. Adding --extra rust resolves khocr-gen-core from rust/ as an editable path dependency, building and installing the native acceleration extension.

Everyday commands

uv run ruff check .      # lint
uv run ruff format .     # format
uv run pytest            # tests (addopts + coverage config from pyproject.toml)
uv run ty check          # type check (CI fails on diagnostics)

Run a single test file or test:

uv run pytest tests/test_rendering.py
uv run pytest tests/test_line_height.py -k sample

With coverage, as CI does:

uv run pytest --cov=khocr_gen --cov-report=term-missing

Code style

Ruff is configured in pyproject.toml:

Setting Value
target-version py312
line-length 100
Enabled rules E, W, F, I, B, C4, UP, SIM, TCH, RUF
Ignored E501 (line too long — handled by the formatter), B008
isort first-party khocr_gen
Format double quotes, space indent, magic trailing comma preserved

Because E501 is ignored, the formatter decides line breaks, not the linter. Run uv run ruff format . before committing.

Tests

Tests live in tests/ and are grouped by subsystem:

tests/
├── test_augmentation.py      test_combine.py        test_config.py
├── test_config_loader.py     test_corpus.py         test_data_generator.py
├── test_errors.py            test_fonts.py          test_generate.py
├── test_line_height.py       test_lmdb_pack.py      test_normalizer.py
├── test_online_aug.py        test_parallel.py       test_rendering.py
├── test_text_decoration.py   test_text_effects.py

pytest is configured with testpaths = ["tests"] and pythonpath = ["src"], so tests import the working tree without an install. Coverage uses branch coverage over src/khocr_gen and omits _rust_accel.py.

When you add behaviour, add a test in the matching file. When you fix a bug, add the regression test that would have caught it.

Type checking

ty runs against src with extra-paths = ["typings"]. Its CI step fails on diagnostics. Workflow checks become enforced merge requirements only through repository/organization rulesets or branch protection; verify those settings separately.

CI

.github/workflows/ci.yml runs on pushes to main and on pull requests targeting main.

python job — matrix Python (3.12, 3.13, 3.14) x Rust (true, false) on Ubuntu 24.04

  1. Install system packages (libraqm-dev, libfribidi-dev, libfreetype6-dev, fonts-noto-core, fonts-noto-cjk)
  2. Set up font directories and compatibility symlinks
  3. Install Rust toolchain (when rust-accel: true)
  4. Install uv 0.13.7 (cache keyed from pyproject.toml)
  5. uv sync --extra dev [--extra rust] --python <version>
  6. Assert native acceleration is active (rust-accel: true) or pure-Python fallback is active (rust-accel: false)
  7. uv run ruff check . — gate
  8. uv run ty check — gate (0 diagnostics required, no continue-on-error)
  9. uv run pytest --cov=khocr_gen --cov-report=term-missing — gate
  10. CLI rendering smoke test (ocr-foundry layout) for words, tables, transforms, vertical CJK, and mixed fallback — gate

fail-fast: false, so all matrix combinations report even if one fails.

rust job — Ubuntu 24.04

  1. cargo fmt --check — gate (strictly enforced, no continue-on-error)
  2. cargo clippy --all-targets -- -D warnings — gate (strictly enforced, no continue-on-error)
  3. cargo build --release — gate

All formatting and clippy diagnostics have been completely eliminated. Local dependency resolution may create uv.lock, but the repository does not track it. Record the exact dependency resolution separately when preparing a reproducible release environment.

Releasing

Publishing is automated by .github/workflows/publish.yml:

  • Triggered by any tag push or manually via workflow_dispatch.
  • Builds sdist and wheel with uv build, then runs uv publish.
  • The publish step is skipped when PYPI_TOKEN is missing. A green run can mean no upload.
  • There is no dependency on the CI workflow, tag/version validation, or GitHub Release creation.

For pending v0.2.0, follow the release runbook. Repository transfer and rename are complete. Require all checks on the exact release commit before any tag push. Package version 0.2.0 is already set; the matching tag will be v0.2.0. Date the pending changelog only when release readiness is established. Tagging, uploading, publishing a GitHub Release and publishing wiki pages are separate external actions requiring authorization. Verify the actual files and version on PyPI, not only the Actions conclusion. No publishing action has been executed in preparation.

The changelog follows Keep a Changelog and the project follows Semantic Versioning.

Working on the Rust crate

See Rust Acceleration, in particular the warning about cd rust && uv run … creating a stray rust/.venv, and about uv sync overwriting a hand-built extension.

Docs

README.md is the repository landing page. README.pypi.md, selected by pyproject.toml, is the package description shown on PyPI. docs/ contains in-repository references; this wiki is the separately published user guide. Keep pages aligned when both describe the same behavior or option.

Update the landing pages when the quick start or project overview changes. For behavior, setup, or configuration changes, update the references and wiki pages that cover them.

See also

Clone this wiki locally