mininterface 0.1.1__tar.gz → 0.4.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.
- {mininterface-0.1.1 → mininterface-0.4.0}/PKG-INFO +2 -1
- {mininterface-0.1.1 → mininterface-0.4.0}/README.md +1 -0
- {mininterface-0.1.1 → mininterface-0.4.0}/mininterface/GuiInterface.py +3 -3
- {mininterface-0.1.1 → mininterface-0.4.0}/mininterface/TuiInterface.py +1 -1
- {mininterface-0.1.1 → mininterface-0.4.0}/mininterface/auxiliary.py +44 -23
- {mininterface-0.1.1 → mininterface-0.4.0}/pyproject.toml +1 -1
- {mininterface-0.1.1 → mininterface-0.4.0}/mininterface/Mininterface.py +0 -0
- {mininterface-0.1.1 → mininterface-0.4.0}/mininterface/__init__.py +0 -0
- {mininterface-0.1.1 → mininterface-0.4.0}/mininterface/__main__.py +0 -0
- {mininterface-0.1.1 → mininterface-0.4.0}/mininterface/common.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mininterface
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
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
|
|
@@ -22,6 +22,7 @@ Description-Content-Type: text/markdown
|
|
|
22
22
|
|
|
23
23
|
# Mininterface – access to GUI, TUI, CLI and config files
|
|
24
24
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
25
|
+
[](https://github.com/CZ-NIC/mininterface/actions)
|
|
25
26
|
|
|
26
27
|
Write the program core, do not bother with the input/output.
|
|
27
28
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Mininterface – access to GUI, TUI, CLI and config files
|
|
2
2
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
3
|
+
[](https://github.com/CZ-NIC/mininterface/actions)
|
|
3
4
|
|
|
4
5
|
Write the program core, do not bother with the input/output.
|
|
5
6
|
|
|
@@ -11,7 +11,7 @@ except ImportError:
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
from .common import InterfaceNotAvailable
|
|
14
|
-
from .auxiliary import FormDict, RedirectText,
|
|
14
|
+
from .auxiliary import FormDict, RedirectText, config_to_dict, config_from_dict, recursive_set_focus, normalize_types
|
|
15
15
|
from .Mininterface import Cancelled, ConfigInstance, Mininterface
|
|
16
16
|
|
|
17
17
|
|
|
@@ -46,11 +46,11 @@ class GuiInterface(Mininterface):
|
|
|
46
46
|
|
|
47
47
|
def ask_args(self) -> ConfigInstance:
|
|
48
48
|
""" Display a window form with all parameters. """
|
|
49
|
-
params_ =
|
|
49
|
+
params_ = config_to_dict(self.args, self.descriptions)
|
|
50
50
|
|
|
51
51
|
# fetch the dict of dicts values from the form back to the namespace of the dataclasses
|
|
52
52
|
data = self.window.run_dialog(params_)
|
|
53
|
-
|
|
53
|
+
config_from_dict(self.args, data)
|
|
54
54
|
return self.args
|
|
55
55
|
|
|
56
56
|
def ask_form(self, args: FormDict, title: str = "") -> dict:
|
|
@@ -41,9 +41,10 @@ FormDict = dict[str, Union[Value, Any, 'FormDict']]
|
|
|
41
41
|
""" Nested form that can have descriptions (through Value) instead of plain values. """
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
def
|
|
44
|
+
def config_to_dict(args: ConfigInstance, descr: dict, _path="") -> FormDict:
|
|
45
45
|
""" Convert the dataclass produced by tyro into dict of dicts. """
|
|
46
46
|
main = ""
|
|
47
|
+
# print(args)# TODO
|
|
47
48
|
params = {main: {}} if not _path else {}
|
|
48
49
|
for param, val in vars(args).items():
|
|
49
50
|
annotation = None
|
|
@@ -64,11 +65,12 @@ def dataclass_to_dict(args: ConfigInstance, descr: dict, _path="") -> FormDict:
|
|
|
64
65
|
logger.warn(f"Annotation {wanted_type} of `{param}` not supported by Mininterface."
|
|
65
66
|
"None converted to False.")
|
|
66
67
|
if hasattr(val, "__dict__"): # nested config hierarchy
|
|
67
|
-
params[param] =
|
|
68
|
+
params[param] = config_to_dict(val, descr, _path=f"{_path}{param}.")
|
|
68
69
|
elif not _path: # scalar value in root
|
|
69
70
|
params[main][param] = Value(val, descr.get(param), annotation)
|
|
70
71
|
else: # scalar value in nested
|
|
71
72
|
params[param] = Value(val, descr.get(f"{_path}{param}"), annotation)
|
|
73
|
+
# print(params) # TODO
|
|
72
74
|
return params
|
|
73
75
|
|
|
74
76
|
|
|
@@ -76,34 +78,53 @@ def normalize_types(origin: FormDict, data: dict) -> dict:
|
|
|
76
78
|
""" Run validators of all Value objects. If fails, outputs info.
|
|
77
79
|
Return corrected data. (Ex: Some values might be nulled from "".)
|
|
78
80
|
"""
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
81
|
+
def check(ordict, orkey, orval, dataPos: dict, dataKey, val):
|
|
82
|
+
if isinstance(orval, Value) and orval.annotation:
|
|
83
|
+
if val == "" and type(None) in get_args(orval.annotation):
|
|
84
|
+
# The user is not able to set the value to None, they left it empty.
|
|
85
|
+
# Cast back to None as None is one of the allowed types.
|
|
86
|
+
# Ex: `severity: int | None = None`
|
|
87
|
+
dataPos[dataKey] = val = None
|
|
88
|
+
elif orval.annotation == Optional[int]:
|
|
89
|
+
try:
|
|
90
|
+
dataPos[dataKey] = val = int(val)
|
|
91
|
+
except ValueError:
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
if not isinstance(val, orval.annotation):
|
|
95
|
+
orval.set_error_text(f"Type must be `{orval.annotation}`!")
|
|
96
|
+
raise RuntimeError # revision needed
|
|
97
|
+
|
|
98
|
+
# keep values if revision needed
|
|
99
|
+
# We merge new data to the origin. If form is re-submitted, the values will stay there.
|
|
100
|
+
if isinstance(orval, Value):
|
|
101
|
+
orval.val = val
|
|
102
|
+
else:
|
|
103
|
+
ordict[orkey] = val
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
for (key1, val1), (orkey1, orval1) in zip(data.items(), origin.items()):
|
|
107
|
+
if isinstance(val1, dict): # nested config hierarchy
|
|
108
|
+
# NOTE: This allows only single nested dict.
|
|
109
|
+
for (key2, val2), (orkey2, orval2) in zip(val1.items(), orval1.items()):
|
|
110
|
+
check(orval1, orkey2, orval2, data[key1], key2, val2)
|
|
111
|
+
else:
|
|
112
|
+
check(origin, orkey1, orval1, data, key1, val1)
|
|
113
|
+
except RuntimeError:
|
|
114
|
+
return False
|
|
115
|
+
|
|
96
116
|
return data
|
|
97
117
|
|
|
98
118
|
|
|
99
|
-
def
|
|
100
|
-
"""
|
|
119
|
+
def config_from_dict(args: ConfigInstance, data: dict):
|
|
120
|
+
""" Fetch back data.
|
|
121
|
+
Merge the dict of dicts from the GUI back into the object holding the configuration. """
|
|
101
122
|
for group, params in data.items():
|
|
102
123
|
for key, val in params.items():
|
|
103
124
|
if group:
|
|
104
|
-
setattr(getattr(args, group), key, val)
|
|
125
|
+
setattr(getattr(args, group), key, val.val if isinstance(val, Value) else val)
|
|
105
126
|
else:
|
|
106
|
-
setattr(args, key, val)
|
|
127
|
+
setattr(args, key, val.val if isinstance(val, Value) else val)
|
|
107
128
|
|
|
108
129
|
|
|
109
130
|
def get_terminal_size():
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "mininterface"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "A minimal access to GUI, TUI, CLI and config"
|
|
9
9
|
authors = ["Edvard Rejthar <edvard.rejthar@nic.cz>"]
|
|
10
10
|
license = "GPL-3.0-or-later"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|