mininterface 1.2.0__tar.gz → 1.2.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-1.2.0 → mininterface-1.2.1}/PKG-INFO +1 -1
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/__main__.py +0 -1
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/cli_flags.py +119 -3
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/cli_parser.py +38 -18
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/run.py +2 -12
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/tyro_patches.py +67 -81
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/exceptions.py +16 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/pyproject.toml +1 -1
- {mininterface-1.2.0 → mininterface-1.2.1}/LICENSE +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/README.md +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/__init__.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/__init__.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/argparse_support.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/auxiliary.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/cli_utils.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/config_file.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/dataclass_creation.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/form_dict.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/future_compatibility.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/redirectable.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/shortcuts.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/showcase.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_lib/start.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_mininterface/__init__.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_mininterface/adaptor.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_mininterface/mixin.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_text_interface/__init__.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_text_interface/adaptor.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_text_interface/facet.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_text_interface/timeout.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/__init__.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/adaptor.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/button_contents.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/facet.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/file_picker_input.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/form_contents.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/secret_input.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/style.tcss +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/textual_app.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/timeout.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/widgets.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_tk_interface/__init__.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_tk_interface/adaptor.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_tk_interface/date_entry.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_tk_interface/external_fix.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_tk_interface/facet.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_tk_interface/redirect_text_tkinter.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_tk_interface/secret_entry.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_tk_interface/select_input.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_tk_interface/timeout.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_tk_interface/utils.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_web_interface/__init__.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_web_interface/app.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_web_interface/child_adaptor.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_web_interface/parent_adaptor.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/cli.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/experimental.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/facet/__init__.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/interfaces.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/settings.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/tag/__init__.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/tag/alias.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/tag/callback_tag.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/tag/datetime_tag.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/tag/flag.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/tag/internal.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/tag/path_tag.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/tag/secret_tag.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/tag/select_tag.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/tag/tag.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/tag/tag_factory.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/tag/type_stubs.py +0 -0
- {mininterface-1.2.0 → mininterface-1.2.1}/mininterface/validators.py +0 -0
|
@@ -1,15 +1,22 @@
|
|
|
1
|
-
from
|
|
1
|
+
from argparse import ArgumentParser
|
|
2
2
|
import logging
|
|
3
|
-
|
|
3
|
+
import sys
|
|
4
4
|
from typing import Optional, Sequence
|
|
5
5
|
|
|
6
|
+
from tyro.conf import FlagConversionOff
|
|
7
|
+
|
|
6
8
|
from .form_dict import EnvClass
|
|
7
9
|
|
|
10
|
+
from typing import List, Any, Optional
|
|
11
|
+
|
|
12
|
+
from tyro._fields import FieldDefinition
|
|
13
|
+
from tyro.conf._confstruct import _ArgConfig
|
|
14
|
+
|
|
8
15
|
|
|
9
16
|
class CliFlags:
|
|
10
17
|
|
|
11
18
|
_add_verbose: bool = False
|
|
12
|
-
version:
|
|
19
|
+
version: str = ""
|
|
13
20
|
_add_quiet: bool = False
|
|
14
21
|
|
|
15
22
|
default_verbosity: int = logging.WARNING
|
|
@@ -56,6 +63,17 @@ class CliFlags:
|
|
|
56
63
|
# config
|
|
57
64
|
self.config = add_config
|
|
58
65
|
|
|
66
|
+
self.orig_stream = (
|
|
67
|
+
sys.stderr
|
|
68
|
+
) # NOTE might be removed now. Might be used if we redirect_stderr while setting basicConfig.
|
|
69
|
+
|
|
70
|
+
self.field_list: list[FieldDefinition] = []
|
|
71
|
+
""" List of FieldDefinitions corresponding to the arguments added via this helper"""
|
|
72
|
+
|
|
73
|
+
self.arguments_prepared: list[dict[str, Any]] = []
|
|
74
|
+
self.setup_done = False
|
|
75
|
+
""" Setup might be called multiple times – ex. parsing fails and we call tyro.cli in recursion. """
|
|
76
|
+
|
|
59
77
|
def should_add(self, env_classes: list[EnvClass]) -> bool:
|
|
60
78
|
# Flags are added only if neither the env_class nor any of the subcommands have the same-name flag already
|
|
61
79
|
self._enabled["verbose"] = self._add_verbose and self._attr_not_present("verbose", env_classes)
|
|
@@ -116,3 +134,101 @@ class CliFlags:
|
|
|
116
134
|
seq = self._verbosity_sequence
|
|
117
135
|
log_level = {i + 1: level for i, level in enumerate(seq)}.get(count, logging.NOTSET)
|
|
118
136
|
return log_level
|
|
137
|
+
|
|
138
|
+
def add_typed_argument(
|
|
139
|
+
self,
|
|
140
|
+
prefix: str,
|
|
141
|
+
*aliases: str,
|
|
142
|
+
action: Optional[str] = None,
|
|
143
|
+
default: Any = False,
|
|
144
|
+
helptext: Optional[str] = None,
|
|
145
|
+
metavar: Optional[str] = None,
|
|
146
|
+
version: Optional[str] = None,
|
|
147
|
+
) -> FieldDefinition:
|
|
148
|
+
# Prepare FieldDefinition
|
|
149
|
+
name = aliases[0]
|
|
150
|
+
aliases_ = tuple((prefix * (1 if len(n) == 1 else 2) + n) for n in aliases) if aliases else None
|
|
151
|
+
typ_ = bool if action in ("store_true", "store_false") else int if action == "count" else str
|
|
152
|
+
|
|
153
|
+
field = FieldDefinition(
|
|
154
|
+
intern_name=name,
|
|
155
|
+
extern_name=name,
|
|
156
|
+
type=typ_,
|
|
157
|
+
type_stripped=typ_,
|
|
158
|
+
default=default,
|
|
159
|
+
helptext=helptext,
|
|
160
|
+
markers={FlagConversionOff},
|
|
161
|
+
custom_constructor=False,
|
|
162
|
+
argconf=_ArgConfig(
|
|
163
|
+
name=aliases_[0],
|
|
164
|
+
metavar="",
|
|
165
|
+
help=helptext,
|
|
166
|
+
help_behavior_hint="",
|
|
167
|
+
aliases=aliases_[1:] or None,
|
|
168
|
+
prefix_name=False,
|
|
169
|
+
constructor_factory=None,
|
|
170
|
+
default=default,
|
|
171
|
+
),
|
|
172
|
+
mutex_group=None,
|
|
173
|
+
call_argname=name,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
self.field_list.append(field)
|
|
177
|
+
|
|
178
|
+
# prepare argparse
|
|
179
|
+
self.arguments_prepared.append(
|
|
180
|
+
{
|
|
181
|
+
"field": field,
|
|
182
|
+
"names": aliases_,
|
|
183
|
+
"kwargs": {
|
|
184
|
+
"action": action,
|
|
185
|
+
"default": default,
|
|
186
|
+
"help": helptext,
|
|
187
|
+
"metavar": metavar,
|
|
188
|
+
"version": version,
|
|
189
|
+
},
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
return field
|
|
194
|
+
|
|
195
|
+
def setup(self, parser: ArgumentParser):
|
|
196
|
+
if self.setup_done:
|
|
197
|
+
# tyro.cli might be called multiple times if some missing required fields
|
|
198
|
+
return
|
|
199
|
+
self.setup_done = True
|
|
200
|
+
prefix = "-" if "-" in parser.prefix_chars else parser.prefix_chars[0]
|
|
201
|
+
if self.add_verbose:
|
|
202
|
+
self.add_typed_argument(
|
|
203
|
+
prefix,
|
|
204
|
+
"verbose",
|
|
205
|
+
"v",
|
|
206
|
+
action="count",
|
|
207
|
+
default=0,
|
|
208
|
+
helptext="verbosity level, can be used multiple times to increase",
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
if self.add_version:
|
|
212
|
+
self.add_typed_argument(
|
|
213
|
+
prefix,
|
|
214
|
+
"version",
|
|
215
|
+
action="version",
|
|
216
|
+
version=self.version,
|
|
217
|
+
default="",
|
|
218
|
+
helptext=f"show program's version number ({self.version}) and exit",
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
if self.add_quiet:
|
|
222
|
+
self.add_typed_argument(
|
|
223
|
+
prefix, "quiet", "q", action="store_true", helptext="suppress warnings, display only errors"
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
if self.add_config:
|
|
227
|
+
self.add_typed_argument(
|
|
228
|
+
prefix, "config", helptext=f"path to config file to fetch the defaults from", metavar="PATH"
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
def apply_to_parser(self, parser):
|
|
232
|
+
for item in self.arguments_prepared:
|
|
233
|
+
kwargs = {k: v for k, v in item["kwargs"].items() if v is not None}
|
|
234
|
+
parser.add_argument(*item["names"], **kwargs)
|
|
@@ -11,7 +11,6 @@ from contextlib import ExitStack, redirect_stderr, redirect_stdout
|
|
|
11
11
|
from typing import Annotated, Optional, Sequence, Type, Union
|
|
12
12
|
from unittest.mock import patch
|
|
13
13
|
|
|
14
|
-
from .cli_flags import CliFlags
|
|
15
14
|
|
|
16
15
|
from ..cli import Command
|
|
17
16
|
from ..settings import CliSettings
|
|
@@ -33,10 +32,20 @@ from .dataclass_creation import (
|
|
|
33
32
|
from .form_dict import EnvClass, TagDict, dataclass_to_tagdict, MissingTagValue, dict_added_main
|
|
34
33
|
|
|
35
34
|
try:
|
|
35
|
+
from .cli_flags import CliFlags
|
|
36
36
|
from tyro import cli
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
|
|
38
|
+
try: # tyro >= 0.10
|
|
39
|
+
from tyro import _experimental_options
|
|
40
|
+
|
|
41
|
+
_experimental_options["backend"] = "argparse"
|
|
42
|
+
from tyro._backends._argparse import _SubParsersAction, ArgumentParser
|
|
43
|
+
from tyro._backends._argparse_formatter import TyroArgumentParser
|
|
44
|
+
except ImportError:
|
|
45
|
+
from tyro._argparse import _SubParsersAction, ArgumentParser
|
|
46
|
+
from tyro._argparse_formatter import TyroArgumentParser
|
|
47
|
+
from tyro._parsers import ParserSpecification
|
|
48
|
+
|
|
40
49
|
from tyro.conf import OmitArgPrefixes, OmitSubcommandPrefixes, DisallowNone, FlagCreatePairsOff
|
|
41
50
|
|
|
42
51
|
from .tyro_patches import (
|
|
@@ -45,7 +54,8 @@ try:
|
|
|
45
54
|
custom_init,
|
|
46
55
|
custom_parse_known_args,
|
|
47
56
|
failed_fields,
|
|
48
|
-
|
|
57
|
+
patched__parse_known_args,
|
|
58
|
+
patched__format_help,
|
|
49
59
|
subparser_call,
|
|
50
60
|
argparse_init,
|
|
51
61
|
)
|
|
@@ -183,6 +193,7 @@ def parse_cli(
|
|
|
183
193
|
helponly = False
|
|
184
194
|
try:
|
|
185
195
|
# Why redirect_stdout? Help-text shows the defaults, which also uses the subcommanded-config.
|
|
196
|
+
# TODO maybe new tyro 0.10 will not output to stdout, get rid of the buffer
|
|
186
197
|
with redirect_stdout(buffer):
|
|
187
198
|
try:
|
|
188
199
|
# Standard way.
|
|
@@ -234,16 +245,16 @@ def parse_cli(
|
|
|
234
245
|
kwargs, None if helponly else m, args, type_form, env_classes, _custom_registry, annot, _req_fields
|
|
235
246
|
)
|
|
236
247
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
248
|
+
# Why setting m.env instead of putting into into a constructor of a new get_interface() call?
|
|
249
|
+
# 1. Getting the interface is a costly operation
|
|
250
|
+
# 2. There is this bug so that we need to use single interface:
|
|
251
|
+
# TODO
|
|
252
|
+
# As this works badly, lets make sure we use single interface now
|
|
253
|
+
# and will not need the second one.
|
|
254
|
+
# get_interface("gui")
|
|
255
|
+
# m = get_interface("gui")
|
|
256
|
+
# m.select([1,2,3])
|
|
257
|
+
m.env = env
|
|
247
258
|
except SystemExit as exception:
|
|
248
259
|
# --- (C) The dialog missing section ---
|
|
249
260
|
# Some fields are needed to be filled up.
|
|
@@ -339,8 +350,7 @@ def _apply_patches(cf: Optional[CliFlags], ask_for_missing, env_classes, kwargs)
|
|
|
339
350
|
patches = []
|
|
340
351
|
|
|
341
352
|
patches.append(patch.object(_SubParsersAction, "__call__", subparser_call))
|
|
342
|
-
patches.append(patch.object(TyroArgumentParser, "_parse_known_args",
|
|
343
|
-
|
|
353
|
+
patches.append(patch.object(TyroArgumentParser, "_parse_known_args", patched__parse_known_args))
|
|
344
354
|
kw = {
|
|
345
355
|
k: v for k, v in kwargs.items() if k != "default"
|
|
346
356
|
} # NOTE I might separate kwargs['default'] and do not do this filtering
|
|
@@ -359,6 +369,11 @@ def _apply_patches(cf: Optional[CliFlags], ask_for_missing, env_classes, kwargs)
|
|
|
359
369
|
"__init__",
|
|
360
370
|
custom_init(cf),
|
|
361
371
|
),
|
|
372
|
+
patch.object(
|
|
373
|
+
TyroArgumentParser,
|
|
374
|
+
"format_help",
|
|
375
|
+
patched__format_help(cf),
|
|
376
|
+
),
|
|
362
377
|
patch.object(
|
|
363
378
|
TyroArgumentParser,
|
|
364
379
|
"parse_known_args",
|
|
@@ -486,7 +501,12 @@ def _fetch_currently_failed(requireds) -> TagDict:
|
|
|
486
501
|
missing_req = {}
|
|
487
502
|
for field in failed_fields.get():
|
|
488
503
|
# ex: `_subcommands._nested_subcommands (positional)`
|
|
489
|
-
fname =
|
|
504
|
+
fname = (
|
|
505
|
+
field.dest.replace(" (positional)", "")
|
|
506
|
+
.replace("-", "_")
|
|
507
|
+
.replace("__tyro_dummy_inner__.", "")
|
|
508
|
+
.replace("__tyro_dummy_inner__", "")
|
|
509
|
+
) # `_subcommands._nested_subcommands`
|
|
490
510
|
fname_raw = fname.rsplit(".", 1)[-1] # `_nested_subcommands`
|
|
491
511
|
|
|
492
512
|
if isinstance(field, _SubParsersAction):
|
|
@@ -7,7 +7,7 @@ from typing import Literal, Optional, Sequence, Type
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
from .._mininterface import Mininterface
|
|
10
|
-
from ..exceptions import DependencyRequired, ValidationFail
|
|
10
|
+
from ..exceptions import DependencyRequired, ValidationFail, _debug_wanted
|
|
11
11
|
from ..interfaces import get_interface
|
|
12
12
|
from ..settings import CliSettings, MininterfaceSettings, UiSettings
|
|
13
13
|
from .form_dict import EnvClass
|
|
@@ -332,17 +332,7 @@ def run(
|
|
|
332
332
|
try:
|
|
333
333
|
parse_cli(env_or_list, kwargs, m, cf, ask_for_missing, args, ask_on_empty_cli, cliset)
|
|
334
334
|
except Exception as e:
|
|
335
|
-
|
|
336
|
-
from ast import literal_eval
|
|
337
|
-
|
|
338
|
-
if literal_eval(environ.get("MININTERFACE_DEBUG", "0")):
|
|
339
|
-
import traceback
|
|
340
|
-
|
|
341
|
-
import ipdb
|
|
342
|
-
|
|
343
|
-
traceback.print_exception(e)
|
|
344
|
-
ipdb.post_mortem()
|
|
345
|
-
else:
|
|
335
|
+
if not _debug_wanted(e):
|
|
346
336
|
raise
|
|
347
337
|
|
|
348
338
|
# Command run
|
|
@@ -5,14 +5,22 @@ from collections import deque
|
|
|
5
5
|
from contextvars import ContextVar
|
|
6
6
|
from gettext import gettext as _
|
|
7
7
|
import sys
|
|
8
|
-
from typing import Optional, Callable
|
|
9
8
|
|
|
10
|
-
from tyro import _argparse as argparse
|
|
11
|
-
from tyro._argparse import Action, _SubParsersAction, ArgumentParser
|
|
12
|
-
from tyro._argparse_formatter import TyroArgumentParser
|
|
13
9
|
|
|
14
10
|
from .cli_flags import CliFlags
|
|
15
11
|
|
|
12
|
+
try:
|
|
13
|
+
# tyro >= 0.10
|
|
14
|
+
from tyro._backends._argparse import _get_action_name, SUPPRESS, ArgumentError
|
|
15
|
+
from tyro._backends._argparse import Action, _SubParsersAction, ArgumentParser
|
|
16
|
+
from tyro._backends._argparse_formatter import TyroArgumentParser
|
|
17
|
+
except ImportError:
|
|
18
|
+
from tyro._argparse import _get_action_name, SUPPRESS, ArgumentError
|
|
19
|
+
from tyro._argparse import Action, _SubParsersAction, ArgumentParser
|
|
20
|
+
from tyro._argparse_formatter import TyroArgumentParser
|
|
21
|
+
from tyro import _arguments
|
|
22
|
+
|
|
23
|
+
|
|
16
24
|
failed_fields: ContextVar[list[Action]] = ContextVar("failed_fields", default=[])
|
|
17
25
|
_orig_call = _SubParsersAction.__call__
|
|
18
26
|
_crawling = ContextVar("_crawling", default=deque())
|
|
@@ -25,18 +33,7 @@ _orig_init = ArgumentParser.__init__
|
|
|
25
33
|
#
|
|
26
34
|
# The only line changed: failed_fields
|
|
27
35
|
#
|
|
28
|
-
def
|
|
29
|
-
"""We override _parse_known_args() to improve error messages in the presence of
|
|
30
|
-
subcommands. Difference is marked with <new>...</new> below."""
|
|
31
|
-
|
|
32
|
-
# <new>
|
|
33
|
-
# Reset the unused argument list in the root parser.
|
|
34
|
-
# Subparsers will have spaces in self.prog.
|
|
35
|
-
if " " not in self.prog:
|
|
36
|
-
global global_unrecognized_arg_and_prog
|
|
37
|
-
global_unrecognized_arg_and_prog = []
|
|
38
|
-
# </new>
|
|
39
|
-
|
|
36
|
+
def patched__parse_known_args(self, arg_strings, namespace):
|
|
40
37
|
# replace arg strings that are file references
|
|
41
38
|
if self.fromfile_prefix_chars is not None:
|
|
42
39
|
arg_strings = self._read_args_from_files(arg_strings)
|
|
@@ -58,6 +55,7 @@ def patched_parse_known_args(self, arg_strings, namespace): # type: ignore # p
|
|
|
58
55
|
arg_string_pattern_parts = []
|
|
59
56
|
arg_strings_iter = iter(arg_strings)
|
|
60
57
|
for i, arg_string in enumerate(arg_strings_iter):
|
|
58
|
+
|
|
61
59
|
# all args after -- are non-options
|
|
62
60
|
if arg_string == "--":
|
|
63
61
|
arg_string_pattern_parts.append("-")
|
|
@@ -94,16 +92,17 @@ def patched_parse_known_args(self, arg_strings, namespace): # type: ignore # p
|
|
|
94
92
|
for conflict_action in action_conflicts.get(action, []):
|
|
95
93
|
if conflict_action in seen_non_default_actions:
|
|
96
94
|
msg = _("not allowed with argument %s")
|
|
97
|
-
action_name =
|
|
98
|
-
raise
|
|
95
|
+
action_name = _get_action_name(conflict_action)
|
|
96
|
+
raise ArgumentError(action, msg % action_name)
|
|
99
97
|
|
|
100
98
|
# take the action if we didn't receive a SUPPRESS value
|
|
101
99
|
# (e.g. from a default)
|
|
102
|
-
if argument_values is not
|
|
100
|
+
if argument_values is not SUPPRESS:
|
|
103
101
|
action(self, namespace, argument_values, option_string)
|
|
104
102
|
|
|
105
103
|
# function to convert arg_strings into an optional action
|
|
106
104
|
def consume_optional(start_index):
|
|
105
|
+
|
|
107
106
|
# get the optional identified at this index
|
|
108
107
|
option_tuple = option_string_indices[start_index]
|
|
109
108
|
action, option_string, sep, explicit_arg = option_tuple
|
|
@@ -113,14 +112,9 @@ def patched_parse_known_args(self, arg_strings, namespace): # type: ignore # p
|
|
|
113
112
|
match_argument = self._match_argument
|
|
114
113
|
action_tuples = []
|
|
115
114
|
while True:
|
|
115
|
+
|
|
116
116
|
# if we found no optional action, skip it
|
|
117
117
|
if action is None:
|
|
118
|
-
# <new>
|
|
119
|
-
# Manually track unused arguments to assist with error messages
|
|
120
|
-
# later.
|
|
121
|
-
if not self._parsing_known_args:
|
|
122
|
-
global_unrecognized_arg_and_prog.append((option_string, self.prog))
|
|
123
|
-
# </new>
|
|
124
118
|
extras.append(arg_strings[start_index])
|
|
125
119
|
return start_index + 1
|
|
126
120
|
|
|
@@ -136,7 +130,7 @@ def patched_parse_known_args(self, arg_strings, namespace): # type: ignore # p
|
|
|
136
130
|
if arg_count == 0 and option_string[1] not in chars and explicit_arg != "":
|
|
137
131
|
if sep or explicit_arg[0] in chars:
|
|
138
132
|
msg = _("ignored explicit argument %r")
|
|
139
|
-
raise
|
|
133
|
+
raise ArgumentError(action, msg % explicit_arg)
|
|
140
134
|
action_tuples.append((action, [], option_string))
|
|
141
135
|
char = option_string[0]
|
|
142
136
|
option_string = char + explicit_arg[0]
|
|
@@ -167,7 +161,7 @@ def patched_parse_known_args(self, arg_strings, namespace): # type: ignore # p
|
|
|
167
161
|
# explicit argument
|
|
168
162
|
else:
|
|
169
163
|
msg = _("ignored explicit argument %r")
|
|
170
|
-
raise
|
|
164
|
+
raise ArgumentError(action, msg % explicit_arg)
|
|
171
165
|
|
|
172
166
|
# if there is no explicit argument, try to match the
|
|
173
167
|
# optional's string arguments with the following strings
|
|
@@ -220,6 +214,7 @@ def patched_parse_known_args(self, arg_strings, namespace): # type: ignore # p
|
|
|
220
214
|
else:
|
|
221
215
|
max_option_string_index = -1
|
|
222
216
|
while start_index <= max_option_string_index:
|
|
217
|
+
|
|
223
218
|
# consume any Positionals preceding the next option
|
|
224
219
|
next_option_string_index = min([index for index in option_string_indices if index >= start_index])
|
|
225
220
|
if start_index != next_option_string_index:
|
|
@@ -256,7 +251,7 @@ def patched_parse_known_args(self, arg_strings, namespace): # type: ignore # p
|
|
|
256
251
|
if action not in seen_actions:
|
|
257
252
|
if action.required:
|
|
258
253
|
failed_fields.get().append(action) # WE ADDED THIS LINE
|
|
259
|
-
required_actions.append(
|
|
254
|
+
required_actions.append(_get_action_name(action))
|
|
260
255
|
else:
|
|
261
256
|
# Convert action default now instead of doing it before
|
|
262
257
|
# parsing arguments to avoid calling convert functions
|
|
@@ -268,11 +263,7 @@ def patched_parse_known_args(self, arg_strings, namespace): # type: ignore # p
|
|
|
268
263
|
and hasattr(namespace, action.dest)
|
|
269
264
|
and action.default is getattr(namespace, action.dest)
|
|
270
265
|
):
|
|
271
|
-
setattr(
|
|
272
|
-
namespace,
|
|
273
|
-
action.dest,
|
|
274
|
-
self._get_value(action, action.default),
|
|
275
|
-
)
|
|
266
|
+
setattr(namespace, action.dest, self._get_value(action, action.default))
|
|
276
267
|
|
|
277
268
|
if required_actions:
|
|
278
269
|
self.error(_("the following arguments are required: %s") % ", ".join(required_actions))
|
|
@@ -286,13 +277,9 @@ def patched_parse_known_args(self, arg_strings, namespace): # type: ignore # p
|
|
|
286
277
|
|
|
287
278
|
# if no actions were used, report the error
|
|
288
279
|
else:
|
|
289
|
-
names = [
|
|
290
|
-
argparse._get_action_name(action)
|
|
291
|
-
for action in group._group_actions
|
|
292
|
-
if action.help is not argparse.SUPPRESS
|
|
293
|
-
]
|
|
280
|
+
names = [_get_action_name(action) for action in group._group_actions if action.help is not SUPPRESS]
|
|
294
281
|
msg = _("one of the arguments %s is required")
|
|
295
|
-
self.error(msg % " ".join(names))
|
|
282
|
+
self.error(msg % " ".join(names))
|
|
296
283
|
|
|
297
284
|
# return the updated namespace and the extra arguments
|
|
298
285
|
return namespace, extras
|
|
@@ -314,65 +301,62 @@ def custom_error(self: TyroArgumentParser, message: str):
|
|
|
314
301
|
|
|
315
302
|
|
|
316
303
|
def custom_init(cf: CliFlags):
|
|
304
|
+
orig_init = TyroArgumentParser.__init__
|
|
305
|
+
|
|
317
306
|
def _(self: TyroArgumentParser, *args, **kwargs):
|
|
318
|
-
|
|
319
|
-
default_prefix = "-" if "-" in self.prefix_chars else self.prefix_chars[0]
|
|
320
|
-
if cf.add_verbose:
|
|
321
|
-
self.add_argument(
|
|
322
|
-
default_prefix + "v",
|
|
323
|
-
default_prefix * 2 + "verbose",
|
|
324
|
-
action="count",
|
|
325
|
-
default=0,
|
|
326
|
-
help="verbosity level, can be used multiple times to increase",
|
|
327
|
-
)
|
|
307
|
+
orig_init(self, *args, **kwargs)
|
|
328
308
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
default_prefix * 2 + "version",
|
|
332
|
-
# NOTE We use the native version, but it inserts a blank line
|
|
333
|
-
action="version",
|
|
334
|
-
version=cf.version,
|
|
335
|
-
# Our custom version works bad with subcommands, we have to first resolve subcommands,
|
|
336
|
-
# than it comes to the version
|
|
337
|
-
# action="store_const",
|
|
338
|
-
# const=cf.version,
|
|
339
|
-
help=f"show program's version number ({cf.version}) and exit",
|
|
340
|
-
)
|
|
309
|
+
cf.setup(self)
|
|
310
|
+
cf.apply_to_parser(self)
|
|
341
311
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
help="suppress warnings, display only errors",
|
|
348
|
-
)
|
|
312
|
+
return _
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def patched__format_help(cf: CliFlags):
|
|
316
|
+
orig = TyroArgumentParser.format_help
|
|
349
317
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
318
|
+
def _(self, *args, **kwargs):
|
|
319
|
+
parser_spec = self._parser_specification
|
|
320
|
+
|
|
321
|
+
for field in reversed(cf.field_list):
|
|
322
|
+
field_out = _arguments.ArgumentDefinition(
|
|
323
|
+
intern_prefix=field.intern_name,
|
|
324
|
+
extern_prefix=field.extern_name,
|
|
325
|
+
subcommand_prefix="",
|
|
326
|
+
field=field,
|
|
353
327
|
)
|
|
354
328
|
|
|
329
|
+
parser_spec.args.insert(0, field_out)
|
|
330
|
+
|
|
331
|
+
return orig(self, *args, **kwargs)
|
|
332
|
+
|
|
355
333
|
return _
|
|
356
334
|
|
|
357
335
|
|
|
358
336
|
def custom_parse_known_args(cf: CliFlags):
|
|
337
|
+
orig = TyroArgumentParser.parse_known_args
|
|
338
|
+
|
|
359
339
|
def _(self: TyroArgumentParser, args=None, namespace=None):
|
|
360
|
-
namespace, args =
|
|
340
|
+
namespace, args = orig(self, args, namespace)
|
|
361
341
|
# NOTE We may check that the Env does not have its own `verbose``
|
|
362
342
|
# NOTE I do not like much tests need force=True here as they are run in paralel.
|
|
363
343
|
if cf.add_verbose and hasattr(namespace, "verbose"):
|
|
364
344
|
if namespace.verbose > 0:
|
|
365
|
-
logging.basicConfig(
|
|
345
|
+
logging.basicConfig(
|
|
346
|
+
level=cf.get_log_level(namespace.verbose), format="%(message)s", force=True, stream=cf.orig_stream
|
|
347
|
+
)
|
|
366
348
|
else:
|
|
367
|
-
logging.basicConfig(
|
|
349
|
+
logging.basicConfig(
|
|
350
|
+
level=cf.default_verbosity, format="%(message)s", force=True, stream=cf.orig_stream
|
|
351
|
+
)
|
|
368
352
|
delattr(namespace, "verbose")
|
|
369
353
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
354
|
+
if cf.add_version and hasattr(namespace, "version"):
|
|
355
|
+
# This code is now not used, see `custom_init`
|
|
356
|
+
# if namespace.version:
|
|
357
|
+
# print(namespace.version)
|
|
358
|
+
# raise SystemExit(0)
|
|
359
|
+
delattr(namespace, "version")
|
|
376
360
|
|
|
377
361
|
# Note that we do not parse --config here as it is parsed at `run.py`, before CLI parsing.
|
|
378
362
|
# Since config file serves as default fo CLI parsing.
|
|
@@ -381,7 +365,9 @@ def custom_parse_known_args(cf: CliFlags):
|
|
|
381
365
|
|
|
382
366
|
if cf.add_quiet and hasattr(namespace, "quiet"):
|
|
383
367
|
if namespace.quiet:
|
|
384
|
-
logging.basicConfig(
|
|
368
|
+
logging.basicConfig(
|
|
369
|
+
level=cf.get_log_level(-1), format="%(message)s", force=True, stream=cf.orig_stream
|
|
370
|
+
)
|
|
385
371
|
delattr(namespace, "quiet")
|
|
386
372
|
return namespace, args
|
|
387
373
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Exceptions that might make sense to be used outside the library."""
|
|
2
2
|
|
|
3
|
+
from os import environ as _environ
|
|
4
|
+
|
|
3
5
|
|
|
4
6
|
class Cancelled(SystemExit):
|
|
5
7
|
"""User has cancelled.
|
|
@@ -47,4 +49,18 @@ class DependencyRequired(InterfaceNotAvailable):
|
|
|
47
49
|
|
|
48
50
|
def exit(self):
|
|
49
51
|
"""Wrap the exception in a SystemExit so that the program exits without a traceback."""
|
|
52
|
+
_debug_wanted(self)
|
|
50
53
|
raise SystemExit(self)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _debug_wanted(e: Exception):
|
|
57
|
+
# Undocumented MININTERFACE_DEBUG flag. Note ipdb package requirement.
|
|
58
|
+
from ast import literal_eval
|
|
59
|
+
|
|
60
|
+
if literal_eval(_environ.get("MININTERFACE_DEBUG", "0")):
|
|
61
|
+
import traceback
|
|
62
|
+
import ipdb
|
|
63
|
+
|
|
64
|
+
traceback.print_exception(e)
|
|
65
|
+
ipdb.post_mortem(e)
|
|
66
|
+
return True
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "mininterface"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.1"
|
|
8
8
|
description = "CLI & dialog toolkit – a minimal interface to Python application (GUI, TUI, CLI + config files, web)"
|
|
9
9
|
authors = ["Edvard Rejthar <edvard.rejthar@nic.cz>"]
|
|
10
10
|
license = "LGPL-3.0-or-later"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/button_contents.py
RENAMED
|
File without changes
|
|
File without changes
|
{mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_textual_interface/file_picker_input.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mininterface-1.2.0 → mininterface-1.2.1}/mininterface/_tk_interface/redirect_text_tkinter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|