utrain 0.0.4__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 (67) hide show
  1. utrain-0.0.4/.gitignore +7 -0
  2. utrain-0.0.4/.gitlab-ci.yml +195 -0
  3. utrain-0.0.4/.pre-commit-config.yaml +48 -0
  4. utrain-0.0.4/CHANGELOG.md +17 -0
  5. utrain-0.0.4/LICENSE +21 -0
  6. utrain-0.0.4/Makefile +26 -0
  7. utrain-0.0.4/PKG-INFO +15 -0
  8. utrain-0.0.4/README.md +14 -0
  9. utrain-0.0.4/changes/.empty +0 -0
  10. utrain-0.0.4/changes/1.bugfix.md +1 -0
  11. utrain-0.0.4/containers/shakespeare-char/Containerfile +6 -0
  12. utrain-0.0.4/containers/shakespeare-char/shakespeare_char.py +600 -0
  13. utrain-0.0.4/docs/changelog.md +17 -0
  14. utrain-0.0.4/docs/index.md +50 -0
  15. utrain-0.0.4/docs/installation.md +13 -0
  16. utrain-0.0.4/docs/quickstart.md +72 -0
  17. utrain-0.0.4/pyproject.toml +143 -0
  18. utrain-0.0.4/scripts/check-imports +39 -0
  19. utrain-0.0.4/scripts/release.sh +40 -0
  20. utrain-0.0.4/src/utrain/__init__.py +0 -0
  21. utrain-0.0.4/src/utrain/cli/__init__.py +0 -0
  22. utrain-0.0.4/src/utrain/cli/attempts.py +116 -0
  23. utrain-0.0.4/src/utrain/cli/compute.py +172 -0
  24. utrain-0.0.4/src/utrain/cli/db.py +178 -0
  25. utrain-0.0.4/src/utrain/cli/debug.py +38 -0
  26. utrain-0.0.4/src/utrain/cli/exceptions.py +2 -0
  27. utrain-0.0.4/src/utrain/cli/images.py +121 -0
  28. utrain-0.0.4/src/utrain/cli/main.py +382 -0
  29. utrain-0.0.4/src/utrain/cli/orchestrator.py +363 -0
  30. utrain-0.0.4/src/utrain/cli/output.py +37 -0
  31. utrain-0.0.4/src/utrain/cli/phases.py +228 -0
  32. utrain-0.0.4/src/utrain/cli/reconcile.py +144 -0
  33. utrain-0.0.4/src/utrain/cli/runs.py +705 -0
  34. utrain-0.0.4/src/utrain/cli/store.py +22 -0
  35. utrain-0.0.4/src/utrain/config.py +47 -0
  36. utrain-0.0.4/src/utrain/container/__init__.py +3 -0
  37. utrain-0.0.4/src/utrain/container/podman.py +74 -0
  38. utrain-0.0.4/src/utrain/container/run_data.py +107 -0
  39. utrain-0.0.4/src/utrain/container/schema.py +53 -0
  40. utrain-0.0.4/src/utrain/container/wandb_shim/wandb/__init__.py +14 -0
  41. utrain-0.0.4/tests/__init__.py +0 -0
  42. utrain-0.0.4/tests/conftest.py +125 -0
  43. utrain-0.0.4/tests/containers/fake/Containerfile +6 -0
  44. utrain-0.0.4/tests/containers/fake/fake.py +290 -0
  45. utrain-0.0.4/tests/containers/fake-gpu/Containerfile +5 -0
  46. utrain-0.0.4/tests/containers/fake-gpu/fake_gpu.py +48 -0
  47. utrain-0.0.4/tests/cram/attempt-show.t +37 -0
  48. utrain-0.0.4/tests/cram/compute.t +9 -0
  49. utrain-0.0.4/tests/cram/data-store.t +37 -0
  50. utrain-0.0.4/tests/cram/fixtures/compute-empty.json +9 -0
  51. utrain-0.0.4/tests/cram/fixtures/compute.json +19 -0
  52. utrain-0.0.4/tests/cram/gpu.t +11 -0
  53. utrain-0.0.4/tests/cram/id-prefix.t +15 -0
  54. utrain-0.0.4/tests/cram/image.t +28 -0
  55. utrain-0.0.4/tests/cram/phase-show.t +19 -0
  56. utrain-0.0.4/tests/cram/run-config-protocol.t +29 -0
  57. utrain-0.0.4/tests/cram/run-config.t +19 -0
  58. utrain-0.0.4/tests/cram/run-create.t +9 -0
  59. utrain-0.0.4/tests/cram/run-delete.t +33 -0
  60. utrain-0.0.4/tests/cram/run-lifecycle.t +40 -0
  61. utrain-0.0.4/tests/cram/run-restart.t +24 -0
  62. utrain-0.0.4/tests/cram/run-stop.t +16 -0
  63. utrain-0.0.4/tests/cram/setup.sh +16 -0
  64. utrain-0.0.4/tests/cram/wandb-compat.t +26 -0
  65. utrain-0.0.4/tests/test_cram.py +90 -0
  66. utrain-0.0.4/uv.lock +2214 -0
  67. utrain-0.0.4/zensical.toml +124 -0
@@ -0,0 +1,7 @@
1
+ .aleash*
2
+ **/__pycache__/
3
+ **/node_modules/
4
+ frontend/dist
5
+ .coverage*
6
+ **/*.swp
7
+ **/*.t.err
@@ -0,0 +1,195 @@
1
+ # CI pipeline.
2
+ #
3
+ # check stage: run the pre-commit hooks (`make check`) and the pytest suite on
4
+ # every push to main.
5
+ # release stage: on tag pipelines, build every container preset under
6
+ # containers/<name>/ and push it to this project's GitLab
7
+ # container registry. The pre-commit hooks also run on tags (the
8
+ # check stage runs first), so a release only publishes if they pass.
9
+ # Once the images are built, publish-pypi builds the wheel/sdist
10
+ # with `uv build` and uploads them to PyPI.
11
+ # deploy stage: build the docs with zensical and publish them to GitLab Pages,
12
+ # one version per release tag plus a rolling "dev" for main. mike
13
+ # owns the `pages` branch -- it keeps every version there, and
14
+ # the job only unpacks that branch into public/. Nothing should
15
+ # commit to it by hand.
16
+ #
17
+ # Users pull a published preset with:
18
+ # utrain image add docker://$CI_REGISTRY_IMAGE/<name>:latest
19
+ #
20
+ # Prerequisites:
21
+ # - Container Registry enabled (Settings -> General -> Visibility).
22
+ # - Pages enabled (Settings -> General -> Visibility).
23
+ # - MIKE_ACCESS_TOKEN: a project access token with the write_repository scope,
24
+ # masked and protected, so the pages job can push to the `pages` branch.
25
+ # - PYPI_API_TOKEN: a PyPI API token (scoped to the utrain project once it
26
+ # exists on PyPI, or account-wide for the first publish), masked and
27
+ # protected, so publish-pypi can upload releases. gitlab.inria.fr is
28
+ # self-hosted, so PyPI trusted publishing (OIDC) isn't available -- it
29
+ # only supports gitlab.com.
30
+ # - runner has privileged = true
31
+
32
+ stages: [check, release, deploy]
33
+
34
+ pre-commit:
35
+ stage: check
36
+ image: ghcr.io/astral-sh/uv:python3.11-bookworm
37
+ tags:
38
+ - self-linux
39
+ variables:
40
+ PRE_COMMIT_HOME: "$CI_PROJECT_DIR/.cache/pre-commit"
41
+ UV_CACHE_DIR: "$CI_PROJECT_DIR/.cache/uv"
42
+ cache:
43
+ key: pre-commit
44
+ paths:
45
+ - .cache/pre-commit
46
+ - .cache/uv
47
+ rules:
48
+ - if: '$CI_COMMIT_TAG'
49
+ - if: '$CI_COMMIT_BRANCH == "main"'
50
+ script:
51
+ - uv run --frozen pre-commit run --all-files --show-diff-on-failure
52
+
53
+ test:
54
+ stage: check
55
+ image: quay.io/podman/stable
56
+ tags:
57
+ - self-linux
58
+ rules:
59
+ - if: '$CI_COMMIT_TAG'
60
+ - if: '$CI_COMMIT_BRANCH == "main"'
61
+ variables:
62
+ # vfs because the job's container storage is itself inside a container,
63
+ # where overlay needs a host mount it does not have. It is space-hungry --
64
+ # if this job starts failing on disk, give the runner a bigger volume.
65
+ STORAGE_DRIVER: vfs
66
+ UV_CACHE_DIR: "$CI_PROJECT_DIR/.cache/uv"
67
+ cache:
68
+ key: test
69
+ paths:
70
+ - .cache/uv
71
+ script:
72
+ - curl -LsSf https://astral.sh/uv/install.sh | sh
73
+ - export PATH="$HOME/.local/bin:$PATH"
74
+ - podman run --rm docker.io/library/busybox:latest true
75
+ # -rs prints every skip reason, so a suite that goes quiet in CI says why in
76
+ # the job log rather than just shrinking.
77
+ - uv run --frozen pytest -rs
78
+
79
+ build-images:
80
+ stage: release
81
+ image:
82
+ # The :debug tag ships /busybox/sh so the shell loop below can run.
83
+ name: gcr.io/kaniko-project/executor:debug
84
+ entrypoint: [""]
85
+ tags:
86
+ - self-linux
87
+ rules:
88
+ - if: '$CI_COMMIT_TAG'
89
+ script:
90
+ - mkdir -p /kaniko/.docker
91
+ - |
92
+ cat > /kaniko/.docker/config.json <<EOF
93
+ {"auths":{"$CI_REGISTRY":{"username":"$CI_REGISTRY_USER","password":"$CI_REGISTRY_PASSWORD"}}}
94
+ EOF
95
+ - |
96
+ for dir in containers/*/; do
97
+ name=$(basename "$dir")
98
+ [ -f "containers/$name/Containerfile" ] || continue
99
+ echo "Building and pushing $name"
100
+ /kaniko/executor \
101
+ --context "$CI_PROJECT_DIR" \
102
+ --dockerfile "containers/$name/Containerfile" \
103
+ --destination "$CI_REGISTRY_IMAGE/$name:$CI_COMMIT_TAG" \
104
+ --destination "$CI_REGISTRY_IMAGE/$name:latest"
105
+ done
106
+
107
+ publish-pypi:
108
+ stage: release
109
+ image: ghcr.io/astral-sh/uv:python3.11-bookworm
110
+ tags:
111
+ - self-linux
112
+ needs:
113
+ - job: build-images
114
+ rules:
115
+ - if: '$CI_COMMIT_TAG'
116
+ before_script:
117
+ - |
118
+ if [ -z "$PYPI_API_TOKEN" ]; then
119
+ echo "PYPI_API_TOKEN is unset -- add it as a masked, protected CI/CD variable" >&2
120
+ exit 1
121
+ fi
122
+ script:
123
+ - uv build
124
+ - uv publish --token "$PYPI_API_TOKEN"
125
+
126
+ pages:
127
+ stage: deploy
128
+ image: ghcr.io/astral-sh/uv:python3.11-bookworm
129
+ tags:
130
+ - self-linux
131
+ needs:
132
+ - job: pre-commit
133
+ artifacts: false
134
+ - job: test
135
+ artifacts: false
136
+ rules:
137
+ - if: '$CI_COMMIT_TAG'
138
+ - if: '$CI_COMMIT_BRANCH == "main"'
139
+ # A tag is pushed right after the release commit, so the tag pipeline and the
140
+ # main pipeline overlap. Both push $MIKE_BRANCH; serialize them or the second
141
+ # one dies on a non-fast-forward.
142
+ resource_group: pages
143
+ variables:
144
+ UV_CACHE_DIR: "$CI_PROJECT_DIR/.cache/uv"
145
+ # mike appends to the published site by resetting the local branch to
146
+ # origin/$MIKE_BRANCH, comparing the two through their merge-base. A shallow
147
+ # clone has no merge-base to find.
148
+ GIT_DEPTH: "0"
149
+ # Where mike keeps the built site. mike itself takes this from
150
+ # `remote_branch` in zensical.toml; it is repeated here only for the two git
151
+ # commands below, so the two have to be changed together.
152
+ MIKE_BRANCH: pages
153
+ cache:
154
+ key:
155
+ files:
156
+ - uv.lock
157
+ paths:
158
+ - .cache/uv
159
+ before_script:
160
+ # The token has to be masked *and* protected: main and the release tags are
161
+ # protected refs, and an unprotected variable is simply absent here, which
162
+ # would otherwise surface as an opaque auth failure at push time.
163
+ - |
164
+ if [ -z "$MIKE_ACCESS_TOKEN" ]; then
165
+ echo "MIKE_ACCESS_TOKEN is unset -- add it as a masked, protected CI/CD variable" >&2
166
+ exit 1
167
+ fi
168
+ - uv sync --frozen
169
+ - git remote set-url origin "https://oauth2:${MIKE_ACCESS_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git"
170
+ - git config user.name "GitLab CI"
171
+ - git config user.email "gitlab-ci@$CI_SERVER_HOST"
172
+ script:
173
+ # --alias-type=copy because mike defaults to publishing an alias as a
174
+ # symlink to the version it points at, and GitLab Pages serves the artifact
175
+ # archive without resolving symlinks: "latest" would 404 while "1.2.3"
176
+ # works. set-default has no such option -- it always writes a real redirect.
177
+ - |
178
+ if [ -n "$CI_COMMIT_TAG" ]; then
179
+ uv run mike deploy --push --update-aliases --alias-type=copy "$CI_COMMIT_TAG" latest
180
+ uv run mike set-default --push latest
181
+ else
182
+ uv run mike deploy --push --update-aliases --alias-type=copy dev
183
+ # mike only creates the "/" redirect once "set-default" has been
184
+ # run at least once. Bootstrap it to "dev" so the site is reachable
185
+ # at "/" before the first release tag exists; once a tag has set
186
+ # the default to "latest", leave it alone on later dev pushes.
187
+ if ! git cat-file -e "$MIKE_BRANCH:index.html" 2>/dev/null; then
188
+ uv run mike set-default --push dev
189
+ fi
190
+ fi
191
+ - rm -rf public && mkdir public
192
+ - git archive "$MIKE_BRANCH" | tar -x -C public
193
+ artifacts:
194
+ paths:
195
+ - public
@@ -0,0 +1,48 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v6.0.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ exclude: \.t$
7
+ - id: end-of-file-fixer
8
+ - id: check-yaml
9
+ - id: check-toml
10
+ - id: check-merge-conflict
11
+ - id: check-added-large-files
12
+ args: [--maxkb=1000]
13
+ - id: debug-statements
14
+ - repo: https://github.com/codespell-project/codespell
15
+ rev: v2.4.2
16
+ hooks:
17
+ - id: codespell
18
+ name: Spell check source files
19
+ exclude: frontend/package-lock.json
20
+ - repo: https://github.com/astral-sh/ruff-pre-commit
21
+ rev: v0.15.14
22
+ hooks:
23
+ - id: ruff
24
+ args: [--fix]
25
+ - id: ruff-format
26
+ - repo: local
27
+ hooks:
28
+ - id: check-from-imports
29
+ name: Ban from-imports for everything except relative imports
30
+ entry: scripts/check-imports
31
+ language: system
32
+ types: [python]
33
+ - id: pyright
34
+ name: Type checking for python
35
+ entry: uv run --frozen pyright
36
+ language: system
37
+ types: [python]
38
+ pass_filenames: false
39
+ - id: licensecheck
40
+ name: License compatibility
41
+ entry: uv run --frozen licensecheck
42
+ language: system
43
+ pass_filenames: false
44
+ - id: uv-audit
45
+ name: Vulnerability scan (uv audit)
46
+ entry: uv audit
47
+ language: system
48
+ pass_filenames: false
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ <!-- towncrier release notes start -->
4
+
5
+ ## 0.0.4 (2026-08-18)
6
+
7
+ No significant changes.
8
+
9
+
10
+ ## 0.0.3 (2026-08-18)
11
+
12
+ No significant changes.
13
+
14
+
15
+ ## 0.0.2 (2026-08-17)
16
+
17
+ No significant changes.
utrain-0.0.4/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 INRIA
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
utrain-0.0.4/Makefile ADDED
@@ -0,0 +1,26 @@
1
+ .PHONY: all presets frontend check cram FORCE
2
+
3
+ all: presets
4
+
5
+ frontend:
6
+ cd frontend && npm install && npm run build
7
+
8
+ presets: containers/shakespeare-char
9
+
10
+ containers/%: FORCE
11
+ podman build -t utrain-$*:utrain -f containers/$*/Containerfile .
12
+
13
+ cram:
14
+ uv run pytest tests/test_cram.py
15
+
16
+ check:
17
+ uv run pre-commit run --all-files
18
+
19
+ cov:
20
+ @rm -rf .coverage .coverage.*
21
+ PYTHONUNBUFFERED=1 COVERAGE_PROCESS_START=$(shell pwd)/pyproject.toml COVERAGE_FILE=$(shell pwd)/.coverage uv run pytest
22
+
23
+ cov-report:
24
+ COVERAGE_FILE=$(shell pwd)/.coverage uv run coverage combine --rcfile $(shell pwd)/pyproject.toml -a -q || true
25
+ COVERAGE_FILE=$(shell pwd)/.coverage uv run coverage html -d cov --rcfile $(shell pwd)/pyproject.toml
26
+ COVERAGE_FILE=$(shell pwd)/.coverage uv run coverage report
utrain-0.0.4/PKG-INFO ADDED
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.5
2
+ Name: utrain
3
+ Version: 0.0.4
4
+ Summary: Local web UI for end-to-end LLM training
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.11
8
+ Requires-Dist: anyio>=4.0
9
+ Requires-Dist: fastapi>=0.115
10
+ Requires-Dist: naw>=0.0.4
11
+ Requires-Dist: pydantic-settings>=2.0
12
+ Requires-Dist: pydantic>=2.0
13
+ Requires-Dist: pyyaml>=6.0
14
+ Requires-Dist: sqlalchemy>=2.0
15
+ Requires-Dist: uvicorn[standard]>=0.32
utrain-0.0.4/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # utrain
2
+
3
+ UTrain is a python package that can be run on Linux hosts to manage local SLM training runs:
4
+ - download and install training containers
5
+ - configure your training run
6
+ - monitor the status of your training run
7
+ - check benchmark results
8
+ - manually interact with your model for simple testing
9
+
10
+ If you want to learn how to use utrain, head to our [Documentation](https://mlacage.gitlabpages.inria.fr/utrain).
11
+
12
+ ## License
13
+
14
+ MIT — see [LICENSE](https://gitlab.inria.fr/mlacage/utrain/-/raw/main/LICENSE?ref_type=heads)
File without changes
@@ -0,0 +1 @@
1
+ build and publish release packages on pypi
@@ -0,0 +1,6 @@
1
+ FROM docker.io/python:3.11-slim
2
+ WORKDIR /app
3
+ RUN pip install --no-cache-dir torch --index-url https://download.pytorch.org/whl/cu121
4
+ RUN pip install --no-cache-dir pyyaml wandb
5
+ COPY containers/shakespeare-char/shakespeare_char.py /app/shakespeare_char.py
6
+ ENTRYPOINT ["python", "/app/shakespeare_char.py"]