Python SDK and CLI for the Synfire Model Registry
Project description
Synfire Python Package
Python SDK and CLI for the Synfire Model Registry - a public registry for hosting and sharing neuromorphic models in the Neuromorphic Intermediate Representation (NIR) format.
Installation
pip install synfire
This installs both:
- the Python SDK (
from synfire import Client) - the CLI (
synfire ...)
To load NIR models directly (recommended):
pip install synfire[nir]
For development:
pip install synfire[dev]
Quick Start
CLI
synfire --help
synfire login
synfire whoami
Python
from synfire import Client
# Create a client (uses stored credentials)
client = Client()
# Check who you're authenticated as
user = client.whoami()
print(f"Logged in as: {user.email}")
# Search for models
results = client.search("gesture", platforms=["T1"])
for repo in results:
print(f"{repo.full_name}: {repo.latest_version}")
# Download a model
release = client.pull("nrg-lab/gesture-recognition", version="1.0.0")
# Load the NIR graph (requires: pip install synfire[nir])
graph = release.load()
Authentication
The SDK resolves credentials in this order:
- Explicit token parameter:
Client(token="synfire_...") - Environment variable:
SYNFIRE_TOKEN - Credential store: Tokens stored via CLI login (OS keyring)
Interactive Use (Recommended)
For local development, use the CLI bundled with this package to log in:
# Login (stores token securely in OS keyring)
synfire login
# Verify authentication
synfire whoami
Then create a client without specifying a token:
from synfire import Client
client = Client() # Uses token from keyring
user = client.whoami()
print(f"Authenticated as: {user.email}")
CI/CD Pipelines
For automated environments, use the environment variable:
export SYNFIRE_TOKEN="synfire_your_token_here"
from synfire import Client
# Token resolved from environment variable
client = Client()
Explicit Token (Testing/Scripts)
For scripts or testing, pass the token directly:
from synfire import Client
client = Client(token="synfire_your_token_here")
Token Validation
By default, the Client validates the token on initialization by calling the API. This ensures you get immediate feedback if the token is invalid:
from synfire import Client, AuthenticationError
try:
client = Client()
print(f"Valid token for: {client.user.email}")
except AuthenticationError as e:
print(f"Authentication failed: {e}")
To skip validation (e.g., for offline preparation):
client = Client(token="synfire_...", validate_token=False)
Managing Credentials Programmatically
Use CredentialStore for direct credential management:
from synfire import CredentialStore
# Store a token (equivalent to 'synfire login')
CredentialStore.store_token("synfire_your_token_here")
# Get the current token (checks env var first, then keyring)
token = CredentialStore.get_token()
# Check if a token is available
if CredentialStore.has_token():
print("Token available")
# Check the token source
if CredentialStore.is_using_env_token():
print("Using environment variable")
elif CredentialStore.has_stored_token():
print("Using stored credential")
# Delete stored token (equivalent to 'synfire logout')
CredentialStore.delete_token()
Client API
Initialization
from synfire import Client
# Default: uses credential resolution and validates token
client = Client()
# Explicit token
client = Client(token="synfire_...")
# Custom API URL (for local testing or a custom deployment)
client = Client(base_url="http://localhost:8000/api/v1")
# Skip token validation
client = Client(token="synfire_...", validate_token=False)
Context Manager Support
The client supports context managers for automatic resource cleanup:
with Client() as client:
user = client.whoami()
# ... use client ...
# Resources automatically released
Or manually close:
client = Client()
try:
user = client.whoami()
finally:
client.close()
Properties
client = Client()
# How the token was resolved: 'explicit', 'environment', or 'keyring'
print(client.token_source)
# The configured API base URL
print(client.base_url)
# Cached user info (available if validate_token=True)
if client.user:
print(f"User: {client.user.email}")
User Methods
# Get authenticated user info
user = client.whoami()
print(f"Email: {user.email}")
print(f"Username: {user.username}")
print(f"Namespace: {user.username}")
Repository Methods
# Get repository information
repo = client.get_repository("org/repo-name")
print(f"Latest version: {repo.latest_version}")
print(f"Summary: {repo.summary}")
# Get release information
release = client.get_release("org/repo-name", version="1.0.0")
release_latest = client.get_release("org/repo-name") # Gets latest
Search
# Search for repositories
results = client.search("gesture", platforms=["T1", "Loihi2"])
for repo in results:
print(f"{repo.full_name}: {repo.summary}")
# Search with tags
results = client.search("vision", tags=["classification"])
# Pagination
page1 = client.search("model", limit=10, offset=0)
page2 = client.search("model", limit=10, offset=10)
Pull
# Download latest version
release = client.pull("org/repo-name")
# Download specific version
release = client.pull("org/repo-name", version="1.0.0")
# Alternative syntax
release = client.pull("org/repo-name:1.0.0")
# Custom output directory
release = client.pull("org/repo-name", output_dir=Path("./my-models"))
# Load the NIR graph
graph = release.load() # Requires synfire[nir]
Publish
from pathlib import Path
# Publish a new release
release = client.publish(
"my-org/my-model",
version="1.0.0",
model_path=Path("./model.nir"),
card_path=Path("./nir-card.json"),
notes_path=Path("./RELEASE_NOTES.md"), # Optional
)
Verify
# Verify file integrity against registry
is_valid = client.verify(
Path("./model.nir"),
"org/repo-name",
"1.0.0"
)
if is_valid:
print("File integrity verified!")
Hardware Targets
The registry supports models targeting various neuromorphic platforms:
| Target | Description |
|---|---|
T1 |
Innatera T1 SoC |
Pulsar |
Innatera Pulsar (C1) SoC |
Loihi2 |
Intel Loihi 2 |
SpiNNaker2 |
SpiNNaker 2 |
BrainScaleS-2 |
BrainScaleS-2 |
Xylo |
SynSense Xylo |
Speck |
SynSense Speck |
Generic |
Software simulation |
Use the HardwareTarget enum for type-safe values:
from synfire import HardwareTarget
# In search queries
results = client.search("gesture", platforms=[HardwareTarget.T1.value])
# Check valid targets
print(list(HardwareTarget))
Exception Handling
All SDK exceptions inherit from SynfireError:
from synfire import (
Client,
SynfireError,
AuthenticationError,
ValidationError,
NotFoundError,
ConflictError,
TombstonedError,
NetworkError,
ChecksumMismatchError,
)
try:
client = Client()
release = client.pull("org/repo:1.0.0")
except AuthenticationError as e:
# Invalid/missing token or insufficient permissions
print(f"Auth error: {e.message}")
print(f"Error code: {e.error_code}")
except NotFoundError as e:
# Repository or version doesn't exist
print(f"Not found: {e.message}")
except TombstonedError as e:
# Release was tombstoned (soft-deleted)
print(f"Release unavailable: {e.reason}")
except NetworkError as e:
# Connection issues
print(f"Network error: {e.message}")
except SynfireError as e:
# Catch-all for any SDK error
print(f"Error: {e.message}")
Exception Details
| Exception | Cause | Resolution |
|---|---|---|
AuthenticationError |
Invalid/expired token, missing token, insufficient permissions | Run synfire login or check SYNFIRE_TOKEN |
ValidationError |
Invalid data format, schema validation failure | Check nir-card.json and model.nir format |
NotFoundError |
Repository/version doesn't exist | Verify repository name and version |
ConflictError |
Version already exists | Use a different version number |
TombstonedError |
Release was tombstoned | Use a different version |
NetworkError |
Connection failed, timeout | Check internet connection |
ChecksumMismatchError |
Downloaded file corrupted | Re-download the file |
Using with NIR Frameworks
Load models into NIR-compatible frameworks:
from synfire import Client
client = Client()
release = client.pull("nrg-lab/gesture-recognition:1.0.0")
graph = release.load()
# Use with Norse (PyTorch)
import norse.torch as norse
model = norse.from_nir(graph)
# Or with snnTorch
import snntorch as snn
model = snn.from_nir(graph)
# Or with Sinabs
import sinabs
model = sinabs.from_nir(graph)
# Or with Lava
from lava.lib.dl import nir as lava_nir
model = lava_nir.from_nir(graph)
Environment Variables
| Variable | Description | Default |
|---|---|---|
SYNFIRE_TOKEN |
API token for authentication | - |
SYNFIRE_API_URL |
Override API base URL | https://synfire.dev/api/v1 |
Type Hints
The SDK is fully typed with PEP 561 support. Type stubs are included:
from synfire import Client, User, Repository, Release
def get_latest_release(client: Client, repo: str) -> Release:
return client.get_release(repo)
Thread Safety
The Client class is not thread-safe. Create separate client instances
for concurrent use:
import threading
from synfire import Client
def worker():
with Client() as client:
# Use client within this thread
user = client.whoami()
threads = [threading.Thread(target=worker) for _ in range(4)]
for t in threads:
t.start()
for t in threads:
t.join()
Logging
Enable debug logging to see API calls:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("synfire").setLevel(logging.DEBUG)
client = Client() # Will log API calls
Documentation
- SDK Documentation: docs.synfire.dev/sdk
- CLI Reference: docs.synfire.dev/cli
- API Reference: docs.synfire.dev/api
- NIR Specification: github.com/neuromorphs/NIR
Contributing
Contributions are currently managed by the Synfire maintainers. To report issues or get in touch about contributing, contact us at contact@synfire.dev.
License
Copyright (c) Innatera. All rights reserved.
This package may be downloaded, installed, and used to access the Synfire platform. No permission is granted to copy, modify, redistribute, sublicense, or create derivative works except as explicitly permitted by Innatera.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file synfire-0.0.2.tar.gz.
File metadata
- Download URL: synfire-0.0.2.tar.gz
- Upload date:
- Size: 71.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d571b3e5da9f893fd23a1139b3a65731c6da3abded4c95f57b2a503a18dbcc4
|
|
| MD5 |
9767fb1d98b1b20b2094cf94347c899e
|
|
| BLAKE2b-256 |
1e7b6c59b49771003bb0c56c65fa2ee2eec7d69bf1361e83c81ed7cbe437a8aa
|
Provenance
The following attestation bundles were made for synfire-0.0.2.tar.gz:
Publisher:
publish-python-package.yml on InnateraNanosystems/synfire
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
synfire-0.0.2.tar.gz -
Subject digest:
2d571b3e5da9f893fd23a1139b3a65731c6da3abded4c95f57b2a503a18dbcc4 - Sigstore transparency entry: 2009757839
- Sigstore integration time:
-
Permalink:
InnateraNanosystems/synfire@df72db9417463ddd0507793038396588e0a5cafc -
Branch / Tag:
refs/tags/pypi-v0.0.2 - Owner: https://github.com/InnateraNanosystems
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python-package.yml@df72db9417463ddd0507793038396588e0a5cafc -
Trigger Event:
push
-
Statement type:
File details
Details for the file synfire-0.0.2-py3-none-any.whl.
File metadata
- Download URL: synfire-0.0.2-py3-none-any.whl
- Upload date:
- Size: 88.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58ad404b21be1eccfc6d64c95c9e62ddcc55541e70672c36f5def468a0029aa6
|
|
| MD5 |
637867588f78a719f62ca2e61eca4b83
|
|
| BLAKE2b-256 |
9d662e79346bdbc3b86d51399f9d6e53fe487bf5cd604ea025ea7c935cb296b4
|
Provenance
The following attestation bundles were made for synfire-0.0.2-py3-none-any.whl:
Publisher:
publish-python-package.yml on InnateraNanosystems/synfire
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
synfire-0.0.2-py3-none-any.whl -
Subject digest:
58ad404b21be1eccfc6d64c95c9e62ddcc55541e70672c36f5def468a0029aa6 - Sigstore transparency entry: 2009757913
- Sigstore integration time:
-
Permalink:
InnateraNanosystems/synfire@df72db9417463ddd0507793038396588e0a5cafc -
Branch / Tag:
refs/tags/pypi-v0.0.2 - Owner: https://github.com/InnateraNanosystems
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python-package.yml@df72db9417463ddd0507793038396588e0a5cafc -
Trigger Event:
push
-
Statement type: