Skip to main content

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:

  1. Explicit token parameter: Client(token="synfire_...")
  2. Environment variable: SYNFIRE_TOKEN
  3. 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

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

synfire-0.0.2.tar.gz (71.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

synfire-0.0.2-py3-none-any.whl (88.9 kB view details)

Uploaded Python 3

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

Hashes for synfire-0.0.2.tar.gz
Algorithm Hash digest
SHA256 2d571b3e5da9f893fd23a1139b3a65731c6da3abded4c95f57b2a503a18dbcc4
MD5 9767fb1d98b1b20b2094cf94347c899e
BLAKE2b-256 1e7b6c59b49771003bb0c56c65fa2ee2eec7d69bf1361e83c81ed7cbe437a8aa

See more details on using hashes here.

Provenance

The following attestation bundles were made for synfire-0.0.2.tar.gz:

Publisher: publish-python-package.yml on InnateraNanosystems/synfire

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for synfire-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 58ad404b21be1eccfc6d64c95c9e62ddcc55541e70672c36f5def468a0029aa6
MD5 637867588f78a719f62ca2e61eca4b83
BLAKE2b-256 9d662e79346bdbc3b86d51399f9d6e53fe487bf5cd604ea025ea7c935cb296b4

See more details on using hashes here.

Provenance

The following attestation bundles were made for synfire-0.0.2-py3-none-any.whl:

Publisher: publish-python-package.yml on InnateraNanosystems/synfire

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page