mininterface 1.0.0a1__tar.gz → 1.0.2__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.
Files changed (61) hide show
  1. {mininterface-1.0.0a1 → mininterface-1.0.2}/PKG-INFO +4 -4
  2. {mininterface-1.0.0a1 → mininterface-1.0.2}/README.md +3 -3
  3. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/__init__.py +1 -1
  4. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_mininterface/__init__.py +2 -2
  5. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_text_interface/adaptor.py +10 -6
  6. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_tk_interface/__init__.py +5 -5
  7. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/tag/path_tag.py +6 -12
  8. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/tag/select_tag.py +2 -4
  9. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/tag/tag.py +7 -11
  10. {mininterface-1.0.0a1 → mininterface-1.0.2}/pyproject.toml +1 -1
  11. {mininterface-1.0.0a1 → mininterface-1.0.2}/LICENSE +0 -0
  12. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/__main__.py +0 -0
  13. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_lib/__init__.py +0 -0
  14. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_lib/auxiliary.py +0 -0
  15. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_lib/cli_parser.py +0 -0
  16. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_lib/form_dict.py +0 -0
  17. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_lib/redirectable.py +0 -0
  18. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_lib/showcase.py +0 -0
  19. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_lib/start.py +0 -0
  20. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_mininterface/adaptor.py +0 -0
  21. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_mininterface/mixin.py +0 -0
  22. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_text_interface/__init__.py +0 -0
  23. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_text_interface/facet.py +0 -0
  24. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_textual_interface/__init__.py +0 -0
  25. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_textual_interface/adaptor.py +0 -0
  26. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_textual_interface/button_contents.py +0 -0
  27. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_textual_interface/facet.py +0 -0
  28. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_textual_interface/file_picker_input.py +0 -0
  29. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_textual_interface/form_contents.py +0 -0
  30. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_textual_interface/secret_input.py +0 -0
  31. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_textual_interface/style.tcss +0 -0
  32. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_textual_interface/textual_app.py +0 -0
  33. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_textual_interface/widgets.py +0 -0
  34. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_tk_interface/adaptor.py +0 -0
  35. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_tk_interface/date_entry.py +0 -0
  36. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_tk_interface/external_fix.py +0 -0
  37. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_tk_interface/facet.py +0 -0
  38. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_tk_interface/redirect_text_tkinter.py +0 -0
  39. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_tk_interface/secret_entry.py +0 -0
  40. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_tk_interface/select_input.py +0 -0
  41. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_tk_interface/utils.py +0 -0
  42. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_web_interface/__init__.py +0 -0
  43. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_web_interface/app.py +0 -0
  44. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_web_interface/child_adaptor.py +0 -0
  45. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/_web_interface/parent_adaptor.py +0 -0
  46. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/cli.py +0 -0
  47. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/exceptions.py +0 -0
  48. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/experimental.py +0 -0
  49. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/facet/__init__.py +0 -0
  50. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/interfaces.py +0 -0
  51. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/settings.py +0 -0
  52. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/tag/__init__.py +0 -0
  53. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/tag/alias.py +0 -0
  54. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/tag/callback_tag.py +0 -0
  55. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/tag/datetime_tag.py +0 -0
  56. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/tag/flag.py +0 -0
  57. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/tag/internal.py +0 -0
  58. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/tag/secret_tag.py +0 -0
  59. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/tag/tag_factory.py +0 -0
  60. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/tag/type_stubs.py +0 -0
  61. {mininterface-1.0.0a1 → mininterface-1.0.2}/mininterface/validators.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mininterface
3
- Version: 1.0.0a1
3
+ Version: 1.0.2
4
4
  Summary: A minimal access to GUI, TUI, CLI and config
5
5
  License: LGPL-3.0-or-later
6
6
  Author: Edvard Rejthar
@@ -165,7 +165,7 @@ There are various bundles. We mark the least permissive licence in the bundle.
165
165
  Apart from the minimal bundle (which lacks CLI and dataclass support), they have the same functionality, differring only in the user experience.
166
166
 
167
167
  !!! tip
168
- For automated testing (e.g., in CI environments), the `mininterface[basic]` bundle is sufficient.
168
+ For automated testing (e.g., in CI environments), the `mininterface[basic]` bundle is sufficient.
169
169
 
170
170
  ## MacOS GUI
171
171
 
@@ -188,7 +188,7 @@ Take a look at the following example.
188
188
 
189
189
  1. We define any Env class.
190
190
  2. Then, we initialize mininterface with [`run(Env)`][mininterface.run] – the missing fields will be prompter for
191
- 3. Then, we use various dialog methods, like [`confirm`][mininterface.Mininterface.confirm], [`choice`][mininterface.Mininterface.select] or [`form`][mininterface.Mininterface.form].
191
+ 3. Then, we use various dialog methods, like [`confirm`][mininterface.Mininterface.confirm], [`select`][mininterface.Mininterface.select] or [`form`][mininterface.Mininterface.form].
192
192
 
193
193
  Below, you find the screenshots how the program looks in various environments ([graphic](Interfaces.md#guiinterface-or-tkinterface-or-gui) interface, [web](Interfaces.md#webinterface-or-web) interface...).
194
194
 
@@ -216,7 +216,7 @@ if __name__ == "__main__":
216
216
  # like `confirm` for bool
217
217
  if m.confirm("Do you want to continue?"):
218
218
 
219
- # or `choice` for choosing a value
219
+ # or `select` for choosing a value
220
220
  fruit = m.select(("apple", "banana", "sirup"), "Choose a fruit")
221
221
 
222
222
  if fruit == "apple":
@@ -127,7 +127,7 @@ There are various bundles. We mark the least permissive licence in the bundle.
127
127
  Apart from the minimal bundle (which lacks CLI and dataclass support), they have the same functionality, differring only in the user experience.
128
128
 
129
129
  !!! tip
130
- For automated testing (e.g., in CI environments), the `mininterface[basic]` bundle is sufficient.
130
+ For automated testing (e.g., in CI environments), the `mininterface[basic]` bundle is sufficient.
131
131
 
132
132
  ## MacOS GUI
133
133
 
@@ -150,7 +150,7 @@ Take a look at the following example.
150
150
 
151
151
  1. We define any Env class.
152
152
  2. Then, we initialize mininterface with [`run(Env)`][mininterface.run] – the missing fields will be prompter for
153
- 3. Then, we use various dialog methods, like [`confirm`][mininterface.Mininterface.confirm], [`choice`][mininterface.Mininterface.select] or [`form`][mininterface.Mininterface.form].
153
+ 3. Then, we use various dialog methods, like [`confirm`][mininterface.Mininterface.confirm], [`select`][mininterface.Mininterface.select] or [`form`][mininterface.Mininterface.form].
154
154
 
155
155
  Below, you find the screenshots how the program looks in various environments ([graphic](Interfaces.md#guiinterface-or-tkinterface-or-gui) interface, [web](Interfaces.md#webinterface-or-web) interface...).
156
156
 
@@ -178,7 +178,7 @@ if __name__ == "__main__":
178
178
  # like `confirm` for bool
179
179
  if m.confirm("Do you want to continue?"):
180
180
 
181
- # or `choice` for choosing a value
181
+ # or `select` for choosing a value
182
182
  fruit = m.select(("apple", "banana", "sirup"), "Choose a fruit")
183
183
 
184
184
  if fruit == "apple":
@@ -244,5 +244,5 @@ def run(env_or_list: Type[EnvClass] | list[Type[EnvClass]] | ArgumentParser | No
244
244
 
245
245
 
246
246
  __all__ = ["run", "Mininterface", "Tag",
247
- "InterfaceNotAvailable", "Cancelled",
247
+ "Cancelled",
248
248
  "Validation", "Options"]
@@ -37,10 +37,10 @@ class Mininterface(Generic[EnvClass]):
37
37
  or you can create [one](Interfaces.md) directly (without benefiting from the CLI parsing).
38
38
 
39
39
  Raise:
40
- [Cancelled][mininterface.exceptions.Cancelled]: A SystemExit based exception noting that the program exits without a traceback, ex. if user hits the escape.
40
+ [Cancelled][mininterface.exceptions.Cancelled]: A `SystemExit` based exception noting that the program exits without a traceback, ex. if user hits the escape.
41
41
 
42
42
  Raise:
43
- [InterfaceNotAvailable][mininterface.exceptions.InterfaceNotAvailable]: Interface failed to init, ex. display not available in GUI.
43
+ [InterfaceNotAvailable][mininterface.exceptions.InterfaceNotAvailable]: Interface failed to init, ex. display not available in GUI. You don't have to check for it when invoking an interface through safe methods [`run`][mininterface.run] or [`get_interface`][mininterface.interfaces.get_interface].
44
44
  """
45
45
  # This base interface does not require any user input and hence is suitable for headless testing.
46
46
 
@@ -1,18 +1,22 @@
1
1
  import warnings
2
2
 
3
- from simple_term_menu import TerminalMenu
4
-
5
- from ..tag.select_tag import SelectTag
3
+ try:
4
+ # NOTE does not work in Win, we should find a replacement
5
+ # https://github.com/IngoMeyer441/simple-term-menu/issues/5
6
+ from simple_term_menu import TerminalMenu
7
+ except ImportError:
8
+ from ..exceptions import InterfaceNotAvailable
9
+ raise InterfaceNotAvailable
6
10
 
7
11
  from .._lib.auxiliary import flatten
8
- from ..exceptions import Cancelled
9
12
  from .._lib.form_dict import TagDict
10
13
  from .._mininterface import Tag
11
14
  from .._mininterface.adaptor import BackendAdaptor
15
+ from ..exceptions import Cancelled
12
16
  from ..settings import TextSettings
13
- from ..tag.internal import (BoolWidget, CallbackButtonWidget,
14
- SubmitButtonWidget)
17
+ from ..tag.internal import BoolWidget, CallbackButtonWidget, SubmitButtonWidget
15
18
  from ..tag.secret_tag import SecretTag
19
+ from ..tag.select_tag import SelectTag
16
20
  from .facet import TextFacet
17
21
 
18
22
 
@@ -1,4 +1,4 @@
1
- from typing import Type
1
+ from typing import Iterable, Type
2
2
 
3
3
  try:
4
4
  # It seems tkinter is installed either by default or not installable at all.
@@ -10,7 +10,7 @@ except ImportError:
10
10
 
11
11
  from ..exceptions import InterfaceNotAvailable
12
12
 
13
- from .._mininterface import EnvClass, Mininterface, TagValue
13
+ from .._mininterface import EnvClass, Mininterface, TagValue, ValidationCallback
14
14
  from .._mininterface.mixin import RichUiMixin
15
15
  from ..tag import Tag
16
16
  from ..settings import GuiSettings
@@ -33,8 +33,8 @@ class TkInterface(Redirectable, RichUiMixin, Mininterface):
33
33
  # The window must disappear completely. Otherwise an empty trailing window would appear in the case another TkInterface would start.
34
34
  self._adaptor.destroy()
35
35
 
36
- def ask(self, text: str, annotation: Type[TagValue] | Tag = str) -> TagValue:
37
- if annotation is int:
36
+ def ask(self, text: str, annotation: Type[TagValue] | Tag = str, validation: Iterable[ValidationCallback] | ValidationCallback | None = None) -> TagValue:
37
+ if annotation is int and validation is None:
38
38
  # without 0, tkinter_form would create a mere text Entry
39
39
  return self.form({text: 0})[text]
40
- return super().ask(text, annotation)
40
+ return super().ask(text, annotation, validation)
@@ -82,8 +82,7 @@ class PathTag(Tag[Path | list[Path] | TagValue]):
82
82
  value = super()._validate(value)
83
83
  # Check for multiple paths before any conversion
84
84
  if not self.multiple and isinstance(value, (list, tuple)):
85
- self.set_error_text("Multiple paths are not allowed")
86
- raise ValueError()
85
+ raise ValueError("Multiple paths are not allowed")
87
86
  # Convert to list for validation
88
87
  paths = value if isinstance(value, list) else [value]
89
88
 
@@ -93,23 +92,18 @@ class PathTag(Tag[Path | list[Path] | TagValue]):
93
92
  try:
94
93
  path = Path(path)
95
94
  except Exception:
96
- self.set_error_text(f"Invalid path format: {path}")
97
- raise ValueError()
95
+ raise ValueError(f"Invalid path format: {path}")
98
96
 
99
97
  if self.exist and not path.exists():
100
- self.set_error_text(f"Path does not exist: {path}")
101
- raise ValueError()
98
+ raise ValueError(f"Path does not exist: {path}")
102
99
 
103
100
  if self.is_dir and self.is_file:
104
- self.set_error_text(f"Path cannot be both a file and a directory: {path}")
105
- raise ValueError()
101
+ raise ValueError(f"Path cannot be both a file and a directory: {path}")
106
102
 
107
103
  if self.is_dir and not path.is_dir():
108
- self.set_error_text(f"Path is not a directory: {path}")
109
- raise ValueError()
104
+ raise ValueError(f"Path is not a directory: {path}")
110
105
 
111
106
  if self.is_file and not path.is_file():
112
- self.set_error_text(f"Path is not a file: {path}")
113
- raise ValueError()
107
+ raise ValueError(f"Path is not a file: {path}")
114
108
 
115
109
  return value
@@ -312,11 +312,9 @@ class SelectTag(Tag[TagValue]):
312
312
  if all(v in vals for v in out_value):
313
313
  return out_value
314
314
  else:
315
- self.set_error_text(f"A value is not one of the allowed")
316
- raise ValueError
315
+ raise ValueError(f"A value is not one of the options")
317
316
  else:
318
317
  if out_value in vals:
319
318
  return out_value
320
319
  else:
321
- self.set_error_text(f"Not one of the allowed values")
322
- raise ValueError
320
+ raise ValueError(f"Not one of the allowed values")
@@ -749,8 +749,7 @@ class Tag(Generic[TagValue]):
749
749
  # Ex. putting "2.0" into an int.
750
750
  # It would generate type problem later here in the method,
751
751
  # but even now comparison failed Ex. TypeError("2.0" > 0)
752
- self.set_error_text(f"Type must be {self._repr_annotation()}!")
753
- raise ValueError
752
+ raise ValueError(f"Type must be {self._repr_annotation()}!")
754
753
  else:
755
754
  res = vald(self)
756
755
  if isinstance(res, tuple):
@@ -760,16 +759,14 @@ class Tag(Generic[TagValue]):
760
759
  passed = res
761
760
  self.val = last
762
761
  if passed is not True: # we did not pass, there might be an error message in passed
763
- self.set_error_text(passed or f"Validation fail")
764
- raise ValueError
762
+ raise ValueError(passed or f"Validation fail")
765
763
 
766
764
  # pydantic_check
767
765
  if self._pydantic_field:
768
766
  try:
769
767
  create_model('ValidationModel', check=(self.annotation, self._pydantic_field))(check=out_value)
770
768
  except PydanticValidationError as e:
771
- self.set_error_text(e.errors()[0]["msg"])
772
- raise ValueError
769
+ raise ValueError(e.errors()[0]["msg"])
773
770
  # attrs check
774
771
  if self._attrs_field:
775
772
  try:
@@ -778,13 +775,11 @@ class Tag(Generic[TagValue]):
778
775
  {"check": attr.ib(validator=self._attrs_field.validator)}
779
776
  )(check=out_value)
780
777
  except ValueError as e:
781
- self.set_error_text(str(e))
782
- raise
778
+ raise ValueError(str(e))
783
779
 
784
780
  # Type check
785
781
  if not self._is_right_instance(out_value):
786
- self.set_error_text(f"Type must be {self._repr_annotation()}!")
787
- raise ValueError
782
+ raise ValueError(f"Type must be {self._repr_annotation()}!")
788
783
 
789
784
  return out_value
790
785
 
@@ -870,7 +865,8 @@ class Tag(Generic[TagValue]):
870
865
  # User and type validation check
871
866
  try:
872
867
  self.val = self._validate(out_value) # checks succeeded, confirm the value
873
- except ValueError:
868
+ except ValueError as e:
869
+ self.set_error_text(str(e))
874
870
  return False
875
871
  self._update_source(out_value)
876
872
  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.0.0-alpha.1"
7
+ version = "1.0.2"
8
8
  description = "A minimal access to GUI, TUI, CLI and config"
9
9
  authors = ["Edvard Rejthar <edvard.rejthar@nic.cz>"]
10
10
  license = "LGPL-3.0-or-later"
File without changes