Skip to content
Open
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
37 changes: 37 additions & 0 deletions .github/workflows/nix.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Nix

on:
pull_request:
branches: [master]
push:
branches: [master]

permissions:
contents: read

concurrency:
group: nix-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
flake:
name: nix flake check
runs-on: ['self-hosted','ubuntu-22.04']

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install Nix
uses: cachix/install-nix-action@v31
with:
extra_nix_config: |
experimental-features = nix-command flakes

# Builds the package, imports the SDK and verifies that the version and
# the packaged dependencies match `pyproject.toml`.
- name: Check the flake
run: nix flake check --print-build-logs

- name: Build the package
run: nix build .#status-sdk
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ on:
jobs:
build:
name: Build distribution
runs-on: ubuntu-latest
runs-on: ['self-hosted','ubuntu-22.04']

steps:
- name: Check out repository
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
jobs:
version:
name: Verify Version Bump
runs-on: ubuntu-latest
runs-on: ['self-hosted','ubuntu-22.04']

steps:
- name: Check out repository
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,11 @@ The compose file reads three variables from the environment. All of them have a
```
STATUS_GO_COMMIT=2bee8b6a38cdc8f92d74e2dbb8c4e77fbbeea149 PLATFORM=linux/amd64 docker compose -f status_sdk/docker-compose.yaml up -d
```

### Nix

The SDK is packaged as a nix flake. It provides the library itself, a development shell and a set of checks.

```bash
nix develop
```
27 changes: 27 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

240 changes: 240 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
{
description = "Status Python SDK";

inputs = {
# A channel URL: the exact revision is pinned in `flake.lock` and can be
# moved forward with `nix flake update`.
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};

outputs =
{ self, nixpkgs }:
let
inherit (nixpkgs) lib;

systems = lib.filter (system: lib.elem system nixpkgs.lib.systems.flakeExposed) [
"x86_64-linux"
"aarch64-linux"
"aarch64-darwin"
];

forAllSystems = lib.genAttrs systems;
pkgsFor = system: nixpkgs.legacyPackages.${system};

version = "1.4.0";

release = {
rev = "1.4.0";
hash = "sha256-vNXGUaqJdzoCCVl/CnubBdR7TiVG94g+/FcFJAJSdUU=";
};

fetchRelease =
pkgs:
pkgs.fetchFromGitHub {
owner = "status-im";
repo = "status-python-sdk";
rev = release.rev;
hash = release.hash;
};

mkStatusSdk =
{
system,
pname ? "status-sdk",
}:
let
pkgs = pkgsFor system;

# nixpkgs' `eth-utils` 6.0.0 imports `pydantic` at runtime but lists
# it as a test dependency only, so `import eth_utils` fails without
# it. `eth-abi` depends on `eth-utils` and the SDK depends on
# `eth-abi`, so the missing transitive dependency is fixed here
# instead of adding `pydantic` to the SDK's own dependencies.
python = pkgs.python3.override {
packageOverrides = pySelf: pySuper: {
eth-utils = pySuper.eth-utils.overridePythonAttrs (old: {
dependencies = old.dependencies ++ [ pySuper.pydantic ];
});
};
};
in
python.pkgs.buildPythonPackage {
inherit pname version;

src = fetchRelease pkgs;

format = "pyproject";
build-system = [ python.pkgs.setuptools ];

dependencies = with python.pkgs; [
requests
websocket-client
websockets
pandas
pillow
eth-abi
pyyaml
pycryptodome
];

doCheck = false;

pythonImportsCheck = [ "status_sdk" ];

# at runtime the SDK writes into its own installation directory
# (`assets/`, `data/`, `backups/`). That directory is read-only inside
meta = {
description = "Python SDK for the Status App backend (status-im/status-go)";
homepage = "https://github.com/status-im/status-python-sdk";
license = lib.licenses.mit;
platforms = lib.platforms.unix;
maintainers = [
{
name = "Nick Ninov";
email = "nikolay@status.im";
}
{
name = "Alexis Pentori";
email = "alexis@status.im";
}
];
};
};
in
{
packages = forAllSystems (
system:
let
base = mkStatusSdk { inherit system; };
in
{
default = base;
status-sdk = base;
}
);

formatter = forAllSystems (system: (pkgsFor system).nixfmt);

overlays.default = final: prev: {
python3Packages = prev.python3Packages // {
status-sdk = self.packages.${final.stdenv.hostPlatform.system}.status-sdk;
};
};

devShells = forAllSystems (
system:
let
pkgs = pkgsFor system;
python = pkgs.python3;
base = self.packages.${system}.status-sdk;
in
{
default = pkgs.mkShell {
name = "status-sdk-shell";
packages = [
(python.withPackages (ps: [ base ]))

# Linting and testing.
pkgs.ruff
python.pkgs.mypy
python.pkgs.pytest

# Tools the SDK shells out to: Docker for `launch_docker_container`,
# Nix and Git for `build_and_launch`.
pkgs.docker-client
pkgs.nix
pkgs.git
pkgs.curl
pkgs.jq
pkgs.gnumake
];

shellHook = ''
# Prefer the working tree over the packaged copy, so that edits are
# picked up without reinstalling anything.
if [ -d "$PWD/status_sdk" ]; then
export PYTHONPATH="$PWD''${PYTHONPATH:+:$PYTHONPATH}"
fi

echo "status-sdk development shell"
echo " the SDK is importable: python3 -c 'import status_sdk'"
echo " linting: ruff check . && ruff format --check ."
echo " the optional extras (agents, community-greet) are not packaged"
echo " in Nix - see the README for how to run the examples"
'';
};
}
);

checks = forAllSystems (
system:
let
pkgs = pkgsFor system;
python = pkgs.python3;
base = self.packages.${system}.status-sdk;
in
{
default = base;

import =
pkgs.runCommand "status-sdk-import-check"
{
nativeBuildInputs = [ (python.withPackages (ps: [ base ])) ];
}
''
python3 -c "import status_sdk; print('status-sdk', status_sdk.__version__)"
touch $out
'';

version =
pkgs.runCommand "status-sdk-version-check"
{
nativeBuildInputs = [ python ];
released = fetchRelease pkgs;
flakeSrc = ./.;
flakeVersion = version;
}
''
released="$released" flake_src="$flakeSrc" flake_version="$flakeVersion" python3 - <<'PY'
import os, re, tomllib, pathlib

def version(path):
return tomllib.loads(pathlib.Path(path).read_text())["project"]["version"]

released = version(os.path.join(os.environ["released"], "pyproject.toml"))
local = version(os.path.join(os.environ["flake_src"], "pyproject.toml"))
flake = os.environ["flake_version"]

assert released == local, f"released sources are {released}, pyproject.toml is {local}"
assert released == flake, f"released sources are {released}, the flake is {flake}"

changelog = pathlib.Path(os.path.join(os.environ["flake_src"], "CHANGELOG.md")).read_text()
entry = r"^## \[" + re.escape(local) + r"\] - \d{4}-\d{2}-\d{2}$"
assert re.search(entry, changelog, re.M), f"no changelog entry for {local}"
PY
touch $out
'';

dependencies =
pkgs.runCommand "status-sdk-dependencies-check"
{
nativeBuildInputs = [ python ];
flakeSrc = ./.;
nixDependencies = builtins.concatStringsSep " " (map (dep: dep.pname) base.dependencies);
}
''
nix_dependencies="$nixDependencies" flake_src="$flakeSrc" python3 - <<'PY'
import os, re, tomllib, pathlib

pyproject = tomllib.loads(pathlib.Path(os.path.join(os.environ["flake_src"], "pyproject.toml")).read_text())
declared = sorted(re.split(r"[^\w.-]", dep)[0] for dep in pyproject["project"]["dependencies"])
packaged = sorted(os.environ["nix_dependencies"].split())

assert packaged == declared, f"packaged dependencies {packaged} do not match pyproject.toml {declared}"
PY
touch $out
'';
}
);
};
}
Loading