menucmd 1.0__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.
menucmd-1.0/PKG-INFO ADDED
@@ -0,0 +1,810 @@
1
+ Metadata-Version: 2.1
2
+ Name: menucmd
3
+ Version: 1.0
4
+ Summary: Command line menu interface
5
+ Home-page: https://github.com/Casey-Litmer/menucmd
6
+ Author: Casey Litmer
7
+ Author-email: litmerc@msn.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.6
11
+ Description-Content-Type: text/markdown
12
+
13
+ Getting Started
14
+ -
15
+ -----------------------------------------------------------------------------------------------------
16
+ MenuCMD is a library designed to easily create simple command line menus in a functional programming style.
17
+ The main goal is to separate functions from the way in which they are composed and how the user navigates them.
18
+
19
+
20
+ This module can be used in several ways:
21
+
22
+ - as a debugging tool
23
+ - as a dedicated command line application interface
24
+ - as a framework for delayed function evaluation
25
+
26
+ Separating navigation from function definitions allows the user to later repurpose a program to run automatically
27
+ without relying on user input. What one creates as a command line interface one day, can easily be automated
28
+ the next.
29
+
30
+ Other features such as lazy evaluation with the `Bind` class can also be used independently from the menu
31
+ interface for your functional programming needs.
32
+
33
+ *For developers wishing to contribute to this module, a test script is included to ensure all
34
+ features work correctly between changes **(requires numpy)**. Feel free to update it as you see fit!*
35
+
36
+ ---
37
+ ## Sections:
38
+ ### 1. Hello World
39
+ - Initializing a Menu
40
+ - Menu Item Format
41
+ - Writing Arguments
42
+ - Running 'Hello World'
43
+ ### 2. Multiple Menus
44
+ - Defining Two Menus
45
+ - Exit Key Behaviour
46
+ - Adding More Entries
47
+ - End Chain Behaviour
48
+ - Serializing End Returns
49
+ ### 3. Function Composition
50
+ - Using the Result Type
51
+ - Using Past Results
52
+ - Using the Bind Class
53
+ - Binding Functions and Kwargs
54
+ ### 4. Other Menu Attributes
55
+ - Using Kwargs
56
+ - Using Manual Escapes
57
+ - Using Matching Keywords
58
+ ### 5. Builtins
59
+ - In-line Functions
60
+ - Builtin Menus
61
+
62
+
63
+
64
+
65
+ ---
66
+ 1). Hello World
67
+ -
68
+
69
+ -----
70
+ ### Initializing a Menu
71
+
72
+ Start by importing the `Menu` class.
73
+
74
+ ```
75
+ from MenuCMD import Menu
76
+ ```
77
+
78
+ Create a new menu with a custom name.
79
+ This is what will appear at the top of the menu when run.
80
+
81
+ ```
82
+ #Create New Menu
83
+ menu1 = Menu(name = "First Menu")
84
+ ```
85
+ -------
86
+ ### Menu Item Format
87
+ You can add one or more items to a menu with the `append` method.
88
+ An item is a `tuple` composed of a key, a message, and another `tuple`
89
+ containing a chain of functions and arguments.
90
+
91
+ ```
92
+ ("key", "message", (func1, (*args1), func2, (*args2),))
93
+ ```
94
+
95
+ -----
96
+ ### Writing Arguments
97
+ When the user selects an item, **func1** will run with **args1**, then **func2** will run with **args2**.
98
+
99
+ If a function only has one argument, you can simply write the pair as **(func1, arg1)**. \
100
+ **arg1** will automatically be wrapped as a `tuple`.
101
+
102
+ **If **arg1** is itself a tuple, write **(arg1,)**. Otherwise its contents will be interpreted as separate arguments!*
103
+
104
+ It is generally best practice to
105
+ keep the singleton tuple notation **(x,)** but is not strictly necessary.
106
+
107
+ -------
108
+
109
+ To add an item that prints 'hello world!' append the following:
110
+ ```commandline
111
+ ("x", "hello world program", (print, "Hello World!"))
112
+ ```
113
+ This will display "hello world program" on the menu, and run the **print** function with argument "Hello World!"
114
+ when the user inputs "x".
115
+
116
+ To append item(s) to a menu:
117
+
118
+ ```
119
+ #Add an Item
120
+ menu1.append(
121
+ ("x", "hello world program", (
122
+ print, "hello world!"
123
+ )),
124
+ item2,
125
+ item3,
126
+ ...
127
+ )
128
+ ```
129
+ *All menu items will appear in the order of appension.*
130
+
131
+ ----
132
+ ### Running 'Hello World'
133
+ Now all that's left is to run the menu by calling it with no arguments.
134
+
135
+ ```
136
+ from MenuCMD import Menu
137
+
138
+ #Create New Menu
139
+ menu1 = Menu(name = "First Menu")
140
+
141
+ #Add an Item
142
+ menu1.append(
143
+ ("x", "hello world program", (
144
+ print, "hello world!"
145
+ ))
146
+ )
147
+
148
+ #Run menu
149
+ menu1()
150
+ ```
151
+
152
+ The result should look like:
153
+ ```commandline
154
+ First Menu
155
+ [x]- hello world program
156
+ [e]- exit
157
+ ```
158
+ Inputing 'x' will print the desired text, returning to the menu:
159
+ ```commandline
160
+ First Menu
161
+ [x]- hello world program
162
+ [e]- exit
163
+ x
164
+ hello world!
165
+
166
+ First Menu
167
+ [x]- hello world program
168
+ [e]- exit
169
+ ```
170
+
171
+ In addition to the items you add, all menus will automatically add an exit key at the end of the list which
172
+ will break out of the menu by default. (This behaviour can be changed with the menu initialization)
173
+
174
+ When there is no more code to be run after the menu breaks, the program ends.
175
+
176
+ ---
177
+ 2). Multiple Menus
178
+ -
179
+ ----
180
+ ### Defining Two Menus
181
+ Menus can open other menus by running them as functions allowing the user to navigate through a deeper menu structure.
182
+
183
+ First create a new `Menu` instance in the same way as **menu1**:
184
+
185
+ ```commandline
186
+ #Create New Menus
187
+ menu1 = Menu(name = "First Menu")
188
+ menu2 = Menu(name = "Second Menu")
189
+ ```
190
+ Then, add another entry to **menu1** that runs **menu2** with no arguments:
191
+
192
+ ```commandline
193
+ menu1.append(
194
+ ("x", "hello world program", (
195
+ print, "hello world!"
196
+ )),
197
+ ("a", "menu2", (
198
+ menu2, ()
199
+ ))
200
+ )
201
+ ```
202
+
203
+ If we run the code and navigate to **menu2**, the following will happen:
204
+
205
+ ```commandline
206
+ First Menu
207
+ [x]- hello world program
208
+ [a]- menu2
209
+ [e]- exit
210
+ a
211
+ --*No Entries*--
212
+
213
+ Process finished with exit code 0
214
+ ```
215
+
216
+ We defined no entries for **menu2** so it automatically exits and, subsequently, the program,
217
+ as **menu1** has no more code to run.
218
+
219
+ *This results in the same outcome as pressing the exit key in **menu2**.*
220
+
221
+ -----------------------
222
+ ### Exit Key Behaviour
223
+ The behaviour of the exit key can be changed with three keyword arguments
224
+ in a menu initiliazation:
225
+ ```commandline
226
+ #exit_to : a function to be called on exit
227
+ #exit_key : the key to press (default 'e')
228
+ #exit_message : the message displayed on the menu (default 'exit')
229
+ ```
230
+ ----
231
+ To change the exit key behaviour to return to **menu1**, for example,
232
+ we can change the `exit_to` tag in the definition of **menu2** and the message it displays:
233
+
234
+ ```commandline
235
+ menu1 = Menu(name = "First Menu")
236
+ menu2 = Menu(name = "Second Menu", exit_to = menu1, exit_message = "to menu1")
237
+ ```
238
+
239
+ This will call **menu1** when the exit key is pressed or when **menu2** is empty.
240
+
241
+ *Additionally, you can change the `empty_message` keyword argument to change what message is displayed:*
242
+
243
+ ```commandline
244
+ Menu(empty_message = "No more functions to run!")
245
+ ```
246
+
247
+ ------
248
+ ### Adding More Entries
249
+
250
+ Let's add some entries to **menu2**:
251
+
252
+ ```commandline
253
+ from MenuCMD import Menu
254
+
255
+ #Create New Menu
256
+ menu1 = Menu(name = "First Menu")
257
+ menu2 = Menu(name = "Second Menu", exit_to = menu1, exit_message = "to menu1")
258
+
259
+ #Add Items
260
+ menu1.append(
261
+ ("x", "hello world program", (
262
+ print, "hello world!"
263
+ )),
264
+ ("a", "menu2", (
265
+ menu2, ()
266
+ ))
267
+ )
268
+
269
+ menu2.append(
270
+ ("b", "happy b-day", (
271
+ print, "Happy Birthday!"
272
+ )),
273
+ ("c", "merry christmas", (
274
+ print, "Merry Christmas!", menu1, ()
275
+ )),
276
+ )
277
+
278
+ #Run Menu
279
+ menu1()
280
+ ```
281
+ Pressing 'b' will print 'Happy Birthday!' and return to **menu2**. Pressing 'c'
282
+ will print 'Merry Christmas!' and return to **menu1**. This is because the second item runs the `print` function
283
+ first, and then calls **menu1**. The first item, however, does not call **menu1** so it returns to
284
+ **menu2** automatically.
285
+
286
+
287
+ ---
288
+ ### End Chain Behaviour
289
+
290
+ The default behaviour of a `None`-type return of the function chain can be changed
291
+ with the `end_to` keyword:
292
+ ```commandline
293
+ #end_to : function to be called when the last function of a chain returns None
294
+ ```
295
+
296
+ *By default, if the **last** function in a chain returns
297
+ `None`, the current menu will open **itself** after all functions are executed.*
298
+
299
+ ----
300
+ ### Serializing End Returns
301
+
302
+ The `print` function always returns `None`, so if you want all of the items in menu2 to return to menu1, you can
303
+ set
304
+ `end_to` = **menu1**, and neglect chaining **menu1** at the end of the entry.
305
+
306
+ ```commandline
307
+ from MenuCMD import Menu
308
+
309
+ #Create New Menu
310
+ menu1 = Menu(name = "First Menu")
311
+ menu2 = Menu(name = "Second Menu",
312
+ exit_to = menu1, exit_message = "to menu1",
313
+ end_to = menu1
314
+ )
315
+
316
+ #Add Items
317
+ menu1.append(
318
+ ("x", "hello world program", (
319
+ print, "hello world!"
320
+ )),
321
+ ("a", "menu2", (
322
+ menu2, ()
323
+ ))
324
+ )
325
+
326
+ menu2.append(
327
+ ("b", "happy b-day", (
328
+ print, "happy birthday!"
329
+ )),
330
+ ("c", "merry christmas", (
331
+ print, "merry christmas!"
332
+ )),
333
+ )
334
+
335
+ #Run Menu
336
+ menu1()
337
+ ```
338
+
339
+ This will not work for all functions, but for very simple menus, where the last function
340
+ always returns `None`, the `end_to` tag is a simple way to serialize menu behaviour.
341
+
342
+ ---
343
+ 3). Function Composition
344
+ -
345
+ --------
346
+ ### Using the Result Type
347
+ The `result` type allows the user to compose function returns in a chain.
348
+ Let's create a menu item that asks for a
349
+ number as input, squares it, and then prints the result.
350
+
351
+ For sake of terseness, redefine the namespace of `Menu.result` above the menu declarations.
352
+ ```commandline
353
+ result = Menu.result
354
+
355
+ menu1 = Menu(name = "Function Composition")
356
+ ```
357
+
358
+ The first function in the chain asks the user for a number, the second function converts it to `float`, the third function
359
+ squares it, and the last function prints it.
360
+
361
+ `input -> float -> square -> print` => `print(square(float(input())))`
362
+
363
+ Use the `result` object for the argument of each consecutive function in the item:
364
+
365
+ ```commandline
366
+ menu1.append(
367
+ ("n", "square a number", (
368
+ input, "number ",
369
+ float, result,
370
+ lambda n: n**2, result,
371
+ print, result
372
+ )),
373
+ )
374
+ ```
375
+ When the user selects an item, the result of each function is stored into the `result` object and
376
+ retrieved when calling the next function. A function may have `result` as any of its arguments as long as the chain composes types.
377
+
378
+ You can also substitute `result` for functions if the previous return type is a `function`.
379
+
380
+ ```
381
+ #func1: *args1 -> function
382
+
383
+ (func1, (*args1), result, (*args2)) => (func1(*args1))(*args2)
384
+ ```
385
+
386
+ --------
387
+ ### Using Past Results
388
+
389
+ The `result` object can also be indexed to retrieve all past results in a chain.
390
+
391
+ By default, it is indexed at -1, which is the previous return value.
392
+ ```
393
+ result := result[-1]
394
+ ```
395
+
396
+ The indexing works exactly the same as a list.
397
+
398
+ If you want the first result in the chain, write `result[0]`.\
399
+ The result before the last; `result[-2]`.\
400
+ etc...
401
+
402
+ ```commandline
403
+ # func1: () -> 1
404
+ # func2: x -> x+1
405
+ # func3: x -> x*2
406
+ # func4: x -> x**3
407
+
408
+ ._________________________________________________.
409
+ .__________|_________.___________________. |
410
+ | | | | |
411
+ | | V V V
412
+ (func1, (), func2, (result[-1],), func3, (result[0],), func4, (result[-2],))
413
+ | | | |
414
+ V | | |
415
+ result[0] = 1 V | |
416
+ result[1] = 2 V |
417
+ result[2] = 2 V
418
+ result[3] = 8
419
+
420
+
421
+ ```
422
+
423
+ For example, if we also wanted to print the pre-squared `float` value, we can add:
424
+ ```commandline
425
+ #Create Menus
426
+ result = Menu.result
427
+
428
+ menu1 = Menu(name = "Function Composition")
429
+
430
+
431
+ #Append Items
432
+ menu1.append(
433
+ ("n", "square a number", (
434
+ input, "number: ",
435
+ float, result,
436
+ lambda n: n**2, result,
437
+ print, result,
438
+ print, result[1]
439
+ ) #result[1] prints the second result (= result[-3])
440
+ )
441
+
442
+
443
+ #Run
444
+ menu1()
445
+ ```
446
+
447
+
448
+ -------
449
+ ### Using the Bind Class
450
+
451
+ The `Bind` class allows lazy evaluation of functions. If the arguments defined in a menu item are not determined yet,
452
+ or a previous result must be converted before the menu substitutes its value, the `Bind` class will hold off evaluating a
453
+ function until it needs to.
454
+
455
+ Start by importing `Bind` into a convenient namespace:
456
+ ```commandline
457
+ from MenuCMD import Menu, Bind as B
458
+ ```
459
+
460
+ An object of the `Bind` class is essentially a *callable* function/argument(s) pair of the form
461
+ ```commandline
462
+ B(func, *args)
463
+ ```
464
+ The object takes a depth-first approach to evaluation so the deepest nested `Bind` object
465
+ will be evaluated first, and all the way up.
466
+
467
+ ```commandline
468
+ B(func1, B(func2, B(func3, *args)))
469
+
470
+ #Evaluates to:
471
+ func1(func2(func3(*args)))
472
+ ```
473
+ When a menu runs its function chains, it will evaluate all nested `Bind` objects as required.
474
+
475
+ *Outside of integrated menu usage, a `Bind` object can be called with no arguments and it will return its function
476
+ evaluated with its arguments.*
477
+
478
+ ```commandline
479
+ lazy_func = B(func, *args)
480
+
481
+ lazy_func() -> func(*args)
482
+ ```
483
+
484
+ By default, if you don't use `Bind` in a menu item, and set the internal **args** to `result`, Python will attempt
485
+ to evaluate **func3(result)** before the item is even appended to the menu. But **result** *doesn't exist yet!*
486
+
487
+ A different way to appraoch the square number entry is to bind `float` with `result` and use it as the argument
488
+ to the squaring function:
489
+
490
+ ```commandline
491
+ from MenuCMD import Menu, Bind as B
492
+
493
+ #Create New Menu
494
+ result = Menu.result
495
+
496
+ menu1 = Menu(name = "Function Composition")
497
+
498
+
499
+ #Add Items
500
+ menu1.append(
501
+ ("n", "square a number", (
502
+ input, "number: ",
503
+ float, result,
504
+ lambda n: n**2, result,
505
+ print, result
506
+ )),
507
+
508
+ ("m", "square a number (bind result)", (
509
+ input, "number: ",
510
+ lambda n: n**2, B(float, result),
511
+ print, result
512
+ ))
513
+ )
514
+
515
+
516
+ #Run Menu
517
+ menu1()
518
+ ```
519
+ This will effectively wait to evaluate the argument for lambda until `result` is known,
520
+ and then converts it to `float`.
521
+
522
+ ------
523
+ ### Binding Functions and Kwargs
524
+
525
+ Additionally, `Bind` objects can be nested in both the function and arguments.
526
+
527
+ For example, this is a completely valid `Bind` object:
528
+ ```commandline
529
+ B(B(B(func1, *args1), *args2), B(func2, *args3))
530
+
531
+ #Evaluates to:
532
+ ((func1(*args))(*args2))(func2(*args3))
533
+ ```
534
+ If a **function** is undetermined, then it can also wait until the very last minute.
535
+
536
+ *Furthermore, `Bind` works exactly the same with keyword arguments.*
537
+ ```commandline
538
+ B(func, *args, **kwargs)
539
+ ```
540
+ ---
541
+ 4). Other Menu Attributes
542
+ -
543
+ -----
544
+ ### Using kwargs
545
+
546
+ If a function also takes keyword arguments, use the `kwargs` wrapper from `Menu`. \
547
+ `kwargs` is simply a copy of `dict`. You may either wrap a set of keyword arguments
548
+ or input a dictionary:
549
+
550
+ ```commandline
551
+ kwargs = Menu.kwargs
552
+ ```
553
+ ```
554
+ menu1.append(
555
+ ("x", "function with kwargs", (
556
+ func, (*args, kwargs(kw1 = "a", kw2 = "b"))
557
+ ))
558
+ )
559
+ ```
560
+ Or
561
+ ```
562
+ menu1.append(
563
+ ("x", "function with kwargs", (
564
+ func, (*args, kwargs({"kw1":"a", "kw2":"b"})})
565
+ ))
566
+ )
567
+ ```
568
+ Both will evaluate to the same. If you do not wrap a dictionary with `kwargs`, it will be
569
+ interpreted as an argument.
570
+
571
+ ----
572
+
573
+ ### Using Manual Escapes
574
+
575
+ The `escape` type allows for manually breaking from a menu before a chain completes.
576
+
577
+ ```commandline
578
+ escape = Menu.escape
579
+ ```
580
+
581
+ If *any* function in the chain returns `escape`, no following functions will be executed and the
582
+ menu will instead run a different function.
583
+
584
+ By default, if an `escape` object is returned, the menu will return to itself but the behaviour
585
+ can be changed on menu initialization:
586
+ ```commandline
587
+ # escape_to : a function to be called on manual escape
588
+ ```
589
+
590
+ For example, define a function that returns `escape` if its input is empty:
591
+ ```commandline
592
+ def check_if_empty(x):
593
+ if x:
594
+ return x
595
+ else:
596
+ return Menu.escape
597
+ ```
598
+
599
+ Then, say, if it isn't empty, print the string in reverse:
600
+
601
+ ```commandline
602
+ menu2.append(
603
+ ("x", "print if not empty", (
604
+ input, "Input a string ",
605
+ check_if_empty, result, #nothing will run after here if escape is returned
606
+ print, "reversed:",
607
+ print, B(lambda s: s[::-1], result[-2])
608
+ ))
609
+ )
610
+ ```
611
+
612
+ While this module is designed to allow complete independence of menu structures and functions,
613
+ the manual escape is the one exception to the rule. Although, in some cases, this can
614
+ be avoided with the builtin `escape_on` and `f_escape` functions covered in *Section 5)*.
615
+
616
+
617
+
618
+ ### Using Matching Keywords
619
+
620
+ ----
621
+
622
+ If a menu *exits*, *ends*, or *escapes* to the same function, you can optionally use matching
623
+ keywords to avoid writing the arguments multiple times.
624
+
625
+ For example, instead of writing
626
+ ```commandline
627
+ menu1 = Menu()
628
+
629
+ menu2 = Menu(exit_to = menu1, end_to = menu1, escape_to = menu1)
630
+
631
+ menu3 = Menu(exit_to = menu2, end_to = menu1, escape_to = menu1)
632
+ ```
633
+
634
+ you can use the `Menu.exit_to` and `Menu.end_to` keyword objects:
635
+
636
+ ```commandline
637
+ menu1 = Menu()
638
+
639
+ menu2 = Menu(exit_to = menu1, end_to = Menu.exit_to, escape_to = Menu.exit_to)
640
+
641
+ menu3 = Menu(exit_to = menu2, end_to = menu1, escape_to = Menu.end_to)
642
+ ```
643
+
644
+ Setting any of the keyword arguments to `Menu.exit_to` will mirror the value of `exit_to`,
645
+ likewise for `Menu.end_to`.
646
+
647
+ The order of precedence for the `Menu.exit_to` and `Menu.end_to` objects is as follows:
648
+ ```commandline
649
+ .______________.
650
+ ._________._____|___________. |
651
+ | V | V V
652
+ exit_to | end_to | escape_to
653
+ | | | |
654
+ V | V |
655
+ Menu.exit_to Menu.end_to
656
+ ```
657
+
658
+ `exit_to` will always be defined first, `end_to` second, and lastly `escape_to`. There is hence no
659
+ *Menu.escape_to* object.
660
+
661
+ Matching keywords serve as a nifty way to serialize `Menu` parameters.
662
+
663
+ ---
664
+ 5). Builtins
665
+ -
666
+ ------
667
+
668
+ So far, this tutorial has approached creating menus as separate entities from the functions they compose.
669
+ While this is an intended feature of the module, you may still use menus within functions. MenuCMD has a number
670
+ of builtin functions to create template menus and to make in-line composition easier.
671
+
672
+ *This list is subject to change as community members can submit their own if anyone finds any common uses or improvements for MenuCMD!*
673
+
674
+
675
+ ## In-line Functions
676
+
677
+ These functions are designed to be composed in menu item function chains to control command flow.
678
+
679
+ -----
680
+
681
+ ### escape_on(x, value) -> value | Menu.escape
682
+ ```
683
+ Returns an escape if the two arguments are equal, or both Truthy or both Falsy.
684
+ Otherwise, returns value.
685
+ ```
686
+ Use this to break function chain execution on an equality condition. For example, to *escape* the menu on
687
+ empty input write:
688
+ ```commandline
689
+ (input, "input", escape_on, ("", result), print, "your input:", print, result[-2])
690
+ ```
691
+ This will bypass the print statements if the user inputs an empty string and calls whatever `escape_to`
692
+ is defined as.
693
+
694
+ -----
695
+ ### f_escape(*args, **kwargs) -> Menu.escape
696
+ ```
697
+ Polymorphic in-line escape function.
698
+ ```
699
+ This function takes any **args** and **kwargs** and returns the `escape` object.
700
+
701
+ *For nerds, this can be viewed as the collection of terminal morphisms in **Hom(x, escape)***
702
+
703
+ ----
704
+ ### f_switch(n: int | bool, funcs: tuple[function]) -> Bind.Wrapper
705
+
706
+
707
+ ```commandline
708
+ Returns a lazy function of type (int -> function)
709
+ ```
710
+ Takes an `int` and a `tuple` of functions and returns a `Bind` that indexes each function.
711
+
712
+ Use this if you want a previous result to change which function runs next.
713
+ ```commandline
714
+ functions = (func1, func2, func3)
715
+
716
+ (input, "choose a function (0-2) ", f_switch(result, functions), (*args))
717
+ #Call f_switch
718
+ ```
719
+ Since `f_switch` returns a `Bind` object that subsequently returns a `function`, be sure to *call*
720
+ it in the function slot of the chain. Whatever function it switches to upon evaluating `result` (an integer),
721
+ will then be evaluated with **args**, so be sure that all of the functions in the `tuple` have the same domain!
722
+
723
+
724
+ -----
725
+ ## Builtin Menus
726
+
727
+ These functions construct temporary menus that determine their returns. Optionally, all menu **kwargs**
728
+ can be passed through them to change the behaviour and appearance of the menus they invoke.
729
+
730
+ *Avoid changing the `exit_to` keyword argument as it will change the return type of the functions!*
731
+
732
+ ------
733
+
734
+ ### yesno_ver(**kwargs) -> bool
735
+
736
+ ```commandline
737
+ Simple yes/no verification returning bool
738
+ ```
739
+ Asks the user a yes/no question, and returns the bool of the result.
740
+
741
+ ```commandline
742
+ yesno = yesno_ver()
743
+
744
+ print(yesno)
745
+ ```
746
+ V V V V V V V
747
+ ```commandline
748
+ Are you sure?
749
+ [x]- yes
750
+ [e]- cancel
751
+ x
752
+ True
753
+ ```
754
+ ```commandline
755
+ Are you sure?
756
+ [x]- yes
757
+ [e]- cancel
758
+ e
759
+ False
760
+ ```
761
+
762
+ -----
763
+ ### edit_list(entries: list | tuple, **kwargs) -> list | tuple
764
+ ```commandline
765
+ Delete items in a list/tuple; returns updated list/tuple
766
+ ```
767
+ Takes a `list` or `tuple` and displays a menu of numbered items to delete. Upon each selection, the menu
768
+ will display itself again with the item removed and will only return the updated `list`/`tuple` when the
769
+ exit key is pressed.
770
+
771
+ ```commandline
772
+ L = ['a','b','c','d','e']
773
+
774
+ L = edit_list(L)
775
+
776
+ print(L)
777
+ ```
778
+ V V V V V V V
779
+ ```commandline
780
+ Edit List
781
+ [0]- a
782
+ [1]- b
783
+ [2]- c
784
+ [3]- d
785
+ [4]- e
786
+ [e]- exit
787
+ 0
788
+
789
+ Edit List
790
+ [0]- b
791
+ [1]- c
792
+ [2]- d
793
+ [3]- e
794
+ [e]- exit
795
+ 2
796
+
797
+ Edit List
798
+ [0]- b
799
+ [1]- c
800
+ [2]- e
801
+ [e]- exit
802
+ 2
803
+
804
+ Edit List
805
+ [0]- b
806
+ [1]- c
807
+ [e]- exit
808
+ e
809
+ ['b', 'c']
810
+ ```