tuft 0.1.0__tar.gz → 0.1.2__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.
Files changed (88) hide show
  1. tuft-0.1.2/.gitattributes +3 -0
  2. tuft-0.1.2/.github/workflows/checks.yml +65 -0
  3. tuft-0.1.2/.github/workflows/docker/docker-compose.yml +56 -0
  4. tuft-0.1.2/.github/workflows/docker.yml +77 -0
  5. tuft-0.1.2/.github/workflows/install-script.yml +246 -0
  6. tuft-0.1.2/.github/workflows/publish.yml +56 -0
  7. tuft-0.1.2/.github/workflows/unittest.yml +102 -0
  8. tuft-0.1.2/.gitignore +72 -0
  9. tuft-0.1.2/.gitmodules +0 -0
  10. tuft-0.1.2/.pre-commit-config.yaml +51 -0
  11. tuft-0.1.2/.python-version +1 -0
  12. tuft-0.1.2/.secrets.baseline +152 -0
  13. {tuft-0.1.0 → tuft-0.1.2}/LICENSE +2 -2
  14. tuft-0.1.2/PKG-INFO +633 -0
  15. tuft-0.1.2/README.md +571 -0
  16. tuft-0.1.2/assets/countdown_rl.png +3 -0
  17. tuft-0.1.2/assets/test_nll_sft.png +3 -0
  18. tuft-0.1.2/assets/train_mean_nll_sft.png +3 -0
  19. tuft-0.1.2/assets/tuft-logo-colorful.svg +47 -0
  20. tuft-0.1.2/config/tuft_config.example.yaml +120 -0
  21. tuft-0.1.2/docker/Dockerfile +48 -0
  22. tuft-0.1.2/docs/chat_sft.md +322 -0
  23. tuft-0.1.2/docs/countdown_rl.md +300 -0
  24. tuft-0.1.2/docs/how_to_write_tests.md +238 -0
  25. tuft-0.1.2/examples/chat_sft.ipynb +783 -0
  26. tuft-0.1.2/examples/countdown_rl.ipynb +2013 -0
  27. tuft-0.1.2/pyproject.toml +112 -0
  28. tuft-0.1.2/scripts/install.sh +540 -0
  29. tuft-0.1.2/scripts/install_flash_attn.py +72 -0
  30. tuft-0.1.2/src/tuft/__init__.py +6 -0
  31. tuft-0.1.2/src/tuft/__main__.py +7 -0
  32. tuft-0.1.2/src/tuft/auth.py +35 -0
  33. tuft-0.1.2/src/tuft/backend.py +254 -0
  34. tuft-0.1.2/src/tuft/backends/__init__.py +10 -0
  35. tuft-0.1.2/src/tuft/backends/base_backend.py +112 -0
  36. tuft-0.1.2/src/tuft/backends/hf_training_model.py +404 -0
  37. tuft-0.1.2/src/tuft/backends/sampling_backend.py +253 -0
  38. tuft-0.1.2/src/tuft/backends/training_backend.py +327 -0
  39. tuft-0.1.2/src/tuft/checkpoints.py +193 -0
  40. tuft-0.1.2/src/tuft/cli.py +124 -0
  41. tuft-0.1.2/src/tuft/config.py +123 -0
  42. tuft-0.1.2/src/tuft/exceptions.py +138 -0
  43. tuft-0.1.2/src/tuft/futures.py +431 -0
  44. tuft-0.1.2/src/tuft/loss_fn/__init__.py +48 -0
  45. tuft-0.1.2/src/tuft/loss_fn/cispo.py +40 -0
  46. tuft-0.1.2/src/tuft/loss_fn/cross_entropy.py +26 -0
  47. tuft-0.1.2/src/tuft/loss_fn/dro.py +37 -0
  48. tuft-0.1.2/src/tuft/loss_fn/importance_sampling.py +33 -0
  49. tuft-0.1.2/src/tuft/loss_fn/ppo.py +43 -0
  50. tuft-0.1.2/src/tuft/persistence/__init__.py +32 -0
  51. tuft-0.1.2/src/tuft/persistence/file_redis.py +268 -0
  52. tuft-0.1.2/src/tuft/persistence/redis_store.py +488 -0
  53. tuft-0.1.2/src/tuft/sampling_controller.py +368 -0
  54. tuft-0.1.2/src/tuft/server.py +720 -0
  55. tuft-0.1.2/src/tuft/state.py +352 -0
  56. tuft-0.1.2/src/tuft/telemetry/__init__.py +17 -0
  57. tuft-0.1.2/src/tuft/telemetry/metrics.py +335 -0
  58. tuft-0.1.2/src/tuft/telemetry/provider.py +198 -0
  59. tuft-0.1.2/src/tuft/telemetry/tracing.py +43 -0
  60. tuft-0.1.2/src/tuft/training_controller.py +728 -0
  61. tuft-0.1.2/tests/__init__.py +1 -0
  62. tuft-0.1.2/tests/conftest.py +191 -0
  63. tuft-0.1.2/tests/data/models.yaml +19 -0
  64. tuft-0.1.2/tests/helpers.py +245 -0
  65. tuft-0.1.2/tests/test_checkpoints.py +55 -0
  66. tuft-0.1.2/tests/test_cli.py +68 -0
  67. tuft-0.1.2/tests/test_file_redis.py +49 -0
  68. tuft-0.1.2/tests/test_futures.py +83 -0
  69. tuft-0.1.2/tests/test_integration.py +346 -0
  70. tuft-0.1.2/tests/test_integration_persistence.py +210 -0
  71. tuft-0.1.2/tests/test_loss_fn.py +223 -0
  72. tuft-0.1.2/tests/test_persistence.py +727 -0
  73. tuft-0.1.2/tests/test_sampling_backend.py +105 -0
  74. tuft-0.1.2/tests/test_server.py +180 -0
  75. tuft-0.1.2/tests/test_state_controllers.py +491 -0
  76. tuft-0.1.2/tests/test_telemetry.py +490 -0
  77. tuft-0.1.2/tests/test_training_backend.py +322 -0
  78. tuft-0.1.0/PKG-INFO +0 -77
  79. tuft-0.1.0/README.md +0 -49
  80. tuft-0.1.0/pyproject.toml +0 -51
  81. tuft-0.1.0/setup.cfg +0 -4
  82. tuft-0.1.0/src/tuft/__init__.py +0 -3
  83. tuft-0.1.0/src/tuft.egg-info/PKG-INFO +0 -77
  84. tuft-0.1.0/src/tuft.egg-info/SOURCES.txt +0 -10
  85. tuft-0.1.0/src/tuft.egg-info/dependency_links.txt +0 -1
  86. tuft-0.1.0/src/tuft.egg-info/requires.txt +0 -7
  87. tuft-0.1.0/src/tuft.egg-info/top_level.txt +0 -1
  88. tuft-0.1.0/tests/test_tuft.py +0 -11
@@ -0,0 +1,3 @@
1
+ assets/countdown_rl.png filter=lfs diff=lfs merge=lfs -text
2
+ assets/test_nll_sft.png filter=lfs diff=lfs merge=lfs -text
3
+ assets/train_mean_nll_sft.png filter=lfs diff=lfs merge=lfs -text
@@ -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,56 @@
1
+ services:
2
+ # use 2 nodes to simulate a cluster environment
3
+ tuft-node-1:
4
+ image: nvcr.io/nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04
5
+ pull_policy: never
6
+ command: bash -c "
7
+ chmod 1777 /tmp && apt update && apt install -y --no-install-recommends \
8
+ build-essential \
9
+ curl git wget vim tmux net-tools \
10
+ python3 python3-pip python3-dev python3-packaging python3-venv \
11
+ libomp-dev infiniband-diags libibverbs-dev librdmacm-dev rdma-core perftest \
12
+ && rm -rf /var/lib/apt/lists/* \
13
+ && ln -sf /usr/bin/python3 /usr/bin/python \
14
+ && ln -sf /usr/bin/pip3 /usr/bin/pip \
15
+ && bash /workspace/scripts/install.sh --local-source /workspace \
16
+ && source $HOME/.local/bin/env \
17
+ && source /root/.tuft/venv/bin/activate \
18
+ && uv pip install .[dev] \
19
+ && ray start --head --dashboard-host 0.0.0.0 --include-dashboard true --block"
20
+ environment:
21
+ - HF_ENDPOINT=https://hf-mirror.com
22
+ - RAY_ADDRESS=auto
23
+ - TUFT_CHECKPOINT_DIR=/mnt/checkpoints
24
+ - TUFT_TEST_MODEL=/mnt/models/Qwen3-0.6B
25
+ - TUFT_TEST_MODEL_1=/mnt/models/Qwen3-0.6B
26
+ - TUFT_TEST_MODEL_2=/mnt/models/Qwen3-1.7B
27
+ - TEST_REDIS_URL=redis://tuft-redis:6379
28
+ - VIRTUAL_ENV=/root/.tuft/venv
29
+ working_dir: /workspace
30
+ networks:
31
+ - tuft-network
32
+ volumes:
33
+ - tuft-volume:/mnt
34
+ - ../../..:/workspace
35
+ shm_size: "64G"
36
+ deploy:
37
+ resources:
38
+ reservations:
39
+ devices:
40
+ - driver: nvidia
41
+ device_ids: ['0', '1', '2', '3']
42
+ capabilities: [gpu]
43
+
44
+ tuft-redis:
45
+ image: redis:7.0
46
+ command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"]
47
+ networks:
48
+ - tuft-network
49
+
50
+ networks:
51
+ tuft-network:
52
+ driver: bridge
53
+
54
+ volumes:
55
+ tuft-volume:
56
+ 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,246 @@
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 launch --help
63
+ run: |
64
+ export PATH="${TUFT_HOME}/bin:$PATH"
65
+ tuft launch --help
66
+ env:
67
+ TUFT_HOME: ${{ runner.temp }}/tuft
68
+
69
+ - name: Test tuft launch requires config
70
+ run: |
71
+ export PATH="${TUFT_HOME}/bin:$PATH"
72
+ # Should fail with config error when no config provided
73
+ if tuft launch 2>&1; then
74
+ echo "Expected tuft launch to fail without config"
75
+ exit 1
76
+ fi
77
+ # Verify error message mentions config
78
+ tuft launch 2>&1 | grep -qi "config"
79
+ env:
80
+ TUFT_HOME: ${{ runner.temp }}/tuft
81
+
82
+ - name: Test tuft launch with config file
83
+ run: |
84
+ export PATH="${TUFT_HOME}/bin:$PATH"
85
+ # Create a minimal config file
86
+ cat > "${TUFT_HOME}/configs/tuft_config.yaml" << 'EOF'
87
+ model_owner: test
88
+ supported_models:
89
+ - model_name: test-model
90
+ model_path: /nonexistent/path
91
+ max_model_len: 1024
92
+ authorized_users:
93
+ test-key: test-user
94
+ EOF
95
+ # Launch should fail due to missing model, but get past config validation
96
+ # We just verify it doesn't fail on config parsing
97
+ tuft launch 2>&1 | grep -v "Configuration file must be provided" || true
98
+ env:
99
+ TUFT_HOME: ${{ runner.temp }}/tuft
100
+
101
+ - name: Clean up installation
102
+ run: rm -rf "${TUFT_HOME}"
103
+ env:
104
+ TUFT_HOME: ${{ runner.temp }}/tuft
105
+
106
+ test-backend-dependencies:
107
+ runs-on: ubuntu-latest
108
+
109
+ steps:
110
+ - name: Checkout code
111
+ uses: actions/checkout@v4
112
+
113
+ - name: Run install script
114
+ run: |
115
+ bash scripts/install.sh --local-source "$GITHUB_WORKSPACE"
116
+ env:
117
+ TUFT_HOME: ${{ runner.temp }}/tuft
118
+
119
+ - name: Verify backend dependencies installed
120
+ run: |
121
+ "${TUFT_HOME}/venv/bin/python" -c "import peft; print('peft imported successfully')"
122
+ "${TUFT_HOME}/venv/bin/python" -c "import redis; print('redis imported successfully')"
123
+ env:
124
+ TUFT_HOME: ${{ runner.temp }}/tuft
125
+
126
+ - name: Clean up installation
127
+ run: rm -rf "${TUFT_HOME}"
128
+ env:
129
+ TUFT_HOME: ${{ runner.temp }}/tuft
130
+
131
+ test-wrapper-commands:
132
+ runs-on: ubuntu-latest
133
+
134
+ steps:
135
+ - name: Checkout code
136
+ uses: actions/checkout@v4
137
+
138
+ - name: Install tuft
139
+ run: bash scripts/install.sh --local-source "$GITHUB_WORKSPACE"
140
+ env:
141
+ TUFT_HOME: ${{ runner.temp }}/tuft
142
+
143
+ - name: Test help command
144
+ run: |
145
+ export PATH="${TUFT_HOME}/bin:$PATH"
146
+ tuft help
147
+ env:
148
+ TUFT_HOME: ${{ runner.temp }}/tuft
149
+
150
+ - name: Test version command
151
+ run: |
152
+ export PATH="${TUFT_HOME}/bin:$PATH"
153
+ tuft version
154
+ env:
155
+ TUFT_HOME: ${{ runner.temp }}/tuft
156
+
157
+ - name: Test upgrade command (from PyPI)
158
+ run: |
159
+ export PATH="${TUFT_HOME}/bin:$PATH"
160
+ tuft upgrade
161
+ env:
162
+ TUFT_HOME: ${{ runner.temp }}/tuft
163
+
164
+ - name: Test upgrade command (from local source)
165
+ run: |
166
+ export PATH="${TUFT_HOME}/bin:$PATH"
167
+ tuft upgrade --local-source "$GITHUB_WORKSPACE"
168
+ env:
169
+ TUFT_HOME: ${{ runner.temp }}/tuft
170
+
171
+ - name: Clean up installation
172
+ run: rm -rf "${TUFT_HOME}"
173
+ env:
174
+ TUFT_HOME: ${{ runner.temp }}/tuft
175
+
176
+ test-clean-install:
177
+ runs-on: ubuntu-latest
178
+
179
+ steps:
180
+ - name: Checkout code
181
+ uses: actions/checkout@v4
182
+
183
+ - name: Initial install
184
+ run: |
185
+ bash scripts/install.sh --local-source "$GITHUB_WORKSPACE"
186
+ env:
187
+ TUFT_HOME: ${{ runner.temp }}/tuft
188
+
189
+ - name: Create marker file to verify clean
190
+ run: |
191
+ echo "marker" > "${TUFT_HOME}/marker.txt"
192
+ test -f "${TUFT_HOME}/marker.txt"
193
+ env:
194
+ TUFT_HOME: ${{ runner.temp }}/tuft
195
+
196
+ - name: Reinstall with --clean
197
+ run: |
198
+ bash scripts/install.sh --local-source "$GITHUB_WORKSPACE" --clean
199
+ env:
200
+ TUFT_HOME: ${{ runner.temp }}/tuft
201
+
202
+ - name: Verify marker file was removed
203
+ run: |
204
+ # Marker file should be gone after --clean
205
+ test ! -f "${TUFT_HOME}/marker.txt"
206
+ # But tuft should still be installed
207
+ "${TUFT_HOME}/venv/bin/python" -c "import tuft; print('tuft imported successfully')"
208
+ env:
209
+ TUFT_HOME: ${{ runner.temp }}/tuft
210
+
211
+ - name: Clean up installation
212
+ run: rm -rf "${TUFT_HOME}"
213
+ env:
214
+ TUFT_HOME: ${{ runner.temp }}/tuft
215
+
216
+ test-upgrade-from-source:
217
+ runs-on: ubuntu-latest
218
+
219
+ steps:
220
+ - name: Checkout code
221
+ uses: actions/checkout@v4
222
+
223
+ - name: Install tuft
224
+ run: bash scripts/install.sh --local-source "$GITHUB_WORKSPACE"
225
+ env:
226
+ TUFT_HOME: ${{ runner.temp }}/tuft
227
+
228
+ - name: Test upgrade --from-source
229
+ run: |
230
+ export PATH="${TUFT_HOME}/bin:$PATH"
231
+ tuft upgrade --from-source
232
+ env:
233
+ TUFT_HOME: ${{ runner.temp }}/tuft
234
+
235
+ - name: Verify tuft still works after upgrade
236
+ run: |
237
+ export PATH="${TUFT_HOME}/bin:$PATH"
238
+ tuft version
239
+ tuft launch --help
240
+ env:
241
+ TUFT_HOME: ${{ runner.temp }}/tuft
242
+
243
+ - name: Clean up installation
244
+ run: rm -rf "${TUFT_HOME}"
245
+ env:
246
+ 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,102 @@
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 /root/.tuft/venv/bin/activate && ray status"; then
38
+ break
39
+ fi
40
+ echo "Waiting for ray cluster to be ready... ($i/$MAX_RETRIES)"
41
+ sleep $RETRY_INTERVAL
42
+ if [ "$i" -eq "$MAX_RETRIES" ]; then
43
+ echo "Ray cluster failed to start after $MAX_RETRIES retries."
44
+ exit 1
45
+ fi
46
+ done
47
+
48
+ - name: Run unittest
49
+ working-directory: tuft-${{ github.run_id }}/.github/workflows/docker
50
+ # set a github env variable to indicate tests were run, so that subsequent steps can check it
51
+ run: |
52
+ echo "tests_run=true" >> $GITHUB_ENV
53
+ docker compose exec tuft-node-1 bash -c "source /root/.tuft/venv/bin/activate && pytest tests -v -s --gpu --basetemp /mnt/checkpoints --ctrf report.json"
54
+
55
+ - name: Convert report.json time to ms
56
+ working-directory: tuft-${{ github.run_id }}
57
+ if: env.tests_run == 'true' || failure()
58
+ run: |
59
+ REPORT=report.json
60
+ if [ -f "$REPORT" ]; then
61
+ jq '(.results.tests[] | .duration, .start, .stop) |= (. * 1000) | (.results.summary.start, .results.summary.stop) |= (. * 1000)' "$REPORT" > "$REPORT.tmp" && mv "$REPORT.tmp" "$REPORT"
62
+ fi
63
+
64
+ - name: Clean checkpoint dir
65
+ working-directory: tuft-${{ github.run_id }}/.github/workflows/docker
66
+ if: always()
67
+ run: |
68
+ docker compose exec tuft-node-1 rm -rf /mnt/checkpoints/*
69
+ continue-on-error: true
70
+
71
+ - name: Upload test results
72
+ if: env.tests_run == 'true' || failure()
73
+ uses: actions/upload-artifact@v4
74
+ with:
75
+ name: pytest-results
76
+ path: tuft-${{ github.run_id }}/report.json
77
+ continue-on-error: true
78
+
79
+ - name: Publish Test Report
80
+ if: env.tests_run == 'true' || failure()
81
+ uses: ctrf-io/github-test-reporter@v1
82
+ with:
83
+ report-path: tuft-${{ github.run_id }}/report.json
84
+ summary: true
85
+ pull-request: false
86
+ issue: ${{ github.event.issue.number }}
87
+ env:
88
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
89
+ continue-on-error: true
90
+
91
+ - name: Remove docker compose
92
+ working-directory: tuft-${{ github.run_id }}/.github/workflows/docker
93
+ if: always()
94
+ run: |
95
+ docker compose down --remove-orphans
96
+ continue-on-error: true
97
+
98
+ - name: Cleanup workspace
99
+ if: always()
100
+ run: |
101
+ rm -rf tuft-${{ github.run_id }} 2>/dev/null
102
+ continue-on-error: true
tuft-0.1.2/.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.2/.gitmodules ADDED
File without changes