Skip to main content

Monalisten is an async library for handling GitHub webhook events in an easy way

Project description

uv Ruff

Monalisten

Monalisten is a Python 3.9+ asynchronous library that helps you handle webhook events received from GitHub in an easy way. It is built on top of the amazing githubkit and httpx libraries and relies on SSE (with httpx-sse) to stream events without exposing any endpoints.

Installation

monalisten is available on PyPI and can be installed with any package manager:

pip install monalisten
# or
poetry add monalisten
# or
uv add monalisten

You can also install it from source:

pip install git+https://github.com/trag1c/monalisten.git

Usage

Foreword on how this works

GitHub webhooks can only send event data to publicly accessible HTTP endpoints. If your environment is behind a firewall, or a NAT, or you simply don't want to set up a server, you can use a relay service, like smee.io. It generates a unique relay URL to which GitHub sends requests to, and the relay then streams them to your local client via SSE. Monalisten connects to the relay's SSE URL and receives events as they arrive without any direct incoming connection to your machine.

[!warning] Relay URLs are essentially private endpoints. Anyone who knows your relay URL can send forged events. To mitigate this, configure a webhook secret in your GitHub repository or organization webhook settings. Pass the same secret to Monalisten through the token parameter. Now, Monalisten will validate incoming payloads and discard invalid ones.

Basic example

import asyncio

from monalisten import Monalisten
from monalisten.types import PushEvent

client = Monalisten("https://smee.io/aBCDef1gHijKLM2N", token="foobar")


@client.on("push")
async def log_push(event: PushEvent) -> None:
    actor = event.sender.login if event.sender else "Someone"
    print(f"{actor} pushed to the repo!")


asyncio.run(client.listen())

Monalisten heavily relies on the githubkit SDK for parsing and verifying payloads. The monalisten.types module (meant for type annotations) is actually a re-export of the githubkit.versions.v2022_11_28.webhooks module!

One event, multiple hooks

You can decorate several functions with the same event passed to Monalisten.on, and both of them will be registered:

@client.on("pull_request")
async def log_opened_pr(event: PullRequestEvent) -> None:
    if event.action != "opened":
        return
    print(f"New PR: #{event.number}")

@client.on("pull_request")
async def log_pr_action(event: PullRequestEvent) -> None:
    print(f"Something happened to PR #{event.number}!")

When an event type has several hooks attached, they're all run concurrently.

One hook, multiple events

You can decorate the same function with Monalisten.on several times:

@client.on("pull_request")
@client.on("push")
async def log_things(event: PullRequestEvent | PushEvent) -> None:
    if "PullRequest" in type(event).__name__:
        print("Something happened to a PR!")
    else:
        print("Someone pushed!")

Wildcard hooks

You can define a hook to be triggered for ALL events by setting the event name to *:

@client.on("*")
async def log(event: WebhookEvent) -> None:
    print(f"Something definitely happened... a {type(event).__name__} perhaps")

Warnings & authentication behavior

During its authentication step, Monalisten can issue warnings for unexpected state if you pass log_auth_warnings=True when creating a client.

Monalisten will issue warnings in the following cases:

  • the client sets a token, but:

    • the received event doesn't have a signature header
    • the received event's signature cannot be validated with the client's token

    (the event is not processed in both cases)

  • the client doesn't set a token, but the received event has a signature header (the event is still processed)

API reference

Monalisten

class Monalisten:
    def __init__(
        self,
        source: str,
        *,
        token: str | None = None,
        log_auth_warnings: bool = False,
    ) -> None: ...

Creates a Monalisten client streaming events from source, optionally secured by the secret token. For details on log_auth_warnings, see the Warnings & authentication behavior section.

Monalisten.listen

class Monalisten:
    async def listen(self) -> None: ...

Instantiates an internal HTTP client and starts streaming events from source.

Monalisten.on

class Monalisten:
    def on(self, event: HookTrigger) -> Callable[[Hook[H]], Hook[H]]: ...

Meant to be used as a decorator. Registers the decorated function as a hook for the event event. Raises an error if an invalid event name is provided. HookTrigger is either a GitHub event name or the wildcard hook "*".

In technical terms, this returns a function that registers the function passed in as a Monalisten hook.

MonalistenError

class MonalistenError(Exception): ...

An exception for errors encountered by the Monalisten client (e.g. invalid event name or missing payload data).

GitHub event name reference

For a list of event names that can be passed to Monalisten.on, see GitHub's documentation page on Webhook events and payloads.

monalisten.types reference

For a list of type names that can be used as event annotations, see the src/monalisten/types.py file, or, if you use one, rely on your LSP's autocomplete!

License

monalisten is licensed under the MIT License.
© trag1c, 2025

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

monalisten-0.1.0.tar.gz (5.8 kB view details)

Uploaded Source

Built Distribution

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

monalisten-0.1.0-py3-none-any.whl (7.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: monalisten-0.1.0.tar.gz
  • Upload date:
  • Size: 5.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.10

File hashes

Hashes for monalisten-0.1.0.tar.gz
Algorithm Hash digest
SHA256 886e12f6bb77653f27e4b091d5d8df15afc0aabd9c9062115b95a46aca5f835a
MD5 826cb7977f0c5c450bc0bcfa479e544b
BLAKE2b-256 d0956fbb0be409798df149118861c98948936ef76bfbf84ed5e4aed15aab1820

See more details on using hashes here.

File details

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

File metadata

  • Download URL: monalisten-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 7.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.10

File hashes

Hashes for monalisten-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9b28888073291c37796c4e539dcef8ffffd14acbbdbcd4e4ecb88064bf51a5f8
MD5 c05f8fb53472e025e3ea7e226f5184ba
BLAKE2b-256 0880f92c94bd58460058bf00411b2113f2956e7fb10b6a55e6f37184315290d6

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