Skip to content

system_info

sleap.system_info

System information and startup banner for SLEAP.

Classes:

Name Description
BinaryInfo

Information about a CLI binary.

CondaInfo

Information about conda environment.

GPUInfo

Information about GPU.

PackageInfoData

Information about an installed Python package.

UVInfo

Information about uv installation and configuration.

Functions:

Name Description
analyze_path

Analyze PATH for conflicts.

get_all_package_info

Get info for all relevant SLEAP packages.

get_binary_info

Get detailed information about a CLI binary.

get_conda_info_data

Get conda environment information.

get_default_python_version

Get the default Python version from .python-version files or UV_PYTHON.

get_detailed_package_info

Get detailed package info including git status for editables.

get_disk_info

Get disk usage info for path: (used, available, total).

get_ffmpeg_info

Get ffmpeg binary information from PATH and imageio-ffmpeg.

get_git_info

Get git information for a directory.

get_memory_info

Get RAM usage info: (used, available, total). Cross-platform.

get_nvidia_info

Get NVIDIA driver version, CUDA version, and GPU info.

get_package_info

Get package version, location, and install source without importing.

get_pytorch_info

Get PyTorch version and device information.

get_pytorch_info_detailed

Get PyTorch version, accelerator, and CUDA version.

get_sleap_commit

Get the short git commit SHA the installed SLEAP was built from.

get_uv_config_value

Get a uv config value by checking config files and env vars.

get_uv_info_data

Get comprehensive uv information including config settings.

print_startup_banner

Print the SLEAP startup banner with version info.

resolve_tag_commit

Resolve a release version to its commit SHA via the GitHub REST API.

run_command

Run a command and return (returncode, stdout, stderr).

short_sha

Shorten a git commit SHA for display.

BinaryInfo dataclass

Information about a CLI binary.

Source code in sleap/system_info.py
@dataclass
class BinaryInfo:
    """Information about a CLI binary."""

    name: str
    path: str
    real_path: str  # resolved symlink
    python_path: str = ""
    source: str = ""  # uv-tool, conda, pip, venv

CondaInfo dataclass

Information about conda environment.

Source code in sleap/system_info.py
@dataclass
class CondaInfo:
    """Information about conda environment."""

    active: bool = False
    environment: str = ""
    prefix: str = ""
    version: str = ""
    auto_activate_base: Optional[bool] = None
    sleap_packages: list[str] = field(default_factory=list)

GPUInfo dataclass

Information about GPU.

Source code in sleap/system_info.py
@dataclass
class GPUInfo:
    """Information about GPU."""

    name: str
    memory_total: str
    memory_free: str
    utilization: str

PackageInfoData dataclass

Information about an installed Python package.

Source code in sleap/system_info.py
@dataclass
class PackageInfoData:
    """Information about an installed Python package."""

    name: str
    version: str
    source: str  # pip, editable, git, conda, local
    location: str = ""
    editable: bool = False
    # Git info (for editable/git installs)
    git_commit: Optional[str] = None
    git_branch: Optional[str] = None
    git_dirty: bool = False
    git_remote: Optional[str] = None

UVInfo dataclass

Information about uv installation and configuration.

Source code in sleap/system_info.py
@dataclass
class UVInfo:
    """Information about uv installation and configuration."""

    version: str = ""
    path: str = ""
    cache_dir: str = ""
    tool_dir: str = ""
    tool_bin_dir: str = ""
    python_dir: str = ""
    installed_tools: list[str] = field(default_factory=list)
    # Configuration settings
    default_python: str = ""  # From .python-version or UV_PYTHON
    resolved_python: str = ""  # From `uv python find`
    python_preference: str = ""  # managed, system, only-managed, only-system
    resolution_strategy: str = ""  # highest, lowest, lowest-direct
    index_strategy: str = ""  # first-index, unsafe-first-match, unsafe-best-match
    prerelease: str = ""  # if-necessary, allow

analyze_path()

Analyze PATH for conflicts.

Source code in sleap/system_info.py
def analyze_path() -> tuple[list[str], list[str]]:
    """Analyze PATH for conflicts."""
    path_str = os.environ.get("PATH", "")
    entries = path_str.split(os.pathsep)

    conflicts = []

    # Check for common conflict patterns
    # Normalize path separators for cross-platform matching
    normalized = [p.replace("\\", "/").lower() for p in entries]
    conda_paths = [p for p in normalized if "conda" in p or "miniconda" in p]
    uv_paths = [p for p in normalized if ".local/share/uv" in p or ".local/bin" in p]

    if conda_paths and uv_paths:
        # Check priority - which comes first?
        for i, path in enumerate(normalized):
            if "conda" in path:
                first_conda = i
                break
        else:
            first_conda = len(entries)

        for i, path in enumerate(normalized):
            if ".local/bin" in path:
                first_uv = i
                break
        else:
            first_uv = len(entries)

        if first_conda < first_uv:
            conflicts.append(
                "Conda paths appear before uv paths in PATH - "
                "conda binaries may take precedence"
            )

    return entries, conflicts

get_all_package_info()

Get info for all relevant SLEAP packages.

Returns:

Type Description
Dict

Dict mapping package names to their info dicts. Only includes packages that are installed.

Source code in sleap/system_info.py
def get_all_package_info() -> Dict:
    """Get info for all relevant SLEAP packages.

    Returns:
        Dict mapping package names to their info dicts.
        Only includes packages that are installed.
    """
    result = {}
    for pkg in PACKAGES:
        info = get_package_info(pkg)
        # Only include if installed
        if info["version"] is not None:
            result[pkg] = info
    return result

get_binary_info(name)

Get detailed information about a CLI binary.

Source code in sleap/system_info.py
def get_binary_info(name: str) -> Optional[BinaryInfo]:
    """Get detailed information about a CLI binary."""
    path = shutil.which(name)
    if not path:
        return None

    info = BinaryInfo(name=name, path=path, real_path=path)

    # Resolve symlinks
    try:
        real_path = Path(path).resolve()
        info.real_path = str(real_path)

        # Determine source based on path
        real_str = str(real_path)
        if ".local/share/uv/tools" in real_str:
            info.source = "uv-tool"
        elif "conda" in real_str.lower() or "miniconda" in real_str.lower():
            info.source = "conda"
        elif ".venv" in real_str or "venv" in real_str:
            info.source = "venv"
        else:
            info.source = "pip"

        # Try to get the Python interpreter from script shebang
        if real_path.exists():
            try:
                with open(real_path) as f:
                    first_line = f.readline()
                    if first_line.startswith("#!") and "python" in first_line:
                        info.python_path = first_line[2:].strip()
            except (OSError, UnicodeDecodeError):
                pass

    except OSError:
        pass

    return info

get_conda_info_data()

Get conda environment information.

Source code in sleap/system_info.py
def get_conda_info_data() -> Optional[CondaInfo]:
    """Get conda environment information."""
    conda_prefix = os.environ.get("CONDA_PREFIX")
    if not conda_prefix:
        # Check if conda is installed but not activated
        conda_path = shutil.which("conda")
        if not conda_path:
            return None
        info = CondaInfo(active=False)
    else:
        info = CondaInfo(
            active=True,
            prefix=conda_prefix,
            environment=os.environ.get("CONDA_DEFAULT_ENV", "base"),
        )

    # Get conda version
    rc, stdout, _ = run_command(["conda", "--version"])
    if rc == 0:
        info.version = stdout

    # Check auto_activate_base setting
    rc, stdout, _ = run_command(["conda", "config", "--show", "auto_activate_base"])
    if rc == 0:
        if "True" in stdout:
            info.auto_activate_base = True
        elif "False" in stdout:
            info.auto_activate_base = False

    # Check for sleap packages in conda environment
    if info.active:
        rc, stdout, _ = run_command(["conda", "list", "sleap"])
        if rc == 0:
            for line in stdout.split("\n"):
                if line and not line.startswith("#"):
                    parts = line.split()
                    if parts and "sleap" in parts[0].lower():
                        info.sleap_packages.append(parts[0])

    return info

get_default_python_version()

Get the default Python version from .python-version files or UV_PYTHON.

Source code in sleap/system_info.py
def get_default_python_version() -> str:
    """Get the default Python version from .python-version files or UV_PYTHON."""
    # Check UV_PYTHON env var first
    uv_python = os.environ.get("UV_PYTHON", "")
    if uv_python:
        return f"{uv_python} (UV_PYTHON)"

    # Check .python-version in current directory and parents
    cwd = Path.cwd()
    for parent in [cwd] + list(cwd.parents):
        pv_file = parent / ".python-version"
        if pv_file.exists():
            try:
                version = pv_file.read_text().strip().split("\n")[0]
                if version:
                    return f"{version} ({pv_file})"
            except OSError:
                pass

    # Check user-level .python-version
    user_pv = Path.home() / ".config" / "uv" / ".python-version"
    if user_pv.exists():
        try:
            version = user_pv.read_text().strip().split("\n")[0]
            if version:
                return f"{version} ({user_pv})"
        except OSError:
            pass

    return ""

get_detailed_package_info(name)

Get detailed package info including git status for editables.

Source code in sleap/system_info.py
def get_detailed_package_info(name: str) -> Optional[PackageInfoData]:
    """Get detailed package info including git status for editables."""
    try:
        dist = importlib.metadata.distribution(name)
        version = dist.version

        # Determine source and editability
        is_editable = False
        source = "pip"
        location = ""
        # Commit info recorded by pip for git-URL installs (vcs_info).
        vcs_commit: Optional[str] = None
        vcs_revision: Optional[str] = None
        vcs_remote: Optional[str] = None

        # Check direct_url.json for modern pip installs
        try:
            direct_url_text = dist.read_text("direct_url.json")
            if direct_url_text:
                direct_url = json.loads(direct_url_text)
                is_editable = direct_url.get("dir_info", {}).get("editable", False)
                if is_editable:
                    source = "editable"
                    # Get location from URL
                    url = direct_url.get("url", "")
                    if url.startswith("file://"):
                        location = url[7:]  # Strip file://
                elif "vcs_info" in direct_url:
                    # e.g. pip install git+https://github.com/talmolab/sleap@ref
                    source = "git"
                    vcs_info = direct_url["vcs_info"]
                    vcs_commit = vcs_info.get("commit_id")
                    vcs_revision = vcs_info.get("requested_revision")
                    vcs_remote = direct_url.get("url") or None
                elif direct_url.get("url", "").startswith("file://"):
                    source = "local"
        except FileNotFoundError:
            pass

        # Fallback: detect old-style editable installs
        if not is_editable and hasattr(dist, "_path") and dist._path:
            path_str = str(dist._path)
            if ".egg-info" in path_str and "site-packages" not in path_str:
                is_editable = True
                source = "editable"
                location = str(dist._path.parent) if dist._path else ""

        # Check for conda install
        if source == "pip":
            try:
                installer = dist.read_text("INSTALLER")
                if installer and installer.strip() == "conda":
                    source = "conda"
            except FileNotFoundError:
                pass

        # Get location if not already set
        if not location and hasattr(dist, "_path") and dist._path:
            path = dist._path.parent
            if not path.is_absolute():
                path = Path.cwd() / path
            location = str(path)

        # Create PackageInfoData
        pkg_info = PackageInfoData(
            name=name,
            version=version,
            source=source,
            location=location,
            editable=is_editable,
        )

        # Get git info for editable installs (live working tree)
        if is_editable and location:
            git_info = get_git_info(location)
            if git_info:
                pkg_info.git_commit = git_info.get("commit")
                pkg_info.git_branch = git_info.get("branch")
                pkg_info.git_dirty = git_info.get("dirty", False)
                pkg_info.git_remote = git_info.get("remote")

        # Git-URL installs (pip install git+...): pip records the exact commit in
        # direct_url.json, so we get provenance without a working tree or git.
        if source == "git":
            pkg_info.git_commit = vcs_commit
            pkg_info.git_branch = vcs_revision
            pkg_info.git_remote = vcs_remote

        return pkg_info

    except importlib.metadata.PackageNotFoundError:
        return None

get_disk_info(path)

Get disk usage info for path: (used, available, total).

Source code in sleap/system_info.py
def get_disk_info(path: str) -> tuple[str, str, str]:
    """Get disk usage info for path: (used, available, total)."""
    try:
        usage = shutil.disk_usage(path)

        def fmt(b):
            if b >= 1024**4:
                return f"{b / 1024**4:.1f} TB"
            elif b >= 1024**3:
                return f"{b / 1024**3:.1f} GB"
            elif b >= 1024**2:
                return f"{b / 1024**2:.1f} MB"
            return f"{b / 1024:.1f} KB"

        return fmt(usage.used), fmt(usage.free), fmt(usage.total)
    except (OSError, AttributeError):
        return "", "", ""

get_ffmpeg_info()

Get ffmpeg binary information from PATH and imageio-ffmpeg.

Source code in sleap/system_info.py
def get_ffmpeg_info() -> list[BinaryInfo]:
    """Get ffmpeg binary information from PATH and imageio-ffmpeg."""
    binaries = []

    # Check PATH for ffmpeg
    ffmpeg_path = shutil.which("ffmpeg")
    if ffmpeg_path:
        info = BinaryInfo(name="ffmpeg", path=ffmpeg_path, real_path=ffmpeg_path)
        try:
            real_path = Path(ffmpeg_path).resolve()
            info.real_path = str(real_path)
        except OSError:
            pass
        info.source = "PATH"

        # Get version
        rc, stdout, _ = run_command(["ffmpeg", "-version"])
        if rc == 0:
            # First line is like "ffmpeg version X.Y.Z ..."
            first_line = stdout.split("\n")[0] if stdout else ""
            if "version" in first_line:
                parts = first_line.split()
                for i, p in enumerate(parts):
                    if p == "version" and i + 1 < len(parts):
                        info.python_path = f"v{parts[i + 1]}"  # Reuse field for version
                        break
        binaries.append(info)

    # Check imageio-ffmpeg
    try:
        import imageio_ffmpeg

        imageio_path = imageio_ffmpeg.get_ffmpeg_exe()
        if imageio_path and imageio_path != ffmpeg_path:
            info = BinaryInfo(
                name="ffmpeg (imageio)",
                path=imageio_path,
                real_path=imageio_path,
                source="imageio-ffmpeg",
            )
            try:
                real_path = Path(imageio_path).resolve()
                info.real_path = str(real_path)
            except OSError:
                pass

            # Get version
            rc, stdout, _ = run_command([imageio_path, "-version"])
            if rc == 0:
                first_line = stdout.split("\n")[0] if stdout else ""
                if "version" in first_line:
                    parts = first_line.split()
                    for i, p in enumerate(parts):
                        if p == "version" and i + 1 < len(parts):
                            info.python_path = f"v{parts[i + 1]}"
                            break
            binaries.append(info)
    except (ImportError, Exception):
        pass

    return binaries

get_git_info(path)

Get git information for a directory.

Source code in sleap/system_info.py
def get_git_info(path: str) -> dict:
    """Get git information for a directory."""
    if not path or not Path(path).exists():
        return {}

    # Check if it's a git repo
    rc, _, _ = run_command(["git", "-C", path, "rev-parse", "--git-dir"])
    if rc != 0:
        return {}

    info = {}

    # Get commit hash (full SHA; shortened with short_sha() at display time)
    rc, stdout, _ = run_command(["git", "-C", path, "rev-parse", "HEAD"])
    if rc == 0:
        info["commit"] = stdout

    # Get branch name
    rc, stdout, _ = run_command(
        ["git", "-C", path, "rev-parse", "--abbrev-ref", "HEAD"]
    )
    if rc == 0:
        info["branch"] = stdout

    # Check if dirty
    rc, stdout, _ = run_command(["git", "-C", path, "status", "--porcelain"])
    if rc == 0:
        info["dirty"] = bool(stdout)

    # Get remote URL
    rc, stdout, _ = run_command(["git", "-C", path, "remote", "get-url", "origin"])
    if rc == 0:
        info["remote"] = stdout

    return info

get_memory_info()

Get RAM usage info: (used, available, total). Cross-platform.

Source code in sleap/system_info.py
def get_memory_info() -> tuple[str, str, str]:
    """Get RAM usage info: (used, available, total). Cross-platform."""

    def fmt(b):
        if b >= 1024**3:
            return f"{b / 1024**3:.1f} GB"
        elif b >= 1024**2:
            return f"{b / 1024**2:.1f} MB"
        return f"{b / 1024:.1f} KB"

    # Try platform-specific methods
    system = platform.system()

    if system == "Linux":
        try:
            with open("/proc/meminfo") as f:
                meminfo = {}
                for line in f:
                    parts = line.split()
                    if len(parts) >= 2:
                        key = parts[0].rstrip(":")
                        meminfo[key] = int(parts[1]) * 1024  # kB to bytes

            total = meminfo.get("MemTotal", 0)
            available = meminfo.get("MemAvailable", 0)
            used = total - available
            return fmt(used), fmt(available), fmt(total)
        except (OSError, KeyError, ValueError):
            pass

    elif system == "Darwin":  # macOS
        try:
            # Use vm_stat for memory info
            rc, stdout, _ = run_command(["vm_stat"])
            if rc == 0:
                # Parse vm_stat output
                stats = {}
                for line in stdout.split("\n"):
                    if ":" in line:
                        key, val = line.split(":", 1)
                        val = val.strip().rstrip(".")
                        try:
                            stats[key.strip()] = int(val)
                        except ValueError:
                            pass

                page_size = 16384  # Default, could parse from header
                # Try to get page size from first line
                if "page size of" in stdout:
                    match = re.search(r"page size of (\d+) bytes", stdout)
                    if match:
                        page_size = int(match.group(1))

                # Get total via sysctl
                rc2, stdout2, _ = run_command(["sysctl", "-n", "hw.memsize"])
                if rc2 == 0:
                    total = int(stdout2.strip())
                    free_pages = stats.get("Pages free", 0)
                    inactive_pages = stats.get("Pages inactive", 0)
                    available = (free_pages + inactive_pages) * page_size
                    used = total - available
                    return fmt(used), fmt(available), fmt(total)
        except (OSError, ValueError):
            pass

    elif system == "Windows":
        try:
            # Use wmic for memory info
            wmic_fields = "TotalVisibleMemorySize,FreePhysicalMemory"
            rc, stdout, _ = run_command(["wmic", "OS", "get", wmic_fields, "/VALUE"])
            if rc == 0:
                values = {}
                for line in stdout.split("\n"):
                    if "=" in line:
                        key, val = line.strip().split("=", 1)
                        try:
                            values[key] = int(val) * 1024  # kB to bytes
                        except ValueError:
                            pass
                total = values.get("TotalVisibleMemorySize", 0)
                available = values.get("FreePhysicalMemory", 0)
                used = total - available
                if total:
                    return fmt(used), fmt(available), fmt(total)
        except (OSError, ValueError):
            pass

    return "", "", ""

get_nvidia_info()

Get NVIDIA driver version, CUDA version, and GPU info.

Source code in sleap/system_info.py
def get_nvidia_info() -> tuple[str, str, list[GPUInfo]]:
    """Get NVIDIA driver version, CUDA version, and GPU info."""
    if not shutil.which("nvidia-smi"):
        return "", "", []

    # Driver version
    driver = ""
    rc, stdout, _ = run_command(
        ["nvidia-smi", "--query-gpu=driver_version", "--format=csv,noheader"]
    )
    if rc == 0:
        driver = stdout.split("\n")[0]

    # System CUDA version (from nvidia-smi header)
    # nvidia-smi shows "CUDA Version: X.Y" in the header
    cuda_version = ""
    rc, stdout, _ = run_command(["nvidia-smi"])
    if rc == 0:
        match = re.search(r"CUDA Version:\s*(\d+\.\d+)", stdout)
        if match:
            cuda_version = match.group(1)

    # GPU info
    gpus = []
    rc, stdout, _ = run_command(
        [
            "nvidia-smi",
            "--query-gpu=name,memory.total,memory.free,utilization.gpu",
            "--format=csv,noheader,nounits",
        ]
    )
    if rc == 0:
        for line in stdout.split("\n"):
            if line:
                parts = [p.strip() for p in line.split(",")]
                if len(parts) >= 4:
                    gpus.append(
                        GPUInfo(
                            name=parts[0],
                            memory_total=f"{parts[1]} MB",
                            memory_free=f"{parts[2]} MB",
                            utilization=f"{parts[3]}%",
                        )
                    )

    return driver, cuda_version, gpus

get_package_info(name)

Get package version, location, and install source without importing.

Uses importlib.metadata so we don't have to import heavy packages just to check their versions.

Parameters:

Name Type Description Default
name str

Package name (e.g., "sleap", "sleap-io", "numpy")

required

Returns:

Type Description
Dict

Dict with version, location, source, and editable fields. If package is not installed, version will be None.

Source code in sleap/system_info.py
def get_package_info(name: str) -> Dict:
    """Get package version, location, and install source without importing.

    Uses importlib.metadata so we don't have to import heavy packages just
    to check their versions.

    Args:
        name: Package name (e.g., "sleap", "sleap-io", "numpy")

    Returns:
        Dict with version, location, source, and editable fields.
        If package is not installed, version will be None.
    """
    try:
        dist = importlib.metadata.distribution(name)
        version = dist.version

        # Check for editable install and source via direct_url.json
        is_editable = False
        source = "pip"  # Default assumption
        try:
            direct_url_text = dist.read_text("direct_url.json")
            if direct_url_text:
                direct_url = json.loads(direct_url_text)
                is_editable = direct_url.get("dir_info", {}).get("editable", False)
                if is_editable:
                    source = "editable"
                elif "vcs_info" in direct_url:
                    source = "git"
                elif direct_url.get("url", "").startswith("file://"):
                    source = "local"
        except FileNotFoundError:
            pass

        # Fallback: detect old-style editable installs (.egg-info not in site-packages)
        if not is_editable and hasattr(dist, "_path") and dist._path:
            path_str = str(dist._path)
            # Old-style editable: .egg-info in source dir, not site-packages
            if ".egg-info" in path_str and "site-packages" not in path_str:
                is_editable = True
                source = "editable"

        # Check for conda install via INSTALLER file (only if not already known)
        if source == "pip":
            try:
                installer = dist.read_text("INSTALLER")
                if installer and installer.strip() == "conda":
                    source = "conda"
            except FileNotFoundError:
                pass

        # Get location
        location = ""
        if hasattr(dist, "_path") and dist._path:
            path = dist._path.parent
            if not path.is_absolute():
                path = Path.cwd() / path
            location = str(path)

        return {
            "version": version,
            "location": location,
            "source": source,
            "editable": is_editable,
        }
    except importlib.metadata.PackageNotFoundError:
        return {
            "version": None,  # None = not installed
            "location": "",
            "source": "",
            "editable": False,
        }

get_pytorch_info()

Get PyTorch version and device information.

Avoids importing torch at module level for fast startup.

Returns:

Type Description
Dict

Dict with: - installed: bool - whether PyTorch is installed - version: str or None - PyTorch version - accelerator: str - "cuda", "mps", or "cpu" - cuda_version: str or None - CUDA version if available - driver_version: str or None - NVIDIA driver version if available - device_name: str or None - GPU name if available

Source code in sleap/system_info.py
def get_pytorch_info() -> Dict:
    """Get PyTorch version and device information.

    Avoids importing torch at module level for fast startup.

    Returns:
        Dict with:
            - installed: bool - whether PyTorch is installed
            - version: str or None - PyTorch version
            - accelerator: str - "cuda", "mps", or "cpu"
            - cuda_version: str or None - CUDA version if available
            - driver_version: str or None - NVIDIA driver version if available
            - device_name: str or None - GPU name if available
    """
    # First check if torch is installed via metadata (fast, no import)
    torch_info = get_package_info("torch")
    if torch_info["version"] is None:
        return {
            "installed": False,
            "version": None,
            "accelerator": "cpu",
            "cuda_version": None,
            "driver_version": None,
            "device_name": None,
        }

    # torch is installed, now we need to import to get device info
    try:
        import torch

        result = {
            "installed": True,
            "version": torch.__version__,
            "accelerator": "cpu",
            "cuda_version": None,
            "driver_version": None,
            "device_name": None,
        }

        # Check CUDA
        if torch.cuda.is_available():
            result["accelerator"] = "cuda"
            result["cuda_version"] = torch.version.cuda
            result["driver_version"] = _get_nvidia_driver_version()
            # Get first GPU name
            if torch.cuda.device_count() > 0:
                result["device_name"] = torch.cuda.get_device_name(0)

        # Check MPS (Apple Silicon)
        elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
            result["accelerator"] = "mps"

        return result

    except Exception:
        # If import fails for some reason, return basic info
        return {
            "installed": True,
            "version": torch_info["version"],
            "accelerator": "cpu",
            "cuda_version": None,
            "driver_version": None,
            "device_name": None,
        }

get_pytorch_info_detailed()

Get PyTorch version, accelerator, and CUDA version.

Source code in sleap/system_info.py
def get_pytorch_info_detailed() -> tuple[str, str, str]:
    """Get PyTorch version, accelerator, and CUDA version."""
    # Check if torch is installed first (fast check via metadata)
    torch_pkg = get_package_info("torch")
    if torch_pkg["version"] is None:
        return "", "", ""

    try:
        import torch

        version = torch.__version__
        if torch.cuda.is_available():
            accelerator = "cuda"
            cuda_version = torch.version.cuda or ""
        elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
            accelerator = "mps"
            cuda_version = ""
        else:
            accelerator = "cpu"
            cuda_version = ""
        return version, accelerator, cuda_version
    except ImportError:
        return "", "", ""

get_sleap_commit(resolve_remote=False)

Get the short git commit SHA the installed SLEAP was built from.

Works without a network for editable installs (live git checkout) and for installs from a git URL (e.g. pip install git+https://github.com/talmolab/ sleap), where pip records the commit in direct_url.json.

Parameters:

Name Type Description Default
resolve_remote bool

If True and no commit is available locally (a plain PyPI/conda release install), resolve the release tag to its commit via the GitHub API. Off by default since it requires network access.

False

Returns:

Type Description
Optional[str]

The shortened commit SHA, or None if it could not be determined.

Source code in sleap/system_info.py
def get_sleap_commit(resolve_remote: bool = False) -> Optional[str]:
    """Get the short git commit SHA the installed SLEAP was built from.

    Works without a network for editable installs (live git checkout) and for
    installs from a git URL (e.g. ``pip install git+https://github.com/talmolab/
    sleap``), where pip records the commit in ``direct_url.json``.

    Args:
        resolve_remote: If ``True`` and no commit is available locally (a plain
            PyPI/conda release install), resolve the release tag to its commit
            via the GitHub API. Off by default since it requires network access.

    Returns:
        The shortened commit SHA, or ``None`` if it could not be determined.
    """
    info = get_detailed_package_info("sleap")
    if info and info.git_commit:
        return short_sha(info.git_commit)
    if resolve_remote:
        from sleap.version import __version__

        sha = resolve_tag_commit(SLEAP_REPO, __version__)
        return short_sha(sha) if sha else None
    return None

get_uv_config_value(key)

Get a uv config value by checking config files and env vars.

Source code in sleap/system_info.py
def get_uv_config_value(key: str) -> str:
    """Get a uv config value by checking config files and env vars."""
    # Check environment variable first (takes precedence)
    env_key = f"UV_{key.upper().replace('-', '_')}"
    env_val = os.environ.get(env_key, "")
    if env_val:
        return env_val

    # Skip TOML parsing if tomllib not available
    if tomllib is None:
        return ""

    # Check config files (user config at ~/.config/uv/uv.toml)
    # On Windows, use APPDATA; on Unix, use ~/.config
    if platform.system() == "Windows":
        appdata = os.environ.get("APPDATA", "")
        config_paths = [
            Path(appdata) / "uv" / "uv.toml" if appdata else None,
        ]
    else:
        config_paths = [
            Path.home() / ".config" / "uv" / "uv.toml",
            Path("/etc/uv/uv.toml"),
        ]

    for config_path in config_paths:
        if config_path and config_path.exists():
            try:
                with open(config_path, "rb") as f:
                    config = tomllib.load(f)
                    # Check top-level and [tool.uv] section
                    if key in config:
                        return str(config[key])
                    if "tool" in config and "uv" in config["tool"]:
                        if key in config["tool"]["uv"]:
                            return str(config["tool"]["uv"][key])
            except (OSError, Exception):
                pass

    return ""

get_uv_info_data()

Get comprehensive uv information including config settings.

Source code in sleap/system_info.py
def get_uv_info_data() -> Optional[UVInfo]:
    """Get comprehensive uv information including config settings."""
    uv_path = shutil.which("uv")
    if not uv_path:
        return None

    info = UVInfo(path=uv_path)

    # Version
    rc, stdout, _ = run_command(["uv", "--version"])
    if rc == 0:
        info.version = stdout

    # Cache directory
    rc, stdout, _ = run_command(["uv", "cache", "dir"])
    if rc == 0:
        info.cache_dir = stdout

    # Tool directory
    rc, stdout, _ = run_command(["uv", "tool", "dir"])
    if rc == 0:
        info.tool_dir = stdout

    # Tool bin directory
    rc, stdout, _ = run_command(["uv", "tool", "dir", "--bin"])
    if rc == 0:
        info.tool_bin_dir = stdout

    # Python directory
    rc, stdout, _ = run_command(["uv", "python", "dir"])
    if rc == 0:
        info.python_dir = stdout

    # Installed tools
    rc, stdout, _ = run_command(["uv", "tool", "list"])
    if rc == 0:
        for line in stdout.split("\n"):
            if line and not line.startswith("-") and not line.startswith(" "):
                # Format: "tool_name vX.Y.Z"
                parts = line.split()
                if parts:
                    info.installed_tools.append(parts[0])

    # Configuration settings
    info.default_python = get_default_python_version()

    # Get resolved Python using `uv python find`
    rc, stdout, _ = run_command(["uv", "python", "find"])
    if rc == 0 and stdout:
        info.resolved_python = stdout

    info.python_preference = get_uv_config_value("python-preference")
    info.resolution_strategy = get_uv_config_value("resolution")
    info.index_strategy = os.environ.get(
        "UV_INDEX_STRATEGY", ""
    ) or get_uv_config_value("index-strategy")
    info.prerelease = get_uv_config_value("prerelease")

    return info

print_startup_banner(verbose=False, console=None)

Print the SLEAP startup banner with version info.

Displays a colorful ASCII art banner with SLEAP branding, version information, and helpful links for documentation and support.

Parameters:

Name Type Description Default
verbose bool

If True, show detailed package table with versions and locations.

False
console Optional[Console]

Optional Rich Console instance. If None, creates a new one.

None
Source code in sleap/system_info.py
def print_startup_banner(verbose: bool = False, console: Optional[Console] = None):
    """Print the SLEAP startup banner with version info.

    Displays a colorful ASCII art banner with SLEAP branding, version
    information, and helpful links for documentation and support.

    Args:
        verbose: If True, show detailed package table with versions and locations.
        console: Optional Rich Console instance. If None, creates a new one.
    """
    if console is None:
        console = Console()

    console.print()

    # Build styled ASCII art with gradient
    lines = SLEAP_ASCII.strip("\n").split("\n")
    max_width = max(len(line) for line in lines)
    total_chars = sum(len(line.replace(" ", "")) for line in lines)

    ascii_art = Text()
    char_count = 0
    for i, line in enumerate(lines):
        # Pad line to max width to preserve alignment when centered
        padded_line = line.ljust(max_width)
        for char in padded_line:
            if char != " ":
                t = char_count / total_chars if total_chars > 0 else 0
                r, g, b = _multi_gradient(SLEAP_GRADIENT, t)
                ascii_art.append(
                    char, style=Style(color=Color.from_rgb(r, g, b), bold=True)
                )
                char_count += 1
            else:
                ascii_art.append(char)
        if i < len(lines) - 1:
            ascii_art.append("\n")

    # Tagline
    tagline = Text("Social LEAP Estimates Animal Poses", style="bold rgb(26,188,156)")

    # Version info line (SLEAP, sleap-io, sleap-nn)
    version_text = _build_version_line()

    # System info line (platform, Python)
    system_text = _build_system_line()

    # PyTorch info line (version and device) - only in verbose mode (slow)
    pytorch_text = _build_pytorch_line() if verbose else None

    # Links
    link_docs = Text()
    link_docs.append("Docs: ", style="dim")
    link_docs.append("https://docs.sleap.ai", style="rgb(93,173,226)")

    link_support = Text()
    link_support.append("Support: ", style="dim")
    link_support.append(
        "https://github.com/talmolab/sleap/discussions", style="rgb(93,173,226)"
    )

    # Happy SLEAPing with gradient
    welcome = _create_gradient_text("Happy SLEAPing!", SLEAP_GRADIENT)

    # Combine all content - center everything
    content_parts = [
        Align.center(ascii_art),
        Text(),
        Align.center(tagline),
        Text(),
        Align.center(version_text),
        Align.center(system_text),
    ]

    # Add PyTorch line if available
    if pytorch_text:
        content_parts.append(Align.center(pytorch_text))

    content_parts.extend(
        [
            Text(),
            Align.center(link_docs),
            Align.center(link_support),
            Text(),
            Align.center(welcome),
        ]
    )

    content = Group(*content_parts)

    # Create fitted panel with teal border
    panel = Panel(
        content,
        box=box.ROUNDED,
        border_style="rgb(26,188,156)",
        padding=(1, 3),
        expand=False,
    )

    console.print(panel)

    # Show verbose package table if requested
    if verbose:
        console.print()
        _print_package_table(console)

    console.print()

resolve_tag_commit(repo, version, timeout=3)

Resolve a release version to its commit SHA via the GitHub REST API.

Release installs (PyPI/conda) don't record a commit locally, but each release is tagged vX.Y.Z. This looks that tag up on GitHub and returns the commit it points to. It is fully offline-safe: any failure (no network, rate limit, missing tag, unexpected response) returns None so callers degrade gracefully.

Parameters:

Name Type Description Default
repo str

GitHub "owner/name", e.g. "talmolab/sleap".

required
version str

Package version, e.g. "1.6.3" (mapped to tag "v1.6.3").

required
timeout int

Per-request timeout in seconds.

3

Returns:

Type Description
Optional[str]

The full commit SHA the tag points to, or None if it could not be resolved.

Source code in sleap/system_info.py
def resolve_tag_commit(repo: str, version: str, timeout: int = 3) -> Optional[str]:
    """Resolve a release version to its commit SHA via the GitHub REST API.

    Release installs (PyPI/conda) don't record a commit locally, but each release
    is tagged ``vX.Y.Z``. This looks that tag up on GitHub and returns the commit
    it points to. It is fully offline-safe: any failure (no network, rate limit,
    missing tag, unexpected response) returns ``None`` so callers degrade
    gracefully.

    Args:
        repo: GitHub "owner/name", e.g. ``"talmolab/sleap"``.
        version: Package version, e.g. ``"1.6.3"`` (mapped to tag ``"v1.6.3"``).
        timeout: Per-request timeout in seconds.

    Returns:
        The full commit SHA the tag points to, or ``None`` if it could not be
        resolved.
    """
    if not repo or not version:
        return None

    import urllib.error
    import urllib.request

    # The /commits/{ref} endpoint dereferences tags (lightweight or annotated).
    url = f"https://api.github.com/repos/{repo}/commits/v{version}"
    request = urllib.request.Request(
        url,
        headers={
            "Accept": "application/vnd.github+json",
            "User-Agent": "sleap-doctor",  # GitHub rejects requests without a UA
        },
    )
    try:
        with urllib.request.urlopen(request, timeout=timeout) as response:
            payload = json.loads(response.read().decode("utf-8"))
    except (urllib.error.URLError, OSError, ValueError):
        return None

    sha = payload.get("sha") if isinstance(payload, dict) else None
    return sha or None

run_command(cmd, timeout=5)

Run a command and return (returncode, stdout, stderr).

Source code in sleap/system_info.py
def run_command(cmd: list[str], timeout: int = 5) -> tuple[int, str, str]:
    """Run a command and return (returncode, stdout, stderr)."""
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
        return result.returncode, result.stdout.strip(), result.stderr.strip()
    except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
        return -1, "", ""

short_sha(sha)

Shorten a git commit SHA for display.

Parameters:

Name Type Description Default
sha Optional[str]

Full or short commit SHA, or None.

required

Returns:

Type Description
str

The first SHORT_SHA_LEN characters of sha, or an empty string if sha is falsy.

Source code in sleap/system_info.py
def short_sha(sha: Optional[str]) -> str:
    """Shorten a git commit SHA for display.

    Args:
        sha: Full or short commit SHA, or None.

    Returns:
        The first ``SHORT_SHA_LEN`` characters of ``sha``, or an empty string
        if ``sha`` is falsy.
    """
    return sha[:SHORT_SHA_LEN] if sha else ""