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
14 changes: 7 additions & 7 deletions .claude/skills/port-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ intentionally skip.
| `PascalCase` methods / `camelCase` locals / `_camelCase` fields | `snake_case` functions/vars |
| `IReadOnlyList<T>` / `IDictionary<,>` / `ISet<T>` etc. | `Sequence[T]`/`list` / `Mapping`/`dict` / `Set`/`set` etc. |
| NUnit `Assert.That(...)` | pytest plain `assert` (check neighboring test files) |
| `AssemblyInfo`/`.csproj` `<Version>` | `pyproject.toml` `version` (poetry) |
| `AssemblyInfo`/`.csproj` `<Version>` | `pyproject.toml` `version` |

The top-level Python areas are: `annotations`, `clusterers`, `corpora`, `jobs`,
`optimization`, `punctuation_analysis`, `scripture`, `sequence_alignment`, `statistics`,
Expand Down Expand Up @@ -90,12 +90,12 @@ Apply the ported changes with Edit/Write.
Install, format, lint, type-check, and test (this is `local_check.sh`):

```bash
poetry install
poetry run black .
poetry run flake8 .
poetry run isort .
poetry run pyright
poetry run pytest
uv sync --all-extras
uv run black .
uv run flake8 .
uv run isort .
uv run pyright
uv run pytest
```

`black` and `isort` rewrite files in place; `flake8` and `pyright` are gates that must pass
Expand Down
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
]
}
},
"postStartCommand": "poetry install"
"postStartCommand": "uv sync"
// Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "devcontainer"
}
13 changes: 6 additions & 7 deletions .devcontainer/dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
ARG PYTHON_VERSION=3.10
ARG POETRY_VERSION=2.4.1
ARG UV_VERSION=0.12.17
ARG CUDA_VERSION=12.6.1-base-ubuntu24.04

FROM ghcr.io/astral-sh/uv:$UV_VERSION AS uv

FROM nvidia/cuda:$CUDA_VERSION
ARG PYTHON_VERSION
ARG POETRY_VERSION

ENV POETRY_VENV=/opt/poetry-venv
ENV PIP_DISABLE_PIP_VERSION_CHECK=on
ENV TZ=America/New_York
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
Expand All @@ -29,14 +29,13 @@ RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python$PYTHON_VERSION
RUN ln -sfn /usr/bin/python${PYTHON_VERSION} /usr/bin/python3 & \
ln -sfn /usr/bin/python${PYTHON_VERSION} /usr/bin/python

COPY --from=uv /uv /uvx /bin/

# Install python packages
RUN pip install -U pip setuptools \
&& pip install poetry==${POETRY_VERSION} black pipenv virtualenv clearml \
&& poetry config virtualenvs.in-project true \
&& pip install black pipenv virtualenv clearml \
&& pip install cffi

COPY ./.devcontainer/clearml.conf /root/clearml.conf

ENV EFLOMAL_PATH=/workspaces/machine.py/.venv/lib/python${PYTHON_VERSION}/site-packages/eflomal/bin

CMD ["bash"]
47 changes: 17 additions & 30 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,28 @@ jobs:

steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
id: setup-python
uses: actions/setup-python@v6
- name: Install uv and Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v10.2.0
with:
version: 0.12.17
python-version: ${{ matrix.python-version }}
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 2.4.1
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true
enable-cache: true
- name: Install dependencies
run: poetry install --no-interaction --all-extras
run: uv sync --locked --all-extras
- name: Lint with Black
run: poetry run black . --check --diff
run: uv run black . --check --diff
- name: Lint with Flake8
run: poetry run flake8 . --statistics --show-source
run: uv run flake8 . --statistics --show-source
- name: Lint with isort
run: poetry run isort . --check-only
run: uv run isort . --check-only
- name: Setup Node for pyright
uses: actions/setup-node@v6
with:
node-version: "24"
- name: Lint with pyright
run: poetry run pyright
run: uv run pyright
- name: Test with pytest
run: poetry run pytest --cov --cov-report=xml
run: uv run pytest --cov --cov-report=xml
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v7
env:
Expand All @@ -61,27 +55,20 @@ jobs:

steps:
- uses: actions/checkout@v7
- name: Set up Python 3.10
id: setup-python
uses: actions/setup-python@v6
- name: Install uv and Python 3.10
uses: astral-sh/setup-uv@v10.2.0
with:
version: 0.12.17
python-version: "3.10"
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 2.4.1
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true
- name: Build
run: poetry build
run: uv build
- name: Upload package
uses: actions/upload-artifact@v7
with:
name: wheel
path: dist/*.whl
- name: Publish
if: startsWith(github.ref, 'refs/tags/v')
run: |
poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }}
poetry publish
run: uv publish
env:
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
28 changes: 8 additions & 20 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ jobs:
needs: changes
# Secrets are not available to workflows triggered by pull requests from forked
# repositories, so only review pull requests from branches in this repository.
# This also keeps `poetry install` below from running build hooks authored by
# This also keeps `uv sync` below from running build hooks authored by
# someone without push access, and keeps AGENTS.md trusted: CLAUDE.md is
# restored from main, but the AGENTS.md it imports comes from the PR head.
if: >-
Expand All @@ -86,29 +86,17 @@ jobs:
# the base branch locally rather than only seeing the PR's final state.
fetch-depth: 0

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v6
- name: Install uv and Python ${{ env.PYTHON_VERSION }}
uses: astral-sh/setup-uv@v10.2.0
with:
version: 0.12.17
python-version: ${{ env.PYTHON_VERSION }}

- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 2.4.1
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true

- name: Restore virtualenv
uses: actions/cache@v4
with:
path: .venv
key: review-venv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('poetry.lock') }}
enable-cache: true

# Gives the reviewer an interpreter to falsify its own findings with. It is not
# here to lint or run the suite -- the CI build already does both.
- name: Install dependencies
run: poetry install --no-interaction --all-extras
run: uv sync --locked --all-extras

- name: Run Claude Code Review
id: claude-review
Expand All @@ -129,8 +117,8 @@ jobs:
# behavior and cost can change with no commit here.
claude_args: >-
--model opus
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr comment:*),Bash(gh pr list:*),Bash(gh pr checks:*),Bash(gh api:*),Bash(gh search:*),Bash(git log:*),Bash(git blame:*),Bash(git show:*),Bash(git diff:*),Bash(poetry run:*),Bash(.venv/bin/python:*)"
--append-system-prompt "Allowed commands match by prefix, so run poetry run and .venv/bin/python from the repository root as they are, not after cd or inside a wrapper such as timeout."
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr comment:*),Bash(gh pr list:*),Bash(gh pr checks:*),Bash(gh api:*),Bash(gh search:*),Bash(git log:*),Bash(git blame:*),Bash(git show:*),Bash(git diff:*),Bash(uv run:*),Bash(.venv/bin/python:*)"
--append-system-prompt "Allowed commands match by prefix, so run uv run and .venv/bin/python from the repository root as they are, not after cd or inside a wrapper such as timeout."
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options

Expand Down
26 changes: 7 additions & 19 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,28 +49,16 @@ jobs:
# pushes went out as github-actions[bot] and were denied.
persist-credentials: false

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v6
- name: Install uv and Python ${{ env.PYTHON_VERSION }}
uses: astral-sh/setup-uv@v10.2.0
with:
version: 0.12.17
python-version: ${{ env.PYTHON_VERSION }}

- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 2.4.1
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true

- name: Restore virtualenv
uses: actions/cache@v4
with:
path: .venv
key: claude-venv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('poetry.lock') }}
enable-cache: true

# A change made from an issue is validated before its pull request is opened.
- name: Install dependencies
run: poetry install --no-interaction --all-extras
run: uv sync --locked --all-extras

# port-pr reads the C# source from a sibling clone, as of each source PR's merge
# commit, so it needs full history. Outside the workspace, black and flake8 skip it.
Expand All @@ -93,8 +81,8 @@ jobs:
# appended prompt has Claude open the pull request itself.
claude_args: >-
--add-dir ../machine
--allowedTools "Bash(gh pr create:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh issue view:*),Bash(git log:*),Bash(git blame:*),Bash(git show:*),Bash(git diff:*),Bash(git status:*),Bash(git -C ../machine show:*),Bash(git -C ../machine cat-file:*),Bash(git -C ../machine log:*),Bash(git -C ../machine blame:*),Bash(poetry run:*),Bash(./local_check.sh:*),Bash(tail:*),Bash(head:*)"
--append-system-prompt "When invoked on an issue and you change code, open the pull request yourself once your commits are pushed: gh pr create --base main --head <your branch>. Post its link in your comment in place of a Create a PR link. Write the title and body with the pr-authoring skill, and put Closes #<issue number> in the body. Before opening it, run ./local_check.sh --agent-strict and commit the files black and isort rewrite. Whenever you report local_check, in a PR body or a comment, quote its last line, local_check: PASSED or local_check: FAILED (...), and never a pytest count in its place; if it did not run to that line, say it did not run. Dependencies are already installed, and you work on the branch this action created: where a skill such as port-pr says to install, create or switch branches, or push, commit on the current branch and push it the way these instructions say. Allowed commands match by prefix, so run poetry run and ./local_check.sh from the repository root as they are, not after cd or inside a wrapper such as timeout. When the issue is labeled porting, port it with the port-pr skill."
--allowedTools "Bash(gh pr create:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh issue view:*),Bash(git log:*),Bash(git blame:*),Bash(git show:*),Bash(git diff:*),Bash(git status:*),Bash(git -C ../machine show:*),Bash(git -C ../machine cat-file:*),Bash(git -C ../machine log:*),Bash(git -C ../machine blame:*),Bash(uv run:*),Bash(./local_check.sh:*),Bash(tail:*),Bash(head:*)"
--append-system-prompt "When invoked on an issue and you change code, open the pull request yourself once your commits are pushed: gh pr create --base main --head <your branch>. Post its link in your comment in place of a Create a PR link. Write the title and body with the pr-authoring skill, and put Closes #<issue number> in the body. Before opening it, run ./local_check.sh --agent-strict and commit the files black and isort rewrite. Whenever you report local_check, in a PR body or a comment, quote its last line, local_check: PASSED or local_check: FAILED (...), and never a pytest count in its place; if it did not run to that line, say it did not run. Dependencies are already installed, and you work on the branch this action created: where a skill such as port-pr says to install, create or switch branches, or push, commit on the current branch and push it the way these instructions say. Allowed commands match by prefix, so run uv run and ./local_check.sh from the repository root as they are, not after cd or inside a wrapper such as timeout. When the issue is labeled porting, port it with the port-pr skill."
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/comment-hygiene.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ concurrency:
cancel-in-progress: true

jobs:
# Separate from CI build so the report does not wait on the Poetry install and
# Separate from CI build so the report does not wait on the uv sync and
# the test matrix. The checker is standard library only, so it needs no
# dependencies of its own.
comment_hygiene:
Expand Down
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,5 @@ out/
# omit IDE data
.idea/

# Ignore Poetry plugins
.poetry/

# Local, generated review summaries
.review/
6 changes: 2 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"files.associations": {
"*.SFM": "usfm"
},
"black-formatter.path": ["poetry", "run", "black"],
"black-formatter.path": ["uv", "run", "black"],
"isort.args": ["--profile", "black"],
"cSpell.words": [
"CLEARML",
Expand All @@ -26,7 +26,5 @@
"typeshed",
"Usfm",
"venv"
],
"python-envs.defaultEnvManager": "ms-python.python:poetry",
"python-envs.defaultPackageManager": "ms-python.python:poetry"
]
}
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 SIL International
Copyright (c) 2026 SIL Global

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
28 changes: 7 additions & 21 deletions dockerfile
Original file line number Diff line number Diff line change
@@ -1,30 +1,18 @@
# syntax=docker/dockerfile:1
ARG PYTHON_VERSION=3.12
ARG POETRY_VERSION=2.4.1
ARG UV_VERSION=0.12.17

FROM python:$PYTHON_VERSION-slim-bookworm AS builder
ARG POETRY_VERSION

ENV POETRY_HOME=/opt/poetry
ENV POETRY_VENV=/opt/poetry-venv
ENV POETRY_CACHE_DIR=/opt/.cache

# Install poetry separated from system interpreter
RUN python3 -m venv $POETRY_VENV \
&& $POETRY_VENV/bin/pip install -U pip setuptools \
&& $POETRY_VENV/bin/pip install poetry==${POETRY_VERSION}
FROM ghcr.io/astral-sh/uv:$UV_VERSION AS uv

# Add `poetry` to PATH
ENV PATH="${PATH}:${POETRY_VENV}/bin"
FROM python:$PYTHON_VERSION-slim-bookworm AS builder
COPY --from=uv /uv /bin/uv

WORKDIR /src
COPY poetry.lock pyproject.toml /src/
RUN poetry self add poetry-plugin-export
RUN poetry export --with=gpu --all-extras --without-hashes -f requirements.txt > requirements.txt

COPY uv.lock pyproject.toml /src/
# dev dependencies are left out of the image
RUN uv export --frozen --no-default-groups --group gpu --all-extras --no-hashes --no-emit-project -o requirements.txt

FROM python:$PYTHON_VERSION-slim-bookworm
ARG PYTHON_VERSION

ENV PIP_DISABLE_PIP_VERSION_CHECK=on
ENV TZ=America/New_York
Expand Down Expand Up @@ -57,6 +45,4 @@ RUN --mount=type=cache,target=/root/.cache \
RUN python -m pip install --no-deps . && rm -r /root/*
ENV CLEARML_AGENT_SKIP_PYTHON_ENV_INSTALL=1

ENV EFLOMAL_PATH=/usr/local/lib/python${PYTHON_VERSION}/site-packages/eflomal/bin

CMD ["bash"]
27 changes: 7 additions & 20 deletions dockerfile.cpu_only
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
# syntax=docker/dockerfile:1
ARG PYTHON_VERSION=3.12
ARG POETRY_VERSION=2.4.1
ARG UV_VERSION=0.12.17

FROM python:$PYTHON_VERSION-slim-bookworm AS builder
ARG POETRY_VERSION

ENV POETRY_HOME=/opt/poetry
ENV POETRY_VENV=/opt/poetry-venv
ENV POETRY_CACHE_DIR=/opt/.cache

# Install poetry separated from system interpreter
RUN python3 -m venv $POETRY_VENV \
&& $POETRY_VENV/bin/pip install -U pip setuptools \
&& $POETRY_VENV/bin/pip install poetry==${POETRY_VERSION}
FROM ghcr.io/astral-sh/uv:$UV_VERSION AS uv

# Add `poetry` to PATH
ENV PATH="${PATH}:${POETRY_VENV}/bin"
FROM python:$PYTHON_VERSION-slim-bookworm AS builder
COPY --from=uv /uv /bin/uv

WORKDIR /src
COPY poetry.lock pyproject.toml /src/
RUN poetry self add poetry-plugin-export
RUN poetry export --with=gpu --all-extras --without-hashes -f requirements.txt > requirements.txt

COPY uv.lock pyproject.toml /src/
# dev dependencies are left out of the image
RUN uv export --frozen --no-default-groups --group gpu --all-extras --no-hashes --no-emit-project -o requirements.txt

FROM python:$PYTHON_VERSION-slim-bookworm
WORKDIR /root
Expand All @@ -43,6 +32,4 @@ RUN --mount=type=cache,target=/root/.cache \
RUN python -m pip install --no-deps . && rm -r /root/*
ENV CLEARML_AGENT_SKIP_PYTHON_ENV_INSTALL=1

ENV EFLOMAL_PATH=/usr/local/lib/python${PYTHON_VERSION}/site-packages/eflomal/bin

CMD ["bash"]
Loading
Loading