Skip to main content

triggon

PyPI Python Python Package Size Downloads

Overview

Triggon is a Python library for reducing repetitive conditional logic and boilerplate around temporary state changes. It lets you switch values by label, run deferred calls, restore temporary updates, and exit early with a custom return value. The goal is to make branching logic easier to write, reuse, and manage from one place.

Table of Contents

Features

  • Switch multiple values and update registered variables or attributes at once, without writing if statements
  • Execute deferred functions and methods through TrigFunc
  • Exit early with a custom return value inside a context manager
  • Schedule trigger and revert operations with conditions or delays
  • Roll back temporary changes with a context manager

Installation

pip install triggon

Quick Start

from triggon import Triggon

tg = Triggon.from_labels(
    {
        "prod": "https://api.example.com",
        "dev": "http://localhost:8000",
    }
)


def get_base_url() -> str:
    return tg.switch_lit(("prod", "dev"), original_val="http://127.0.0.1:5000")


print(get_base_url())
# http://127.0.0.1:5000

tg.set_trigger("dev")
print(get_base_url())
# http://localhost:8000

API Reference

Triggon

Use one of the recommended constructors:

Triggon.from_label(label, /, new_values, *, debug=False) -> Triggon
Triggon.from_labels(label_values, /, *, debug=False) -> Triggon

from_label() registers a single label and its values.
from_labels() registers labels from a mapping, including multiple labels at once.

Direct construction via Triggon(...) is also supported if needed.

Notes:

  • A non-string sequence provided as a label value is unpacked into indexed values for that label
  • To treat a non-string sequence as a single value, wrap it in an outer sequence
  • In methods such as set_trigger(), revert(), switch_lit(), and register_ref(), * can be used as an index shorthand: *A means label A at index 1, and **A means index 2
  • debug accepts False, True, a single label name, or a sequence of label names
from triggon import Triggon

tg = Triggon.from_label("A", new_values=[1, 2, 3]) # one label with multiple indexed values

tg = Triggon.from_labels(
    {
        "A": 10,
        "B": 20,
    }
)

add_label() and add_labels()

add_label() adds a single label and its values.

add_labels() adds one or more labels and their values from a mapping.

add_label(label, /, new_values=None) -> None
add_labels(label_values, /) -> None

If a label is already registered, it is ignored.

set_trigger()

Activate one or more labels and update the values of variables or attributes registered with register_ref or register_refs.

set_trigger(
    labels=None,
    /,
    *,
    indices=None,
    all=False,
    cond="",
    after=0,
    reschedule=False,
) -> None

labels accepts a single label or a sequence of labels.

indices accepts a single index or a sequence of indices.

If the update value applied when a label is triggered is deferred by TrigFunc, it is executed automatically and its result is used instead.

For *-prefixed labels, the number of * symbols determines the index, but explicit indices take precedence.

Keyword arguments:

  • indices: explicit indices specifying which value to use for each label
  • all: activate all registered labels
  • cond: only activate the labels if the condition evaluates to true
  • after: delay label activation in seconds
  • reschedule: replace an existing scheduled activation for the same labels

Note: Timer execution may be delayed by system scheduling.

from triggon import Triggon

tg = Triggon.from_labels({"A": 10, "B": 20})

tg.set_trigger(all=True)

print(tg.switch_lit("A", original_val=1))
# 10
print(tg.switch_lit("B", original_val=2))
# 20
from time import sleep

x = 0

tg = Triggon.from_label("A", new_values=50)
tg.register_ref("A", name="x")

tg.set_trigger("A", after=0.5)

print(x)
# 0
sleep(0.6)
print(x)
# 50

is_triggered()

Check whether one or more labels are currently active.

is_triggered(*labels, match_all=True) -> bool

labels accepts either multiple positional labels or a single sequence of labels.

If match_all is True, this method returns True only if all given labels are active. If False, it returns True if any given label is active.

tg = Triggon.from_labels({"A": 1, "B": 2})
tg.set_trigger("B")

print(tg.is_triggered("A"))
# False
print(tg.is_triggered("A", "B", match_all=False))
# True

switch_lit()

Return the value registered for the selected label, or original_val if none of the given labels are active.

switch_lit(labels, /, original_val, *, indices=None) -> Any

labels accepts a single label or a sequence of labels.

indices accepts a single index or a sequence of indices.

If more than one label is active, the first active label in the sequence is used.
If the value selected for that label is deferred by TrigFunc, it is executed automatically and its result is returned.

Use indices to explicitly specify which value to use for each label.
For *-prefixed labels, the number of * symbols determines the index, but explicit indices take precedence.

tg = Triggon.from_labels({"A": "dev", "B": "prod"})

tg.set_trigger(all=True)

print(tg.switch_lit(("B", "A"), original_val="local"))
# prod
print(tg.switch_lit(("A", "B"), original_val="local"))
# dev

register_ref() and register_refs()

Register global variables or attribute paths so set_trigger() can update them automatically when their labels become active. If a label is already active, registration updates the target immediately.

register_ref(label, /, name, *, index=None) -> None
register_refs(label_to_refs, /) -> None

Notes:

  • Local variables themselves cannot be registered
  • Attribute roots may come from the current local scope or the global scope
  • If the value applied to the target is deferred by TrigFunc, it is executed during the update
  • Matching is based on the current file and the scope where you call the method

In register_ref(), use index to specify which indexed value to apply if the label is already active when the target is registered.
If the label is prefixed with *, the number of * symbols determines the index, but an explicit index takes precedence.

from triggon import Triggon

tg = Triggon.from_labels({"enabled": True, "name": "prod"})

flag = False


class Config:
    value = "local"


tg.set_trigger("enabled")
tg.register_ref("enabled", name="flag") # updates immediately because "enabled" is already active
tg.register_ref("name", name="Config.value")

print(flag)
# True

tg.set_trigger("name")
print(Config.value)
# prod

Use register_refs() to register multiple targets at once.
The mapping uses the form {label: {target_name: index}}.

tg.register_refs(
    {
        "enabled": {"flag": 0},
        "name": {"Config.value": 0},
    }
)

is_registered()

Check whether target names are registered in the current file and callsite scope.

is_registered(*names, label=None, match_all=True) -> bool

names accepts either multiple positional target names or a single sequence of target names.

This checks registered names only, not the current value or object state of the target.

Keyword arguments:

  • label: limit the check to names registered under a specific label
  • match_all: return True only if all given names are registered. Use False to check whether any given name is registered.
from triggon import Triggon

tg = Triggon.from_label("A", None)

a = 0
b = 0
tg.register_ref("A", name="a")

print(tg.is_registered("a", "b"))
# False
print(tg.is_registered("a", "b", match_all=False))
# True

unregister_refs()

Remove one or more registered names from the selected labels.

unregister_refs(names, /, *, labels=None) -> None

names accepts a single registered name or a sequence of them.

labels accepts a single label or a sequence of labels.

If labels is given, the specified names are removed only from those labels.
Otherwise, they are removed from all labels they are registered under.

revert()

Deactivate labels and restore registered targets to their original values.

revert(
    labels=None,
    /,
    *,
    all=False,
    disable=False,
    cond="",
    after=0,
    reschedule=False,
) -> None

labels accepts a single label or a sequence of labels.

Keyword arguments:

  • all: deactivate all registered labels
  • disable: keep the specified labels disabled
  • cond: only deactivate the labels if the condition evaluates to true
  • after: delay label deactivation in seconds
  • reschedule: replace an existing scheduled deactivation for the same labels

Note: Timer execution may be delayed by system scheduling.

from triggon import Triggon

tg = Triggon.from_label("status", new_values="active")

tg.set_trigger("status")
print(tg.switch_lit("status", original_val="inactive"))
# active

tg.revert("status")
print(tg.switch_lit("status", original_val="inactive"))
# inactive
tg = Triggon.from_label("status", new_values="active")


def get_status():
    tg.set_trigger("status")
    return tg.switch_lit("status", "inactive")


print(get_status())
# "active"

tg.revert("status", disable=True)
print(get_status())
# inactive

capture_return() and trigger_return()

Returns early within a scoped context when specified labels are active.

capture_return() -> ContextManager[EarlyReturnResult]
trigger_return(labels, /, *, value=None) -> None

labels accepts a single label or a sequence of labels.

Use capture_return() as a context manager, and call trigger_return() inside it when you want to exit early.

Available fields in EarlyReturnResult:

  • triggered: whether trigger_return() was triggered
  • value: the captured return value

For trigger_return(), use value to specify the return value.

Notes:

  • trigger_return() works only inside capture_return()
  • Deferred TrigFunc values are executed by capture_return() before the result is stored
from triggon import Triggon

tg = Triggon.from_label("stop", new_values=True)


def task():
    print("start")
    tg.trigger_return("stop", value="stopped")
    print("end")


def main():
    with tg.capture_return() as result:
        task()
        print("after task")
    return result


result = main()
# start
# end
# after task
print(result.triggered)
# False
print(result.value)
# None

tg.set_trigger("stop")

result = main()
# start
print(result.triggered)
# True
print(result.value)
# stopped

trigger_call()

Execute a deferred TrigFunc target when any of the given labels is active.

trigger_call(labels, /, target) -> Any

labels accepts a single label or a sequence of labels.

target must be a deferred TrigFunc call chain ending in a call.

from triggon import TrigFunc, Triggon

tg = Triggon.from_label("debug", new_values=True)
f = TrigFunc()


def show_debug():
    print("debug mode")


tg.trigger_call("debug", target=f.show_debug())
# no output

tg.set_trigger("debug")
tg.trigger_call("debug", target=f.show_debug())
# debug mode

rollback()

Temporarily change target values and restore them automatically when the context exits.

rollback(targets=None) -> ContextManager[None]

Notes:

  • Requires CPython 3.13 or later
  • You can pass explicit target names such as "x" or "obj.value"
  • If targets is omitted, targets assigned inside the block are collected automatically
from triggon import Triggon

x = 1

with Triggon.rollback():
    x = 99
    print(x)
    # 99

print(x)
# 1

TrigFunc

TrigFunc records deferred function or method calls without executing them immediately.
The recorded chain can later be used by switch_lit(), trigger_call(), or trigger_return().

TrigFunc()

Typical uses:

  • Store a deferred value in label data for switch_lit()
  • Run a deferred call through trigger_call()
  • Return a deferred value through trigger_return()

Deferred names are resolved from the captured local scope, global scope, and builtins when the chain is executed.
A TrigFunc instance can also be reused across scopes.

from triggon import TrigFunc, Triggon

def greet(name):
    return f"hello, {name}"


f = TrigFunc()
tg = Triggon.from_label("greet", new_values=f.greet("world"))

tg.set_trigger("greet")
print(tg.switch_lit("greet", original_val=None))
# hello, world

Debug Logging

Enable debug output by passing debug= to Triggon(...), from_label(), or from_labels().

  • debug=False: disable logging
  • debug=True: use settings from the environment, defaulting to verbosity 3
  • debug="A" or debug=("A", "B"): restrict output to selected labels

Environment variables:

  • TRIGGON_LOG_VERBOSITY
    • 0: off
    • 1: trigger, revert, early-return, and trigger-call events
    • 2: also log value updates
    • 3: also log delayed actions and register/unregister events
  • TRIGGON_LOG_FILE: write logs to a file instead of stderr
  • TRIGGON_LOG_LABELS: comma-separated label filter used when debug=True

Errors

  • InvalidArgumentError: a public API received invalid arguments or an invalid argument combination
  • UnregisteredLabelError: an operation refers to a label that has not been registered
  • InactiveCaptureError: trigger_return() was called outside capture_return()
  • RollbackNotSupportedError: rollback() was used on a runtime earlier than CPython 3.13
  • RollbackSourceError: the caller's source file could not be found during rollback()
  • UpdateError: a registered target could not be updated or restored

License

This project is licensed under the MIT License. See LICENSE for details.

Author

Created by Tsuruko GitHub: @tsuruko12 X: @tool_tsuruko12

Metadata

Release files for triggon 2.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for triggon 2.0.2
File Size Uploaded
triggon-2.0.2.tar.gz 43.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for triggon 2.0.2
File Interpreter ABI Platform
triggon-2.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 79.3 kB

Release files / triggon-2.0.2.tar.gz

Download URL triggon-2.0.2.tar.gz
Size 43.4 kB
Tags Source
SHA-256 checksum
How to use checksums
3a71d8e4a4be6da14d8e2d28681f8ea798a563643fe2eb1bf51718858df77747
BLAKE2b-256 checksum
How to use checksums
42ce6144467cf2f099903cac63469ca004bd502ac434901834837ddd8dc528a7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.

Transparency log

Release files / triggon-2.0.2-py3-none-any.whl

Download URL triggon-2.0.2-py3-none-any.whl
Size 35.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
35f651f150902e38c1f63bf88fb04fb6bd2d4fad2b3d2a402cbecc525cc08fd5
BLAKE2b-256 checksum
How to use checksums
f854e2475f992669a0f443233312f659acc8a7c4e602e214949bde665ec07895
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page