mirror of
https://github.com/elder-plinius/OBLITERATUS.git
synced 2026-09-21 08:50:42 +02:00
Merge pull request #205 from electrobrian/packaging/unpinned-build-backends
Integrate packaging fix after merging current main without rewriting contributor history.
Validated head: 92db941ed0 (GitHub verified signature).
Local Python 3.12 CPU validation: 636 selected tests passed; Ruff F, actionlint, uv lock --check, conditional policy, risk map, import and CLI checks passed. Built sdist and wheel. No changed executable production lines.
Hosted CI: https://github.com/elder-plinius/OBLITERATUS/actions/runs/35549530703 (success).
Android runtime and Docker runtime not exercised.
This commit is contained in:
+5
-3
@@ -10,15 +10,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install Python deps first (cache layer)
|
||||
# Install Python deps first (cache layer). requirements.txt is the core
|
||||
# package graph; the Spaces extra adds Gradio for app.py without pulling
|
||||
# the quantization extra.
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copy project
|
||||
COPY . .
|
||||
|
||||
# Install the package itself (for obliteratus imports)
|
||||
RUN pip install --no-cache-dir .
|
||||
# Install the package itself (for obliteratus imports) plus the UI extra.
|
||||
RUN pip install --no-cache-dir ".[spaces]"
|
||||
|
||||
# Run as non-root user for security
|
||||
RUN useradd -m appuser
|
||||
|
||||
@@ -170,7 +170,9 @@ and rollback requirements.
|
||||
Install `.[spaces,quantization]` instead when the UI must load supported
|
||||
bitsandbytes 8-bit or 4-bit models. Jetson users must follow the dedicated
|
||||
[Jetson bootstrap](docs/platforms/jetson.md); its bitsandbytes path is not yet
|
||||
supported.
|
||||
supported. Android/Termux is not a supported runtime; if you install there
|
||||
anyway, follow the [Android install notes](docs/platforms/android.md) so pip
|
||||
does not isolate a second setuptools or replace host wheels.
|
||||
|
||||
### 3. Google Colab (free GPU)
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
"scripts/select_pr_tests.py",
|
||||
"scripts/setup_jetson.py",
|
||||
"pyproject.toml",
|
||||
"requirements.txt",
|
||||
"Dockerfile",
|
||||
"docs/platforms/**",
|
||||
"uv.lock",
|
||||
"tests/fixtures/distributed_checkpoints/**"
|
||||
],
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# Android / Termux install notes
|
||||
|
||||
Android is not a supported OBLITERATUS runtime. These notes exist so a
|
||||
Termux (or other Android Python) install does not fight host wheels or
|
||||
download a second setuptools behind PEP 517 isolation.
|
||||
|
||||
`sys.platform` on current Android CPython is `android`, not `linux`. The
|
||||
locked CPU PyTorch index in `pyproject.toml` is intentionally limited to
|
||||
`linux` and `win32` manylinux/Windows wheels. Do not point Android at that
|
||||
index.
|
||||
|
||||
## Layout
|
||||
|
||||
1. Install the platform's own `python`, `setuptools`, and scientific
|
||||
wheels first (`torch`, `numpy`, and whatever Termux already packages).
|
||||
Those builds carry the Android patches that PyPI wheels do not.
|
||||
`safetensors` and `tokenizers` are Rust extensions; rustup does not
|
||||
host `aarch64-linux-android`, so install Termux `rust` before pip
|
||||
and export the API level Python was built against (24 on current
|
||||
Termux):
|
||||
|
||||
```bash
|
||||
pkg install rust
|
||||
export ANDROID_API_LEVEL=24
|
||||
```
|
||||
|
||||
2. Isolated pip builds of meson packages (pandas, matplotlib) will try
|
||||
to compile `cmake`/`ninja` from source and can hang under proot.
|
||||
Install those binaries from Termux first (`pkg install ninja cmake
|
||||
python-matplotlib python-scipy python-pillow python-psutil
|
||||
python-pyarrow python-greenlet python-brotli python-cryptography
|
||||
python-rpds-py python-msgpack libraqm harfbuzz`). PyPI `psutil`
|
||||
sdists reject `sys.platform == "android"`; the Termux package is
|
||||
patched. Termux matplotlib needs `libraqm`. PyPI `tokenizers` abi3
|
||||
wheels fail on CPython 3.14 (`PyBaseObject_Type`); rebuild without
|
||||
the `abi3` cargo feature so the extension is `cp314` instead of
|
||||
`abi3`. Then install OBLITERATUS without build isolation:
|
||||
|
||||
```bash
|
||||
python -m pip install --no-build-isolation -e ".[spaces]"
|
||||
```
|
||||
|
||||
3. If pip still tries to compile `torch` or `numpy` from source, install
|
||||
the project over the host packages instead:
|
||||
|
||||
```bash
|
||||
python -m pip install --no-build-isolation --no-deps -e .
|
||||
python -m pip install --no-build-isolation "gradio>=6.7,<7.0"
|
||||
```
|
||||
|
||||
Do not use `uv sync --locked` on Android. The lock resolves Linux/Windows
|
||||
CPU PyTorch and does not contain `android_*` wheels for torch, numpy,
|
||||
pyarrow, tokenizers, or bitsandbytes.
|
||||
|
||||
The `quantization` and `qwen-hybrid` extras are CUDA-oriented and are not
|
||||
an Android install path.
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
[build-system]
|
||||
requires = ["setuptools==80.9.0", "wheel==0.45.1"]
|
||||
# Lower bound only. Exact backend pins block platform-specific setuptools patches.
|
||||
# A separate wheel package is not required for the PEP 517 backend.
|
||||
requires = ["setuptools>=80.9.0"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
|
||||
+2
-2
@@ -1,4 +1,5 @@
|
||||
gradio>=6.7,<7.0
|
||||
# Mirrors [project].dependencies in pyproject.toml.
|
||||
# Optional extras (spaces, quantization, qwen-hybrid, dev) are not included.
|
||||
torch>=2.0
|
||||
transformers>=4.40
|
||||
datasets>=2.14
|
||||
@@ -13,4 +14,3 @@ numpy>=1.24
|
||||
scikit-learn>=1.3
|
||||
tqdm>=4.64
|
||||
optuna>=4.9,<5
|
||||
bitsandbytes>=0.46.1
|
||||
|
||||
@@ -225,6 +225,28 @@ def test_ci_evidence_names_the_pull_request_head_not_the_synthetic_merge_commit(
|
||||
assert '--head-sha "$GITHUB_SHA"' not in workflow
|
||||
|
||||
|
||||
def test_build_backend_requirements_use_lower_bounds_not_exact_pins():
|
||||
pyproject = (ROOT / "pyproject.toml").read_text(encoding="utf-8")
|
||||
match = re.search(
|
||||
r"(?ms)^\[build-system\]\n(?:#[^\n]*\n)*requires = \[([^\]]+)\]",
|
||||
pyproject,
|
||||
)
|
||||
assert match is not None
|
||||
requires = re.findall(r'"([^"]+)"', match.group(1))
|
||||
assert requires
|
||||
for requirement in requires:
|
||||
spec = requirement.split(";", 1)[0]
|
||||
name = re.split(r"[<>=!~]", spec, maxsplit=1)[0].strip()
|
||||
assert name != "wheel", requirement
|
||||
assert "==" not in spec, requirement
|
||||
assert ">=" in spec, requirement
|
||||
lower = re.findall(r">=([^,]+)", spec)
|
||||
upper = re.findall(r"<=([^,]+)", spec)
|
||||
assert not (
|
||||
lower and upper and lower[0] == upper[0]
|
||||
), f"collapsed exact pin written as a range: {requirement}"
|
||||
|
||||
|
||||
def test_ci_runs_checkpoint_portability_contracts_on_windows():
|
||||
workflow = WORKFLOW.read_text(encoding="utf-8")
|
||||
checkpoint_job = workflow.split(" checkpoint-windows:\n", maxsplit=1)[1].split(
|
||||
|
||||
@@ -217,6 +217,26 @@ def test_bitsandbytes_is_opt_in_for_quantization_only():
|
||||
assert extras["quantization"] == ["bitsandbytes>=0.46.1"]
|
||||
|
||||
|
||||
def test_requirements_txt_mirrors_core_pyproject_dependencies():
|
||||
metadata = tomllib.loads((ROOT / "pyproject.toml").read_text())
|
||||
requirements = [
|
||||
line.strip()
|
||||
for line in (ROOT / "requirements.txt").read_text().splitlines()
|
||||
if line.strip() and not line.startswith("#")
|
||||
]
|
||||
|
||||
assert requirements == metadata["project"]["dependencies"]
|
||||
assert not any(value.startswith("bitsandbytes") for value in requirements)
|
||||
assert not any(value.startswith("gradio") for value in requirements)
|
||||
|
||||
|
||||
def test_dockerfile_installs_spaces_extra_not_quantization():
|
||||
dockerfile = (ROOT / "Dockerfile").read_text()
|
||||
|
||||
assert 'pip install --no-cache-dir ".[spaces]"' in dockerfile
|
||||
assert "bitsandbytes" not in dockerfile
|
||||
|
||||
|
||||
def test_jetson_issue_form_requires_reproducible_sanitized_hardware_evidence():
|
||||
form = yaml.safe_load(
|
||||
(ROOT / ".github" / "ISSUE_TEMPLATE" / "jetson-runtime.yml").read_text(),
|
||||
|
||||
Reference in New Issue
Block a user