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
256 lines (247 loc) · 12.7 KB
/
Copy pathpyproject.toml
File metadata and controls
256 lines (247 loc) · 12.7 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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "soup-cli"
version = "0.73.3"
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 6 replaced the module-level plotting API with Figure methods.
# Soup supports both the 5.x and 6.x surfaces through plotext_compat (#522).
"plotext>=5.2.0",
# `env check` reads declared bounds via packaging (Requirement/marker/version).
# It ships with pip and is pulled in transitively, but `env check` degrades to
# a silent "clean" without it — the wrong direction for a checker — so it is
# declared explicitly (#368 review).
"packaging>=21.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.
train = [
"torch>=2.0.0",
# 5.16.1 is the validated Qwen4-Exp floor: an outer `qwen4_exp` config
# selects the text-only Qwen4ExpForCausalLM, and the patch release restores
# tensor-parallel compatibility needed by large-model training. The v5
# range also keeps `[train,mlx]` resolvable because mlx-lm requires v5.
"transformers>=5.16.1,<6.0.0",
# 0.20 is the validated Transformers 5 adapter floor. It still needs Soup's
# explicit qwen3_5_text target policy below the automatic PEFT mapping layer.
"peft>=0.20.0,<1.0.0",
# #326 migrated the six preference trainers (bco, dpo, ipo, kto, orpo,
# simpo) across TRL's staged API moves using capability probes instead of
# version checks. That lets the supported floor move to 0.29 here.
#
# 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.
#
# Transformers 5 changed a private availability helper that trl<=0.28
# imported, which makes absent optional packages look present and prevents
# DPO/GRPO modules from importing (#503). trl 0.29 vendors its own probe and
# is the first compatible release. It also moves BasePairwiseJudge to
# `trl.experimental.judges`; Soup resolves that capability from either home.
# Keep the upper bound below trl 1 because 1.x removes the pairwise `judge=`
# API and is a separate online-DPO migration.
#
# 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.
#
"trl>=0.29.0,<1.0.0",
"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"]
# Aider's normal CLI. Its Polyglot harness is source-only, so `soup eval aider`
# additionally requires the upstream benchmark Docker image documented in
# docs/evaluation.md; the wheel alone cannot supply benchmark/benchmark.py.
aider = ["aider-chat>=0.86.2,<0.87"]
data = ["datasketch>=1.6.0", "scikit-learn>=1.0.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,data]", "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.31.3",
# mlx-lm imports transformers at runtime; keep the standalone contract from
# depending on that transitive requirement remaining undeclared here.
"transformers>=5.16.1,<6.0.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.
# v0.73.4 (#296): floor raised from 1.2.0 for the sse / streamable-http
# transports. Measured against the published wheels rather than the
# changelog: `mcp/server/streamable_http_manager.py` first appears in
# 1.8.0 (absent in 1.7.0) and `mcp/server/transport_security.py` in
# 1.10.0 (absent in 1.9.4). `--transport sse` alone would have run on
# the old floor; DNS-rebinding protection would not, and a listener
# whose origin checking silently vanishes on an older SDK is worse than
# a resolver error. No new package: `mcp` already requires starlette,
# uvicorn, sse-starlette and httpx-sse.
#
# v0.73.4 (#322): cap lifted to `<3`. The two removals that forced it are
# bridged rather than pinned around. `build_server` probes the `Server`
# constructor for `on_list_tools` — 2.x registers handlers there, 1.x through
# decorators — and the round-trip tests were rebuilt on
# `create_client_server_memory_streams`, which both majors still ship, instead
# of the 2.x-removed `create_connected_server_and_client_session`. Verified by
# running the MCP suite twice, once per major, not by reading release notes.
# The three modules the sse / streamable-http transports depend on
# (`sse`, `streamable_http_manager`, `transport_security`) all survive in 2.0.0,
# so those needed no change at all. The floor stays 1.10.0 for the reason above.
mcp = ["mcp>=1.10.0,<3"]
[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"