triggon 0.1.0b0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Tsuruko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,541 @@
1
+ Metadata-Version: 2.4
2
+ Name: triggon
3
+ Version: 0.1.0b0
4
+ Summary: Automatically switches values at labeled trigger points, supporting multi-value switching, early returns, and function calls.
5
+ Author-email: Tsuruko <tsuruko-12@outlook.com>
6
+ Maintainer-email: Tsuruko <tsuruko-12@outlook.com>
7
+ License: MIT License
8
+
9
+ Copyright (c) 2025 Tsuruko
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in
19
+ all copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
+ THE SOFTWARE.
28
+ Project-URL: Repository, https://github.com/tsuruko12/triggon
29
+ Keywords: switch,trigger,label,auto,dynamic,early return,function call
30
+ Classifier: Programming Language :: Python :: 3.12
31
+ Classifier: Programming Language :: Python :: 3.13
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
36
+ Requires-Python: >=3.13
37
+ Description-Content-Type: text/markdown
38
+ License-File: LICENSE
39
+ Dynamic: license-file
40
+
41
+ # triggon
42
+
43
+ ## Overview
44
+ Dynamically switch multiple values at specific trigger points.
45
+
46
+ > ⚠️ **This library is currently in beta. APIs may change in future releases, and bugs may still be present.**
47
+
48
+ ## Table of Contents
49
+ - [Installation](#installation)
50
+ - [Usage](#usage)
51
+ - [License](#license)
52
+ - [Author](#author)
53
+
54
+
55
+ ## Features
56
+ - Switch multiple values at once with a single trigger point.
57
+ - No `if` or `match` statements needed.
58
+ - Switch both literal values and variables.
59
+ - Trigger early returns with optional return values.
60
+ - Automatically jump to other functions at a trigger point.
61
+
62
+ ## Installation
63
+ ```bash
64
+ pip install triggon
65
+ ```
66
+
67
+ ## Usage
68
+ This section explains how to use each function.
69
+
70
+ ### Triggon
71
+ `Triggon(self, label: str | dict[str, Any], /, new: Any=None, *, debug: bool=False)`
72
+
73
+ `Triggon()` is initialized with label-value pairs.
74
+ You can pass a single label with its value, or multiple labels using a dictionary.
75
+
76
+ If you pass multiple values to a label using a list,
77
+ each value will correspond to index 0, 1, 2, and so on, in the order you provide.
78
+
79
+ ```python
80
+ from triggon import Triggon
81
+
82
+ # Set index 0 to 100 and index 1 to 0 as their new values
83
+ tg = Triggon("num", new=[100, 0])
84
+
85
+ def example():
86
+ x = tg.alter_literal("num", 0) # index 0
87
+ y = tg.alter_literal("*num", 100) # index 1
88
+
89
+ print(f"{x} -> {y}")
90
+
91
+ example()
92
+ # Output: 0 -> 100
93
+
94
+ tg.set_trigger("num")
95
+
96
+ example()
97
+ # Output: 100 -> 0
98
+ ```
99
+
100
+ When passing a list or tuple that should be used as a single value,
101
+ make sure to wrap it in another list or tuple to avoid it being unpacked.
102
+
103
+ ```python
104
+ tg = Triggon({
105
+ "seq1": [(1, 2, 3)], # index 0 holds (1, 2, 3)
106
+ "seq2": [1, 2, 3], # indexes 0, 1, and 2 hold 1, 2, and 3
107
+ })
108
+
109
+ def example():
110
+ x = tg.alter_literal("seq1", 10) # index 0
111
+ y = tg.alter_literal("seq2", 10) # index 0
112
+
113
+ print(f"For 'seq1': {x}")
114
+ print(f"For 'seq2': {y}")
115
+
116
+ tg.set_trigger(("seq1", "seq2"))
117
+
118
+ example()
119
+ # == Output ==
120
+ # For 'seq1': (1, 2, 3)
121
+ # For 'seq2': 1
122
+ ```
123
+
124
+ A single index can have multiple values assigned to it.
125
+
126
+ ```python
127
+ from dataclasses import dataclass
128
+
129
+ from triggon import Triggon
130
+
131
+ tg = Triggon("mode", new=True) # Set index 0 to True for label 'mode'
132
+
133
+ @dataclass
134
+ class ModeFlags:
135
+ mode_a: bool = False
136
+ mode_b: bool = False
137
+ mode_c: bool = False
138
+
139
+ def set_mode(self, enable: bool):
140
+ if enable:
141
+ tg.set_trigger("mode")
142
+
143
+ tg.alter_var("mode", [self.mode_a, self.mode_b, self.mode_c]) # All values share index 0
144
+
145
+ print(
146
+ f"mode_a is {self.mode_a}\n"
147
+ f"mode_b is {self.mode_b}\n"
148
+ f"mode_c is {self.mode_c}\n"
149
+ )
150
+
151
+ s = ModeFlags()
152
+
153
+ s.set_mode(False)
154
+ # == Output ==
155
+ # mode_a is False
156
+ # mode_b is False
157
+ # mode_c is False
158
+
159
+ s.set_mode(True)
160
+ # == Output ==
161
+ # mode_a is True
162
+ # mode_b is True
163
+ # mode_c is True
164
+ ```
165
+
166
+ If you want to trace label activity in real time, set the `debug` keyword to `True`.
167
+
168
+ > **Note:**
169
+ Labels with the * prefix cannot be used during initialization
170
+ and will raise an `InvalidArgumentError`.
171
+
172
+ ### set_trigger
173
+ `def set_trigger(self, label: str | list[str] | tuple[str, ...], /) -> None`
174
+
175
+ Marks the specified label(s) as triggered, allowing their values to be updated on the next call.
176
+ All values associated with the specified label will be changed, regardless of their index.
177
+ The `label` parameter accepts a single string or a list/tuple of labels.
178
+
179
+ If any of the specified labels have been disabled using `revert()`, this function has no effect on them.
180
+
181
+ ```python
182
+ from triggon import Triggon
183
+
184
+ tg = Triggon({
185
+ "milk": 3,
186
+ "banana": 0.4,
187
+ "msg": "We're having a sale for milk today!",
188
+ })
189
+
190
+ def example():
191
+ msg = tg.alter_literal("msg", org="We're open as usual today.")
192
+ print(msg)
193
+
194
+ milk = tg.alter_literal('milk', 4)
195
+ banana = tg.alter_literal('banana', 0.6)
196
+
197
+ print(f"Milk: ${milk}")
198
+ print(f"Banana: ${banana}")
199
+
200
+ example()
201
+ # == Output ==
202
+ # We're open as usual today.
203
+ # Milk: $4
204
+ # Banana: $0.6
205
+
206
+ tg.set_trigger(["milk", "msg"]) # Triggers for 'milk' and 'msg' are activated here.
207
+
208
+ example()
209
+ # == Output ==
210
+ # We're having a sale for milk today!
211
+ # Milk: $3
212
+ # Banana: $0.6
213
+ ```
214
+
215
+ ### alter_literal
216
+ `def alter_literal(self, label: str, /, org: Any, *, index: int=None) -> Any`
217
+
218
+ Changes a literal value when the flag is set to `True`.
219
+ You can also use this function directly inside a print().
220
+ When using a dictionary for `label`, the `index` keyword cannot be used.
221
+
222
+ ```python
223
+ from triggon import Triggon
224
+
225
+ tg = Triggon("text", new="After")
226
+
227
+ def example():
228
+ text = tg.alter_literal("text", org="Before", index=0)
229
+ print(text)
230
+
231
+ # You can also write:
232
+ # print(tg.alter_literal('text', 'Before'))
233
+
234
+ tg.set_trigger("text")
235
+
236
+ example() # Output: Before
237
+ example() # Output: After
238
+ ```
239
+
240
+ Alternatively, you can use the `*` character as a prefix to specify the index.
241
+ For example, `"label"` refers to index 0, and `"*label"` refers to index 1.
242
+
243
+ You can use the `index` keyword or the `*` prefix.
244
+ When both are provided, the keyword takes precedence.
245
+ `*` used elsewhere (not as a prefix) is ignored and has no special meaning.
246
+
247
+ ```python
248
+ # Set the value to 'A' for index 0 and to 'B' for index 1
249
+ tg = Triggon("char", new=("A", "B"))
250
+
251
+ def example():
252
+ tg.set_trigger("char")
253
+
254
+ print(tg.alter_literal("char", 0)) # index 0 (no '*' — defaults to index 0)
255
+ print(tg.alter_literal("*char", 1)) # index 1 (using '*')
256
+ print(tg.alter_literal("*char", 0, index=0)) # index 0 ('index' keyword takes precedence over '*')
257
+ print(tg.alter_literal("char", 1, index=1)) # index 1 (using 'index' keyword)
258
+
259
+ example()
260
+ # == Output ==
261
+ # A
262
+ # B
263
+ # A
264
+ # B
265
+ ```
266
+
267
+ > **Note:**
268
+ For better readability when working with multiple indices,
269
+ it's recommended to use the `index` keyword.
270
+
271
+ ### alter_var
272
+ `def alter_var(self, label: str | dict[str, Any], var: Any=None, /, *, index: int=None) -> None`
273
+
274
+ Changes variable value(s) directly when the flag is set to `True`.
275
+ It supports global variables and class attributes, but not local variables.
276
+
277
+ You can pass multiple labels and variables using a dictionary.
278
+ The `index` keyword cannot be used in that case.
279
+ If the target index is 1 or greater,
280
+ add a `*` prefix to the label corresponding to the index
281
+ (e.g., `*label` for index 1, `**label` for index 2).
282
+
283
+ In such cases, it is recommended to use individual calls to this function
284
+ with the `index` keyword instead, for better readability.
285
+
286
+ ```python
287
+ import random
288
+
289
+ from triggon import Triggon
290
+
291
+ tg = Triggon({
292
+ "level_1": ["an uncommon", 80],
293
+ "level_2": ["a rare", 100],
294
+ "level_3": ["a legendary", 150],
295
+ })
296
+
297
+ level = None
298
+ attack = None
299
+
300
+ def spin_gacha():
301
+ items = ["level_1", "level_2", "level_3"]
302
+ result = random.choice(items)
303
+
304
+ tg.set_trigger(result)
305
+
306
+ tg.alter_var(result, level)
307
+ tg.alter_var(result, attack, index=1)
308
+
309
+ # Outputs vary randomly.
310
+ # Example: result = 'level_2'
311
+ print(f"You pulled {level} sword!") # Output: You pulled a rare sword!
312
+ print(f"Attack Power: {attack}") # Output: Attack Power: 100
313
+
314
+ spin_gacha()
315
+ ```
316
+
317
+ ```python
318
+ from dataclasses import dataclass
319
+
320
+ from triggon import Triggon
321
+
322
+ tg = Triggon("even", [0, 2, 4])
323
+
324
+ @dataclass
325
+ class Example:
326
+ a: int = 1
327
+ b: int = 3
328
+ c: int = 5
329
+
330
+ def change_field_values(self, change: bool):
331
+ if change:
332
+ tg.set_trigger("even")
333
+
334
+ tg.alter_var({
335
+ "even": self.a, # index 0
336
+ "*even": self.b, # index 1
337
+ "**even": self.c, # index 2
338
+ })
339
+
340
+ exm = Example()
341
+
342
+ exm.change_field_values(False)
343
+ print(f"a: {exm.a}, b: {exm.b}, c: {exm.c}")
344
+ # Output: a: 1, b: 3, c: 5
345
+
346
+ exm.change_field_values(True)
347
+ print(f"a: {exm.a}, b: {exm.b}, c: {exm.c}")
348
+ # Output: a: 0, b: 2, c: 4
349
+ ```
350
+
351
+ > **Notes:**
352
+ Values are typically updated when `set_trigger()` is called.
353
+ However, on the first call,
354
+ the value won't change unless the variable has been registered via `alter_var()`.
355
+ In that case, the value is changed by `alter_var()`.
356
+ Once registration is complete, each call to `set_trigger()` immediately updates the value.
357
+
358
+ The `index` keyword does not accept a variable — only integer literals are allowed.
359
+
360
+ ### revert
361
+ `def revert(self, label: str, /, *, disable: bool=False) -> None`
362
+
363
+ Reverts all values previously changed by `alter_literal()` or `alter_var()`
364
+ to their original state.
365
+ The reversion remains effective until the next call to `set_trigger()`.
366
+ All values associated with the specified label will be reverted, regardless of their index.
367
+
368
+ If the `disable` keyword is set to `True`, the reversion becomes permanent.
369
+
370
+ ```python
371
+ from triggon import Triggon
372
+
373
+ tg = Triggon("hi", new="Hello")
374
+
375
+ @dataclass
376
+ class User:
377
+ name: str = "Guest"
378
+ init_done: bool = False
379
+
380
+ def initialize(self):
381
+ tg.set_trigger("hi") # Set the trigger for the first-time greeting
382
+
383
+ self.init_done = True
384
+ self.greet()
385
+
386
+ def greet(self):
387
+ msg = tg.alter_literal("hi", org="Welcome back")
388
+ print(f"{msg}, {self.name}!")
389
+
390
+ def entry(self):
391
+ if self.init_done:
392
+ self.greet()
393
+ else:
394
+ self.initialize()
395
+ tg.revert("hi") # Revert to the original value
396
+
397
+ user = User()
398
+
399
+ user.entry() # Output: Hello, Guest!
400
+
401
+ user.entry() # Output: Welcome back, Guest!
402
+ ```
403
+
404
+ ```python
405
+ tg = Triggon("A", "Updated value")
406
+
407
+ x = "Original value"
408
+ tg.alter_var("A", x)
409
+
410
+ def example():
411
+ print(x)
412
+
413
+ tg.set_trigger("A")
414
+
415
+ print(x)
416
+
417
+ tg.revert("A", disable=True)
418
+
419
+ example()
420
+ # == Output ==
421
+ # Original value
422
+ # Updated value
423
+
424
+ example()
425
+ # == Output ==
426
+ # Original value
427
+ # Original value
428
+ ```
429
+
430
+ ### exit_point
431
+ `def exit_point(self, label: str, func: TrigFunc, /) -> None | Any`
432
+
433
+ Defines the exit point where an early return is triggered by `trigger_return()`.
434
+ The `func` argument must be a `TrigFunc` instance that wraps the target function.
435
+
436
+ An index with the `*` prefix can be used, but it is ignored.
437
+
438
+ ### trigger_return
439
+ `trigger_return(self, label: str, /, *, index: int=None, do_print: bool=False) -> None | Any`
440
+
441
+ Triggers an early return with any value when the flag is set to `True`.
442
+ The return value must be set during initialization.
443
+ If nothing needs to be returned, set it to `None`.
444
+
445
+ If the `do_print` keyword is set to `True`, the return value will be printed.
446
+ If the value is not a string, an `InvalidArgumentError` is raised.
447
+
448
+ ```python
449
+ from triggon import Triggon, TrigFunc
450
+
451
+ # Define label and early-return value
452
+ tg = Triggon("skip", new="(You don't have enough money...)")
453
+ F = TrigFunc() # Wraps the target function for early return
454
+
455
+ def check_funds(money: int):
456
+ if money < 300:
457
+ tg.set_trigger("skip")
458
+
459
+ print(f"You now have {money}G.")
460
+ board_ship()
461
+
462
+ def board_ship():
463
+ print("It'll cost you 300G to board the ship.")
464
+
465
+ # Triggers early return and prints the value if the flag is set
466
+ tg.trigger_return("skip", do_print=True)
467
+
468
+ print("Enjoy the ride!")
469
+
470
+ tg.exit_point("skip", F.check_funds(500))
471
+ # == Output ==
472
+ # You now have 500G.
473
+ # It'll cost you 300G to board the ship.
474
+ # Enjoy the ride!
475
+
476
+ tg.exit_point("skip", F.check_funds(200))
477
+ # == Output ==
478
+ # You now have 200G.
479
+ # It'll cost you 300G to board the ship.
480
+ # (You don't have enough money...)
481
+ ```
482
+
483
+ ### trigger_func
484
+ `def trigger_func(self, label: str, func: TrigFunc, /) -> None | Any`
485
+
486
+ Triggers a function when the flag is set to `True`.
487
+ The `func` argument must be a `TrigFunc` instance that wraps the target function.
488
+
489
+ The label must be initialized with `None` when creating the `Triggon` instance.
490
+ An index with the `*` prefix can be used, but it is ignored.
491
+
492
+ If the function returns a value, it will also be returned.
493
+
494
+ ```python
495
+ from triggon import Triggon, TrigFunc
496
+
497
+ tg = Triggon({
498
+ "skip": None,
499
+ "call": None,
500
+ })
501
+ F = TrigFunc()
502
+
503
+ def example():
504
+ tg.set_trigger(["skip", "call"]) # Set triggers for early return and function call
505
+
506
+ print("If the 'call' flag is active, jump to example_2().")
507
+
508
+ tg.trigger_func("call", F.example_2()) # Use the TrigFunc instance F for example_2()
509
+
510
+ print("This message may be skipped depending on the trigger.")
511
+
512
+
513
+ def example_2():
514
+ print("You’ve reached the example_2() function!")
515
+ tg.trigger_return("skip")
516
+
517
+ tg.exit_point("skip", F.example())
518
+ # == Output ==
519
+ # If the 'call' flag is active, jump to example_2().
520
+ # You’ve reached the example_2() function!
521
+ ```
522
+
523
+ ### TrigFunc
524
+ This class wraps a function to delay its execution.
525
+ You can create an instance without any arguments and use it to wrap the target function.
526
+
527
+ > **Note:**
528
+ When using this class, you must create an instance first (e.g., F = TrigFunc()) before using it.
529
+
530
+ ### Error
531
+ - `InvalidArgumentError`
532
+ Raised when the number of arguments, their types, or usage is incorrect.
533
+
534
+ ## License
535
+ This project is licensed under the MIT License.
536
+ See [LICENSE](./LICENSE) for details.
537
+
538
+ ## Author
539
+ Created by Tsuruko
540
+ GitHub: [@tsuruko12](https://github.com/tsuruko12)
541
+ X: [@tool_tsuruko12](https://x.com/tsuruko)