[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/andevsr/pythonnative/main/src/pythonnative/project/devices.py [Back]  [Original]

"""Device and simulator discovery for ``pn devices`` / ``pn run --device``.

Enumerates the three kinds of targets a PythonNative app can run on:

- **Android devices and emulators** via ``adb devices -l``.
- **iOS Simulators** via ``xcrun simctl list devices --json``.
- **Physical iOS devices** via ``xcrun devicectl list devices`` (Xcode
  15+; earlier Xcodes simply report no physical devices).

The shell-outs are isolated in ``list_*`` functions; the parsers are
pure functions over captured text/JSON so they can be unit tested
without any toolchain installed.
"""

from __future__ import annotations

import json
import re
import subprocess
import tempfile
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Any, Dict, List, Optional

__all__ = [
    "Device",
    "list_devices",
    "list_android_devices",
    "list_ios_simulators",
    "list_ios_physical_devices",
    "find_device",
    "parse_adb_devices",
    "parse_simctl_devices",
    "parse_devicectl_devices",
]


@dataclass
class Device:
    """One runnable target.

    Attributes:
        platform: ``"android"`` or ``"ios"``.
        kind: ``"device"``, ``"emulator"``, or ``"simulator"``.
        identifier: The stable id used to target the device (adb
            serial, simulator UDID, or devicectl identifier).
        name: Human-readable model or simulator name.
        os_version: OS version string when known.
        state: ``"booted"``, ``"connected"``, ``"shutdown"``, or
            ``"offline"``.
    """

    platform: str
    kind: str
    identifier: str
    name: str
    os_version: str = ""
    state: str = ""

    @property
    def is_ready(self) -> bool:
        """Whether the target can be used right now (or booted on demand)."""
        if self.kind == "simulator":
            return self.state in ("booted", "shutdown")
        return self.state in ("booted", "connected")

    def to_dict(self) -> Dict[str, Any]:
        """Return a JSON-serializable view of this target.

        Derived from the dataclass fields so a field added later is
        carried into the payload automatically, plus the computed
        ``is_ready`` that consumers would otherwise have to re-derive
        from ``kind`` and ``state``.

        Returns:
            The declared fields in declaration order, then ``is_ready``.
        """
        return {**asdict(self), "is_ready": self.is_ready}

    def format(self) -> str:
        """Return one aligned listing row for the CLI."""
        os_part = f" ({self.os_version})" if self.os_version else ""
        return f"  {self.identifier:

Web Proxy Viewer  |  New URL  |  Original Page