tuft 0.1.0__tar.gz → 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tuft-0.1.1/.gitattributes +3 -0
- tuft-0.1.1/.github/workflows/checks.yml +65 -0
- tuft-0.1.1/.github/workflows/docker/docker-compose.yml +72 -0
- tuft-0.1.1/.github/workflows/docker.yml +77 -0
- tuft-0.1.1/.github/workflows/install-script.yml +241 -0
- tuft-0.1.1/.github/workflows/publish.yml +56 -0
- tuft-0.1.1/.github/workflows/unittest.yml +103 -0
- tuft-0.1.1/.gitignore +72 -0
- tuft-0.1.1/.gitmodules +0 -0
- tuft-0.1.1/.pre-commit-config.yaml +51 -0
- tuft-0.1.1/.python-version +1 -0
- tuft-0.1.1/.secrets.baseline +152 -0
- {tuft-0.1.0 → tuft-0.1.1}/LICENSE +2 -2
- tuft-0.1.1/PKG-INFO +633 -0
- tuft-0.1.1/README.md +571 -0
- tuft-0.1.1/assets/countdown_rl.png +3 -0
- tuft-0.1.1/assets/test_nll_sft.png +3 -0
- tuft-0.1.1/assets/train_mean_nll_sft.png +3 -0
- tuft-0.1.1/assets/tuft-logo-colorful.svg +47 -0
- tuft-0.1.1/config/tuft_config.example.yaml +120 -0
- tuft-0.1.1/docker/Dockerfile +50 -0
- tuft-0.1.1/docs/chat_sft.md +322 -0
- tuft-0.1.1/docs/countdown_rl.md +300 -0
- tuft-0.1.1/docs/how_to_write_tests.md +238 -0
- tuft-0.1.1/examples/chat_sft.ipynb +783 -0
- tuft-0.1.1/examples/countdown_rl.ipynb +2013 -0
- tuft-0.1.1/pyproject.toml +112 -0
- tuft-0.1.1/scripts/install.sh +625 -0
- tuft-0.1.1/scripts/install_flash_attn.py +72 -0
- tuft-0.1.1/src/tuft/__init__.py +6 -0
- tuft-0.1.1/src/tuft/auth.py +35 -0
- tuft-0.1.1/src/tuft/backend.py +254 -0
- tuft-0.1.1/src/tuft/backends/__init__.py +10 -0
- tuft-0.1.1/src/tuft/backends/base_backend.py +112 -0
- tuft-0.1.1/src/tuft/backends/hf_training_model.py +404 -0
- tuft-0.1.1/src/tuft/backends/sampling_backend.py +253 -0
- tuft-0.1.1/src/tuft/backends/training_backend.py +327 -0
- tuft-0.1.1/src/tuft/checkpoints.py +193 -0
- tuft-0.1.1/src/tuft/cli.py +91 -0
- tuft-0.1.1/src/tuft/config.py +121 -0
- tuft-0.1.1/src/tuft/exceptions.py +138 -0
- tuft-0.1.1/src/tuft/futures.py +431 -0
- tuft-0.1.1/src/tuft/loss_fn/__init__.py +48 -0
- tuft-0.1.1/src/tuft/loss_fn/cispo.py +40 -0
- tuft-0.1.1/src/tuft/loss_fn/cross_entropy.py +26 -0
- tuft-0.1.1/src/tuft/loss_fn/dro.py +37 -0
- tuft-0.1.1/src/tuft/loss_fn/importance_sampling.py +33 -0
- tuft-0.1.1/src/tuft/loss_fn/ppo.py +43 -0
- tuft-0.1.1/src/tuft/persistence/__init__.py +32 -0
- tuft-0.1.1/src/tuft/persistence/file_redis.py +268 -0
- tuft-0.1.1/src/tuft/persistence/redis_store.py +488 -0
- tuft-0.1.1/src/tuft/sampling_controller.py +366 -0
- tuft-0.1.1/src/tuft/server.py +720 -0
- tuft-0.1.1/src/tuft/state.py +352 -0
- tuft-0.1.1/src/tuft/telemetry/__init__.py +17 -0
- tuft-0.1.1/src/tuft/telemetry/metrics.py +335 -0
- tuft-0.1.1/src/tuft/telemetry/provider.py +198 -0
- tuft-0.1.1/src/tuft/telemetry/tracing.py +43 -0
- tuft-0.1.1/src/tuft/training_controller.py +723 -0
- tuft-0.1.1/tests/__init__.py +1 -0
- tuft-0.1.1/tests/conftest.py +191 -0
- tuft-0.1.1/tests/data/models.yaml +19 -0
- tuft-0.1.1/tests/helpers.py +198 -0
- tuft-0.1.1/tests/test_checkpoints.py +55 -0
- tuft-0.1.1/tests/test_cli.py +67 -0
- tuft-0.1.1/tests/test_file_redis.py +49 -0
- tuft-0.1.1/tests/test_futures.py +83 -0
- tuft-0.1.1/tests/test_integration.py +350 -0
- tuft-0.1.1/tests/test_integration_persistence.py +213 -0
- tuft-0.1.1/tests/test_loss_fn.py +223 -0
- tuft-0.1.1/tests/test_persistence.py +727 -0
- tuft-0.1.1/tests/test_sampling_backend.py +103 -0
- tuft-0.1.1/tests/test_server.py +178 -0
- tuft-0.1.1/tests/test_state_controllers.py +491 -0
- tuft-0.1.1/tests/test_telemetry.py +493 -0
- tuft-0.1.1/tests/test_training_backend.py +307 -0
- tuft-0.1.0/PKG-INFO +0 -77
- tuft-0.1.0/README.md +0 -49
- tuft-0.1.0/pyproject.toml +0 -51
- tuft-0.1.0/setup.cfg +0 -4
- tuft-0.1.0/src/tuft/__init__.py +0 -3
- tuft-0.1.0/src/tuft.egg-info/PKG-INFO +0 -77
- tuft-0.1.0/src/tuft.egg-info/SOURCES.txt +0 -10
- tuft-0.1.0/src/tuft.egg-info/dependency_links.txt +0 -1
- tuft-0.1.0/src/tuft.egg-info/requires.txt +0 -7
- tuft-0.1.0/src/tuft.egg-info/top_level.txt +0 -1
- tuft-0.1.0/tests/test_tuft.py +0 -11
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: Checks
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, dev/**, feature/**]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
checks:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ['3.11', '3.12', '3.13']
|
|
15
|
+
|
|
16
|
+
services:
|
|
17
|
+
redis:
|
|
18
|
+
image: redis:7-alpine
|
|
19
|
+
ports:
|
|
20
|
+
- 6379:6379
|
|
21
|
+
options: >-
|
|
22
|
+
--health-cmd "redis-cli ping"
|
|
23
|
+
--health-interval 10s
|
|
24
|
+
--health-timeout 5s
|
|
25
|
+
--health-retries 5
|
|
26
|
+
|
|
27
|
+
env:
|
|
28
|
+
TEST_REDIS_URL: redis://localhost:6379/15
|
|
29
|
+
|
|
30
|
+
steps:
|
|
31
|
+
- name: Checkout code
|
|
32
|
+
uses: actions/checkout@v6
|
|
33
|
+
|
|
34
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
35
|
+
uses: actions/setup-python@v6
|
|
36
|
+
with:
|
|
37
|
+
python-version: ${{ matrix.python-version }}
|
|
38
|
+
|
|
39
|
+
- name: Install uv
|
|
40
|
+
uses: astral-sh/setup-uv@v7
|
|
41
|
+
with:
|
|
42
|
+
version: '0.9.21'
|
|
43
|
+
|
|
44
|
+
- name: Install dependencies
|
|
45
|
+
run: |
|
|
46
|
+
uv sync --extra dev
|
|
47
|
+
|
|
48
|
+
- name: Run ruff linter
|
|
49
|
+
run: uv run ruff check .
|
|
50
|
+
|
|
51
|
+
- name: Run ruff formatter check
|
|
52
|
+
run: uv run ruff format --check .
|
|
53
|
+
|
|
54
|
+
- name: Run nbqa-ruff on notebooks
|
|
55
|
+
run: uv run nbqa ruff --exclude .venv --exclude tinker .
|
|
56
|
+
|
|
57
|
+
- name: Run pyright type checker
|
|
58
|
+
run: uv run pyright
|
|
59
|
+
|
|
60
|
+
- name: Run pytest
|
|
61
|
+
run: uv run pytest
|
|
62
|
+
|
|
63
|
+
# - name: Check uv lockfile is up to date
|
|
64
|
+
# run: |
|
|
65
|
+
# uv lock --check
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
services:
|
|
2
|
+
# use 2 nodes to simulate a cluster environment
|
|
3
|
+
tuft-node-1:
|
|
4
|
+
image: tuft-unittest:20260123
|
|
5
|
+
pull_policy: never
|
|
6
|
+
command: bash -c "source /opt/venv/bin/activate && uv pip install -e .[dev,backend,persistence] && ray start --head --dashboard-host 0.0.0.0 --include-dashboard true --block"
|
|
7
|
+
environment:
|
|
8
|
+
- HF_ENDPOINT=https://hf-mirror.com
|
|
9
|
+
- RAY_ADDRESS=auto
|
|
10
|
+
- TUFT_CHECKPOINT_DIR=/mnt/checkpoints
|
|
11
|
+
- TUFT_TEST_MODEL=/mnt/models/Qwen3-0.6B
|
|
12
|
+
- TUFT_TEST_MODEL_1=/mnt/models/Qwen3-0.6B
|
|
13
|
+
- TUFT_TEST_MODEL_2=/mnt/models/Qwen3-1.7B
|
|
14
|
+
- TEST_REDIS_URL=redis://tuft-redis:6379
|
|
15
|
+
- VIRTUAL_ENV=/opt/venv
|
|
16
|
+
working_dir: /workspace
|
|
17
|
+
networks:
|
|
18
|
+
- tuft-network
|
|
19
|
+
volumes:
|
|
20
|
+
- tuft-volume:/mnt
|
|
21
|
+
- ../../..:/workspace
|
|
22
|
+
shm_size: "64G"
|
|
23
|
+
deploy:
|
|
24
|
+
resources:
|
|
25
|
+
reservations:
|
|
26
|
+
devices:
|
|
27
|
+
- driver: nvidia
|
|
28
|
+
device_ids: ['0', '1']
|
|
29
|
+
capabilities: [gpu]
|
|
30
|
+
|
|
31
|
+
tuft-node-2:
|
|
32
|
+
image: tuft-unittest:20260123
|
|
33
|
+
pull_policy: never
|
|
34
|
+
command: bash -c "source /opt/venv/bin/activate && uv pip install -e .[dev,backend,persistence] && ray start --address=tuft-node-1:6379 --block"
|
|
35
|
+
environment:
|
|
36
|
+
- HF_ENDPOINT=https://hf-mirror.com
|
|
37
|
+
- TUFT_CHECKPOINT_DIR=/mnt/checkpoints
|
|
38
|
+
- TUFT_TEST_MODEL=/mnt/models/Qwen3-0.6B
|
|
39
|
+
- TUFT_TEST_MODEL_1=/mnt/models/Qwen3-0.6B
|
|
40
|
+
- TUFT_TEST_MODEL_2=/mnt/models/Qwen3-1.7B
|
|
41
|
+
- TEST_REDIS_URL=redis://tuft-redis:6379
|
|
42
|
+
- VIRTUAL_ENV=/opt/venv
|
|
43
|
+
working_dir: /workspace
|
|
44
|
+
volumes:
|
|
45
|
+
- tuft-volume:/mnt
|
|
46
|
+
- ../../..:/workspace
|
|
47
|
+
depends_on:
|
|
48
|
+
- tuft-node-1
|
|
49
|
+
networks:
|
|
50
|
+
- tuft-network
|
|
51
|
+
shm_size: "64G"
|
|
52
|
+
deploy:
|
|
53
|
+
resources:
|
|
54
|
+
reservations:
|
|
55
|
+
devices:
|
|
56
|
+
- driver: nvidia
|
|
57
|
+
device_ids: ['2', '3']
|
|
58
|
+
capabilities: [gpu]
|
|
59
|
+
|
|
60
|
+
tuft-redis:
|
|
61
|
+
image: redis:7.0
|
|
62
|
+
command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"]
|
|
63
|
+
networks:
|
|
64
|
+
- tuft-network
|
|
65
|
+
|
|
66
|
+
networks:
|
|
67
|
+
tuft-network:
|
|
68
|
+
driver: bridge
|
|
69
|
+
|
|
70
|
+
volumes:
|
|
71
|
+
tuft-volume:
|
|
72
|
+
external: true
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
name: Build and Publish Docker Image
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
ref:
|
|
10
|
+
description: 'The git ref (branch or tag) to build the Docker image from.'
|
|
11
|
+
required: true
|
|
12
|
+
version:
|
|
13
|
+
description: 'Version tag for the Docker image (e.g., 0.1.0)'
|
|
14
|
+
required: true
|
|
15
|
+
|
|
16
|
+
env:
|
|
17
|
+
REGISTRY: ghcr.io
|
|
18
|
+
IMAGE_NAME: ${{ github.repository }}
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
build-and-push-image:
|
|
22
|
+
runs-on: self-hosted # TODO: setup a self-hosted runner on a machine with sufficient resources
|
|
23
|
+
timeout-minutes: 360
|
|
24
|
+
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
|
|
25
|
+
permissions:
|
|
26
|
+
contents: read
|
|
27
|
+
packages: write
|
|
28
|
+
attestations: write
|
|
29
|
+
id-token: write
|
|
30
|
+
steps:
|
|
31
|
+
- name: Checkout repository
|
|
32
|
+
uses: actions/checkout@v5
|
|
33
|
+
with:
|
|
34
|
+
ref: ${{ github.event.inputs.ref || github.ref }}
|
|
35
|
+
path: tuft-${{ github.run_id }}
|
|
36
|
+
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
|
|
37
|
+
- name: Log in to the Container registry
|
|
38
|
+
uses: docker/login-action@v2
|
|
39
|
+
with:
|
|
40
|
+
registry: ${{ env.REGISTRY }}
|
|
41
|
+
username: ${{ github.actor }}
|
|
42
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
43
|
+
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
|
|
44
|
+
- name: Extract metadata (tags, labels) for Docker
|
|
45
|
+
id: meta
|
|
46
|
+
uses: docker/metadata-action@v5
|
|
47
|
+
with:
|
|
48
|
+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
49
|
+
tags: |
|
|
50
|
+
type=match,pattern=\d.\d.\d,enable=${{ github.event_name == 'release' }}
|
|
51
|
+
type=raw,value=${{ github.event.inputs.version }},enable=${{ github.event_name == 'workflow_dispatch' }}
|
|
52
|
+
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
|
|
53
|
+
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see [Usage](https://github.com/docker/build-push-action#usage) in the README of the `docker/build-push-action` repository.
|
|
54
|
+
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
|
|
55
|
+
- name: Build and push Docker image
|
|
56
|
+
id: push
|
|
57
|
+
uses: docker/build-push-action@v4
|
|
58
|
+
with:
|
|
59
|
+
context: tuft-${{ github.run_id }}
|
|
60
|
+
push: true
|
|
61
|
+
file: tuft-${{ github.run_id }}/docker/Dockerfile
|
|
62
|
+
shm-size: 128g
|
|
63
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
64
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
65
|
+
|
|
66
|
+
# This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see [Using artifact attestations to establish provenance for builds](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds).
|
|
67
|
+
- name: Generate artifact attestation
|
|
68
|
+
uses: actions/attest-build-provenance@v3
|
|
69
|
+
with:
|
|
70
|
+
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
|
|
71
|
+
subject-digest: ${{ steps.push.outputs.digest }}
|
|
72
|
+
push-to-registry: true
|
|
73
|
+
|
|
74
|
+
- name: Cleanup workspace
|
|
75
|
+
if: always()
|
|
76
|
+
run: |
|
|
77
|
+
sudo rm -rf tuft-${{ github.run_id }} 2>/dev/null
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
name: Install Script
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, dev/**, feature/**]
|
|
6
|
+
paths:
|
|
7
|
+
- 'scripts/install.sh'
|
|
8
|
+
- '.github/workflows/install-script.yml'
|
|
9
|
+
pull_request:
|
|
10
|
+
branches: [main]
|
|
11
|
+
paths:
|
|
12
|
+
- 'scripts/install.sh'
|
|
13
|
+
- '.github/workflows/install-script.yml'
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
test-install-script:
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
os: [ubuntu-latest, macos-latest]
|
|
21
|
+
|
|
22
|
+
runs-on: ${{ matrix.os }}
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- name: Checkout code
|
|
26
|
+
uses: actions/checkout@v4
|
|
27
|
+
|
|
28
|
+
- name: Test install script syntax
|
|
29
|
+
run: bash -n scripts/install.sh
|
|
30
|
+
|
|
31
|
+
- name: Test install script help
|
|
32
|
+
run: bash scripts/install.sh --help
|
|
33
|
+
|
|
34
|
+
- name: Run install script (local source)
|
|
35
|
+
run: |
|
|
36
|
+
bash scripts/install.sh --local-source "$GITHUB_WORKSPACE"
|
|
37
|
+
env:
|
|
38
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
39
|
+
|
|
40
|
+
- name: Verify tuft command exists
|
|
41
|
+
run: |
|
|
42
|
+
export PATH="${TUFT_HOME}/bin:$PATH"
|
|
43
|
+
which tuft
|
|
44
|
+
tuft --help
|
|
45
|
+
env:
|
|
46
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
47
|
+
|
|
48
|
+
- name: Verify tuft version
|
|
49
|
+
run: |
|
|
50
|
+
export PATH="${TUFT_HOME}/bin:$PATH"
|
|
51
|
+
tuft version
|
|
52
|
+
env:
|
|
53
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
54
|
+
|
|
55
|
+
- name: Verify Python environment
|
|
56
|
+
run: |
|
|
57
|
+
test -f "${TUFT_HOME}/venv/bin/python"
|
|
58
|
+
"${TUFT_HOME}/venv/bin/python" -c "import tuft; print('tuft imported successfully')"
|
|
59
|
+
env:
|
|
60
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
61
|
+
|
|
62
|
+
- name: Test tuft (dry run - check config error)
|
|
63
|
+
run: |
|
|
64
|
+
export PATH="${TUFT_HOME}/bin:$PATH"
|
|
65
|
+
# Should fail with config error, not import error
|
|
66
|
+
tuft 2>&1 | grep -q "\-\-config" || tuft 2>&1 | grep -q "config"
|
|
67
|
+
env:
|
|
68
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
69
|
+
|
|
70
|
+
- name: Clean up installation
|
|
71
|
+
run: rm -rf "${TUFT_HOME}"
|
|
72
|
+
env:
|
|
73
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
74
|
+
|
|
75
|
+
test-install-default-with-backend:
|
|
76
|
+
runs-on: ubuntu-latest
|
|
77
|
+
|
|
78
|
+
steps:
|
|
79
|
+
- name: Checkout code
|
|
80
|
+
uses: actions/checkout@v4
|
|
81
|
+
|
|
82
|
+
- name: Run install script (default includes backend)
|
|
83
|
+
run: |
|
|
84
|
+
bash scripts/install.sh --local-source "$GITHUB_WORKSPACE"
|
|
85
|
+
env:
|
|
86
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
87
|
+
|
|
88
|
+
- name: Verify backend dependencies installed
|
|
89
|
+
run: |
|
|
90
|
+
"${TUFT_HOME}/venv/bin/python" -c "import peft; print('peft imported successfully')"
|
|
91
|
+
"${TUFT_HOME}/venv/bin/python" -c "import redis; print('redis imported successfully')"
|
|
92
|
+
env:
|
|
93
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
94
|
+
|
|
95
|
+
- name: Clean up installation
|
|
96
|
+
run: rm -rf "${TUFT_HOME}"
|
|
97
|
+
env:
|
|
98
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
99
|
+
|
|
100
|
+
test-install-without-backend:
|
|
101
|
+
runs-on: ubuntu-latest
|
|
102
|
+
|
|
103
|
+
steps:
|
|
104
|
+
- name: Checkout code
|
|
105
|
+
uses: actions/checkout@v4
|
|
106
|
+
|
|
107
|
+
- name: Run install script without backend
|
|
108
|
+
run: |
|
|
109
|
+
bash scripts/install.sh --local-source "$GITHUB_WORKSPACE" --without-backend
|
|
110
|
+
env:
|
|
111
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
112
|
+
|
|
113
|
+
- name: Verify minimal install (no peft)
|
|
114
|
+
run: |
|
|
115
|
+
# peft should NOT be installed in minimal mode
|
|
116
|
+
"${TUFT_HOME}/venv/bin/python" -c "import peft" 2>&1 && exit 1 || echo "peft not installed (expected)"
|
|
117
|
+
# tuft should still be importable
|
|
118
|
+
"${TUFT_HOME}/venv/bin/python" -c "import tuft; print('tuft imported successfully')"
|
|
119
|
+
env:
|
|
120
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
121
|
+
|
|
122
|
+
- name: Clean up installation
|
|
123
|
+
run: rm -rf "${TUFT_HOME}"
|
|
124
|
+
env:
|
|
125
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
126
|
+
|
|
127
|
+
test-wrapper-commands:
|
|
128
|
+
runs-on: ubuntu-latest
|
|
129
|
+
|
|
130
|
+
steps:
|
|
131
|
+
- name: Checkout code
|
|
132
|
+
uses: actions/checkout@v4
|
|
133
|
+
|
|
134
|
+
- name: Install tuft
|
|
135
|
+
run: bash scripts/install.sh --local-source "$GITHUB_WORKSPACE"
|
|
136
|
+
env:
|
|
137
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
138
|
+
|
|
139
|
+
- name: Test help command
|
|
140
|
+
run: |
|
|
141
|
+
export PATH="${TUFT_HOME}/bin:$PATH"
|
|
142
|
+
tuft help
|
|
143
|
+
env:
|
|
144
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
145
|
+
|
|
146
|
+
- name: Test version command
|
|
147
|
+
run: |
|
|
148
|
+
export PATH="${TUFT_HOME}/bin:$PATH"
|
|
149
|
+
tuft version
|
|
150
|
+
env:
|
|
151
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
152
|
+
|
|
153
|
+
- name: Test upgrade command
|
|
154
|
+
run: |
|
|
155
|
+
export PATH="${TUFT_HOME}/bin:$PATH"
|
|
156
|
+
tuft upgrade
|
|
157
|
+
env:
|
|
158
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
159
|
+
|
|
160
|
+
- name: Clean up installation
|
|
161
|
+
run: rm -rf "${TUFT_HOME}"
|
|
162
|
+
env:
|
|
163
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
164
|
+
|
|
165
|
+
test-clean-install:
|
|
166
|
+
runs-on: ubuntu-latest
|
|
167
|
+
|
|
168
|
+
steps:
|
|
169
|
+
- name: Checkout code
|
|
170
|
+
uses: actions/checkout@v4
|
|
171
|
+
|
|
172
|
+
- name: Initial install
|
|
173
|
+
run: |
|
|
174
|
+
bash scripts/install.sh --local-source "$GITHUB_WORKSPACE" --without-backend
|
|
175
|
+
env:
|
|
176
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
177
|
+
|
|
178
|
+
- name: Create marker file to verify clean
|
|
179
|
+
run: |
|
|
180
|
+
echo "marker" > "${TUFT_HOME}/marker.txt"
|
|
181
|
+
test -f "${TUFT_HOME}/marker.txt"
|
|
182
|
+
env:
|
|
183
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
184
|
+
|
|
185
|
+
- name: Reinstall with --clean
|
|
186
|
+
run: |
|
|
187
|
+
bash scripts/install.sh --local-source "$GITHUB_WORKSPACE" --without-backend --clean
|
|
188
|
+
env:
|
|
189
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
190
|
+
|
|
191
|
+
- name: Verify marker file was removed
|
|
192
|
+
run: |
|
|
193
|
+
# Marker file should be gone after --clean
|
|
194
|
+
test ! -f "${TUFT_HOME}/marker.txt"
|
|
195
|
+
# But tuft should still be installed
|
|
196
|
+
"${TUFT_HOME}/venv/bin/python" -c "import tuft; print('tuft imported successfully')"
|
|
197
|
+
env:
|
|
198
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
199
|
+
|
|
200
|
+
- name: Clean up installation
|
|
201
|
+
run: rm -rf "${TUFT_HOME}"
|
|
202
|
+
env:
|
|
203
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
204
|
+
|
|
205
|
+
test-install-backend-command:
|
|
206
|
+
runs-on: ubuntu-latest
|
|
207
|
+
|
|
208
|
+
steps:
|
|
209
|
+
- name: Checkout code
|
|
210
|
+
uses: actions/checkout@v4
|
|
211
|
+
|
|
212
|
+
- name: Install without backend first
|
|
213
|
+
run: |
|
|
214
|
+
bash scripts/install.sh --local-source "$GITHUB_WORKSPACE" --without-backend
|
|
215
|
+
env:
|
|
216
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
217
|
+
|
|
218
|
+
- name: Verify peft is NOT installed
|
|
219
|
+
run: |
|
|
220
|
+
"${TUFT_HOME}/venv/bin/python" -c "import peft" 2>&1 && exit 1 || echo "peft not installed (expected)"
|
|
221
|
+
env:
|
|
222
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
223
|
+
|
|
224
|
+
- name: Run install-backend command
|
|
225
|
+
run: |
|
|
226
|
+
export PATH="${TUFT_HOME}/bin:$PATH"
|
|
227
|
+
tuft install-backend
|
|
228
|
+
env:
|
|
229
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
230
|
+
|
|
231
|
+
- name: Verify backend dependencies now installed
|
|
232
|
+
run: |
|
|
233
|
+
"${TUFT_HOME}/venv/bin/python" -c "import peft; print('peft imported successfully')"
|
|
234
|
+
"${TUFT_HOME}/venv/bin/python" -c "import redis; print('redis imported successfully')"
|
|
235
|
+
env:
|
|
236
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
237
|
+
|
|
238
|
+
- name: Clean up installation
|
|
239
|
+
run: rm -rf "${TUFT_HOME}"
|
|
240
|
+
env:
|
|
241
|
+
TUFT_HOME: ${{ runner.temp }}/tuft
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
ref:
|
|
7
|
+
description: 'Git ref to checkout (branch, tag, or commit SHA)'
|
|
8
|
+
required: true
|
|
9
|
+
default: 'main'
|
|
10
|
+
type: string
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout code
|
|
17
|
+
uses: actions/checkout@v6
|
|
18
|
+
with:
|
|
19
|
+
ref: ${{ inputs.ref }}
|
|
20
|
+
|
|
21
|
+
- name: Set up Python
|
|
22
|
+
uses: actions/setup-python@v6
|
|
23
|
+
with:
|
|
24
|
+
python-version: '3.11'
|
|
25
|
+
|
|
26
|
+
- name: Install uv
|
|
27
|
+
uses: astral-sh/setup-uv@v7
|
|
28
|
+
with:
|
|
29
|
+
version: '0.9.21'
|
|
30
|
+
|
|
31
|
+
- name: Build package
|
|
32
|
+
run: uv build
|
|
33
|
+
|
|
34
|
+
- name: Upload build artifacts
|
|
35
|
+
uses: actions/upload-artifact@v4
|
|
36
|
+
with:
|
|
37
|
+
name: dist
|
|
38
|
+
path: dist/
|
|
39
|
+
|
|
40
|
+
publish:
|
|
41
|
+
needs: build
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
environment:
|
|
44
|
+
name: pypi
|
|
45
|
+
url: https://pypi.org/project/tuft/
|
|
46
|
+
permissions:
|
|
47
|
+
id-token: write
|
|
48
|
+
steps:
|
|
49
|
+
- name: Download build artifacts
|
|
50
|
+
uses: actions/download-artifact@v4
|
|
51
|
+
with:
|
|
52
|
+
name: dist
|
|
53
|
+
path: dist/
|
|
54
|
+
|
|
55
|
+
- name: Publish to PyPI
|
|
56
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
name: unittest
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issue_comment:
|
|
5
|
+
types: [created]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
checks: write
|
|
10
|
+
pull-requests: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
unittest:
|
|
14
|
+
# only run on pull request
|
|
15
|
+
if: ${{ github.event.issue.pull_request && (startsWith(github.event.comment.body, '/unittest')) && (github.event.comment.author_association == 'COLLABORATOR' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') }}
|
|
16
|
+
runs-on: self-hosted
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
path: tuft-${{ github.run_id }}
|
|
23
|
+
ref: refs/pull/${{ github.event.issue.number }}/head
|
|
24
|
+
|
|
25
|
+
- name: Setup docker compose
|
|
26
|
+
working-directory: tuft-${{ github.run_id }}/.github/workflows/docker
|
|
27
|
+
run: |
|
|
28
|
+
docker compose up -d
|
|
29
|
+
sleep 15s
|
|
30
|
+
|
|
31
|
+
- name: Check ray status
|
|
32
|
+
working-directory: tuft-${{ github.run_id }}/.github/workflows/docker
|
|
33
|
+
run: |
|
|
34
|
+
MAX_RETRIES=20
|
|
35
|
+
RETRY_INTERVAL=5
|
|
36
|
+
for i in $(seq 1 $MAX_RETRIES); do
|
|
37
|
+
if docker compose exec tuft-node-1 bash -c "source /opt/venv/bin/activate && ray status" \
|
|
38
|
+
&& docker compose exec tuft-node-2 bash -c "source /opt/venv/bin/activate && ray status"; then
|
|
39
|
+
break
|
|
40
|
+
fi
|
|
41
|
+
echo "Waiting for ray cluster to be ready... ($i/$MAX_RETRIES)"
|
|
42
|
+
sleep $RETRY_INTERVAL
|
|
43
|
+
if [ "$i" -eq "$MAX_RETRIES" ]; then
|
|
44
|
+
echo "Ray cluster failed to start after $MAX_RETRIES retries."
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
done
|
|
48
|
+
|
|
49
|
+
- name: Run unittest
|
|
50
|
+
working-directory: tuft-${{ github.run_id }}/.github/workflows/docker
|
|
51
|
+
# set a github env variable to indicate tests were run, so that subsequent steps can check it
|
|
52
|
+
run: |
|
|
53
|
+
echo "tests_run=true" >> $GITHUB_ENV
|
|
54
|
+
docker compose exec tuft-node-1 bash -c "source /opt/venv/bin/activate && pytest tests -v -s --gpu --basetemp /mnt/checkpoints --ctrf report.json"
|
|
55
|
+
|
|
56
|
+
- name: Convert report.json time to ms
|
|
57
|
+
working-directory: tuft-${{ github.run_id }}
|
|
58
|
+
if: env.tests_run == 'true' || failure()
|
|
59
|
+
run: |
|
|
60
|
+
REPORT=report.json
|
|
61
|
+
if [ -f "$REPORT" ]; then
|
|
62
|
+
jq '(.results.tests[] | .duration, .start, .stop) |= (. * 1000) | (.results.summary.start, .results.summary.stop) |= (. * 1000)' "$REPORT" > "$REPORT.tmp" && mv "$REPORT.tmp" "$REPORT"
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
- name: Clean checkpoint dir
|
|
66
|
+
working-directory: tuft-${{ github.run_id }}/.github/workflows/docker
|
|
67
|
+
if: always()
|
|
68
|
+
run: |
|
|
69
|
+
docker compose exec tuft-node-1 rm -rf /mnt/checkpoints/*
|
|
70
|
+
continue-on-error: true
|
|
71
|
+
|
|
72
|
+
- name: Upload test results
|
|
73
|
+
if: env.tests_run == 'true' || failure()
|
|
74
|
+
uses: actions/upload-artifact@v4
|
|
75
|
+
with:
|
|
76
|
+
name: pytest-results
|
|
77
|
+
path: tuft-${{ github.run_id }}/report.json
|
|
78
|
+
continue-on-error: true
|
|
79
|
+
|
|
80
|
+
- name: Publish Test Report
|
|
81
|
+
if: env.tests_run == 'true' || failure()
|
|
82
|
+
uses: ctrf-io/github-test-reporter@v1
|
|
83
|
+
with:
|
|
84
|
+
report-path: tuft-${{ github.run_id }}/report.json
|
|
85
|
+
summary: true
|
|
86
|
+
pull-request: false
|
|
87
|
+
issue: ${{ github.event.issue.number }}
|
|
88
|
+
env:
|
|
89
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
90
|
+
continue-on-error: true
|
|
91
|
+
|
|
92
|
+
- name: Remove docker compose
|
|
93
|
+
working-directory: tuft-${{ github.run_id }}/.github/workflows/docker
|
|
94
|
+
if: always()
|
|
95
|
+
run: |
|
|
96
|
+
docker compose down --remove-orphans
|
|
97
|
+
continue-on-error: true
|
|
98
|
+
|
|
99
|
+
- name: Cleanup workspace
|
|
100
|
+
if: always()
|
|
101
|
+
run: |
|
|
102
|
+
rm -rf tuft-${{ github.run_id }} 2>/dev/null
|
|
103
|
+
continue-on-error: true
|
tuft-0.1.1/.gitignore
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
.Python
|
|
8
|
+
build/
|
|
9
|
+
develop-eggs/
|
|
10
|
+
dist/
|
|
11
|
+
downloads/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
*.egg-info/
|
|
19
|
+
.installed.cfg
|
|
20
|
+
*.egg
|
|
21
|
+
|
|
22
|
+
# Virtual environments
|
|
23
|
+
.venv/
|
|
24
|
+
venv/
|
|
25
|
+
ENV/
|
|
26
|
+
.env
|
|
27
|
+
.env.*
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
*.manifest
|
|
31
|
+
*.spec
|
|
32
|
+
|
|
33
|
+
# Unit test / coverage reports
|
|
34
|
+
.coverage
|
|
35
|
+
.coverage.*
|
|
36
|
+
.cache
|
|
37
|
+
nosetests.xml
|
|
38
|
+
coverage.xml
|
|
39
|
+
*.cover
|
|
40
|
+
*.py,cover
|
|
41
|
+
.hypothesis/
|
|
42
|
+
.pytest_cache/
|
|
43
|
+
|
|
44
|
+
# Jupyter Notebook
|
|
45
|
+
.ipynb_checkpoints
|
|
46
|
+
|
|
47
|
+
# mypy
|
|
48
|
+
.mypy_cache/
|
|
49
|
+
.dmypy.json
|
|
50
|
+
dmypy.json
|
|
51
|
+
|
|
52
|
+
# Ruff
|
|
53
|
+
.ruff_cache/
|
|
54
|
+
|
|
55
|
+
# Pyright
|
|
56
|
+
pyrightconfig.json
|
|
57
|
+
|
|
58
|
+
# IDEs / editors
|
|
59
|
+
.vscode/
|
|
60
|
+
.idea/
|
|
61
|
+
*.swp
|
|
62
|
+
*~
|
|
63
|
+
.DS_Store
|
|
64
|
+
|
|
65
|
+
# Ignore uv lockfile
|
|
66
|
+
uv.lock
|
|
67
|
+
|
|
68
|
+
# Ignore rdb files
|
|
69
|
+
*.rdb
|
|
70
|
+
|
|
71
|
+
# Sync history
|
|
72
|
+
.sync_history
|
tuft-0.1.1/.gitmodules
ADDED
|
File without changes
|