forked from MakazhanAlpamys/Soup
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
224 lines (215 loc) · 10.8 KB
/
Copy pathpyproject.toml
File metadata and controls
224 lines (215 loc) · 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "soup-cli"
version = "0.73.0"
description = "Fine-tune and post-train LLMs in one command. No SSH, no config hell."
readme = "README.md"
license = "Apache-2.0"
# Upper-bounded on purpose (#358). CI tests 3.10 / 3.11 / 3.12 and nothing above.
# Without a ceiling, pip on 3.13+ resolves torch wheels nobody here has run, and
# the failure is not a Soup error message — it is a loader crash inside c10.dll /
# libc10.so before any Soup code executes, so the user has nothing to act on.
# `tests/test_requires_python_bound.py` derives this bound from the CI matrix, so
# widening one without the other fails the suite.
requires-python = ">=3.10,<3.13"
authors = [
{ name = "Soup Team", email = "team@trysoup.dev" },
]
keywords = ["llm", "fine-tuning", "lora", "qlora", "machine-learning"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
# Core install (`pip install soup-cli`) is intentionally light: the CLI, config
# system, and data tools — no PyTorch. v0.71.0 split the heavy training stack
# (torch / transformers / peft / trl / datasets / bitsandbytes / accelerate)
# into the `[train]` extra below.
dependencies = [
"typer>=0.9.0,<0.21.0",
"rich>=13.0.0",
"pydantic>=2.0.0",
"pyyaml>=6.0",
"huggingface-hub>=0.16.0",
"plotext>=5.2.0",
]
[project.optional-dependencies]
# v0.71.0 — heavy training stack. `pip install 'soup-cli[train]'` to fine-tune.
# These were core dependencies through v0.70.0; pins are unchanged.
train = [
"torch>=2.0.0",
"transformers>=4.36.0,<5.0.0",
"peft>=0.7.0",
# Capped below 0.29. #326 raised this from `<0.27` after migrating the six
# preference trainers (bco, dpo, ipo, kto, orpo, simpo) off the two trl APIs
# that moved. The cap is no longer set by those trainers at all — see the
# 0.29 note at the bottom, which is about `online_dpo`.
#
# trl removed `max_prompt_length` from the preference configs in STAGES
# rather than in one release — which is why a single spot-check gives the
# wrong answer. This table is now verified the only way that settles it, by
# CONSTRUCTING each config with the exact kwargs the wrappers pass:
#
# version dpo kto orpo cpo bco
# 0.14.0 - 0.26.2 yes yes yes yes yes
# 0.27.0 - 0.27.2 yes NO yes yes yes
# 0.28.0 yes NO NO NO NO
# 0.29.0 - 1.9.2 NO NO NO NO NO
#
# There is NO successor field: `max_length` survives on every version and
# absorbs prompt truncation, so the migration is to stop passing the keyword
# to a config that no longer has it, not to rename it. The trainers now ask
# the config class whether it accepts the keyword (trainer/_trl_compat.py)
# instead of comparing versions, because a version table is exactly what was
# wrong twice before. On every trl that still has the field the behaviour is
# byte-identical — measured: the six train to identical losses on 0.26.2,
# 0.28.0 and 1.9.2 on the same fixture.
#
# Separately, trl 0.29.0 dropped ORPOConfig / CPOConfig / BCOConfig (and
# their trainers) from the public `trl` namespace. They were not deleted —
# they live on under `trl.experimental.<algo>` — so those three trainers now
# fall back to that path when the public import is gone.
#
# WHY THE CAP IS 0.29 AND NOT HIGHER: `soup train --task online_dpo` is
# broken on 0.29.x, and the cause is not in these trainers. trl 0.29 moved
# `BasePairwiseJudge` to `trl.experimental.judges` while still accepting
# `judge=`, so the wrapper correctly selects the judge path and then
# `eval/judge.py::_base_pairwise_judge_cls` cannot import the base class.
# trl 1.x drops `judge=` entirely, so the wrapper falls back to
# `reward_funcs=` and online_dpo works again — measured: all nine tasks build
# on 1.9.2, and the six preference tasks train there. Raising the cap past
# 0.29 therefore needs (a) a `trl.experimental.judges` fallback in
# eval/judge.py and (b) validation of the trl surfaces this bump did not
# exercise (serve, GRPO variants, PPO with a real reward model). Shipping
# against a release nobody has validated is not a substitute for that.
#
# The underlying bug was latent, not new: the trl imports live inside
# `setup()`, which no test had ever called on those wrappers, so CI stayed
# green while anyone pip-installing got a broken install. v0.72.4's
# end-to-end preference tests are what surfaced it.
#
# The floor is 0.14.0, not 0.7.0: `setup()` imports GRPOTrainer
# unconditionally and trl first exports it at 0.14.0 (OnlineDPO / KTO / BCO /
# BasePairwiseJudge arrive at 0.11.0; trl 0.7.0 has none of them). Resolvers
# normally pick the newest allowed version, so the impossible floor only bit
# under a constraints file or anyone reading the metadata as a support claim.
"trl>=0.14.0,<0.29",
"datasets>=2.14.0",
"bitsandbytes>=0.41.0",
"accelerate>=0.25.0",
]
# v0.71.0 — convenience meta-extra pulling the main optional stacks.
all = ["soup-cli[train,serve,ui,data,mcp]"]
eval = ["lm-eval>=0.4.0"]
data = ["datasketch>=1.6.0"]
wandb = ["wandb>=0.15.0,<0.18.0"]
# Self-references `[train]` so CI / contributors get the full training stack
# (CI runs `pip install -e ".[dev]"`; without this every test would fail at
# `import torch`).
dev = ["soup-cli[train,mcp]", "cryptography>=41.0.0", "reportlab>=4.0.0", "pytest>=7.0", "ruff>=0.1.0", "pytest-cov>=4.0", "httpx>=0.24.0", "mypy>=1.8.0", "pre-commit>=3.5.0"]
ui = ["fastapi>=0.104.0", "uvicorn>=0.24.0"]
serve = ["fastapi>=0.104.0", "uvicorn>=0.24.0"]
serve-fast = ["vllm>=0.4.0", "fastapi>=0.104.0", "uvicorn>=0.24.0"]
generate = ["httpx>=0.24.0"]
deepspeed = ["deepspeed>=0.12.0"]
fast = ["unsloth>=2024.8"]
vision = ["Pillow>=9.0.0"]
qat = ["torchao>=0.4.0"]
liger = ["liger-kernel>=0.3.0"]
ring-attn = ["ring-flash-attn>=0.1.0"]
onnx = ["optimum[onnxruntime]>=1.16.0"]
tensorrt = ["tensorrt_llm>=0.9.0"]
audio = ["librosa>=0.10.0", "soundfile>=0.12.0"]
awq = ["autoawq>=0.2.0"]
gptq = ["auto-gptq>=0.7.0"]
sglang = ["sglang>=0.2.0", "fastapi>=0.104.0", "uvicorn>=0.24.0"]
mlx = ["mlx>=0.20.0", "mlx-lm>=0.20.0"]
cce = ["cut-cross-entropy>=24.10.0"]
tui = ["textual>=0.50.0"]
# v0.53.8 #89 — bundle MLflow / SwanLab / Trackio for `--tracker` users.
trackers = ["mlflow>=2.0.0", "swanlab>=0.3.0", "trackio>=0.0.1"]
# v0.53.8 #85 — fsspec backends for remote dataset loading (s3 / gs / az / oci).
remote = ["fsspec>=2024.1.0", "s3fs>=2024.1.0", "gcsfs>=2024.1.0", "adlfs>=2024.1.0"]
# v0.53.10 #150 — bundle scikit-optimize so `soup data mix --optimize` runs the
# Bayesian-style loop instead of falling back to the v0.48.0 Dirichlet sampler.
mix = ["scikit-optimize>=0.9.0"]
# v0.53.10 #113 — production-grade data quality: langdetect (language) +
# presidio-analyzer (PII). Llama-Guard-3-1B is documented as a manual recipe
# (license + ~600 MB weight blob too large to bundle by default).
data-pro = ["langdetect>=1.0.9", "presidio-analyzer>=2.2.0"]
# v0.71.2 #179/#185 — ed25519 detached signing for `soup attest` / `soup
# adapters sign`. Pure-offline; Sigstore keyless (OIDC + Fulcio/Rekor network)
# stays infra-blocked and is NOT bundled here.
sign = ["cryptography>=41.0.0"]
# v0.71.3 #181 — reportlab PDF rendering for `soup train --annex-xi *.pdf`.
pdf = ["reportlab>=4.0.0"]
# v0.71.3 #180 — codecarbon offline energy/CO2 measurement for
# `soup train --track-energy` (offline; no IP-geolocation network call).
carbon = ["codecarbon>=2.0.0"]
# v0.71.13 #225/#227 — prompt-program / tool-schema compilers
# (`soup compile` / `soup compile-tools`). Lazy-imported with a friendly
# ImportError; not installed by default (heavy dependency trees).
compile = ["dspy-ai>=2.5.0", "textgrad>=0.1.0", "gepa>=0.0.1"]
# v0.71.18 #16 — serverless cloud GPU training (`soup train --cloud modal`).
# Lazy-imported; only needed for `--cloud-submit` (plan-only render needs no
# dependency). Modal auth is via `modal setup`.
modal = ["modal>=0.60.0"]
# v0.71.28 - `soup mcp serve` MCP server. The official `mcp` python SDK is
# lazy-imported (only src/soup_cli/mcp_server/server.py touches it), so the CLI
# stays light without it. Floor pinned to guard against SDK API churn.
#
# v0.72.3: capped below 2.0. The floor alone was not enough — mcp 2.0.0 removed
# `mcp.shared.memory.create_connected_server_and_client_session` and dropped
# `Server.list_tools`, which broke every `soup mcp serve` round-trip test on all
# nine CI jobs the day it was published. 1.29.0 (the newest 1.x) still exposes
# both, verified directly. Migrating to the 2.x API is its own piece of work,
# and shipping against a major nobody has validated is not a substitute for it.
mcp = ["mcp>=1.2.0,<2"]
[project.scripts]
soup = "soup_cli.cli:run"
[project.urls]
Homepage = "https://github.com/MakazhanAlpamys/Soup"
Repository = "https://github.com/MakazhanAlpamys/Soup"
Issues = "https://github.com/MakazhanAlpamys/Soup/issues"
Discord = "https://discord.gg/8RgVbFA6Zq"
[tool.hatch.build.targets.wheel]
packages = ["src/soup_cli"]
# v0.53.8 #93 — include bundled fixture JSONLs as package data so
# `soup data demo` works in zipapp / namespace-package installs.
# Hatchling's ``packages = ["src/soup_cli"]`` already recurses into the
# package directory, so we use the artifacts directive (NOT
# force-include, which double-shipped the files in v0.53.8 and produced
# a "duplicate filename in local headers" 400 from PyPI upload).
artifacts = [
"src/soup_cli/data/_fixtures/*.jsonl",
"src/soup_cli/data/_fixtures/unlearning/*.jsonl",
"src/soup_cli/data/_fixtures/behavior/*.jsonl",
"src/soup_cli/data/_fixtures/gate/*.jsonl",
]
[tool.ruff]
target-version = "py310"
line-length = 100
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W"]
[tool.mypy]
# Intentionally lenient: the codebase leans on torch / transformers / peft / trl,
# none of which ship complete stubs. This config surfaces type issues in our own
# code without drowning in third-party `Any`s. The CI `type-check` job is
# non-blocking; tighten incrementally as modules gain annotations.
python_version = "3.10"
files = ["src/soup_cli"]
ignore_missing_imports = true
follow_imports = "silent"
[tool.pytest.ini_options]
testpaths = ["tests"]
markers = [
"smoke: slow smoke tests that download models and run training (run with: pytest -m smoke)",
"unit: fast isolated tests — no subprocess, network, filesystem, or real model load",
"integration: tests that touch real subprocess, SQLite, filesystem, or HTTP",
]
addopts = "-m 'not smoke' --cov=soup_cli --cov-fail-under=77 --cov-report=term-missing:skip-covered"