Skip to main content

Python SDK and CLI for the Synfire NIR Model Registry

Project description

Synfire Python Package

Python SDK and CLI for the Synfire NIR 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.1.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.1-py3-none-any.whl (88.9 kB view details)

Uploaded Python 3

File details

Details for the file synfire-0.0.1.tar.gz.

File metadata

  • Download URL: synfire-0.0.1.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.1.tar.gz
Algorithm Hash digest
SHA256 3da46a278d9d6c5b902d3cde36ae6f93d3b3e430ed192703f04e3abc8cee0a45
MD5 5c9792159e2c1e8c8413244bd8569cad
BLAKE2b-256 be89f0b824ee529f99c2491527366a195499c7f319390478616955499040914f

See more details on using hashes here.

Provenance

The following attestation bundles were made for synfire-0.0.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: synfire-0.0.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0a6a17e2981e92714b56863016de4b1e5a920c1b5f6ec2920f45dce1005c8568
MD5 154d2be1663ae5421bfe327de2fb4fdc
BLAKE2b-256 65db336757ce1453ca7fb9517574571c2366fe5301ac33ec8093859af0b3ef28

See more details on using hashes here.

Provenance

The following attestation bundles were made for synfire-0.0.1-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