# `MobDev.PythonAppleSupport`
[🔗](https://github.com/genericjam/mob_dev/blob/main/lib/mob_dev/python_apple_support.ex#L1)

Downloads and caches BeeWare's Python-Apple-support bundle so iOS
builds can embed CPython.

Mirrors the `MobDev.OtpDownloader` pattern: hashed URL + cached download
at `~/.mob/cache/python-apple-support-<version>/`, validated against
the expected `Python.xcframework` layout. Reused across projects.

Used by `MobDev.NativeBuild` whenever the user's project depends on
`:pythonx` — the build templates source `PYTHON_APPLE_SUPPORT` from
`extracted_dir/0` and bundle the framework + stdlib + lib-dynload
inside the `.app`.

## Scope

Only the bare CPython runtime + standard library + standard arch-specific
C extensions ship via this module. Third-party wheels (cryptography, RNS,
numpy, …) are out of scope; users who need those should produce their
own wheels with BeeWare's `mobile-forge` and drop them into their
project. See `guides/python_embedding.md`.

# `download_url`

```elixir
@spec download_url() :: String.t()
```

URL the bundle is fetched from.

# `ensure`

```elixir
@spec ensure() :: {:ok, String.t()} | {:error, term()}
```

Ensures the BeeWare Python-Apple-support bundle is cached and extracted.
Returns `{:ok, extracted_dir}` or `{:error, reason}`.

# `extracted_dir`

```elixir
@spec extracted_dir() :: String.t()
```

Returns the cached extraction directory path. May not exist if `ensure/0`
hasn't been called.

# `framework_path`

```elixir
@spec framework_path(String.t(), :ios_device | :ios_simulator) :: String.t()
```

Path to `Python.framework` inside the given extracted bundle for the
named platform slice.

`slice` is one of `:ios_device` (`ios-arm64/`) or `:ios_simulator`
(`ios-arm64_x86_64-simulator/`).

# `lib_dynload_path`

```elixir
@spec lib_dynload_path(String.t(), :ios_device | :ios_simulator) :: String.t()
```

Path to the arch-specific C-extension dir (`_ctypes.so`, `_ssl.so`, …).
These live OUTSIDE the shared stdlib because they're per-slice.

# `python_version`

```elixir
@spec python_version() :: String.t()
```

Pinned Python version (`3.13`, `3.14`, …).

# `release_tag`

```elixir
@spec release_tag() :: String.t()
```

Pinned BeeWare release tag.

# `stdlib_path`

```elixir
@spec stdlib_path(String.t()) :: String.t()
```

Path to the shared (slice-independent) Python standard library directory.
This is the pure-Python `os.py`, `urllib/`, etc. layout that goes under
`PYTHONHOME/lib/python3.13/`.

# `tarball_name`

```elixir
@spec tarball_name() :: String.t()
```

Tarball file name (used for caching the downloaded artifact).

# `valid_dir?`

```elixir
@spec valid_dir?(String.t()) :: boolean()
```

Validates that the extracted bundle has the `Python.xcframework` layout
this module expects (both device and simulator slices, plus shared stdlib).

Public to enable testing (per AGENTS.md convention) and to let
`MobDev.NativeBuild` cheaply detect a partial cache.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
