Skip to main content

A delightfully Pythonic library for managing DNS at Porkbun

Project description

๐Ÿท Oinker

DNS management that doesn't stink! ๐Ÿฝ

A delightfully Pythonic library for managing DNS at Porkbun. Async-first with sync wrappers, type-safe, and thoroughly tested.

๐Ÿ“š Full Documentation | ๐Ÿฝ Not affiliated with Porkbun

CI codecov PyPI version Python 3.13+ License: MIT

Features

  • ๐Ÿš€ Async-first design - Built on httpx for modern async/await support
  • ๐Ÿ”’ Type-safe records - Dataclasses with validation for all DNS record types
  • ๐Ÿ”„ Sync wrappers - Use Piglet when you don't need async
  • ๐Ÿ’ป CLI included - Manage DNS from the command line
  • ๐Ÿ” Auto-retry - Exponential backoff for transient failures
  • ๐Ÿ Python 3.13+ - Modern Python with full type annotations

๐Ÿ“ฆ Installation

pip install oinker

For CLI support:

pip install "oinker[cli]"

๐Ÿš€ Quick Start

Set your Porkbun API credentials:

export PORKBUN_API_KEY="pk1_..."
export PORKBUN_SECRET_KEY="sk1_..."

Async (Recommended)

from oinker import AsyncPiglet, ARecord

async with AsyncPiglet() as piglet:
    # Test connection
    pong = await piglet.ping()
    print(f"Your IP: {pong.your_ip}")

    # List DNS records
    records = await piglet.dns.list("example.com")
    for record in records:
        print(f"{record.record_type} {record.name} -> {record.content}")

    # Create an A record
    record_id = await piglet.dns.create(
        "example.com",
        ARecord(content="1.2.3.4", name="www")
    )

    # Delete by ID
    await piglet.dns.delete("example.com", record_id=record_id)

Sync

from oinker import Piglet, ARecord

with Piglet() as piglet:
    pong = piglet.ping()
    print(f"Your IP: {pong.your_ip}")

    records = piglet.dns.list("example.com")

CLI

# Test connection
$ oinker ping
๐Ÿท Oink! Connected successfully.
   Your IP: 203.0.113.42

# List DNS records
$ oinker dns list example.com
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”
โ”‚ ID     โ”‚ Name            โ”‚ Type โ”‚ Content   โ”‚ TTL โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 123456 โ”‚ example.com     โ”‚ A    โ”‚ 1.2.3.4   โ”‚ 600 โ”‚
โ”‚ 123457 โ”‚ www.example.com โ”‚ A    โ”‚ 1.2.3.4   โ”‚ 600 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”˜

# Create an A record
$ oinker dns create example.com A www 1.2.3.4
๐Ÿท Squeee! Created record 123458

# Delete a record
$ oinker dns delete example.com --id 123458
๐Ÿท Gobbled up record 123458

๐Ÿ“ DNS Record Types

Oinker provides type-safe dataclasses for all Porkbun-supported record types:

from oinker import (
    ARecord,      # IPv4 address
    AAAARecord,   # IPv6 address
    MXRecord,     # Mail server
    TXTRecord,    # Text record
    CNAMERecord,  # Canonical name
    ALIASRecord,  # ALIAS/ANAME
    NSRecord,     # Name server
    SRVRecord,    # Service record
    TLSARecord,   # DANE/TLSA
    CAARecord,    # CA Authorization
    HTTPSRecord,  # HTTPS binding
    SVCBRecord,   # Service binding
    SSHFPRecord,  # SSH fingerprint
)

Records validate their content on construction:

from oinker import ARecord, ValidationError

try:
    ARecord(content="not-an-ip")
except ValidationError as e:
    print(e)  # Invalid IPv4 address: not-an-ip

๐ŸŒ Domain Operations

async with AsyncPiglet() as piglet:
    # List all domains
    domains = await piglet.domains.list()

    # Get/update nameservers
    ns = await piglet.domains.get_nameservers("example.com")
    await piglet.domains.update_nameservers("example.com", [
        "ns1.example.com",
        "ns2.example.com",
    ])

    # URL forwarding
    forwards = await piglet.domains.get_url_forwards("example.com")

    # Check domain availability
    availability = await piglet.domains.check("example.com")

๐Ÿ” DNSSEC

from oinker import DNSSECRecordCreate

async with AsyncPiglet() as piglet:
    # List DNSSEC records
    records = await piglet.dnssec.list("example.com")

    # Create DNSSEC record
    await piglet.dnssec.create("example.com", DNSSECRecordCreate(
        key_tag="64087",
        algorithm="13",
        digest_type="2",
        digest="15E445BD...",
    ))

๐Ÿ”’ SSL Certificates

async with AsyncPiglet() as piglet:
    bundle = await piglet.ssl.retrieve("example.com")
    print(bundle.certificate_chain)
    print(bundle.private_key)

โš ๏ธ Error Handling

from oinker import (
    AsyncPiglet,
    OinkerError,
    AuthenticationError,
    RateLimitError,
    NotFoundError,
)

async with AsyncPiglet() as piglet:
    try:
        await piglet.dns.list("example.com")
    except AuthenticationError:
        print("Check your API credentials")
    except NotFoundError:
        print("Domain not found or API access not enabled")
    except RateLimitError as e:
        print(f"Slow down! Retry after {e.retry_after}s")
    except OinkerError as e:
        print(f"API error: {e}")

๐Ÿ“š Documentation

For more examples and detailed API reference, check out the full documentation.

๐Ÿท Disclaimer

This project is not affiliated with Porkbun in any way. It's just a passion project by someone who really, really loves Porkbun. They're amazing! ๐Ÿฝ

๐Ÿ“„ License

MIT

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

oinker-0.1.0.tar.gz (27.6 kB view details)

Uploaded Source

Built Distribution

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

oinker-0.1.0-py3-none-any.whl (43.6 kB view details)

Uploaded Python 3

File details

Details for the file oinker-0.1.0.tar.gz.

File metadata

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

File hashes

Hashes for oinker-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d07875a84bc5eadf6358d17692c855558655233d81b8ca207c6e9c0a6c8636c6
MD5 932a003af4bb94aed04fb8051a658a50
BLAKE2b-256 889626e3790eb686ff7e6d853a41b8e6748f769aa043cf3a20e474899e3dc4a7

See more details on using hashes here.

Provenance

The following attestation bundles were made for oinker-0.1.0.tar.gz:

Publisher: publish.yml on major/oinker

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

File details

Details for the file oinker-0.1.0-py3-none-any.whl.

File metadata

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

File hashes

Hashes for oinker-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2ea0b096bcae3e37d9fa29f239bc44d77e79018f8c26f68b3c0243d4ad23a4c9
MD5 3f702157af0dc9711397640691ae37f4
BLAKE2b-256 24e44f039cc820a176bcbf3c5a84ecff28018e65a6f2a336138754b4f402dcf4

See more details on using hashes here.

Provenance

The following attestation bundles were made for oinker-0.1.0-py3-none-any.whl:

Publisher: publish.yml on major/oinker

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