Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to `status-python-sdk` will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.2.1] - 2026-09-25

### Changed

- `def download_build_and_launch`
- A `launcher` can be passed to launch a [status-go] build that is already on disk, skipping the release download and extraction
- The path of the launched build is now returned

## [1.2.0] - 2026-09-22

### Added
Expand Down Expand Up @@ -201,6 +209,7 @@ will try to log in without a hashed password
- Launch [status-go] Docker container with Python instead of manual `docker compose up -d` setup.
- Custom library errors

[1.2.1]: https://github.com/status-im/status-python-sdk/releases/tag/1.2.1
[1.2.0]: https://github.com/status-im/status-python-sdk/releases/tag/1.2.0
[1.1.6]: https://github.com/status-im/status-python-sdk/releases/tag/1.1.6
[1.1.5]: https://github.com/status-im/status-python-sdk/releases/tag/1.1.5
Expand Down
2 changes: 1 addition & 1 deletion docs/account.md
Original file line number Diff line number Diff line change
Expand Up @@ -1821,7 +1821,7 @@ The exact shape depends on how the backend was launched:

| Launched with | Reported version | `status_go_commit_sha` |
|--------|--------|-------------|
| [`build_and_launch`](./utils.md#build_and_launchcommitnone-repo_dirnone-addresslocalhost8080-wait_seconds30-install_depstrue) / [`download_build_and_launch`](./utils.md#download_build_and_launchfile_namenone-repo_namestatus-imstatus-go-tagnone-tokennone-addresslocalhost8080-wait_seconds30) | `v10.35.0-48-g9f09f9027` | `9f09f9027` - the short SHA, taken out of the `git describe` version |
| [`build_and_launch`](./utils.md#build_and_launchcommitnone-repo_dirnone-addresslocalhost8080-wait_seconds30-install_depstrue) / [`download_build_and_launch`](./utils.md#download_build_and_launchlaunchernone-repo_namestatus-imstatus-go-tagnone-tokennone-addresslocalhost8080-wait_seconds30) | `v10.35.0-48-g9f09f9027` | `9f09f9027` - the short SHA, taken out of the `git describe` version |
| [`launch_docker_container`](./utils.md#launch_docker_containercommitnone-wait_seconds5-platformlinuxamd64-data_foldernone) | `9f09f902762292fbe8264dd75a68e739ecd17444` | the same value, unchanged |

The two differ because a native build is compiled inside a git clone, so `status-go` embeds a `git describe` version that the SDK extracts the SHA from. The Docker image is built from a git **context** that carries no `.git` folder, so `docker-compose.yaml` injects the ref it was told to build instead - meaning the full SHA comes back as-is.
Expand Down
26 changes: 17 additions & 9 deletions docs/utils.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,20 +156,20 @@ build_and_launch(address="localhost:9500", wait_seconds=60)
account = Account(backend_port=9500)
```

### `download_build_and_launch(file_name=None, repo_name="status-im/status-go", tag=None, token=None, address="localhost:8080", wait_seconds=30)`
### `download_build_and_launch(launcher=None, repo_name="status-im/status-go", tag=None, token=None, address="localhost:8080", wait_seconds=30)`

Download a prebuilt `status-backend` bundle from a GitHub release and launch it. This is an **alternative to [`build_and_launch`](./utils.md#build_and_launchcommitnone-repo_dirnone-addresslocalhost8080-wait_seconds30-install_depstrue)** for setups that do not want to build [`status-im/status-go`](https://github.com/status-im/status-go) from source.
Download a prebuilt `status-backend` bundle from a GitHub release, extract it and launch it. This is an **alternative to [`build_and_launch`](./utils.md#build_and_launchcommitnone-repo_dirnone-addresslocalhost8080-wait_seconds30-install_depstrue)** for setups that do not want to build [`status-im/status-go`](https://github.com/status-im/status-go) from source - no Nix or Go toolchain is needed.

| Name | Type | Required | Description |
|-----|-----|-----|-------------|
| `file_name` | `str` | No | The release asset to download, exactly as it appears on the release page. When omitted, the asset matching this machine is picked using the pattern `status-backend_{platform}_{arch}_{version}`, e.g. `status-backend_linux_x86_64_2.34.0`. |
| `launcher` | `str` | No | Path to a `status-backend` binary that is **already on disk**. When given, **nothing is downloaded**. Use it to re-launch a bundle you already have, or a binary from somewhere else entirely. |
| `repo_name` | `str` | No | The `owner/name` of the repository to pull the release from. Defaults to `status-im/status-go`. |
| `tag` | `str` | No | A release tag. When omitted, the latest release is used. |
| `token` | `str` | No | A GitHub token. Required for private repositories. |
| `address` | `str` | No | The `host:port` to run `status-backend` on. Defaults to `localhost:8080`, which matches the defaults of [`Account`](./account.md#accountdomainlocalhost-backend_port8080-media_port9000-is_securefalse-backup_foldernone-volume_foldernone). If you change it, pass the matching `domain` and `backend_port` when creating the `Account`. |
| `wait_seconds` | `int` | No | How long to poll the backend's `/health` endpoint before giving up, in seconds. Defaults to `30`. **Downloading itself is not subject to this timeout** - only the startup that follows it. |
| `wait_seconds` | `int` | No | How long to poll the backend's `/health` endpoint before giving up, in seconds. Defaults to `30`. **Downloading and extracting are not subject to this timeout** - only the startup that follows them. |

The bundle is extracted into a `status-backend-bundle` folder in the current working directory, and reused on later calls instead of downloading again.
Returns `str` - the path of the file that was launched. A custom exception is raised when the release has no asset for this machine, when the extracted bundle contains nothing runnable, or when the backend does not answer on `/health` in time.

```python
from status_sdk import download_build_and_launch, Account
Expand All @@ -185,23 +185,31 @@ params = {
account.login(**params)

print(account.info["public_key"])

# Stop the backend when you are done
process.terminate()
```

Download a specific release tag from a private repository:

```python
from status_sdk import download_build_and_launch

download_build_and_launch(
launcher = download_build_and_launch(
repo_name="status-im/status-go",
tag="v2.34.0",
token="ghp_xxxxxxxxxxxxxxxxxxxx"
)
print(f"Launched {launcher}")
```

Re-launch a bundle that is already on disk, with no network access at all:

```python
from status_sdk import download_build_and_launch

download_build_and_launch("./status-backend-bundle/run.sh")
```

**Note**: if something already answers on `address`, the backend is **not** launched a second time and the function returns straight away. That makes repeated calls safe, but it also means a backend left running from an earlier session is reused - stop it first if you want a different build.

## Properties

### `__version__`
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "status-sdk"
version = "1.2.0"
version = "1.2.1"
description = "Private chat. Communities. Multi-chain wallet. Browser. dApps all in one app, powered by SNT."
readme = "README.md"
requires-python = ">=3.11"
Expand Down
21 changes: 16 additions & 5 deletions status_sdk/utils/external.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,21 +198,29 @@ def run(cmd: list[str], cwd: Optional[str] = None) -> subprocess.CompletedProces

builds.launch_build(binary_path, repo_dir, address, wait_seconds)

def download_build_and_launch(file_name: Optional[str] = None, repo_name: str = "status-im/status-go", tag: Optional[str] = None, token: Optional[str] = None, address: str = "localhost:8080", wait_seconds: int = 30):
def download_build_and_launch(launcher: Optional[str] = None, repo_name: str = "status-im/status-go", tag: Optional[str] = None, token: Optional[str] = None, address: str = "localhost:8080", wait_seconds: int = 30):
"""
Download a prebuilt `status-backend` bundle from a GitHub release, extract it and launch it.
This is an alternative to `build_and_launch` for setups that do not want to build
`status-im/status-go` from source - no Nix or Go toolchain is needed.

Parameters:
- `file_name` - the release asset to download, exactly as it appears on the release page. If not provided, the asset matching this machine is picked
- `launcher` - the `status-backend` binary to launch
- `repo_name` - the `owner/name` of the repository
- `tag` - a release tag. If not provided, the latest release is used
- `token` - a GitHub token. Required for private repositories
- `address` - the `host:port` to launch `status-backend` on. Defaults to `localhost:8080`.
- `wait_seconds` - number of seconds to wait, polling the health endpoint, before giving up on the backend starting. Downloading itself is not subject to this timeout.

Output:
- the `status-backend` binary to launch
"""
logger = logging.getLogger(__name__)
destination = os.getcwd()
if launcher:
builds.launch_build(launcher, destination, address, wait_seconds)
return launcher

headers = {"Accept": "application/vnd.github+json"}
if token:
headers["Authorization"] = f"Bearer {token}"
Expand All @@ -231,7 +239,6 @@ def download_build_and_launch(file_name: Optional[str] = None, repo_name: str =

selected = assets[0]
file_name = selected["name"]
destination = os.getcwd()
archive_path = os.path.join(destination, file_name)
bundle_dir = os.path.join(destination, "status-backend-bundle")
if not os.path.exists(bundle_dir):
Expand All @@ -250,12 +257,16 @@ def download_build_and_launch(file_name: Optional[str] = None, repo_name: str =
if not os.path.basename(member.name).startswith("._")
]

common_prefix = os.path.commonpath([member.name for member in members])
for member in members:
member.name = os.path.relpath(member.name, common_prefix)

# A bundle from a previous release must not mix with the new one
shutil.rmtree(bundle_dir, ignore_errors=True)
logger.info(f"Extracting '{file_name}' into {bundle_dir}...")
# The `data` filter blocks paths escaping `destination`. Only available from Python 3.11.4
extract_options = {"filter": "data"} if hasattr(tarfile, "data_filter") else {}
archive.extractall(destination, members=members, **extract_options)
archive.extractall(bundle_dir, members=members, **extract_options)

os.remove(archive_path)
else:
Expand All @@ -279,4 +290,4 @@ def download_build_and_launch(file_name: Optional[str] = None, repo_name: str =
logger.warning(f"Failed to clear quarantine attribute on {bundle_dir}: {result.stderr.strip()}")

builds.launch_build(launcher, destination, address, wait_seconds)

return launcher
Loading