triggon


Nametriggon JSON
Version 0.1.0b4 PyPI version JSON
download
home_pageNone
SummaryAutomatically switches values at labeled trigger points, supporting multi-value switching, early returns, and function calls.
upload_time2025-07-21 19:17:51
maintainerNone
docs_urlNone
authorNone
requires_python>=3.13
licenseMIT License Copyright (c) 2025 Tsuruko Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords switch trigger label auto dynamic early return function call
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # triggon

[![PyPI](https://img.shields.io/pypi/v/triggon)](https://pypi.org/project/triggon/)
![Python](https://img.shields.io/pypi/pyversions/triggon)
![Python](https://img.shields.io/pypi/l/triggon)
![Package Size](https://img.shields.io/badge/size-20.3KB-lightgrey)

## Overview
Dynamically switch multiple values at specific trigger points.

> ⚠️ **This library is currently in beta. 
> APIs may change in future releases, and some bugs may still be present.**

> ⚠️ Function names like `alter_var()` and `alter_literal()` have been renamed 
> to `switch_var()` and `switch_lit()` in the next update.  
> The old names will remain available during the beta period for compatibility.

## Table of Contents
- [Installation](#installation)
- [Usage](#usage)
- [License](#license)
- [Author](#author)

## Features
- Switch multiple values at once with a single trigger point
- No `if` or `match` statements needed
- Switch both literal values and variables
- Trigger early returns with optional return values
- Automatically jump to other functions at a trigger point

## Planned Feature
- Support switching beyond values and function calls—toward broader code behavior control

## Upcoming Feature
- Support for delayed trigger execution (e.g., after N seconds)

## Installation
```bash
pip install triggon
```

## Usage
This section explains how to use each function.

### Triggon 
`Triggon(self, label: str | dict[str, Any], /, new: Any=None, *, debug: bool=False)`

`Triggon()` is initialized with label-value pairs.  
You can pass a single label with its value, or multiple labels using a dictionary.

If you pass multiple values to a label using a list,  
each value will correspond to index 0, 1, 2, and so on, in the order you provide.

```python
from triggon import Triggon

# Set index 0 to 100 and index 1 to 0 as their new values
tg = Triggon("num", new=[100, 0])

def example():
    x = tg.switch_lit("num", 0)    # index 0
    y = tg.switch_lit("*num", 100) # index 1

    print(f"{x} -> {y}")

example()
# Output: 0 -> 100

tg.set_trigger("num")

example()
# Output: 100 -> 0
```

When passing a list or tuple that should be used as a single value,  
make sure to wrap it in another list or tuple to avoid it being unpacked.

```python
tg = Triggon({
    "seq1": [(1, 2, 3)], # index 0 holds (1, 2, 3)  
    "seq2": [1, 2, 3],   # indexes 0, 1, and 2 hold 1, 2, and 3
})

def example():
    x = tg.switch_lit("seq1", 10) # index 0
    y = tg.switch_lit("seq2", 10) # index 0

    print(f"For 'seq1': {x}")
    print(f"For 'seq2': {y}")

tg.set_trigger(("seq1", "seq2"))

example()
# == Output ==
# For 'seq1': (1, 2, 3)
# For 'seq2': 1
```

A single index can have multiple values assigned to it.

```python
from dataclasses import dataclass

from triggon import Triggon

tg = Triggon("mode", new=True) # Set index 0 to True for label 'mode'

@dataclass
class ModeFlags:
    mode_a: bool = False
    mode_b: bool = False
    mode_c: bool = False

    def set_mode(self, enable: bool):
        tg.set_trigger("mode", cond="enable")

        tg.switch_var("mode", [self.mode_a, self.mode_b, self.mode_c]) # All values share index 0

        print(
            f"mode_a is {self.mode_a}\n"
            f"mode_b is {self.mode_b}\n"
            f"mode_c is {self.mode_c}\n"
        )

s = ModeFlags()

s.set_mode(False)
# == Output ==
# mode_a is False
# mode_b is False
# mode_c is False

s.set_mode(True)
# == Output ==
# mode_a is True
# mode_b is True
# mode_c is True
```

If you want to trace label activity in real time, set the `debug` keyword to `True`.

> ⚠️ **Note:** 
Labels with the `*` prefix cannot be used during initialization 
and will raise an `InvalidArgumentError`.

### set_trigger
`def set_trigger(self, label: str | list[str] | tuple[str, ...], /, *, cond: str=None) -> None`

Marks the specified label(s) as triggered, 
allowing their values to be updated on the next call.  
All values associated with the specified label will be changed, regardless of their index.  
The `label` parameter accepts a single string or a list/tuple of labels.

You can set conditions using the `cond` keyword 
but control structures such as `if` are not allowed.

If any of the specified labels have been disabled using `revert()`, 
this function has no effect on them.

```python
from triggon import Triggon

tg = Triggon({
    "milk": 3,
    "banana": 0.4,
    "msg": "We're having a sale for milk today!",
})

def example():
    msg = tg.switch_lit("msg", org="We're open as usual today.")
    print(msg)

    milk = tg.switch_lit('milk', 4)
    banana = tg.switch_lit('banana', 0.6)

    print(f"Milk: ${milk}")
    print(f"Banana: ${banana}")

example()
# == Output ==
# We're open as usual today.
# Milk: $4
# Banana: $0.6

tg.set_trigger(["milk", "msg"]) # Triggers for 'milk' and 'msg' are activated here.

example()
# == Output ==
# We're having a sale for milk today!
# Milk: $3
# Banana: $0.6
```

```python
tg = Triggon("msg", "Call me?")

def sample(print_msg: bool):
    # Activate "msg" if print_msg is True
    tg.set_trigger("msg", cond="print_msg")

    # Print the message if triggered
    print(tg.switch_lit("msg", ""))

sample(False) # Output:
sample(True)  # Output: Call me? 
```

> **Note:**
This function uses `eval()` internally to evaluate the `cond` argument.
However, **only comparison expressions (e.g., `x > 0 > y`, `value == 10`) are allowed**.
Non-comparison expressions will raise an `InvalidArgumentError`.

### switch_lit (alter_literal)
`def switch_lit(self, label: str | list[str] | tuple[str, ...], /, org: Any, *, index: int=None) -> Any`

Changes a literal value when the flag is active.  
You can also use this function directly inside a print().  
When using a dictionary for `label`, the `index` keyword cannot be used.

```python
from triggon import Triggon

tg = Triggon("text", new="After") 

def example():
    text = tg.switch_lit("text", org="Before", index=0)
    print(text)  

    # You can also write: 
    # print(tg.alter_literal('text', 'Before'))

    tg.set_trigger("text")

example() # Output: Before
example() # Output: After
```

Alternatively, you can use the `*` character as a prefix to specify the index.  
For example, `"label"` refers to index 0, and `"*label"` refers to index 1.

You can use the `index` keyword or the `*` prefix.  
When both are provided, the keyword takes precedence.  
`*` used elsewhere (not as a prefix) is ignored and has no special meaning.

> **Note:**   
For better readability when working with multiple indices, 
it's recommended to use the `index` keyword.

```python
# Set the value to 'A' for index 0 and to 'B' for index 1
tg = Triggon("char", new=("A", "B"))

def example():
    tg.set_trigger("char")

    print(tg.switch_lit("char", 0))           # index 0 (no '*' — defaults to index 0)
    print(tg.switch_lit("*char", 1))          # index 1 (using '*')
    print(tg.switch_lit("*char", 0, index=0)) # index 0 ('index' keyword takes precedence over '*')
    print(tg.switch_lit("char", 1, index=1))  # index 1 (using 'index' keyword)

example()
# == Output ==
# A
# B
# A
# B
```

```python
tg = Triggon({"A": True, "B": False})

def sample():
    # Applies the new value if any label is active.
    # If both are active, the earlier one takes priority.
    x = tg.switch_lit(["A", "B"], None)

    print(x)

sample()            # Output: None 

tg.set_trigger("A") # Output: True
sample()

tg.set_trigger("B") # Output: True
sample()
```

> **Note:**   
When multiple labels are passed and multiple flags are active,  
the earliest label in the sequence takes precedence.
In that case, if the `index` keyword is passed,  
it will be applied to all labels.

### switch_var (alter_var)
`def switch_var(self, label: str | dict[str, Any], var: Any=None, /, *, index: int=None) -> None | Any`

Changes variable value(s) directly when the flag is active.  
**It supports global variables and class attributes, but not local variables.**

You can pass multiple labels and variables using a dictionary.    
The `index` keyword cannot be used in that case.  
If the target index is 1 or greater, 
add a `*` prefix to the label corresponding to the index  
(e.g., `*label` for index 1, `**label` for index 2).

This function returns the updated value **only when a single label is passed**.  
If a dictionary is passed, the function returns `None`.

> **Note:**  
In such cases, it is recommended to use individual calls to this function  
with the `index` keyword instead, for better readability.

```python
import random

from triggon import Triggon

tg = Triggon({
    "level_1": ["an uncommon", 80],
    "level_2": ["a rare", 100],
    "level_3": ["a legendary", 150],
})

level = None
attack = None

def spin_gacha():
    items = ["level_1", "level_2", "level_3"]
    result = random.choice(items)

    tg.set_trigger(result)

    tg.switch_var(result, level)
    tg.switch_var(result, attack, index=1)

    # Outputs vary randomly.
    # Example: result = 'level_2'
    print(f"You pulled {level} sword!") # Output: You pulled a rare sword!
    print(f"Attack Power: {attack}")    # Output: Attack Power: 100 

spin_gacha()
```

```python
from dataclasses import dataclass

from triggon import Triggon

tg = Triggon("even", [0, 2, 4])

@dataclass
class Example:
    a: int = 1
    b: int = 3
    c: int = 5

    def change_field_values(self, change: bool):
        if change:
            tg.set_trigger("even")

        tg.alter_var({
            "even": self.a,    # index 0
            "*even": self.b,   # index 1
            "**even": self.c,  # index 2
        })

exm = Example()

exm.change_field_values(False)
print(f"a: {exm.a}, b: {exm.b}, c: {exm.c}")
# Output: a: 1, b: 3, c: 5

exm.change_field_values(True)
print(f"a: {exm.a}, b: {exm.b}, c: {exm.c}")
# Output: a: 0, b: 2, c: 4
```

Also, you can assign multiple values to a single variable.

```python
tg = Triggon({
    "flag": [True, False],
    "num": [0, 100],
})

@dataclass
class Sample:
    flag: bool = None
    num: int = None

    def sample(self, label: str, label_2: str):
        tg.switch_var({label: self.flag, label_2: self.num})

        print(f"flag is {self.flag} and num is {self.num}")

s = Sample()
tg.set_trigger(["flag", "num"])

s.sample("flag", "num")   # Output: flag is True and num is 0
s.sample("*flag", "*num") # Output: flag is False and num is 100
```

> **Notes:** 
> Values are typically updated when `set_trigger()` is called.  
> However, on the first call, 
> the value won't change unless the variable has been registered via `switch_var()`.  
> In that case, the value is changed by `switch_var()`.  
> Once registration is complete, each call to `set_trigger()` immediately updates the value.  
>
> In some environments (e.g., Jupyter or REPL),  
> calls to alter_var or switch_var may not be detected due to source code unavailability.
>
> This function only supports  
> literal values, variables, or simple attribute chains for labels and the `index` keyword.  
> Other types will raise an `InvalidArgumentError`.

### revert
`def revert(self, label: str | list[str] | tuple[str, ...]=None, /, *, all: bool=False, disable: bool=False) -> None`

Reverts all values previously changed by `switch_lit()` or `switch_var()`  
to their original state.  
To revert all labels, set the `all` keyword to `True`.

The reversion remains effective until the next call to `set_trigger()`.  
All values associated with the specified label will be reverted, 
regardless of their index.

If the `disable` keyword is set to `True`, the reversion becomes permanent.

```python
from dataclasses import dataclass

from triggon import Triggon

tg = Triggon("hi", new="Hello")

@dataclass
class User:
    name: str = "Guest"
    init_done: bool = False

    def initialize(self):
        # Set the trigger for the first-time greeting
        tg.set_trigger("hi")

        self.init_done = True
        self.greet()

    def greet(self):
        msg = tg.switch_lit("hi", org="Welcome back")
        print(f"{msg}, {self.name}!")

    def entry(self):
        if self.init_done:
            self.greet()
        else:
            self.initialize()
            tg.revert("hi") # Revert to the original value

user = User()

user.entry() # Output: Hello, Guest!

user.entry() # Output: Welcome back, Guest!
```

```python
tg = Triggon({"name": "John", "state": True})

@dataclass
class User:
    name: str = None
    online: bool = False

    def login(self):
        # Set the variable for each label
        tg.switch_var({"name": self.name, "state": self.online})
        tg.set_trigger(["name", "state"])

user = User()
print(f"User name: {user.name}\nOnline: {user.online}")
# == Output ==
# User name: None
# Online: False

user.login()
print(f"User name: {user.name}\nOnline: {user.online}")
# == Output ==
# User name: John
# Online: True
```

### exit_point
`def exit_point(self, label: str, func: TrigFunc, /) -> None | Any`

Defines the exit point where an early return is triggered by `trigger_return()`.  
The `func` argument must be a `TrigFunc` instance that wraps the target function.  

An index with the `*` prefix can be used, but it is ignored.

> **Note:** `exit_point()` is not required if `trigger_return()` is not triggered.

### trigger_return
`trigger_return(self, label: str, /, ret: Any=None, *, index: int=None, do_print: bool=False) -> None | Any`

Triggers an early return with any value when the flag is active.  
The return value must be set during initialization.  
If nothing needs to be returned, set it to `None` or simply omit the value..

You can also set the return value with the `ret` keyword,  
which takes precedence over the one set during initialization.
In that case, you don't need to provide any value if you're not using a dictionary.

If the `do_print` keyword is set to `True`, the return value will be printed.  
If the value is not a string, an `InvalidArgumentError` is raised.

```python
from triggon import Triggon, TrigFunc

# Define label and early-return value
tg = Triggon("skip", new="(You don't have enough money...)")
F = TrigFunc() # Wraps the target function for early return

def check_funds(money: int):
    if money < 300:
        tg.set_trigger("skip")

    print(f"You now have {money}G.")
    board_ship()

def board_ship():
    print("It'll cost you 300G to board the ship.")

    # Triggers early return and prints the value if the flag is set
    tg.trigger_return("skip", do_print=True) 

    print("Enjoy the ride!")  

tg.exit_point("skip", F.check_funds(500))
# == Output ==
# You now have 500G.
# It'll cost you 300G to board the ship.
# Enjoy the ride!

tg.exit_point("skip", F.check_funds(200))
# == Output ==
# You now have 200G.
# It'll cost you 300G to board the ship.
# (You don't have enough money...)
```

```python
tg = Triggon("zero")
F = TrigFunc()

def sample():
    num = get_number()

    # The "zero" label will be activated if `num` is 0
    tg.set_trigger("zero", cond="num == 0")

    # Return early with the message if triggered
    tg.trigger_return("zero", ret=f"{num} ...", do_print=True) 

    num_2 = get_number()

    print(f"The total number is {num + num_2}!")

def get_number():
    return random.randint(0, 10) 

tg.exit_point("zero", F.sample()) # The output is random!
```

### trigger_func
`def trigger_func(self, label: str, func: TrigFunc, /) -> None | Any`

Triggers a function when the flag is active.  
The `func` argument must be a `TrigFunc` instance that wraps the target function.

A label must be initialized with any value in order to register it when creating a `Triggon` instance.  
The value won't be returned, so you can use any placeholder.  
If you're not using a dictionary, there's no need to provide a value at all.  
**If the function returns a value, that value will also be returned.**.

An index with the `*` prefix can be used, but it is ignored.

```python
from triggon import Triggon, TrigFunc

tg = Triggon({
    "skip": None,
    "call": None,
})
F = TrigFunc()

def example():
    tg.set_trigger(["skip", "call"]) # Set triggers for early return and function call

    print("If the 'call' flag is active, jump to example_2().")

    tg.trigger_func("call", F.example_2()) # Use the TrigFunc instance F for example_2()

    print("This message may be skipped depending on the trigger.")


def example_2():
    print("You’ve reached the example_2() function!")
    tg.trigger_return("skip")

tg.exit_point("skip", F.example())
# == Output ==
# If the 'call' flag is active, jump to example_2().
# You’ve reached the example_2() function!
```

### TrigFunc
This class wraps a function to delay its execution.   
You can create an instance without any arguments and use it to wrap the target function.

> ⚠️ **Note:**  
When using this class,  
you must create an instance first (e.g., F = TrigFunc()) before using it.

### Error
- `InvalidArgumentError`  
Raised when the number of arguments, their types, or usage is incorrect.

- `MissingLabelError`
Raised when a specific label has not been registered.

## License
This project is licensed under the MIT License.  
See [LICENSE](./LICENSE) for details.

## Author
Created by Tsuruko  
GitHub: [@tsuruko12](https://github.com/tsuruko12)  
X: [@tool_tsuruko12](https://x.com/tsuruko)

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "triggon",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.13",
    "maintainer_email": "Tsuruko <tsuruko-12@outlook.com>",
    "keywords": "switch, trigger, label, auto, dynamic, early return, function call",
    "author": null,
    "author_email": "Tsuruko <tsuruko-12@outlook.com>",
    "download_url": "https://files.pythonhosted.org/packages/71/f4/dc91ab378817def88547074785f345e9db04b15c1bc2c78a15fcc9ca7c4c/triggon-0.1.0b4.tar.gz",
    "platform": null,
    "description": "# triggon\r\n\r\n[![PyPI](https://img.shields.io/pypi/v/triggon)](https://pypi.org/project/triggon/)\r\n![Python](https://img.shields.io/pypi/pyversions/triggon)\r\n![Python](https://img.shields.io/pypi/l/triggon)\r\n![Package Size](https://img.shields.io/badge/size-20.3KB-lightgrey)\r\n\r\n## Overview\r\nDynamically switch multiple values at specific trigger points.\r\n\r\n> \u26a0\ufe0f **This library is currently in beta. \r\n> APIs may change in future releases, and some bugs may still be present.**\r\n\r\n> \u26a0\ufe0f Function names like `alter_var()` and `alter_literal()` have been renamed \r\n> to `switch_var()` and `switch_lit()` in the next update.  \r\n> The old names will remain available during the beta period for compatibility.\r\n\r\n## Table of Contents\r\n- [Installation](#installation)\r\n- [Usage](#usage)\r\n- [License](#license)\r\n- [Author](#author)\r\n\r\n## Features\r\n- Switch multiple values at once with a single trigger point\r\n- No `if` or `match` statements needed\r\n- Switch both literal values and variables\r\n- Trigger early returns with optional return values\r\n- Automatically jump to other functions at a trigger point\r\n\r\n## Planned Feature\r\n- Support switching beyond values and function calls\u2014toward broader code behavior control\r\n\r\n## Upcoming Feature\r\n- Support for delayed trigger execution (e.g., after N seconds)\r\n\r\n## Installation\r\n```bash\r\npip install triggon\r\n```\r\n\r\n## Usage\r\nThis section explains how to use each function.\r\n\r\n### Triggon \r\n`Triggon(self, label: str | dict[str, Any], /, new: Any=None, *, debug: bool=False)`\r\n\r\n`Triggon()` is initialized with label-value pairs.  \r\nYou can pass a single label with its value, or multiple labels using a dictionary.\r\n\r\nIf you pass multiple values to a label using a list,  \r\neach value will correspond to index 0, 1, 2, and so on, in the order you provide.\r\n\r\n```python\r\nfrom triggon import Triggon\r\n\r\n# Set index 0 to 100 and index 1 to 0 as their new values\r\ntg = Triggon(\"num\", new=[100, 0])\r\n\r\ndef example():\r\n    x = tg.switch_lit(\"num\", 0)    # index 0\r\n    y = tg.switch_lit(\"*num\", 100) # index 1\r\n\r\n    print(f\"{x} -> {y}\")\r\n\r\nexample()\r\n# Output: 0 -> 100\r\n\r\ntg.set_trigger(\"num\")\r\n\r\nexample()\r\n# Output: 100 -> 0\r\n```\r\n\r\nWhen passing a list or tuple that should be used as a single value,  \r\nmake sure to wrap it in another list or tuple to avoid it being unpacked.\r\n\r\n```python\r\ntg = Triggon({\r\n    \"seq1\": [(1, 2, 3)], # index 0 holds (1, 2, 3)  \r\n    \"seq2\": [1, 2, 3],   # indexes 0, 1, and 2 hold 1, 2, and 3\r\n})\r\n\r\ndef example():\r\n    x = tg.switch_lit(\"seq1\", 10) # index 0\r\n    y = tg.switch_lit(\"seq2\", 10) # index 0\r\n\r\n    print(f\"For 'seq1': {x}\")\r\n    print(f\"For 'seq2': {y}\")\r\n\r\ntg.set_trigger((\"seq1\", \"seq2\"))\r\n\r\nexample()\r\n# == Output ==\r\n# For 'seq1': (1, 2, 3)\r\n# For 'seq2': 1\r\n```\r\n\r\nA single index can have multiple values assigned to it.\r\n\r\n```python\r\nfrom dataclasses import dataclass\r\n\r\nfrom triggon import Triggon\r\n\r\ntg = Triggon(\"mode\", new=True) # Set index 0 to True for label 'mode'\r\n\r\n@dataclass\r\nclass ModeFlags:\r\n    mode_a: bool = False\r\n    mode_b: bool = False\r\n    mode_c: bool = False\r\n\r\n    def set_mode(self, enable: bool):\r\n        tg.set_trigger(\"mode\", cond=\"enable\")\r\n\r\n        tg.switch_var(\"mode\", [self.mode_a, self.mode_b, self.mode_c]) # All values share index 0\r\n\r\n        print(\r\n            f\"mode_a is {self.mode_a}\\n\"\r\n            f\"mode_b is {self.mode_b}\\n\"\r\n            f\"mode_c is {self.mode_c}\\n\"\r\n        )\r\n\r\ns = ModeFlags()\r\n\r\ns.set_mode(False)\r\n# == Output ==\r\n# mode_a is False\r\n# mode_b is False\r\n# mode_c is False\r\n\r\ns.set_mode(True)\r\n# == Output ==\r\n# mode_a is True\r\n# mode_b is True\r\n# mode_c is True\r\n```\r\n\r\nIf you want to trace label activity in real time, set the `debug` keyword to `True`.\r\n\r\n> \u26a0\ufe0f **Note:** \r\nLabels with the `*` prefix cannot be used during initialization \r\nand will raise an `InvalidArgumentError`.\r\n\r\n### set_trigger\r\n`def set_trigger(self, label: str | list[str] | tuple[str, ...], /, *, cond: str=None) -> None`\r\n\r\nMarks the specified label(s) as triggered, \r\nallowing their values to be updated on the next call.  \r\nAll values associated with the specified label will be changed, regardless of their index.  \r\nThe `label` parameter accepts a single string or a list/tuple of labels.\r\n\r\nYou can set conditions using the `cond` keyword \r\nbut control structures such as `if` are not allowed.\r\n\r\nIf any of the specified labels have been disabled using `revert()`, \r\nthis function has no effect on them.\r\n\r\n```python\r\nfrom triggon import Triggon\r\n\r\ntg = Triggon({\r\n    \"milk\": 3,\r\n    \"banana\": 0.4,\r\n    \"msg\": \"We're having a sale for milk today!\",\r\n})\r\n\r\ndef example():\r\n    msg = tg.switch_lit(\"msg\", org=\"We're open as usual today.\")\r\n    print(msg)\r\n\r\n    milk = tg.switch_lit('milk', 4)\r\n    banana = tg.switch_lit('banana', 0.6)\r\n\r\n    print(f\"Milk: ${milk}\")\r\n    print(f\"Banana: ${banana}\")\r\n\r\nexample()\r\n# == Output ==\r\n# We're open as usual today.\r\n# Milk: $4\r\n# Banana: $0.6\r\n\r\ntg.set_trigger([\"milk\", \"msg\"]) # Triggers for 'milk' and 'msg' are activated here.\r\n\r\nexample()\r\n# == Output ==\r\n# We're having a sale for milk today!\r\n# Milk: $3\r\n# Banana: $0.6\r\n```\r\n\r\n```python\r\ntg = Triggon(\"msg\", \"Call me?\")\r\n\r\ndef sample(print_msg: bool):\r\n    # Activate \"msg\" if print_msg is True\r\n    tg.set_trigger(\"msg\", cond=\"print_msg\")\r\n\r\n    # Print the message if triggered\r\n    print(tg.switch_lit(\"msg\", \"\"))\r\n\r\nsample(False) # Output:\r\nsample(True)  # Output: Call me? \r\n```\r\n\r\n> **Note:**\r\nThis function uses `eval()` internally to evaluate the `cond` argument.\r\nHowever, **only comparison expressions (e.g., `x > 0 > y`, `value == 10`) are allowed**.\r\nNon-comparison expressions will raise an `InvalidArgumentError`.\r\n\r\n### switch_lit (alter_literal)\r\n`def switch_lit(self, label: str | list[str] | tuple[str, ...], /, org: Any, *, index: int=None) -> Any`\r\n\r\nChanges a literal value when the flag is active.  \r\nYou can also use this function directly inside a print().  \r\nWhen using a dictionary for `label`, the `index` keyword cannot be used.\r\n\r\n```python\r\nfrom triggon import Triggon\r\n\r\ntg = Triggon(\"text\", new=\"After\") \r\n\r\ndef example():\r\n    text = tg.switch_lit(\"text\", org=\"Before\", index=0)\r\n    print(text)  \r\n\r\n    # You can also write: \r\n    # print(tg.alter_literal('text', 'Before'))\r\n\r\n    tg.set_trigger(\"text\")\r\n\r\nexample() # Output: Before\r\nexample() # Output: After\r\n```\r\n\r\nAlternatively, you can use the `*` character as a prefix to specify the index.  \r\nFor example, `\"label\"` refers to index 0, and `\"*label\"` refers to index 1.\r\n\r\nYou can use the `index` keyword or the `*` prefix.  \r\nWhen both are provided, the keyword takes precedence.  \r\n`*` used elsewhere (not as a prefix) is ignored and has no special meaning.\r\n\r\n> **Note:**   \r\nFor better readability when working with multiple indices, \r\nit's recommended to use the `index` keyword.\r\n\r\n```python\r\n# Set the value to 'A' for index 0 and to 'B' for index 1\r\ntg = Triggon(\"char\", new=(\"A\", \"B\"))\r\n\r\ndef example():\r\n    tg.set_trigger(\"char\")\r\n\r\n    print(tg.switch_lit(\"char\", 0))           # index 0 (no '*' \u2014 defaults to index 0)\r\n    print(tg.switch_lit(\"*char\", 1))          # index 1 (using '*')\r\n    print(tg.switch_lit(\"*char\", 0, index=0)) # index 0 ('index' keyword takes precedence over '*')\r\n    print(tg.switch_lit(\"char\", 1, index=1))  # index 1 (using 'index' keyword)\r\n\r\nexample()\r\n# == Output ==\r\n# A\r\n# B\r\n# A\r\n# B\r\n```\r\n\r\n```python\r\ntg = Triggon({\"A\": True, \"B\": False})\r\n\r\ndef sample():\r\n    # Applies the new value if any label is active.\r\n    # If both are active, the earlier one takes priority.\r\n    x = tg.switch_lit([\"A\", \"B\"], None)\r\n\r\n    print(x)\r\n\r\nsample()            # Output: None \r\n\r\ntg.set_trigger(\"A\") # Output: True\r\nsample()\r\n\r\ntg.set_trigger(\"B\") # Output: True\r\nsample()\r\n```\r\n\r\n> **Note:**   \r\nWhen multiple labels are passed and multiple flags are active,  \r\nthe earliest label in the sequence takes precedence.\r\nIn that case, if the `index` keyword is passed,  \r\nit will be applied to all labels.\r\n\r\n### switch_var (alter_var)\r\n`def switch_var(self, label: str | dict[str, Any], var: Any=None, /, *, index: int=None) -> None | Any`\r\n\r\nChanges variable value(s) directly when the flag is active.  \r\n**It supports global variables and class attributes, but not local variables.**\r\n\r\nYou can pass multiple labels and variables using a dictionary.    \r\nThe `index` keyword cannot be used in that case.  \r\nIf the target index is 1 or greater, \r\nadd a `*` prefix to the label corresponding to the index  \r\n(e.g., `*label` for index 1, `**label` for index 2).\r\n\r\nThis function returns the updated value **only when a single label is passed**.  \r\nIf a dictionary is passed, the function returns `None`.\r\n\r\n> **Note:**  \r\nIn such cases, it is recommended to use individual calls to this function  \r\nwith the `index` keyword instead, for better readability.\r\n\r\n```python\r\nimport random\r\n\r\nfrom triggon import Triggon\r\n\r\ntg = Triggon({\r\n    \"level_1\": [\"an uncommon\", 80],\r\n    \"level_2\": [\"a rare\", 100],\r\n    \"level_3\": [\"a legendary\", 150],\r\n})\r\n\r\nlevel = None\r\nattack = None\r\n\r\ndef spin_gacha():\r\n    items = [\"level_1\", \"level_2\", \"level_3\"]\r\n    result = random.choice(items)\r\n\r\n    tg.set_trigger(result)\r\n\r\n    tg.switch_var(result, level)\r\n    tg.switch_var(result, attack, index=1)\r\n\r\n    # Outputs vary randomly.\r\n    # Example: result = 'level_2'\r\n    print(f\"You pulled {level} sword!\") # Output: You pulled a rare sword!\r\n    print(f\"Attack Power: {attack}\")    # Output: Attack Power: 100 \r\n\r\nspin_gacha()\r\n```\r\n\r\n```python\r\nfrom dataclasses import dataclass\r\n\r\nfrom triggon import Triggon\r\n\r\ntg = Triggon(\"even\", [0, 2, 4])\r\n\r\n@dataclass\r\nclass Example:\r\n    a: int = 1\r\n    b: int = 3\r\n    c: int = 5\r\n\r\n    def change_field_values(self, change: bool):\r\n        if change:\r\n            tg.set_trigger(\"even\")\r\n\r\n        tg.alter_var({\r\n            \"even\": self.a,    # index 0\r\n            \"*even\": self.b,   # index 1\r\n            \"**even\": self.c,  # index 2\r\n        })\r\n\r\nexm = Example()\r\n\r\nexm.change_field_values(False)\r\nprint(f\"a: {exm.a}, b: {exm.b}, c: {exm.c}\")\r\n# Output: a: 1, b: 3, c: 5\r\n\r\nexm.change_field_values(True)\r\nprint(f\"a: {exm.a}, b: {exm.b}, c: {exm.c}\")\r\n# Output: a: 0, b: 2, c: 4\r\n```\r\n\r\nAlso, you can assign multiple values to a single variable.\r\n\r\n```python\r\ntg = Triggon({\r\n    \"flag\": [True, False],\r\n    \"num\": [0, 100],\r\n})\r\n\r\n@dataclass\r\nclass Sample:\r\n    flag: bool = None\r\n    num: int = None\r\n\r\n    def sample(self, label: str, label_2: str):\r\n        tg.switch_var({label: self.flag, label_2: self.num})\r\n\r\n        print(f\"flag is {self.flag} and num is {self.num}\")\r\n\r\ns = Sample()\r\ntg.set_trigger([\"flag\", \"num\"])\r\n\r\ns.sample(\"flag\", \"num\")   # Output: flag is True and num is 0\r\ns.sample(\"*flag\", \"*num\") # Output: flag is False and num is 100\r\n```\r\n\r\n> **Notes:** \r\n> Values are typically updated when `set_trigger()` is called.  \r\n> However, on the first call, \r\n> the value won't change unless the variable has been registered via `switch_var()`.  \r\n> In that case, the value is changed by `switch_var()`.  \r\n> Once registration is complete, each call to `set_trigger()` immediately updates the value.  \r\n>\r\n> In some environments (e.g., Jupyter or REPL),  \r\n> calls to alter_var or switch_var may not be detected due to source code unavailability.\r\n>\r\n> This function only supports  \r\n> literal values, variables, or simple attribute chains for labels and the `index` keyword.  \r\n> Other types will raise an `InvalidArgumentError`.\r\n\r\n### revert\r\n`def revert(self, label: str | list[str] | tuple[str, ...]=None, /, *, all: bool=False, disable: bool=False) -> None`\r\n\r\nReverts all values previously changed by `switch_lit()` or `switch_var()`  \r\nto their original state.  \r\nTo revert all labels, set the `all` keyword to `True`.\r\n\r\nThe reversion remains effective until the next call to `set_trigger()`.  \r\nAll values associated with the specified label will be reverted, \r\nregardless of their index.\r\n\r\nIf the `disable` keyword is set to `True`, the reversion becomes permanent.\r\n\r\n```python\r\nfrom dataclasses import dataclass\r\n\r\nfrom triggon import Triggon\r\n\r\ntg = Triggon(\"hi\", new=\"Hello\")\r\n\r\n@dataclass\r\nclass User:\r\n    name: str = \"Guest\"\r\n    init_done: bool = False\r\n\r\n    def initialize(self):\r\n        # Set the trigger for the first-time greeting\r\n        tg.set_trigger(\"hi\")\r\n\r\n        self.init_done = True\r\n        self.greet()\r\n\r\n    def greet(self):\r\n        msg = tg.switch_lit(\"hi\", org=\"Welcome back\")\r\n        print(f\"{msg}, {self.name}!\")\r\n\r\n    def entry(self):\r\n        if self.init_done:\r\n            self.greet()\r\n        else:\r\n            self.initialize()\r\n            tg.revert(\"hi\") # Revert to the original value\r\n\r\nuser = User()\r\n\r\nuser.entry() # Output: Hello, Guest!\r\n\r\nuser.entry() # Output: Welcome back, Guest!\r\n```\r\n\r\n```python\r\ntg = Triggon({\"name\": \"John\", \"state\": True})\r\n\r\n@dataclass\r\nclass User:\r\n    name: str = None\r\n    online: bool = False\r\n\r\n    def login(self):\r\n        # Set the variable for each label\r\n        tg.switch_var({\"name\": self.name, \"state\": self.online})\r\n        tg.set_trigger([\"name\", \"state\"])\r\n\r\nuser = User()\r\nprint(f\"User name: {user.name}\\nOnline: {user.online}\")\r\n# == Output ==\r\n# User name: None\r\n# Online: False\r\n\r\nuser.login()\r\nprint(f\"User name: {user.name}\\nOnline: {user.online}\")\r\n# == Output ==\r\n# User name: John\r\n# Online: True\r\n```\r\n\r\n### exit_point\r\n`def exit_point(self, label: str, func: TrigFunc, /) -> None | Any`\r\n\r\nDefines the exit point where an early return is triggered by `trigger_return()`.  \r\nThe `func` argument must be a `TrigFunc` instance that wraps the target function.  \r\n\r\nAn index with the `*` prefix can be used, but it is ignored.\r\n\r\n> **Note:** `exit_point()` is not required if `trigger_return()` is not triggered.\r\n\r\n### trigger_return\r\n`trigger_return(self, label: str, /, ret: Any=None, *, index: int=None, do_print: bool=False) -> None | Any`\r\n\r\nTriggers an early return with any value when the flag is active.  \r\nThe return value must be set during initialization.  \r\nIf nothing needs to be returned, set it to `None` or simply omit the value..\r\n\r\nYou can also set the return value with the `ret` keyword,  \r\nwhich takes precedence over the one set during initialization.\r\nIn that case, you don't need to provide any value if you're not using a dictionary.\r\n\r\nIf the `do_print` keyword is set to `True`, the return value will be printed.  \r\nIf the value is not a string, an `InvalidArgumentError` is raised.\r\n\r\n```python\r\nfrom triggon import Triggon, TrigFunc\r\n\r\n# Define label and early-return value\r\ntg = Triggon(\"skip\", new=\"(You don't have enough money...)\")\r\nF = TrigFunc() # Wraps the target function for early return\r\n\r\ndef check_funds(money: int):\r\n    if money < 300:\r\n        tg.set_trigger(\"skip\")\r\n\r\n    print(f\"You now have {money}G.\")\r\n    board_ship()\r\n\r\ndef board_ship():\r\n    print(\"It'll cost you 300G to board the ship.\")\r\n\r\n    # Triggers early return and prints the value if the flag is set\r\n    tg.trigger_return(\"skip\", do_print=True) \r\n\r\n    print(\"Enjoy the ride!\")  \r\n\r\ntg.exit_point(\"skip\", F.check_funds(500))\r\n# == Output ==\r\n# You now have 500G.\r\n# It'll cost you 300G to board the ship.\r\n# Enjoy the ride!\r\n\r\ntg.exit_point(\"skip\", F.check_funds(200))\r\n# == Output ==\r\n# You now have 200G.\r\n# It'll cost you 300G to board the ship.\r\n# (You don't have enough money...)\r\n```\r\n\r\n```python\r\ntg = Triggon(\"zero\")\r\nF = TrigFunc()\r\n\r\ndef sample():\r\n    num = get_number()\r\n\r\n    # The \"zero\" label will be activated if `num` is 0\r\n    tg.set_trigger(\"zero\", cond=\"num == 0\")\r\n\r\n    # Return early with the message if triggered\r\n    tg.trigger_return(\"zero\", ret=f\"{num} ...\", do_print=True) \r\n\r\n    num_2 = get_number()\r\n\r\n    print(f\"The total number is {num + num_2}!\")\r\n\r\ndef get_number():\r\n    return random.randint(0, 10) \r\n\r\ntg.exit_point(\"zero\", F.sample()) # The output is random!\r\n```\r\n\r\n### trigger_func\r\n`def trigger_func(self, label: str, func: TrigFunc, /) -> None | Any`\r\n\r\nTriggers a function when the flag is active.  \r\nThe `func` argument must be a `TrigFunc` instance that wraps the target function.\r\n\r\nA label must be initialized with any value in order to register it when creating a `Triggon` instance.  \r\nThe value won't be returned, so you can use any placeholder.  \r\nIf you're not using a dictionary, there's no need to provide a value at all.  \r\n**If the function returns a value, that value will also be returned.**.\r\n\r\nAn index with the `*` prefix can be used, but it is ignored.\r\n\r\n```python\r\nfrom triggon import Triggon, TrigFunc\r\n\r\ntg = Triggon({\r\n    \"skip\": None,\r\n    \"call\": None,\r\n})\r\nF = TrigFunc()\r\n\r\ndef example():\r\n    tg.set_trigger([\"skip\", \"call\"]) # Set triggers for early return and function call\r\n\r\n    print(\"If the 'call' flag is active, jump to example_2().\")\r\n\r\n    tg.trigger_func(\"call\", F.example_2()) # Use the TrigFunc instance F for example_2()\r\n\r\n    print(\"This message may be skipped depending on the trigger.\")\r\n\r\n\r\ndef example_2():\r\n    print(\"You\u2019ve reached the example_2() function!\")\r\n    tg.trigger_return(\"skip\")\r\n\r\ntg.exit_point(\"skip\", F.example())\r\n# == Output ==\r\n# If the 'call' flag is active, jump to example_2().\r\n# You\u2019ve reached the example_2() function!\r\n```\r\n\r\n### TrigFunc\r\nThis class wraps a function to delay its execution.   \r\nYou can create an instance without any arguments and use it to wrap the target function.\r\n\r\n> \u26a0\ufe0f **Note:**  \r\nWhen using this class,  \r\nyou must create an instance first (e.g., F = TrigFunc()) before using it.\r\n\r\n### Error\r\n- `InvalidArgumentError`  \r\nRaised when the number of arguments, their types, or usage is incorrect.\r\n\r\n- `MissingLabelError`\r\nRaised when a specific label has not been registered.\r\n\r\n## License\r\nThis project is licensed under the MIT License.  \r\nSee [LICENSE](./LICENSE) for details.\r\n\r\n## Author\r\nCreated by Tsuruko  \r\nGitHub: [@tsuruko12](https://github.com/tsuruko12)  \r\nX: [@tool_tsuruko12](https://x.com/tsuruko)\r\n",
    "bugtrack_url": null,
    "license": "MIT License\r\n        \r\n        Copyright (c) 2025 Tsuruko\r\n        \r\n        Permission is hereby granted, free of charge, to any person obtaining a copy\r\n        of this software and associated documentation files (the \"Software\"), to deal\r\n        in the Software without restriction, including without limitation the rights  \r\n        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      \r\n        copies of the Software, and to permit persons to whom the Software is         \r\n        furnished to do so, subject to the following conditions:                       \r\n        \r\n        The above copyright notice and this permission notice shall be included in     \r\n        all copies or substantial portions of the Software.                            \r\n        \r\n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     \r\n        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       \r\n        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE    \r\n        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER        \r\n        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r\n        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN     \r\n        THE SOFTWARE.",
    "summary": "Automatically switches values at labeled trigger points, supporting multi-value switching, early returns, and function calls.",
    "version": "0.1.0b4",
    "project_urls": {
        "Bug Tracker": "https://github.com/tsuruko12/triggon/issues",
        "Changelog": "https://github.com/tsuruko12/triggon/blob/main/CHANGELOG.md",
        "Homepage": "https://github.com/tsuruko12/triggon",
        "Source": "https://github.com/tsuruko12/triggon"
    },
    "split_keywords": [
        "switch",
        " trigger",
        " label",
        " auto",
        " dynamic",
        " early return",
        " function call"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1a9cfcde5f8b0e7e4842864e8bb3a2847ffc0c300b82dde7a5897bbe306fa82b",
                "md5": "207167f4edb436b8da808f7918373bee",
                "sha256": "5fbcfb658fa8fa9892db987abafd505e6dec4a5cae6c01c2b8985ec7679a582d"
            },
            "downloads": -1,
            "filename": "triggon-0.1.0b4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "207167f4edb436b8da808f7918373bee",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.13",
            "size": 22533,
            "upload_time": "2025-07-21T19:17:50",
            "upload_time_iso_8601": "2025-07-21T19:17:50.477319Z",
            "url": "https://files.pythonhosted.org/packages/1a/9c/fcde5f8b0e7e4842864e8bb3a2847ffc0c300b82dde7a5897bbe306fa82b/triggon-0.1.0b4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "71f4dc91ab378817def88547074785f345e9db04b15c1bc2c78a15fcc9ca7c4c",
                "md5": "144adf92f1d603ef29bdab59823f0882",
                "sha256": "9d83b845529df5ba2158c3d9ec7207bb3507496e971e3847d8fd7ecbeae27071"
            },
            "downloads": -1,
            "filename": "triggon-0.1.0b4.tar.gz",
            "has_sig": false,
            "md5_digest": "144adf92f1d603ef29bdab59823f0882",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.13",
            "size": 25059,
            "upload_time": "2025-07-21T19:17:51",
            "upload_time_iso_8601": "2025-07-21T19:17:51.677360Z",
            "url": "https://files.pythonhosted.org/packages/71/f4/dc91ab378817def88547074785f345e9db04b15c1bc2c78a15fcc9ca7c4c/triggon-0.1.0b4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-21 19:17:51",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "tsuruko12",
    "github_project": "triggon",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "triggon"
}
        
Elapsed time: 1.68683s