mininterface 0.6.2rc2__tar.gz → 0.7.1__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.
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/PKG-INFO +51 -30
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/README.md +41 -26
- mininterface-0.7.1/mininterface/ValidationFail.py +5 -0
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/__init__.py +62 -49
- mininterface-0.7.1/mininterface/__main__.py +82 -0
- mininterface-0.7.1/mininterface/auxiliary.py +151 -0
- mininterface-0.7.1/mininterface/cli_parser.py +272 -0
- mininterface-0.7.1/mininterface/exceptions.py +30 -0
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/facet.py +62 -8
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/form_dict.py +73 -32
- mininterface-0.7.1/mininterface/interfaces.py +58 -0
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/mininterface.py +132 -38
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/redirectable.py +9 -1
- mininterface-0.7.1/mininterface/showcase.py +82 -0
- mininterface-0.7.1/mininterface/start.py +95 -0
- mininterface-0.7.1/mininterface/subcommands.py +141 -0
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/tag.py +148 -56
- mininterface-0.7.1/mininterface/tag_factory.py +80 -0
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/text_interface.py +61 -7
- mininterface-0.7.1/mininterface/textual_interface/__init__.py +51 -0
- mininterface-0.7.1/mininterface/textual_interface/textual_adaptor.py +95 -0
- mininterface-0.7.1/mininterface/textual_interface/textual_app.py +105 -0
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/textual_interface/textual_button_app.py +3 -3
- mininterface-0.7.1/mininterface/textual_interface/textual_facet.py +31 -0
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/textual_interface/widgets.py +2 -6
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/tk_interface/__init__.py +17 -11
- mininterface-0.7.1/mininterface/tk_interface/date_entry.py +221 -0
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/tk_interface/redirect_text_tkinter.py +9 -0
- mininterface-0.7.1/mininterface/tk_interface/tk_facet.py +55 -0
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/tk_interface/tk_window.py +49 -22
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/tk_interface/utils.py +19 -13
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/type_stubs.py +3 -2
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/types.py +91 -9
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/validators.py +1 -1
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/pyproject.toml +15 -5
- mininterface-0.6.2rc2/mininterface/__main__.py +0 -39
- mininterface-0.6.2rc2/mininterface/auxiliary.py +0 -61
- mininterface-0.6.2rc2/mininterface/cli_parser.py +0 -210
- mininterface-0.6.2rc2/mininterface/common.py +0 -8
- mininterface-0.6.2rc2/mininterface/tag_factory.py +0 -28
- mininterface-0.6.2rc2/mininterface/textual_interface/__init__.py +0 -59
- mininterface-0.6.2rc2/mininterface/textual_interface/textual_app.py +0 -147
- mininterface-0.6.2rc2/mininterface/textual_interface/textual_facet.py +0 -21
- mininterface-0.6.2rc2/mininterface/tk_interface/tk_facet.py +0 -20
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/LICENSE +0 -0
- {mininterface-0.6.2rc2 → mininterface-0.7.1}/mininterface/experimental.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mininterface
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: A minimal access to GUI, TUI, CLI and config
|
|
5
5
|
Home-page: https://github.com/CZ-NIC/mininterface
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -13,24 +13,30 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Provides-Extra: all
|
|
17
|
+
Provides-Extra: img
|
|
18
|
+
Provides-Extra: web
|
|
16
19
|
Requires-Dist: autocombobox (==1.4.2)
|
|
20
|
+
Requires-Dist: humanize
|
|
17
21
|
Requires-Dist: pyyaml
|
|
18
|
-
Requires-Dist:
|
|
19
|
-
Requires-Dist:
|
|
22
|
+
Requires-Dist: textual (>=0.84,<0.85)
|
|
23
|
+
Requires-Dist: tkcalendar
|
|
20
24
|
Requires-Dist: tkinter-tooltip
|
|
21
25
|
Requires-Dist: tkinter_form (==0.1.5.2)
|
|
22
|
-
Requires-Dist:
|
|
26
|
+
Requires-Dist: tkscrollableframe
|
|
27
|
+
Requires-Dist: typing_extensions
|
|
28
|
+
Requires-Dist: tyro (==0.8.14)
|
|
23
29
|
Description-Content-Type: text/markdown
|
|
24
30
|
|
|
25
31
|
# Mininterface – access to GUI, TUI, CLI and config files
|
|
26
32
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
27
33
|
[](https://github.com/CZ-NIC/mininterface/actions)
|
|
28
|
-
[](https://pepy.tech/project/mininterface)
|
|
34
|
+
[](https://pepy.tech/project/mininterface)
|
|
29
35
|
|
|
30
36
|
Write the program core, do not bother with the input/output.
|
|
31
37
|
|
|
32
|
-

|
|
39
|
+

|
|
34
40
|
|
|
35
41
|
Check out the code, which is surprisingly short, that displays such a window or its textual fallback.
|
|
36
42
|
|
|
@@ -49,10 +55,11 @@ class Env:
|
|
|
49
55
|
""" This number is very important """
|
|
50
56
|
|
|
51
57
|
if __name__ == "__main__":
|
|
52
|
-
|
|
58
|
+
m = run(Env, prog="My application")
|
|
59
|
+
m.form()
|
|
53
60
|
# Attributes are suggested by the IDE
|
|
54
61
|
# along with the hint text 'This number is very important'.
|
|
55
|
-
print(env.my_number)
|
|
62
|
+
print(m.env.my_number)
|
|
56
63
|
```
|
|
57
64
|
|
|
58
65
|
# Contents
|
|
@@ -69,16 +76,18 @@ It was all the code you need. No lengthy blocks of code imposed by an external d
|
|
|
69
76
|
|
|
70
77
|
|
|
71
78
|
```bash
|
|
72
|
-
$ ./
|
|
73
|
-
usage: My application [-h] [--
|
|
79
|
+
$ ./program.py --help
|
|
80
|
+
usage: My application [-h] [-v] [--my-flag | --no-my-flag] [--my-number INT]
|
|
74
81
|
|
|
75
82
|
This calculates something.
|
|
76
83
|
|
|
77
|
-
╭─ options
|
|
78
|
-
│ -h, --help
|
|
79
|
-
│
|
|
80
|
-
│ --
|
|
81
|
-
|
|
84
|
+
╭─ options ───────────────────────────────────────────────────────────────╮
|
|
85
|
+
│ -h, --help show this help message and exit │
|
|
86
|
+
│ -v, --verbose Verbosity level. Can be used twice to increase. │
|
|
87
|
+
│ --my-flag, --no-my-flag │
|
|
88
|
+
│ This switches the functionality (default: False) │
|
|
89
|
+
│ --my-number INT This number is very important (default: 4) │
|
|
90
|
+
╰─────────────────────────────────────────────────────────────────────────╯
|
|
82
91
|
```
|
|
83
92
|
|
|
84
93
|
## You got config file management
|
|
@@ -88,6 +97,12 @@ Loading config file is a piece of cake. Alongside `program.py`, put `program.yam
|
|
|
88
97
|
my_number: 555
|
|
89
98
|
```
|
|
90
99
|
|
|
100
|
+
```bash
|
|
101
|
+
$ program.py --help
|
|
102
|
+
...
|
|
103
|
+
│ --my-number INT This number is very important (default: 555) │
|
|
104
|
+
```
|
|
105
|
+
|
|
91
106
|
## You got dialogues
|
|
92
107
|
Check out several useful methods to handle user dialogues. Here we bound the interface to a `with` statement that redirects stdout directly to the window.
|
|
93
108
|
|
|
@@ -120,11 +135,22 @@ Install with a single command from [PyPi](https://pypi.org/project/mininterface/
|
|
|
120
135
|
pip install mininterface
|
|
121
136
|
```
|
|
122
137
|
|
|
138
|
+
## Minimal installation
|
|
139
|
+
|
|
140
|
+
Should you need just the CLI part and you are happy with basic text dialogs, use these commands instead:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
pip install --no-dependencies mininterface
|
|
144
|
+
pip install tyro typing_extensions pyyaml
|
|
145
|
+
```
|
|
146
|
+
|
|
123
147
|
# Docs
|
|
124
148
|
See the docs overview at [https://cz-nic.github.io/mininterface/](https://cz-nic.github.io/mininterface/Overview/).
|
|
125
149
|
|
|
126
150
|
# Examples
|
|
127
151
|
|
|
152
|
+
A powerful [`m.form`](https://cz-nic.github.io/mininterface/Mininterface/#mininterface.Mininterface.form) dialog method accepts either a dataclass or a dict. Take a look on both.
|
|
153
|
+
|
|
128
154
|
## A complex dataclass.
|
|
129
155
|
|
|
130
156
|
```python3
|
|
@@ -143,7 +169,7 @@ class Env:
|
|
|
143
169
|
nested_config: NestedEnv
|
|
144
170
|
|
|
145
171
|
mandatory_str: str
|
|
146
|
-
""" As there is
|
|
172
|
+
""" As there is no default value, you will be prompted automatically to fill up the field """
|
|
147
173
|
|
|
148
174
|
my_number: int | None = None
|
|
149
175
|
""" This is not just a dummy number, if left empty, it is None. """
|
|
@@ -167,6 +193,14 @@ print(m.env)
|
|
|
167
193
|
m.form()
|
|
168
194
|
```
|
|
169
195
|
|
|
196
|
+
As the attribute `mandatory_str` requires a value, a prompt appears automatically:
|
|
197
|
+
|
|
198
|
+

|
|
199
|
+
|
|
200
|
+
Then, full form appears:
|
|
201
|
+
|
|
202
|
+

|
|
203
|
+
|
|
170
204
|
## Form with paths
|
|
171
205
|
|
|
172
206
|
We have a dict with some paths. Here is how it looks.
|
|
@@ -187,16 +221,3 @@ m.form(my_dictionary)
|
|
|
187
221
|
|
|
188
222
|

|
|
189
223
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Mininterface – access to GUI, TUI, CLI and config files
|
|
2
2
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
3
3
|
[](https://github.com/CZ-NIC/mininterface/actions)
|
|
4
|
-
[](https://pepy.tech/project/mininterface)
|
|
4
|
+
[](https://pepy.tech/project/mininterface)
|
|
5
5
|
|
|
6
6
|
Write the program core, do not bother with the input/output.
|
|
7
7
|
|
|
8
|
-

|
|
9
|
+

|
|
10
10
|
|
|
11
11
|
Check out the code, which is surprisingly short, that displays such a window or its textual fallback.
|
|
12
12
|
|
|
@@ -25,10 +25,11 @@ class Env:
|
|
|
25
25
|
""" This number is very important """
|
|
26
26
|
|
|
27
27
|
if __name__ == "__main__":
|
|
28
|
-
|
|
28
|
+
m = run(Env, prog="My application")
|
|
29
|
+
m.form()
|
|
29
30
|
# Attributes are suggested by the IDE
|
|
30
31
|
# along with the hint text 'This number is very important'.
|
|
31
|
-
print(env.my_number)
|
|
32
|
+
print(m.env.my_number)
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
# Contents
|
|
@@ -45,16 +46,18 @@ It was all the code you need. No lengthy blocks of code imposed by an external d
|
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
```bash
|
|
48
|
-
$ ./
|
|
49
|
-
usage: My application [-h] [--
|
|
49
|
+
$ ./program.py --help
|
|
50
|
+
usage: My application [-h] [-v] [--my-flag | --no-my-flag] [--my-number INT]
|
|
50
51
|
|
|
51
52
|
This calculates something.
|
|
52
53
|
|
|
53
|
-
╭─ options
|
|
54
|
-
│ -h, --help
|
|
55
|
-
│
|
|
56
|
-
│ --
|
|
57
|
-
|
|
54
|
+
╭─ options ───────────────────────────────────────────────────────────────╮
|
|
55
|
+
│ -h, --help show this help message and exit │
|
|
56
|
+
│ -v, --verbose Verbosity level. Can be used twice to increase. │
|
|
57
|
+
│ --my-flag, --no-my-flag │
|
|
58
|
+
│ This switches the functionality (default: False) │
|
|
59
|
+
│ --my-number INT This number is very important (default: 4) │
|
|
60
|
+
╰─────────────────────────────────────────────────────────────────────────╯
|
|
58
61
|
```
|
|
59
62
|
|
|
60
63
|
## You got config file management
|
|
@@ -64,6 +67,12 @@ Loading config file is a piece of cake. Alongside `program.py`, put `program.yam
|
|
|
64
67
|
my_number: 555
|
|
65
68
|
```
|
|
66
69
|
|
|
70
|
+
```bash
|
|
71
|
+
$ program.py --help
|
|
72
|
+
...
|
|
73
|
+
│ --my-number INT This number is very important (default: 555) │
|
|
74
|
+
```
|
|
75
|
+
|
|
67
76
|
## You got dialogues
|
|
68
77
|
Check out several useful methods to handle user dialogues. Here we bound the interface to a `with` statement that redirects stdout directly to the window.
|
|
69
78
|
|
|
@@ -96,11 +105,22 @@ Install with a single command from [PyPi](https://pypi.org/project/mininterface/
|
|
|
96
105
|
pip install mininterface
|
|
97
106
|
```
|
|
98
107
|
|
|
108
|
+
## Minimal installation
|
|
109
|
+
|
|
110
|
+
Should you need just the CLI part and you are happy with basic text dialogs, use these commands instead:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
pip install --no-dependencies mininterface
|
|
114
|
+
pip install tyro typing_extensions pyyaml
|
|
115
|
+
```
|
|
116
|
+
|
|
99
117
|
# Docs
|
|
100
118
|
See the docs overview at [https://cz-nic.github.io/mininterface/](https://cz-nic.github.io/mininterface/Overview/).
|
|
101
119
|
|
|
102
120
|
# Examples
|
|
103
121
|
|
|
122
|
+
A powerful [`m.form`](https://cz-nic.github.io/mininterface/Mininterface/#mininterface.Mininterface.form) dialog method accepts either a dataclass or a dict. Take a look on both.
|
|
123
|
+
|
|
104
124
|
## A complex dataclass.
|
|
105
125
|
|
|
106
126
|
```python3
|
|
@@ -119,7 +139,7 @@ class Env:
|
|
|
119
139
|
nested_config: NestedEnv
|
|
120
140
|
|
|
121
141
|
mandatory_str: str
|
|
122
|
-
""" As there is
|
|
142
|
+
""" As there is no default value, you will be prompted automatically to fill up the field """
|
|
123
143
|
|
|
124
144
|
my_number: int | None = None
|
|
125
145
|
""" This is not just a dummy number, if left empty, it is None. """
|
|
@@ -143,6 +163,14 @@ print(m.env)
|
|
|
143
163
|
m.form()
|
|
144
164
|
```
|
|
145
165
|
|
|
166
|
+
As the attribute `mandatory_str` requires a value, a prompt appears automatically:
|
|
167
|
+
|
|
168
|
+

|
|
169
|
+
|
|
170
|
+
Then, full form appears:
|
|
171
|
+
|
|
172
|
+

|
|
173
|
+
|
|
146
174
|
## Form with paths
|
|
147
175
|
|
|
148
176
|
We have a dict with some paths. Here is how it looks.
|
|
@@ -162,16 +190,3 @@ m.form(my_dictionary)
|
|
|
162
190
|
```
|
|
163
191
|
|
|
164
192
|

|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
@@ -1,31 +1,20 @@
|
|
|
1
1
|
import sys
|
|
2
|
+
from dataclasses import dataclass
|
|
2
3
|
from pathlib import Path
|
|
3
|
-
from typing import
|
|
4
|
+
from typing import Literal, Optional, Sequence, Type
|
|
4
5
|
|
|
5
|
-
from .
|
|
6
|
-
|
|
7
|
-
from .
|
|
6
|
+
from .exceptions import Cancelled, InterfaceNotAvailable
|
|
7
|
+
|
|
8
|
+
from .interfaces import get_interface
|
|
9
|
+
|
|
10
|
+
from . import validators
|
|
11
|
+
from .cli_parser import _parse_cli, assure_args
|
|
12
|
+
from .subcommands import Command, SubcommandPlaceholder
|
|
8
13
|
from .form_dict import DataClass, EnvClass
|
|
9
|
-
from .tag import Tag
|
|
10
14
|
from .mininterface import EnvClass, Mininterface
|
|
11
|
-
from .
|
|
12
|
-
from . import
|
|
13
|
-
|
|
14
|
-
# Import optional interfaces
|
|
15
|
-
try:
|
|
16
|
-
from mininterface.tk_interface import TkInterface
|
|
17
|
-
except ImportError:
|
|
18
|
-
if TYPE_CHECKING:
|
|
19
|
-
pass # Replace TYPE_CHECKING with `type GuiInterface = None` since Python 3.12
|
|
20
|
-
else:
|
|
21
|
-
TkInterface = None
|
|
22
|
-
try:
|
|
23
|
-
from mininterface.textual_interface import TextualInterface
|
|
24
|
-
except ImportError:
|
|
25
|
-
TextualInterface = None
|
|
26
|
-
|
|
27
|
-
GuiInterface = TkInterface
|
|
28
|
-
TuiInterface = TextualInterface or TextInterface
|
|
15
|
+
from .start import Start
|
|
16
|
+
from .tag import Tag
|
|
17
|
+
from .types import Choices, PathTag, Validation
|
|
29
18
|
|
|
30
19
|
# NOTE:
|
|
31
20
|
# ask_for_missing does not work with tyro Positional, stays missing.
|
|
@@ -33,14 +22,22 @@ TuiInterface = TextualInterface or TextInterface
|
|
|
33
22
|
# class Env:
|
|
34
23
|
# files: Positional[list[Path]]
|
|
35
24
|
|
|
25
|
+
# NOTE: imgs missing in Interfaces.md
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class _Empty:
|
|
30
|
+
pass
|
|
31
|
+
|
|
36
32
|
|
|
37
|
-
def run(
|
|
33
|
+
def run(env_or_list: Type[EnvClass] | list[Type[Command]] | None = None,
|
|
38
34
|
ask_on_empty_cli: bool = False,
|
|
39
35
|
title: str = "",
|
|
40
36
|
config_file: Path | str | bool = True,
|
|
41
37
|
add_verbosity: bool = True,
|
|
42
38
|
ask_for_missing: bool = True,
|
|
43
|
-
interface: Type[Mininterface]
|
|
39
|
+
interface: Type[Mininterface] | Literal["gui"] | Literal["tui"] | None = None,
|
|
40
|
+
args: Optional[Sequence[str]] = None,
|
|
44
41
|
**kwargs) -> Mininterface[EnvClass]:
|
|
45
42
|
""" The main access, start here.
|
|
46
43
|
Wrap your configuration dataclass into `run` to access the interface. An interface is chosen automatically,
|
|
@@ -51,7 +48,12 @@ def run(env_class: Type[EnvClass] | None = None,
|
|
|
51
48
|
with the program name ending on *.yaml*, ex: `program.py` will fetch `./program.yaml`.
|
|
52
49
|
|
|
53
50
|
Args:
|
|
54
|
-
|
|
51
|
+
env_or_list:
|
|
52
|
+
* `dataclass` Dataclass with the configuration. Their values will be modified with the CLI arguments.
|
|
53
|
+
* `list` of [Commands][mininterface.subcommands.Command] let you create multiple commands within a single program, each with unique options.
|
|
54
|
+
* `None` You need just the dialogs, no CLI/config file parsing.
|
|
55
|
+
|
|
56
|
+
|
|
55
57
|
ask_on_empty_cli: If program was launched with no arguments (empty CLI), invokes self.form() to edit the fields.
|
|
56
58
|
(Withdrawn when `ask_for_missing` happens.)
|
|
57
59
|
```python
|
|
@@ -106,8 +108,10 @@ def run(env_class: Type[EnvClass] | None = None,
|
|
|
106
108
|
$ program.py # omitting --required-number
|
|
107
109
|
# Dialog for `required_number` appears
|
|
108
110
|
```
|
|
109
|
-
interface: Which interface to prefer. By default, we use the GUI, the fallback is the TUI.
|
|
110
|
-
|
|
111
|
+
interface: Which interface to prefer. By default, we use the GUI, the fallback is the TUI.
|
|
112
|
+
You may write "gui" or "tui" literal or pass a specific Mininterface type,
|
|
113
|
+
see the full [list](Interfaces.md) of possible interfaces.
|
|
114
|
+
args: Parse arguments from a sequence instead of the command line.
|
|
111
115
|
Kwargs:
|
|
112
116
|
The same as for [argparse.ArgumentParser](https://docs.python.org/3/library/argparse.html).
|
|
113
117
|
|
|
@@ -119,8 +123,15 @@ def run(env_class: Type[EnvClass] | None = None,
|
|
|
119
123
|
The stdout will be redirected to the interface (ex. a GUI window).
|
|
120
124
|
|
|
121
125
|
```python
|
|
126
|
+
from dataclasses import dataclass
|
|
127
|
+
from mininterface import run
|
|
128
|
+
|
|
129
|
+
@dataclass
|
|
130
|
+
class Env:
|
|
131
|
+
my_number: int = 4
|
|
132
|
+
|
|
122
133
|
with run(Env) as m:
|
|
123
|
-
print(f"Your important number is {m.env.
|
|
134
|
+
print(f"Your important number is {m.env.my_number}")
|
|
124
135
|
boolean = m.is_yes("Is that alright?")
|
|
125
136
|
```
|
|
126
137
|
|
|
@@ -139,7 +150,7 @@ def run(env_class: Type[EnvClass] | None = None,
|
|
|
139
150
|
# Undocumented experimental: `default` keyword argument for tyro may serve for default values instead of a config file.
|
|
140
151
|
|
|
141
152
|
# Prepare the config file
|
|
142
|
-
if config_file is True and not kwargs.get("default") and
|
|
153
|
+
if config_file is True and not kwargs.get("default") and env_or_list:
|
|
143
154
|
# Undocumented feature. User put a namespace into kwargs["default"]
|
|
144
155
|
# that already serves for defaults. We do not fetch defaults yet from a config file.
|
|
145
156
|
try:
|
|
@@ -155,26 +166,29 @@ def run(env_class: Type[EnvClass] | None = None,
|
|
|
155
166
|
elif isinstance(config_file, str):
|
|
156
167
|
config_file = Path(config_file)
|
|
157
168
|
|
|
158
|
-
#
|
|
169
|
+
# Determine title
|
|
170
|
+
title = title or kwargs.get("prog") or Path(sys.argv[0]).name
|
|
171
|
+
start = Start(title, interface)
|
|
172
|
+
|
|
173
|
+
# Hidden meta-commands in args
|
|
174
|
+
args = assure_args(args)
|
|
175
|
+
if len(args) == 1 and args[0] == "--integrate-to-system":
|
|
176
|
+
start.integrate(env_or_list or _Empty)
|
|
177
|
+
quit()
|
|
178
|
+
|
|
159
179
|
env, wrong_fields = None, {}
|
|
160
|
-
if
|
|
161
|
-
|
|
162
|
-
|
|
180
|
+
if isinstance(env_or_list, list) and SubcommandPlaceholder in env_or_list and args and args[0] == "subcommand":
|
|
181
|
+
start.choose_subcommand(env_or_list, args=args[1:])
|
|
182
|
+
elif isinstance(env_or_list, list) and not args:
|
|
183
|
+
start.choose_subcommand(env_or_list)
|
|
184
|
+
elif env_or_list:
|
|
185
|
+
# Load configuration from CLI and a config file
|
|
186
|
+
env, wrong_fields = _parse_cli(env_or_list, config_file, add_verbosity, ask_for_missing, args, **kwargs)
|
|
187
|
+
else: # even though there is no configuration, yet we need to parse CLI for meta-commands like --help or --verbose
|
|
188
|
+
_parse_cli(_Empty, None, add_verbosity, ask_for_missing, args)
|
|
163
189
|
|
|
164
190
|
# Build the interface
|
|
165
|
-
|
|
166
|
-
if "prog" not in kwargs:
|
|
167
|
-
kwargs["prog"] = title
|
|
168
|
-
try:
|
|
169
|
-
if interface == "tui": # undocumented feature
|
|
170
|
-
interface = TuiInterface
|
|
171
|
-
elif interface == "gui": # undocumented feature
|
|
172
|
-
interface = GuiInterface
|
|
173
|
-
if interface is None:
|
|
174
|
-
raise InterfaceNotAvailable # GuiInterface might be None when import fails
|
|
175
|
-
interface = interface(title, env)
|
|
176
|
-
except InterfaceNotAvailable: # Fallback to a different interface
|
|
177
|
-
interface = TuiInterface(title, env)
|
|
191
|
+
interface = get_interface(title, interface, env)
|
|
178
192
|
|
|
179
193
|
# Empty CLI → GUI edit
|
|
180
194
|
if ask_for_missing and wrong_fields:
|
|
@@ -189,5 +203,4 @@ def run(env_class: Type[EnvClass] | None = None,
|
|
|
189
203
|
|
|
190
204
|
__all__ = ["run", "Tag", "validators", "InterfaceNotAvailable", "Cancelled",
|
|
191
205
|
"Validation", "Choices", "PathTag",
|
|
192
|
-
"Mininterface"
|
|
193
|
-
]
|
|
206
|
+
"Mininterface"]
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
import sys
|
|
3
|
+
from typing import Literal, Optional
|
|
4
|
+
from tyro.conf import FlagConversionOff
|
|
5
|
+
|
|
6
|
+
from .exceptions import DependencyRequired
|
|
7
|
+
|
|
8
|
+
from . import run, Mininterface
|
|
9
|
+
from .showcase import showcase
|
|
10
|
+
|
|
11
|
+
__doc__ = """Simple GUI dialog. Outputs the value the user entered."""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class Web:
|
|
16
|
+
""" Experimenal undocumented feature. """
|
|
17
|
+
|
|
18
|
+
cmd: str = ""
|
|
19
|
+
""" Launch a miniterface program, while the TextualInterface will be exposed to the web."""
|
|
20
|
+
# NOTE: The textual app ends after the first submit. We have to correct that before the web makes sense.
|
|
21
|
+
# with run(interface=TextualInterface) as m:
|
|
22
|
+
# m.form({"hello": 1}) # the app ends here
|
|
23
|
+
# m.form({"hello": 2}) # we never get here
|
|
24
|
+
|
|
25
|
+
port: int = 64646
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
InterfaceType = Literal["gui"] | Literal["tui"] | Literal["all"]
|
|
29
|
+
Showcase = Literal[1] | Literal[2]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class CliInteface:
|
|
34
|
+
web: Web
|
|
35
|
+
alert: str = ""
|
|
36
|
+
""" Display the OK dialog with text. """
|
|
37
|
+
ask: str = ""
|
|
38
|
+
""" Prompt the user to input a text. """
|
|
39
|
+
ask_number: str = ""
|
|
40
|
+
""" Prompt the user to input a number. Empty input = 0. """
|
|
41
|
+
is_yes: str = ""
|
|
42
|
+
""" Display confirm box, focusing 'yes'. """
|
|
43
|
+
is_no: str = ""
|
|
44
|
+
""" Display confirm box, focusing 'no'. """
|
|
45
|
+
|
|
46
|
+
showcase: Optional[tuple[InterfaceType, Showcase]] = None
|
|
47
|
+
""" Prints various form just to show what's possible."""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def web(m: Mininterface):
|
|
51
|
+
try:
|
|
52
|
+
from textual_serve.server import Server
|
|
53
|
+
except ImportError:
|
|
54
|
+
raise DependencyRequired("web")
|
|
55
|
+
server = Server(m.env.web.cmd, port=m.env.web.port)
|
|
56
|
+
server.serve()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def main():
|
|
60
|
+
result = []
|
|
61
|
+
# We tested both GuiInterface and TextualInterface are able to pass a variable to i.e. a bash script.
|
|
62
|
+
# NOTE TextInterface fails (`mininterface --ask Test | grep Hello` – pipe causes no visible output).
|
|
63
|
+
with run(CliInteface, prog="Mininterface", description=__doc__) as m:
|
|
64
|
+
for method, label in vars(m.env).items():
|
|
65
|
+
if method in ["web", "showcase"]: # processed later
|
|
66
|
+
continue
|
|
67
|
+
if label:
|
|
68
|
+
result.append(getattr(m, method)(label))
|
|
69
|
+
|
|
70
|
+
# Displays each result on a new line. Currently, this is an undocumented feature.
|
|
71
|
+
# As we use the script for a single value only and it is not currently possible
|
|
72
|
+
# to ask two numbers or determine a dialog order etc.
|
|
73
|
+
[print(val) for val in result]
|
|
74
|
+
|
|
75
|
+
if m.env.web.cmd:
|
|
76
|
+
web(m)
|
|
77
|
+
if m.env.showcase:
|
|
78
|
+
showcase(*m.env.showcase)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if __name__ == "__main__":
|
|
82
|
+
main()
|