-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
executable file
·214 lines (197 loc) · 9.78 KB
/
Copy pathpyproject.toml
File metadata and controls
executable file
·214 lines (197 loc) · 9.78 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
[project]
name = "halo"
version = "1.0.0"
description = "Halo is an open-source framework built by White Circle for training large language and multimodal models."
readme = "README.md"
requires-python = ">=3.12,<3.13"
license = "LicenseRef-Halo"
license-files = ["LICENSE", "APACHE-2.0.txt"]
authors = [
{ name = "Sergei Bratchikov", email = "sergey@whitecircle.com" },
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Science/Research",
"Programming Language :: Python :: 3.12",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
dependencies = [
"accelerate>=1.11.0,<1.12.0",
"backoff>=2.2.1,<3.0.0",
"bitsandbytes>=0.49.2,<0.50.0", # 0.49.2 ships libbitsandbytes_cuda130.so; 0.46.x errors under cu13
"boto3>=1.35.0,<2.0.0",
"causal-conv1d>=1.6.0,<2.0.0",
"clearml>=2.0.2,<3.0.0",
"click>=8.1.0,<9.0.0", # typer's CLI engine; src/cli.py raises click.UsageError directly
"datasets>=4.8.5,<5.0.0",
"ddgs>=9.10.0,<10.0.0",
"faiss-cpu>=1.10.0,<2.0.0",
"flash-linear-attention>=0.4.1,<0.5.0", # DeltaNet kernels for Qwen3.5 hybrid attention
"gradio>=5.26.0,<6.0.0",
"gram-newton-schulz",
"huggingface-hub>=1.0.0,<2.0.0",
"kernels>=0.10.4,<0.11.0",
"liger-kernel>=0.8.0,<0.9.0",
"loguru>=0.7.2,<0.8.0",
"matplotlib>=3.10.5,<4.0.0",
"mcp>=1.22.0,<2.0.0",
"msgspec>=0.19.0,<0.20.0",
"openai>=1.44.1,<2.0.0",
"pandas>=2.2.1,<3.0.0",
"peft>=0.18.1,<0.19.0",
"pydantic>=2.6.4,<3.0.0",
"ray[default]>=2.52.0,<2.53.0",
"ruamel-yaml>=0.19.1,<0.20.0",
"s3fs>=2024.6.0",
"sentence-transformers>=5.2.2,<6.0.0",
"tabulate>=0.9.0,<0.10.0",
"tokenizers>=0.23.1,<0.24.0",
"torch>=2.11.0,<2.12.0",
"torchvision>=0.26.0,<0.27.0", # transformers fast image processors (VLM training); the Dockerfile drops the NGC copy and reinstalls the locked one
"transformers>=5.16.1,<5.17.0",
"trl>=1.6.0,<1.7.0",
"typer>=0.25.1,<0.26.0",
"wandb>=0.25.0,<0.26.0",
]
[project.urls]
Homepage = "https://github.com/whitecircle/halo"
Repository = "https://github.com/whitecircle/halo"
Issues = "https://github.com/whitecircle/halo/issues"
[project.scripts]
halo = "src.cli:main"
# vllm/sglang run in separate Docker containers (they carry their own torch/transformers stacks).
# See: Dockerfile.vllm, docker-compose.vllm.yml
# flash-attn is installed separately with --no-build-isolation (see Dockerfile).
# nvidia-cutlass-dsl 4.5.2 + quack-kernels 0.5.0 (Blackwell block-scaled MoE grouped-GEMM and
# Muon Newton-Schulz kernels) are pinned by a Dockerfile pip-install over the lock's 4.4.2/0.4.1
# (gram-newton-schulz's hard pin). Not declared here because the resolver can't co-resolve the
# git-dep pin; the kernels degrade gracefully when absent.
[project.optional-dependencies]
flash-optimizers = [
"flashoptim>=0.1.3,<0.2.0",
]
gigatoken = [
"gigatoken>=0.9.0,<0.10.0", # Rust bulk tokenizer backend for dataset preprocessing (pre-1.0 API)
]
# --- Dev tooling groups (PEP 735). Installed in-image so the image is the test runtime;
# `ty` is intentionally absent — type-checking is pyright (basic), run via Pylance / a Node install
# (see [tool.pyright]), not a pip tool. ---
[dependency-groups]
dev = [
{ include-group = "lint" },
{ include-group = "test" },
{ include-group = "profiling" },
]
lint = [
"ruff>=0.9.9,<0.10.0",
]
# anyio and pillow are declared, not left transitive: anyio's pytest11 plugin is what applies
# ``pytest.mark.anyio`` (without it the async environment tests silently collect zero items),
# and tests/common/datasets.py builds VLM fixtures with PIL. Both arrive today only via httpx/openai
# and transformers, so a dependency bump that drops either edge would quietly shrink the suite.
test = [
"pytest>=9.0.1,<10.0.0",
"anyio>=4.13,<5.0",
"pillow>=11.3,<12.0",
]
# Trace analysis + CPU flame graphs (scripts/profiling/, src/diagnostics/debugging.py).
# TraceLens is git-only — the PyPI name `tracelens` is an unrelated project; openpyxl backs its
# .xlsx reports; py-spy backs the stack dumps / CPU flame graphs.
profiling = [
"tracelens",
"openpyxl>=3.1,<4.0",
"py-spy>=0.4.0,<0.5.0",
]
[tool.uv]
required-version = ">=0.10.5"
default-groups = ["dev"]
# DeepEP V2 (EPv2, NCCL Gin backend) is built from source against NCCL >= 2.30.4 (see
# Dockerfile). torch 2.11+cu130's wheel metadata hard-pins nvidia-nccl-cu13==2.28.9, so we
# OVERRIDE it — torch dynamically links libnccl.so.2 (ABI-stable across 2.x).
# EXACT pin, not a floor: all four build sites (both training images, Dockerfile.vllm,
# Dockerfile.sglang) install this one wheel, and under a floor whichever image is rebuilt last
# resolves whatever PyPI has moved to — the RL weight-sync ncclCommInitRank then fails on the skew.
# It must also stay at or above the DeepEP V2 floor (docker/nccl_pin.py MINIMUM) that deep_ep._C is
# compiled against. Bumping it means a `uv lock` AND a rebuild of all four images, not a lock edit.
override-dependencies = ["nvidia-nccl-cu13==2.31.2"]
[tool.uv.sources]
gram-newton-schulz = { git = "https://github.com/Dao-AILab/gram-newton-schulz.git" }
tracelens = { git = "https://github.com/AMD-AGI/TraceLens.git", tag = "v0.4.0" }
torch = { index = "pytorch-cu130" }
[[tool.uv.index]]
name = "pytorch-cu130"
url = "https://download.pytorch.org/whl/cu130"
explicit = true
[tool.ruff]
# Matches the direct upstreams (TRL + Transformers). The code is already ~p95=87 cols,
# so the format-only diff is small. Vendored / third-party trees are excluded.
target-version = "py312"
line-length = 119
# docker/vllm/parity/fixtures carries hub remote-code modules verbatim.
extend-exclude = ["vendors", "docker/vllm/parity/fixtures"]
[tool.ruff.lint]
# E,F,W,I = pycodestyle/pyflakes/isort; UP = pyupgrade; B = bugbear; C4 = comprehensions;
# SIM = simplify; T20 = no stray print() in src/; PLC0415 = no inline imports.
# The whole set is a blocking CI gate (.github/workflows/lint.yml) — `ruff check .` must stay clean.
# PLC0415 is a preview rule: `preview` + `explicit-preview-rules` arm it WITHOUT pulling in every
# other preview rule (without them it is selected but silently does nothing).
preview = true
explicit-preview-rules = true
select = ["E", "F", "I", "W", "UP", "B", "C4", "SIM", "T20", "PLC0415"]
ignore = [
"E501", # line length is enforced by the formatter, not the linter
"UP038", # isinstance(x, A | B) is slower than the tuple form at runtime (rule deprecated upstream)
]
[tool.ruff.lint.per-file-ignores]
# Tests: module-level setup imports (E402), asserts (S101), inline imports + prints are fine.
# E741 (`l`/`I`/`O` names — `for l in losses` is idiomatic here), B007 (unused loop var) and
# B023 (loop var captured in a closure — the closures are consumed within the same iteration in
# these test helpers) and SIM117 (nested `with patch(...)` is the idiomatic mock-stack form) are
# accepted in tests rather than churned across the suite.
"tests/**" = ["E402", "PLC0415", "T20", "E741", "B007", "B023", "SIM117"]
# Scripts are CLIs — prints are the interface.
"scripts/**" = ["T20"]
# Docs diagram generators: `from _theory_style import *` shares one matplotlib theme, and the
# matplotlib `use()`-before-`pyplot` idiom puts an import after a call.
"scripts/diagrams/*" = ["F403", "F405", "E402"]
# Build-time check script: printing each result is its interface, and it imports vLLM (present only
# in the server image) after setting sys.path, so the imports cannot be module-top.
"docker/vllm/plugins/verify_gptoss_plugins.py" = ["T20", "E402"]
# Build-time config-parity gate + its fixture generator: printed results are the interface.
"docker/vllm/parity/*.py" = ["T20"]
# Build-time pin resolver: the printed version IS its interface (a Dockerfile reads it off stdout).
"docker/nccl_pin.py" = ["T20"]
# Gradio's documented progress idiom is `def fn(..., progress=gr.Progress())` — the call in the
# default is how Gradio injects the tracker, so B008 (call in arg default) does not apply here.
# Package re-export shims: re-exported names (F401) and `import *` aggregation (F403/F405).
[tool.ruff.lint.isort]
# Pin import grouping (I001) so it is deterministic regardless of stray directories at the repo root:
# a gitignored `wandb/` run dir and the tracked `launcher-configs/accelerate/` config dir would otherwise make ruff
# infer those third-party packages as first-party locally but not in CI.
known-first-party = ["src", "tests"]
known-third-party = ["wandb", "accelerate"]
[tool.pyright]
# ruff's complement: type-aware checks (call args, None access, attribute typos, bad returns).
# Single source of truth shared with Pylance (.vscode/settings.json). BASIC mode + non-blocking to
# start (53k LOC of dynamic torch/DTensor code); tighten over time like the ruff lint-clean milestone.
# Full checks need the deps installed, so run pyright IN the image (the host has no torch); a bare-host
# run only checks our-code-to-our-code with third-party imports relaxed.
typeCheckingMode = "basic"
pythonVersion = "3.12"
exclude = ["vendors", "**/__pycache__", ".venv"]
reportMissingTypeStubs = false # third-party libs without py.typed shouldn't spam diagnostics
reportMissingModuleSource = false # host runs may not have the torch env installed
[tool.pytest.ini_options]
# CPU tests run inside the image (they import torch); GPU tests are torchrun scripts
# launched as subprocesses by tests/gpu/conftest.py from tests/gpu/manifest.py — pytest
# never imports them. Markers are registered in tests/conftest.py (from manifest.ALL_MARKERS)
# so --strict-markers stays a single source of truth.
testpaths = ["tests"]
python_files = ["test_*.py"]
addopts = "--strict-markers -ra"
norecursedirs = ["*.egg", ".*", "build", "dist", "vendors"]
[build-system]
requires = ["hatchling>=1.27.0"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src"]