mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-30 18:56:16 +00:00
Harden optional science toolbelt probe
This commit is contained in:
parent
3ac033db9b
commit
fdb6761786
4 changed files with 134 additions and 17 deletions
|
|
@ -22,9 +22,16 @@ Equivalent npm convenience commands:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run setup-science-light
|
npm run setup-science-light
|
||||||
|
npm run setup-science-all
|
||||||
npm run probe-science
|
npm run probe-science
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`setup-science-light` installs the pure Python and wheel-backed baseline.
|
||||||
|
`setup-science-all` also asks for Dedalus and `liboqs-python`; those packages
|
||||||
|
still need native libraries on the host. On Arch/CachyOS, Dedalus needed
|
||||||
|
`fftw-openmpi`, and `liboqs-python` was completed by installing liboqs under
|
||||||
|
`$HOME/_oqs`.
|
||||||
|
|
||||||
Native command-line tools are listed in:
|
Native command-line tools are listed in:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@
|
||||||
"setup-cad-env": "cd 5-Applications/text-to-cad && python3.11 -m venv .venv && ./.venv/bin/pip install -r requirements-cad.txt",
|
"setup-cad-env": "cd 5-Applications/text-to-cad && python3.11 -m venv .venv && ./.venv/bin/pip install -r requirements-cad.txt",
|
||||||
"verify-cad": "cd 5-Applications/text-to-cad && ./.venv/bin/python -c \"import build123d; import OCP; print('CAD dependencies OK')\"",
|
"verify-cad": "cd 5-Applications/text-to-cad && ./.venv/bin/python -c \"import build123d; import OCP; print('CAD dependencies OK')\"",
|
||||||
"setup-science-light": "uv venv .venv-science && . .venv-science/bin/activate && uv pip install -r requirements-optional-science.txt",
|
"setup-science-light": "uv venv .venv-science && . .venv-science/bin/activate && uv pip install -r requirements-optional-science.txt",
|
||||||
"probe-science": "python3 scripts/probe_science_toolbelt.py"
|
"setup-science-all": "uv venv --python 3.11 .venv-science && . .venv-science/bin/activate && uv pip install -r requirements-optional-science.txt 'dedalus>=3.0.5' 'liboqs-python>=0.14.1'",
|
||||||
|
"probe-science": "sh -c 'if [ -x .venv-science/bin/python ]; then .venv-science/bin/python scripts/probe_science_toolbelt.py; else python3 scripts/probe_science_toolbelt.py; fi'"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"better-sqlite3": "^12.4.1"
|
"better-sqlite3": "^12.4.1"
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,9 @@ Exit code:
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import importlib
|
import importlib.metadata
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -115,34 +116,136 @@ COMMAND_TOOLS: tuple[CommandTool, ...] = (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _module_version(module: Any) -> str | None:
|
_DISTRIBUTION_NAMES: dict[str, str] = {
|
||||||
for attr in ("__version__", "VERSION", "version"):
|
"pywavelets": "PyWavelets",
|
||||||
value = getattr(module, attr, None)
|
}
|
||||||
if value is None:
|
|
||||||
continue
|
|
||||||
if callable(value):
|
def _distribution_version(tool: PythonTool) -> str | None:
|
||||||
try:
|
name = _DISTRIBUTION_NAMES.get(tool.key, tool.key)
|
||||||
value = value()
|
try:
|
||||||
except Exception:
|
return importlib.metadata.version(name)
|
||||||
continue
|
except importlib.metadata.PackageNotFoundError:
|
||||||
return str(value)
|
return None
|
||||||
return None
|
|
||||||
|
|
||||||
|
def _first_line(text: str) -> str:
|
||||||
|
for line in text.splitlines():
|
||||||
|
stripped = line.strip()
|
||||||
|
if stripped:
|
||||||
|
return stripped
|
||||||
|
return text.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def _liboqs_env() -> dict[str, str]:
|
||||||
|
env = dict(os.environ)
|
||||||
|
if "OQS_INSTALL_PATH" in env:
|
||||||
|
return env
|
||||||
|
|
||||||
|
home_install = Path.home() / "_oqs"
|
||||||
|
if (home_install / "lib" / "liboqs.so").exists() or (
|
||||||
|
home_install / "lib64" / "liboqs.so"
|
||||||
|
).exists():
|
||||||
|
env["OQS_INSTALL_PATH"] = str(home_install)
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
|
def _has_native_liboqs() -> bool:
|
||||||
|
candidates = [
|
||||||
|
Path(os.environ["OQS_INSTALL_PATH"])
|
||||||
|
for key in ("OQS_INSTALL_PATH",)
|
||||||
|
if key in os.environ
|
||||||
|
]
|
||||||
|
candidates.append(Path.home() / "_oqs")
|
||||||
|
for root in candidates:
|
||||||
|
if (root / "lib" / "liboqs.so").exists() or (
|
||||||
|
root / "lib64" / "liboqs.so"
|
||||||
|
).exists():
|
||||||
|
return True
|
||||||
|
for pattern in ("/usr/lib/liboqs.so*", "/usr/local/lib/liboqs.so*"):
|
||||||
|
if list(Path("/").glob(pattern.lstrip("/"))):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _probe_python(tool: PythonTool) -> dict[str, Any]:
|
def _probe_python(tool: PythonTool) -> dict[str, Any]:
|
||||||
|
installed_version = _distribution_version(tool)
|
||||||
|
if installed_version is None:
|
||||||
|
return {
|
||||||
|
**asdict(tool),
|
||||||
|
"available": False,
|
||||||
|
"error": "package is not installed in this Python environment",
|
||||||
|
}
|
||||||
|
|
||||||
|
if tool.key == "liboqs-python" and not _has_native_liboqs():
|
||||||
|
return {
|
||||||
|
**asdict(tool),
|
||||||
|
"available": False,
|
||||||
|
"installed_version": installed_version,
|
||||||
|
"error": "Python package is installed, but native liboqs.so is missing",
|
||||||
|
}
|
||||||
|
|
||||||
|
marker = "__SCIENCE_TOOLBELT_PROBE__"
|
||||||
|
code = f"""
|
||||||
|
import importlib
|
||||||
|
import json
|
||||||
|
|
||||||
|
module = importlib.import_module({tool.module!r})
|
||||||
|
version = None
|
||||||
|
for attr in ("__version__", "VERSION", "version"):
|
||||||
|
value = getattr(module, attr, None)
|
||||||
|
if value is None:
|
||||||
|
continue
|
||||||
|
if callable(value):
|
||||||
|
try:
|
||||||
|
value = value()
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
version = str(value)
|
||||||
|
break
|
||||||
|
print({marker!r} + json.dumps({{"version": version, "path": getattr(module, "__file__", None)}}))
|
||||||
|
"""
|
||||||
|
env = _liboqs_env() if tool.key == "liboqs-python" else dict(os.environ)
|
||||||
try:
|
try:
|
||||||
module = importlib.import_module(tool.module)
|
result = subprocess.run(
|
||||||
|
[sys.executable, "-c", code],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=20,
|
||||||
|
check=False,
|
||||||
|
env=env,
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
return {
|
return {
|
||||||
**asdict(tool),
|
**asdict(tool),
|
||||||
"available": False,
|
"available": False,
|
||||||
|
"installed_version": installed_version,
|
||||||
"error": f"{type(exc).__name__}: {exc}",
|
"error": f"{type(exc).__name__}: {exc}",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
payload = None
|
||||||
|
for line in result.stdout.splitlines():
|
||||||
|
if line.startswith(marker):
|
||||||
|
payload = json.loads(line[len(marker) :])
|
||||||
|
if result.returncode != 0 or payload is None:
|
||||||
|
error = _first_line(result.stderr) or _first_line(result.stdout)
|
||||||
|
return {
|
||||||
|
**asdict(tool),
|
||||||
|
"available": False,
|
||||||
|
"installed_version": installed_version,
|
||||||
|
"error": error or f"import subprocess exited {result.returncode}",
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
**asdict(tool),
|
**asdict(tool),
|
||||||
"available": True,
|
"available": True,
|
||||||
"version": _module_version(module),
|
"version": installed_version,
|
||||||
"path": getattr(module, "__file__", None),
|
**(
|
||||||
|
{"module_version": payload.get("version")}
|
||||||
|
if payload.get("version") and payload.get("version") != installed_version
|
||||||
|
else {}
|
||||||
|
),
|
||||||
|
"path": payload.get("path"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,5 +22,11 @@ zstd
|
||||||
graphviz
|
graphviz
|
||||||
paraview
|
paraview
|
||||||
|
|
||||||
|
# CFD/PDE native helpers
|
||||||
|
# Arch/CachyOS: fftw-openmpi
|
||||||
|
|
||||||
# Chemistry / materials native helpers
|
# Chemistry / materials native helpers
|
||||||
openbabel
|
openbabel
|
||||||
|
|
||||||
|
# Cryptography native helpers
|
||||||
|
# liboqs may need a local source install when no distro package exists.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue