mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-25 00:02:25 +02:00
71 lines
2.4 KiB
Bash
Executable File
71 lines
2.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build patched wheels for Real-ESRGAN's unmaintained dependencies.
|
|
#
|
|
# basicsr / gfpgan / facexlib (xinntao, last released 2022) read their version
|
|
# in setup.py with:
|
|
#
|
|
# exec(compile(f.read(), version_file, 'exec'))
|
|
# return locals()['__version__']
|
|
#
|
|
# Python 3.13+ implements PEP 667: locals() inside a function returns an
|
|
# independent snapshot that exec() can no longer mutate, so the read raises
|
|
# `KeyError: '__version__'` and the sdist build fails. That is why the Cookbook
|
|
# "install realesrgan" button dies on the python:3.14 image. The packages have
|
|
# no fixed release, so we patch get_version() to exec into an explicit namespace
|
|
# dict (works on every Python) and build wheels from the patched source.
|
|
#
|
|
# Usage: build-realesrgan-wheels.sh [OUTPUT_DIR] (default: /wheels)
|
|
set -euo pipefail
|
|
|
|
OUT="${1:-/wheels}"
|
|
mkdir -p "$OUT"
|
|
|
|
work="$(mktemp -d)"
|
|
trap 'rm -rf "$work"' EXIT
|
|
cd "$work"
|
|
|
|
# Pinned to the versions Real-ESRGAN 0.3.0 resolves to.
|
|
SPECS="basicsr==1.4.2 gfpgan==1.3.8 facexlib==0.3.0"
|
|
|
|
for spec in $SPECS; do
|
|
name="${spec%%==*}"
|
|
ver="${spec##*==}"
|
|
# pip download builds metadata (and trips the same bug), so fetch the raw
|
|
# sdist URL from the PyPI JSON API instead.
|
|
url="$(python - "$name" "$ver" <<'PY'
|
|
import json, sys, urllib.request
|
|
name, ver = sys.argv[1], sys.argv[2]
|
|
data = json.load(urllib.request.urlopen(f"https://pypi.org/pypi/{name}/{ver}/json"))
|
|
for f in data["urls"]:
|
|
if f["packagetype"] == "sdist":
|
|
print(f["url"]); break
|
|
else:
|
|
sys.exit(f"no sdist found for {name}=={ver}")
|
|
PY
|
|
)"
|
|
echo ">> fetching ${name} ${ver}: ${url}"
|
|
curl -fsSL "$url" -o "${name}.tar.gz"
|
|
tar xzf "${name}.tar.gz"
|
|
done
|
|
|
|
echo ">> patching get_version()"
|
|
python - <<'PY'
|
|
import pathlib
|
|
old_exec = "exec(compile(f.read(), version_file, 'exec'))"
|
|
new_exec = "_ver_ns = {}\n exec(compile(f.read(), version_file, 'exec'), _ver_ns)"
|
|
old_ret = "return locals()['__version__']"
|
|
new_ret = "return _ver_ns['__version__']"
|
|
patched = 0
|
|
for setup in pathlib.Path(".").glob("*/setup.py"):
|
|
s = setup.read_text()
|
|
if old_exec in s and old_ret in s:
|
|
setup.write_text(s.replace(old_exec, new_exec).replace(old_ret, new_ret))
|
|
print(" patched", setup)
|
|
patched += 1
|
|
assert patched == 3, f"expected to patch 3 setup.py files, patched {patched}"
|
|
PY
|
|
|
|
echo ">> building wheels into ${OUT}"
|
|
pip wheel --no-deps -w "$OUT" ./basicsr-* ./gfpgan-* ./facexlib-*
|
|
ls -l "$OUT"
|