Skip to main content

Modern async/sync Asterisk Manager Interface (AMI) client for Python 3.10+

Project description

Astami

A modern, async-first Python client for the Asterisk Manager Interface (AMI).

PyPI version Python 3.10+ License: MIT

Features

  • Modern Python: Built for Python 3.10+ with full type hints
  • Async & Sync: Both AsyncAMIClient and AMIClient (sync wrapper) available
  • Context Managers: Automatic connection handling and cleanup
  • No Dependencies: Pure Python, no external dependencies
  • Fully Typed: Complete type annotations for IDE support
  • Convenience Methods: High-level methods for common operations

Installation

pip install astami

Quick Start

Synchronous Usage

from astami import AMIClient

with AMIClient("localhost", 5038, "admin", "secret") as ami:
    # Execute CLI commands
    response = ami.command("core show version")
    print(response.output)

    # Reload configuration
    ami.reload("pjsip")

Asynchronous Usage

import asyncio
from astami import AsyncAMIClient

async def main():
    async with AsyncAMIClient("localhost", 5038, "admin", "secret") as ami:
        # Execute CLI commands
        response = await ami.command("core show version")
        print(response.output)

        # Reload configuration
        await ami.reload("pjsip")

asyncio.run(main())

API Reference

Client Classes

AsyncAMIClient

The async client for use in asyncio applications.

AsyncAMIClient(
    host: str = "127.0.0.1",
    port: int = 5038,
    username: str = "",
    secret: str = "",
    timeout: float = 10.0,
)

AMIClient

Synchronous wrapper for use in threaded applications, Celery tasks, etc.

AMIClient(
    host: str = "127.0.0.1",
    port: int = 5038,
    username: str = "",
    secret: str = "",
    timeout: float = 10.0,
)

Response Object

All methods return an AMIResponse object:

@dataclass
class AMIResponse:
    raw: str              # Raw response string
    action_id: str        # ActionID from the request
    response: str         # Response status (Success, Error, etc.)
    message: str          # Message from Asterisk
    data: dict[str, str]  # All key-value pairs
    output: list[str]     # Output lines (for Command actions)

    @property
    def success(self) -> bool:
        """True if response indicates success"""

Available Methods

CLI Commands

# Execute any CLI command
response = ami.command("sip show peers")
for line in response.output:
    print(line)

Asterisk Database (AstDB)

# Store a value
ami.database_put("family", "key", "value")

# Retrieve a value
response = ami.database_get("family", "key")

# Delete a key
ami.database_del("family", "key")

# Delete entire family
ami.database_deltree("family")

Call Origination

# Originate to dialplan
ami.originate(
    channel="PJSIP/1000",
    context="default",
    exten="1001",
    priority=1,
    caller_id="Test Call <1234>",
    variables={"VAR1": "value1", "VAR2": "value2"},
)

# Originate to application
ami.originate(
    channel="PJSIP/1000",
    application="Playback",
    data="hello-world",
)

Channel Operations

# Hangup a channel
ami.hangup("PJSIP/1000-00000001")

# Redirect a channel
ami.redirect(
    channel="PJSIP/1000-00000001",
    context="default",
    exten="1002",
    priority=1,
)

# Get channel variable
response = ami.get_var("PJSIP/1000-00000001", "CALLERID(num)")

# Set channel variable
ami.set_var("PJSIP/1000-00000001", "MY_VAR", "my_value")

Configuration Reload

# Reload specific module
ami.reload("pjsip")
ami.reload("dialplan")

# Reload all
ami.reload()

Raw Actions

For actions not covered by convenience methods:

response = ami.send_action({
    "Action": "QueueStatus",
    "Queue": "support",
})

Error Handling

from astami import AMIClient, AMIError

try:
    with AMIClient("localhost", 5038, "admin", "wrong_password") as ami:
        ami.command("core show version")
except AMIError as e:
    print(f"AMI Error: {e}")
    if e.response:
        print(f"Response: {e.response.message}")

Use Cases

Celery Tasks

from celery import shared_task
from astami import AMIClient, AMIError

@shared_task
def reload_dialplan(server_host: str) -> bool:
    try:
        with AMIClient(server_host, 5038, "admin", "secret") as ami:
            response = ami.command("dialplan reload")
            return response.success
    except AMIError as e:
        logger.error(f"AMI error: {e}")
        return False

Django Management Command

from django.core.management.base import BaseCommand
from astami import AMIClient

class Command(BaseCommand):
    help = "Show Asterisk version"

    def handle(self, *args, **options):
        with AMIClient("localhost", 5038, "admin", "secret") as ami:
            response = ami.command("core show version")
            self.stdout.write(self.style.SUCCESS(response.output[0]))

Async Web Application (FastAPI)

from fastapi import FastAPI
from astami import AsyncAMIClient

app = FastAPI()

@app.get("/asterisk/version")
async def get_version():
    async with AsyncAMIClient("localhost", 5038, "admin", "secret") as ami:
        response = await ami.command("core show version")
        return {"version": response.output[0] if response.output else "Unknown"}

Configuration

Asterisk manager.conf

Ensure your Asterisk server has AMI enabled in /etc/asterisk/manager.conf:

[general]
enabled = yes
port = 5038
bindaddr = 0.0.0.0

[admin]
secret = your_secret_here
read = all
write = all

After changes, reload the manager module:

asterisk -rx "manager reload"

Why Astami?

  • Python 3.10+: Uses modern Python features like match statements, union types with |, and proper async/await patterns
  • No Deprecated APIs: Doesn't use deprecated asyncio patterns that break in Python 3.10+
  • Lightweight: No dependencies beyond the Python standard library
  • Type Safe: Full type hints for better IDE support and fewer bugs
  • Well Tested: Comprehensive test suite

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see LICENSE for details.

Credits

Developed by Real World Technology Solutions.

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

astami-1.0.1.tar.gz (9.9 kB view details)

Uploaded Source

Built Distribution

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

astami-1.0.1-py3-none-any.whl (10.7 kB view details)

Uploaded Python 3

File details

Details for the file astami-1.0.1.tar.gz.

File metadata

  • Download URL: astami-1.0.1.tar.gz
  • Upload date:
  • Size: 9.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for astami-1.0.1.tar.gz
Algorithm Hash digest
SHA256 fc91e475ebffbb4d8f454fd9dd64efb294821632518a6d4db394f323ade89bb0
MD5 220faca6efef19270032e750dc543c0b
BLAKE2b-256 1c9548c2293adb535a19fe717ed81c9be16783c30f09c16d850a14df900f29e1

See more details on using hashes here.

Provenance

The following attestation bundles were made for astami-1.0.1.tar.gz:

Publisher: publish.yml on andrewyager/astami

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

File details

Details for the file astami-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: astami-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 10.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for astami-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9d474562077ab57138d10baa72e85555a34ee0dcd55f98906d7c9ebefe87a997
MD5 eeb5a0774a0d804f06b6d98d9de25afd
BLAKE2b-256 496813522b82a9f42010f9d59b405299d017c6d355154f00e374ea58e7533001

See more details on using hashes here.

Provenance

The following attestation bundles were made for astami-1.0.1-py3-none-any.whl:

Publisher: publish.yml on andrewyager/astami

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