Skip to content

feat(ffi): Python bindings (UniFFI) - #228

Merged
Nic-dorman merged 5 commits into
mainfrom
feat/python-ffi
Sep 3, 2026
Merged

Nic-dorman merged 5 commits into
mainfrom
feat/python-ffi

Conversation

@Nic-dorman

@Nic-dorman Nic-dorman commented Aug 6, 2026

Copy link
Copy Markdown
Member

What

Adds a Python package for the ant-ffi UniFFI surface — the same compiled library that backs the Swift and Kotlin SDKs — giving Python the daemon-less, direct-network client. This complements antd-py, which requires a running antd daemon.

Generated with the in-crate uniffi-bindgen (no Rust changes to ant-ffi). Async Client methods surface as native asyncio async def.

Contents (ffi/python/)

  • ant_ffi/__init__.py — re-exports the generated surface. The generated module (ant_ffi.py) and the native library are build outputs (gitignored), produced by build.sh.
  • pyproject.toml / setup.py — package metadata + platform-wheel tag machinery (py3-none-<platform>: one wheel per OS/arch, valid for any Python 3, since the bindings are pure ctypes over a bundled native lib).
  • tests/test_smoke.py — offline: import + version + EVM address derivation (mirrors ffi/csharp/AntFfi.Tests).
  • examples/upload_download_demo.py — devnet upload/download round-trip.
  • ffi/scripts/build.sh — gains a Python binding-generation step alongside the existing C#/Kotlin/Swift steps.

Proven

  • examples/upload_download_demo.py does a byte-identical file round-trip against a local devnet (paid upload, progress callbacks, sha256 match).
  • tests/test_smoke.py passes offline.

Follow-up

Cross-platform wheel building (manylinux / macOS universal2 / Windows) and PyPI publishing via Trusted Publishing land in a separate PR to keep this focused on the bindings themselves.

Naming

Settled 2026-09-02: the distribution name is ant-sdk (matches the repo; documented in pyproject.toml). The import name ant_ffi is fixed by the UniFFI crate namespace regardless of the PyPI name. If a product-level rename happens later, the PyPI project will be deleted and recreated under the new name (V2-880).

🤖 Generated with Claude Code

Adds a Python package for the ant-ffi UniFFI surface — the same compiled
library that backs the Swift and Kotlin SDKs — giving Python the daemon-less,
direct-network client (complementing antd-py, which needs a running antd).
Generated with the in-crate uniffi-bindgen (no Rust changes); async Client
methods surface as native asyncio `async def`.

Contents (ffi/python/):
- ant_ffi/__init__.py  re-exports the generated surface; the generated module
  and native library are build outputs (gitignored), produced by build.sh
- pyproject.toml / setup.py  package metadata + platform-wheel tag machinery
  (py3-none-<platform>: one wheel per OS/arch, any Python 3)
- tests/test_smoke.py  offline: import + version + EVM address derivation
- examples/upload_download_demo.py  devnet upload/download round-trip
- ffi/scripts/build.sh  gains a Python binding-generation step alongside
  the C#/Kotlin/Swift steps

Proven: the demo does a byte-identical file round-trip against a local devnet;
the smoke tests pass offline. Cross-platform wheel building and PyPI publishing
follow in a separate PR.

Note: the distribution name `ant-ffi` is a deliberate placeholder — the import
name `ant_ffi` is fixed by the UniFFI crate namespace regardless, so the final
PyPI name is a one-line change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nic and others added 3 commits August 6, 2026 13:09
Lockfile-only, semver-compatible bump that clears the cargo-audit failure
on the ffi dependency tree. ruint <1.20.0 has incorrect overflow flags and
truncated shift amounts in Uint shift operations (RUSTSEC-2026-0220); it
comes in transitively via alloy-primitives. ant-ffi compiles unchanged and
cargo audit passes (only the pre-existing allowed unmaintained warnings
remain).

Pre-existing on main — the advisory was published after the last green run,
so it surfaced here because the audit job scans against the live advisory DB.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Working title matching the repo; import name stays ant_ffi (UniFFI
namespace). If a product-level rename happens the PyPI project will be
deleted and recreated under the new name (V2-880).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@dirvine dirvine left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes for two release-artifact failure modes found at exact head 0c4ef5a16cc2e667864d653ec5522af8ee6bedb6.

1. A clean checkout silently builds an unusable wheel

ffi/python/setup.py never checks that the gitignored generated module and native library are present. From a clean copy of ffi/python I ran:

python -m build --wheel

The command succeeded, but the wheel contained only ant_ffi/__init__.py plus metadata. It installed successfully, then failed immediately:

ModuleNotFoundError: No module named 'ant_ffi.ant_ffi'

Please make the package build fail clearly unless ant_ffi/ant_ffi.py and the expected platform native library are staged (or generate them in the build), and add a built-wheel install/import check. The cross-platform release workflow may remain a follow-up; the important point here is not to emit a publishable-looking broken wheel.

2. The sdist embeds the build host's native library

With generated files staged, default python -m build created ant_sdk-0.0.8.tar.gz containing ant_ffi/libant_ffi.dylib. That source distribution is platform-neutral by filename but platform-specific in content, so rebuilding it on Linux or Windows can package the wrong binary.

Please either exclude native libraries from sdists/provide a valid source-build path, or explicitly reject sdist creation for this wheel-only distribution. The release workflow should upload only repaired platform wheels.

The happy path itself checks out: release Rust build and UniFFI generation passed; all 16 ant-ffi tests passed; staged wheels passed twine check, Python 3.9/3.13 smoke tests, installed-wheel import/version checks, and offline wallet derivation. GitHub's three checks are green. The blockers are the two silent/misleading artefact paths above.

…facts

Review findings on this PR: a clean checkout silently produced a wheel
that installs but cannot import (generated module + native lib are
gitignored build outputs setup.py never checked for), and a default
sdist embedded the build host's native library under a platform-neutral
name.

- bdist_wheel now refuses to run unless ant_ffi/ant_ffi.py and the host
  platform's native library are staged, with a pointer at the build
  scripts.
- sdist is blocked outright: this is a wheel-only distribution.
- ffi/scripts/check-python-wheel.sh installs a built wheel into a
  throwaway venv and imports it from outside the repo - the post-build
  proof the wheel works. README documents the wheel-only policy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@dirvine dirvine left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous findings: all resolved at 52b5924c0971a41b98673d843fda3550fd3e415c.

  • Clean-checkout wheel builds now fail clearly unless the generated binding and expected native library are staged.
  • Source distributions are explicitly rejected for this wheel-only package.
  • The installed-wheel import/version checker passes in a fresh environment.

Reverified locally: missing-artifact and sdist failure paths; release build and UniFFI generation; staged wheel build; twine check; Python 3.9/3.13 installed-wheel imports; offline smoke tests; all 16 ant-ffi tests; formatting and diff checks. Current GitHub checks are green.

Independent review consensus found no remaining merge blockers. Minor release-workflow hardening can remain follow-up work.

@Nic-dorman
Nic-dorman merged commit b83bce8 into main Sep 3, 2026
3 checks passed
@Nic-dorman
Nic-dorman deleted the feat/python-ffi branch September 3, 2026 07:55
@Nic-dorman
Nic-dorman restored the feat/python-ffi branch September 3, 2026 07:55
@Nic-dorman
Nic-dorman deleted the feat/python-ffi branch September 3, 2026 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants