Skip to main content

Leash platform SDK - unified Leash() client with auth, env, and integrations namespaces

Project description

Leash SDK (Python)

Python SDK for the Leash platform. Construct a single Leash() client per request and reach identity, env, and integrations through one object.

pip install leash-sdk

Quick start

from leash import Leash

# Pass the request object from your route handler.
# Works with Flask, FastAPI / Starlette, Django, and plain dict-style
# requests (anything that exposes cookies or headers).
leash = Leash(request=request)

# Identity - sync, returns None when not authenticated
user = leash.auth.user()
if user:
    print(user.email)

# Runtime env-var resolution from the Leash platform
api_key = leash.env.get("OPENAI_API_KEY")              # Optional[str]
api_key = leash.env.get("STRIPE_SECRET_KEY", fresh=True)
values = leash.env.get_many(["OPENAI_API_KEY", "STRIPE_KEY"])

# Integrations
messages = leash.integrations.gmail.list_messages(max_results=5)
issues = leash.integrations.linear.list_issues(state_type="started")
events = leash.integrations.google_calendar.list_events(
    time_min="2026-04-01T00:00:00Z",
    time_max="2026-04-30T00:00:00Z",
)

The Leash() constructor

Leash(request=...) is server-only in 0.4. It accepts any framework request object that exposes cookies or headers:

Framework What the SDK reads
Flask request.cookies['leash-auth']
Django request.COOKIES['leash-auth'] or request.META['HTTP_COOKIE']
FastAPI / Starlette request.cookies.get('leash-auth')
Raw / dict request['cookie'] or request.headers['cookie']

Authorization: Bearer <jwt> headers are also recognised - used by the CLI / agent flow.

Authentication precedence

  1. LEASH_API_KEY env var (server-only, never request-bound)
  2. Authorization: Bearer <jwt> header on the request (CLI / agent)
  3. leash-auth cookie on the request (browser to deployed app)

All three may coexist. The SDK forwards each in the appropriate header so the platform can pick the right credential.

Namespaces

leash.auth

user = leash.auth.user()                  # Optional[LeashUser]
authed = leash.auth.is_authenticated()    # bool

leash.env

value = leash.env.get("OPENAI_API_KEY")           # Optional[str]
value = leash.env.get("STRIPE_KEY", fresh=True)
mapping = leash.env.get_many(["A", "B", "C"])     # dict[str, Optional[str]]

Results are cached per Leash instance for 60 seconds.

leash.env.get requires LEASH_API_KEY to be set (env var or api_key= constructor arg). Missing / not-declared keys return None; auth, plan, and platform errors raise LeashError.

leash.integrations

leash.integrations.gmail.list_messages(max_results=5)
leash.integrations.gmail.send_message(to="x@y.com", subject="hi", body="...")

leash.integrations.google_calendar.list_events(time_min="...", time_max="...")
leash.integrations.google_calendar.create_event(
    summary="Sync", start={"dateTime": "..."}, end={"dateTime": "..."},
)

leash.integrations.google_drive.list_files(query="...")
leash.integrations.google_drive.upload_file(
    name="report.txt", content="...", mime_type="text/plain",
)

leash.integrations.linear.list_issues(state_type="started")
leash.integrations.linear.create_issue(team_id="...", title="...")

For providers without a typed wrapper yet (GitHub, HubSpot, Jira, Slack, ...) use the escape hatch:

slack = leash.integrations.provider("slack")
slack.call("post-message", {"channel": "#general", "text": "hi"})

Naming differences vs the TypeScript SDK

The TS SDK exposes leash.integrations.calendar and leash.integrations.drive. The Python SDK uses the longer google_calendar and google_drive names so they match the platform's integration_providers.id values (and so calendar doesn't shadow the stdlib calendar module). The short TS names are wired up as aliases — leash.integrations.calendar and leash.integrations.drive both work and point to the same instances.

Errors

Every SDK call raises a single error type: LeashError. It carries a stable code plus a message, optional action (remediation hint), see_also (docs URL), status (HTTP), and cause.

from leash import Leash, LeashError

try:
    leash.integrations.gmail.list_messages()
except LeashError as err:
    if err.code == "INTEGRATION_NOT_ENABLED":
        print("Connect Gmail at:", err.see_also)
    elif err.code == "UPGRADE_REQUIRED":
        print("Upgrade required:", err.message)
    else:
        raise

Known codes: NO_API_KEY, NO_REQUEST_SERVER_CONSTRUCT, UNAUTHORIZED, NO_AUTH_CONTEXT, INTEGRATION_NOT_ENABLED, INTEGRATION_ERROR, UPGRADE_REQUIRED, NETWORK_ERROR, KEY_NOT_DECLARED, INVALID_KEY, SOURCE_RESYNC_FAILED, ENV_FETCH_ERROR.

What's NOT in 0.4 yet

  • Leash.create_dev_auth_handler() — the local dev cookie-exchange helper from the TS SDK isn't yet implemented in Python (per-framework response types make a clean cross-framework version nontrivial). Tracked: LEA-262.
  • LeashIntegrations legacy helpers (is_connected, get_connections, get_connect_url, etc.) — these were 0.3-era patterns. The TS SDK 0.4 also dropped them. If you need them, file an issue.
  • Async surface — sync only in 0.4.0. Wrap with asyncio.to_thread(...) for async code; native async coming in 0.4.1+ if demand justifies.

Sync only in 0.4

The SDK uses httpx's sync client. Async-first callers can wrap calls:

import asyncio

messages = await asyncio.to_thread(
    leash.integrations.gmail.list_messages, max_results=5,
)

A native async surface is on the 0.4.1 roadmap.

Lifecycle

Leash owns an internal httpx.Client. Either call leash.close() or use it as a context manager:

with Leash(request=request) as leash:
    user = leash.auth.user()
    msgs = leash.integrations.gmail.list_messages()

You can inject your own client with Leash(request=..., http_client=...).

Framework examples

Flask

from flask import Flask, request, jsonify
from leash import Leash

app = Flask(__name__)

@app.get("/me")
def me():
    leash = Leash(request=request)
    user = leash.auth.user()
    return jsonify({"user": user.__dict__ if user else None})

FastAPI

from fastapi import FastAPI, Request
from leash import Leash

app = FastAPI()

@app.get("/me")
async def me(request: Request):
    leash = Leash(request=request)
    user = leash.auth.user()
    return {"user": user.__dict__ if user else None}

Django

from django.http import JsonResponse
from leash import Leash

def me(request):
    leash = Leash(request=request)
    user = leash.auth.user()
    return JsonResponse({"user": user.__dict__ if user else None})

License

Apache-2.0

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

leash_sdk-0.4.0.tar.gz (28.5 kB view details)

Uploaded Source

Built Distribution

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

leash_sdk-0.4.0-py3-none-any.whl (26.9 kB view details)

Uploaded Python 3

File details

Details for the file leash_sdk-0.4.0.tar.gz.

File metadata

  • Download URL: leash_sdk-0.4.0.tar.gz
  • Upload date:
  • Size: 28.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for leash_sdk-0.4.0.tar.gz
Algorithm Hash digest
SHA256 563cda3a723e11ba0155fad3f9a6fc24a23b1c431bb3661f2b0462de0bf49e9f
MD5 46f5c3a627da95d0f2d78e6c6e9a1bed
BLAKE2b-256 710592c06159b4c9dc70ff2614fcc0f3f5505ff7a0ffcae46e886574ac94b8ab

See more details on using hashes here.

File details

Details for the file leash_sdk-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: leash_sdk-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 26.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for leash_sdk-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 39e60aed1cec4a059775b90595e5231c24d6e58a8f1a05315ae6cedf7caf4a91
MD5 ca5ff8db2b412b943e52be567ed9dc8d
BLAKE2b-256 afd2e949110a427863c4db61a985106445022e25922debfa6dba7d24fb341a4c

See more details on using hashes here.

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