Spaces:
Running
Running
File size: 4,007 Bytes
6a1cba7 | 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 | """Build pure-Python wheel and sdist artifacts with only the Python stdlib.
This is used by local release validation in environments where the setuptools
build frontend hangs before reaching the project backend.
"""
from __future__ import annotations
import base64
import csv
import hashlib
import io
import tarfile
import tomllib
import zipfile
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def _hash_record(data: bytes) -> tuple[str, str]:
digest = base64.urlsafe_b64encode(hashlib.sha256(data).digest()).decode().rstrip("=")
return f"sha256={digest}", str(len(data))
def _metadata(project: dict) -> str:
lines = [
"Metadata-Version: 2.4",
f"Name: {project['name']}",
f"Version: {project['version']}",
f"Summary: {project.get('description', '')}",
"License-Expression: Apache-2.0",
f"Requires-Python: {project.get('requires-python', '')}",
"Description-Content-Type: text/markdown",
"License-File: LICENSE",
]
for extra, deps in project.get("optional-dependencies", {}).items():
lines.append(f"Provides-Extra: {extra}")
for dep in deps:
lines.append(f'Requires-Dist: {dep}; extra == "{extra}"')
lines.append("")
lines.append((ROOT / "README.md").read_text(encoding="utf-8"))
return "\n".join(lines) + "\n"
def _build_wheel(out_dir: Path, project: dict) -> Path:
name = project["name"]
version = project["version"]
dist_name = name.replace("-", "_")
dist_info = f"{dist_name}-{version}.dist-info"
entries: dict[str, bytes] = {}
for path in sorted((ROOT / "stem_ai").glob("*.py")):
entries[f"stem_ai/{path.name}"] = path.read_bytes()
entries[f"{dist_info}/METADATA"] = _metadata(project).encode("utf-8")
entries[f"{dist_info}/WHEEL"] = (
b"Wheel-Version: 1.0\n"
b"Generator: stem-ai-stdlib-build\n"
b"Root-Is-Purelib: true\n"
b"Tag: py3-none-any\n"
)
entries[f"{dist_info}/entry_points.txt"] = b"[console_scripts]\nstem = stem_ai.cli:main\n"
entries[f"{dist_info}/top_level.txt"] = b"stem_ai\n"
entries[f"{dist_info}/licenses/LICENSE"] = (ROOT / "LICENSE").read_bytes()
rows = []
for arcname, data in entries.items():
digest, size = _hash_record(data)
rows.append([arcname, digest, size])
rows.append([f"{dist_info}/RECORD", "", ""])
record = io.StringIO()
csv.writer(record, lineterminator="\n").writerows(rows)
entries[f"{dist_info}/RECORD"] = record.getvalue().encode("utf-8")
wheel_path = out_dir / f"{dist_name}-{version}-py3-none-any.whl"
with zipfile.ZipFile(wheel_path, "w", compression=zipfile.ZIP_DEFLATED) as wheel:
for arcname, data in entries.items():
wheel.writestr(arcname, data)
return wheel_path
def _build_sdist(out_dir: Path, project: dict) -> Path:
name = project["name"].replace("-", "_")
version = project["version"]
prefix = f"{name}-{version}"
files = [
"CHANGELOG.md",
"CONTRIBUTING.md",
"LICENSE",
"MANIFEST.in",
"README.md",
"pyproject.toml",
"requirements.txt",
]
files += [str(p.relative_to(ROOT)).replace("\\", "/") for p in sorted((ROOT / "stem_ai").glob("*.py"))]
files += [str(p.relative_to(ROOT)).replace("\\", "/") for p in sorted((ROOT / "tests").glob("*.py"))]
sdist_path = out_dir / f"{prefix}.tar.gz"
with tarfile.open(sdist_path, "w:gz") as sdist:
for rel in files:
path = ROOT / rel
if path.exists():
sdist.add(path, arcname=f"{prefix}/{rel}")
return sdist_path
def main() -> None:
project = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))["project"]
out_dir = ROOT / "dist"
out_dir.mkdir(exist_ok=True)
wheel = _build_wheel(out_dir, project)
sdist = _build_sdist(out_dir, project)
print(wheel)
print(sdist)
if __name__ == "__main__":
main()
|