calculus-animator / scripts /build_release.py
Rsan0948
feat(packaging): canonical launcher, smoke test, pinned deps, release tooling
9e8f271
Raw
History Blame Contribute Delete
2.01 kB
#!/usr/bin/env python3
"""Build a distributable desktop app with PyInstaller.
Entry point is ``window.py`` — the PyWebView shell. The AI-tutor FastAPI
backend is intentionally NOT bundled into the artifact today: it ships as
an optional ``[ai_tutor]`` install group via ``pyproject.toml``. A future
brief should decide whether the release ships with the tutor backend
embedded or as a sidecar; until then this script produces the core
animator.
Build deps (PyInstaller) live in the ``[build]`` extras group of
``pyproject.toml``. Install them with one of:
pip install -e .[build] # editable + build extras
pip install pyinstaller==6.20.0 # standalone, pinned version
Usage:
pip install -e .[build]
python scripts/build_release.py
"""
import os
import platform
from pathlib import Path
from PyInstaller.__main__ import run as pyinstaller_run
def main() -> None:
root = Path(__file__).resolve().parent.parent
sep = ";" if os.name == "nt" else ":"
app_name = "Calculus Animator"
# Note: ``--add-data {root}/data{sep}data`` already bundles the whole
# ``data/`` directory (curriculum + library + capacity report). We
# intentionally do NOT add ``data/calculus_library.json`` a second time
# — duplicate entries trip a PyInstaller conflict warning at build
# time and can shadow the directory copy on extraction.
args = [
"--noconfirm",
"--clean",
"--windowed",
"--name",
app_name,
"--paths",
str(root),
"--add-data",
f"{root / 'ui'}{sep}ui",
"--add-data",
f"{root / 'data'}{sep}data",
"--collect-submodules",
"webview",
"--collect-submodules",
"sympy",
str(root / "window.py"),
]
system = platform.system().lower()
if system == "darwin":
args.extend(["--osx-bundle-identifier", "com.calculusanimator.app"])
pyinstaller_run(args)
if __name__ == "__main__":
main()