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.1.tar.gz (6.3 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.1-py3-none-any.whl (7.4 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for monalisten-0.1.1.tar.gz
Algorithm Hash digest
SHA256 bb3e9984ae4895aeae64b6a190bd0e71c4a9d0aaaca65ba07398618f1cccfbb5
MD5 57a737a7e97d001368e6ce5f343bea32
BLAKE2b-256 09d2281ad15aaca06f7303f2fdf5859b3d991c9131e13654393ffe96ca06dbfa

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for monalisten-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2502979c02195b6f03d537b380f0e45f9e29e91dab353ef03887dd1f50786c20
MD5 cbde711c717b7ed9b00551b08daedfe3
BLAKE2b-256 83dd51e7ec8904c08cad6ff8aa0a82a98d14e3c8f2aea5755532f67e27860e9f

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