wizlib 3.0.0__py3-none-any.whl → 3.1.0__py3-none-any.whl

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.

Potentially problematic release.


This version of wizlib might be problematic. Click here for more details.

wizlib/app.py CHANGED
@@ -22,9 +22,15 @@ class WizApp:
22
22
  """Root of all WizLib-based CLI applications. Subclass it. Can be
23
23
  instantiated and then run multiple commands."""
24
24
 
25
- base_command = None
25
+ # Name of this app, used in argparse (override)
26
26
  name = ''
27
27
 
28
+ # Base command class, typically defined in command/__init__.py (override)
29
+ base = None
30
+
31
+ # List of Handler classes used by this app (override)
32
+ handlers = []
33
+
28
34
  # Set some default types so linting works
29
35
  ui: UI
30
36
 
@@ -37,13 +43,10 @@ class WizApp:
37
43
  def start(cls, *args, debug=False):
38
44
  """Call this from a Python entrypoint"""
39
45
  try:
40
- parser = WizParser(prog=cls.name)
41
- for handler in cls.base_command.handlers:
42
- handler.add_args(parser)
43
- ns, more = parser.parse_known_args(args)
44
- app = cls.initialize(**vars(ns))
45
- more = more if more else [cls.base_command.default]
46
- app.run(*more)
46
+ cls.initialize()
47
+ ns = cls.parser.parse_args(args)
48
+ app = cls(**vars(ns))
49
+ app.run(**vars(ns))
47
50
  except AppCancellation as cancellation:
48
51
  if str(cancellation):
49
52
  print(str(cancellation), file=sys.stderr)
@@ -57,38 +60,39 @@ class WizApp:
57
60
  sys.exit(1)
58
61
 
59
62
  @classmethod
60
- def initialize(cls, **vals):
61
- """Converts argparse values (strings) into actual handlers and
62
- instantiates the app"""
63
- handlers = {}
64
- for handler in cls.base_command.handlers:
65
- val = vals[handler.name] if (
66
- handler.name in vals) else handler.default
67
- handlers[handler.name] = handler.setup(val)
68
- return cls(**handlers)
69
-
70
- def __init__(self, **handlers):
71
- for name, handler in handlers.items():
72
- handler.app = self
73
- setattr(self, name, handler)
74
- self.parser = WizParser()
75
- subparsers = self.parser.add_subparsers(dest='command')
76
- for command in self.base_command.family_members('name'):
63
+ def initialize(cls):
64
+ """Set up the parser for the app class"""
65
+ cls.parser = WizParser(prog=cls.name)
66
+ for handler in cls.handlers:
67
+ handler.add_args(cls.parser)
68
+ subparsers = cls.parser.add_subparsers(dest='command')
69
+ for command in cls.base.family_members('name'):
77
70
  key = command.get_member_attr('key')
78
71
  aliases = [key] if key else []
79
72
  subparser = subparsers.add_parser(command.name, aliases=aliases)
80
73
  command.add_args(subparser)
81
74
 
82
- def run(self, *args):
83
- vals = vars(self.parser.parse_args(args))
75
+ def __init__(self, **vals):
76
+ """Create the app. Only interested in the handlers from the parsed
77
+ values passed in"""
78
+ for hcls in self.handlers:
79
+ val = vals[hcls.name] if (hcls.name in vals) else hcls.default
80
+ handler = hcls.setup(val)
81
+ handler.app = self
82
+ setattr(self, hcls.name, handler)
83
+
84
+ def run(self, **vals):
85
+ """Perform a command. May be called more than once. Only interested in
86
+ the command itself and its specific arguments from the values passed
87
+ in."""
84
88
  if 'help' in vals:
85
89
  return WizHelpCommand(**vals)
86
- command_name = vals.pop('command')
87
- command_class = self.base_command.family_member(
88
- 'name', command_name)
89
- if not command_class:
90
- raise Exception(f"Unknown command {command_name}")
91
- command = command_class(self, **vals)
90
+ c = 'command'
91
+ cname = (vals.pop(c) if c in vals else None) or self.base.default
92
+ ccls = self.base.family_member('name', cname)
93
+ if not ccls:
94
+ raise Exception(f"Unknown command {cname}")
95
+ command = ccls(self, **vals)
92
96
  result = command.execute()
93
97
  if result:
94
98
  print(result, end='')
wizlib/command.py CHANGED
@@ -1,3 +1,5 @@
1
+ # Note that commands once used dataclass, but no longer.
2
+
1
3
  from argparse import ArgumentParser
2
4
  from pathlib import Path
3
5
 
@@ -16,8 +18,6 @@ class WizCommand(ClassFamily, SuperWrapper):
16
18
  """Define all the args you want, but stdin always works."""
17
19
 
18
20
  status = ''
19
- handlers = []
20
- ui: UI = None
21
21
 
22
22
  @classmethod
23
23
  def add_args(self, parser):
wizlib/ui/__init__.py CHANGED
@@ -127,12 +127,12 @@ class Chooser(Prompt):
127
127
  self.choices.append(choice)
128
128
 
129
129
  def choice_by_key(self, key):
130
- if key == '\n':
131
- choice = self.default
130
+ if key == '\n' and self.default:
131
+ choice = self.choices[0].value
132
132
  else:
133
133
  choice = next(
134
134
  (o.value for o in self.choices if key in o.keys), None)
135
- return choice() if callable(choice) else choice
135
+ return choice
136
136
 
137
137
  def choices_by_text(self, text):
138
138
  return [o.value for o in self.choices if o.hit_text(text)]
wizlib/ui/shell_ui.py CHANGED
@@ -3,7 +3,6 @@ import sys
3
3
 
4
4
  from readchar import readkey
5
5
 
6
- from wizlib.rlinput import rlinput
7
6
  from wizlib.ui import UI, Chooser, Emphasis
8
7
  from wizlib.ui.shell.line_editor import ShellLineEditor
9
8
  from wizlib.ui.shell import S
@@ -54,7 +53,7 @@ class ShellUI(UI):
54
53
  self.send(out, emphasis=emphasis)
55
54
  if choice is not None:
56
55
  break
57
- return choice
56
+ return choice() if callable(choice) else choice
58
57
 
59
58
  def get_text(self, prompt='', choices=[], default=''):
60
59
  """Allow the user to input an arbitrary line of text, with possible tab
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wizlib
3
- Version: 3.0.0
3
+ Version: 3.1.0
4
4
  Summary: Framework for flexible and powerful command-line applications
5
5
  License: MIT
6
6
  Author: Steampunk Wizard
@@ -1,20 +1,19 @@
1
1
  wizlib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- wizlib/app.py,sha256=O5126FXF2_JSGlHycMv3-ec7EfYI875wzuYsDrxq5ZI,3263
2
+ wizlib/app.py,sha256=Sb35ib0UzB-84l9JRjAkBbOhpHekUbiJcNL7Gkr35Pg,3350
3
3
  wizlib/class_family.py,sha256=tORSVAaPeWTQMcz2DX-MQClj1GQR3vCmkALPXxHa_pk,4506
4
- wizlib/command.py,sha256=aiDYMBXuhKTwPN5xdv_qOrvxvXGibLnqxwQgW0aUVQo,1686
4
+ wizlib/command.py,sha256=NO1558EYuXxfkpSmX6ljjzae8n8g4w6yytZKTJtigvo,1708
5
5
  wizlib/config_handler.py,sha256=hoDavSMiGM_7PAHI8XIwC8nxPWOZDk302ryyjluoLGg,2588
6
6
  wizlib/error.py,sha256=ypwdMOYhtgKWd48ccfOX8idmCXmm-Skwx3gkPwqJB3c,46
7
7
  wizlib/handler.py,sha256=Oz80aPhDyeY9tdppZ1dvtN-19JU5ydEDVW6jtppVoD4,446
8
8
  wizlib/parser.py,sha256=O34azN4ttVfwwAsza0hujxGxDpzc4xUEVAf26DXJS5g,1505
9
- wizlib/rlinput.py,sha256=l00Pa3rxNeY6LJgz8Aws_rTKoEchw33fuL8yqHF9_-o,1754
10
9
  wizlib/stream_handler.py,sha256=i1EgcBrDiYhFK-CI8At7JtUtMCNunJmSkJLSlili-as,663
11
10
  wizlib/super_wrapper.py,sha256=F834ytHqA7zegTD1ezk_uxlF9PLygh84wReuiqcI7BI,272
12
- wizlib/ui/__init__.py,sha256=JIFBvlqPpHyU6hnyXoherf9va1_ynFuDKlMnJn1SCm8,4249
11
+ wizlib/ui/__init__.py,sha256=ve_p_g4aBujh4jIJMgKkJ6cE5PT0aeY5AgRlneDswGg,4241
13
12
  wizlib/ui/shell/__init__.py,sha256=sPrYe4bG_Xf7Nwssx_dqXVk9jeyYBFUjh4oLdlSOeRY,943
14
13
  wizlib/ui/shell/line_editor.py,sha256=frpsqU5NggcvEz3XeB8YyqgmlExlyx6K1CKPzvARtPk,7419
15
- wizlib/ui/shell_ui.py,sha256=qg7DRAYTkkIfe7BKCfclcaupA42YaAk2expIV1fSm40,2030
14
+ wizlib/ui/shell_ui.py,sha256=f2GErMJg09GPZDS4uK0q8Qq8WEssQFP1dqQyg4ycznI,2029
16
15
  wizlib/ui_handler.py,sha256=JoZadtw9DKAtGvHKP3_BJF2NaYqmcQYNdsY4PeRnOjg,634
17
16
  wizlib/util.py,sha256=x1SyL3iXot0ET2r8Jjb2ySTd_J-3Uu7J1b_CHvFgzew,156
18
- wizlib-3.0.0.dist-info/METADATA,sha256=t1ESltdsHBUdEP5dp4WR4VnWcYVxfLfPwULW57KPQRA,1780
19
- wizlib-3.0.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
20
- wizlib-3.0.0.dist-info/RECORD,,
17
+ wizlib-3.1.0.dist-info/METADATA,sha256=9xX6eax7rHG8yulshf0MVGfNYLLbmxFsmx-JO9ddTW0,1780
18
+ wizlib-3.1.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
19
+ wizlib-3.1.0.dist-info/RECORD,,
wizlib/rlinput.py DELETED
@@ -1,71 +0,0 @@
1
- try: # pragma: nocover
2
- import gnureadline as readline
3
- except ImportError: # pragma: nocover
4
- import readline
5
- import sys
6
-
7
-
8
- # Use tab for completion
9
- readline.parse_and_bind('tab: complete')
10
-
11
- # Only a space separates words
12
- readline.set_completer_delims(' ')
13
-
14
-
15
- # Readline defaults to complete with local filenames. Definitely not what we
16
- # want.
17
-
18
- def null_complete(text, start): # pragma: nocover
19
- return None
20
-
21
-
22
- readline.set_completer(null_complete)
23
-
24
-
25
- def rlinput(prompt: str = "", default: str = "",
26
- options: list = None): # pragma: nocover
27
- """
28
- Get input with preset default and/or tab completion of options
29
-
30
- Parameters:
31
-
32
- prompt:str - string to output before requesting input, same as in the
33
- input() function
34
-
35
- default:str - value with which to prepopulate the response, can be cleared
36
- with ctrl-a, ctrl-k
37
-
38
- options:list - list of choices for tab completion
39
- """
40
-
41
- # Clean out the options
42
- options = [o.strip() + " " for o in options] if options else []
43
-
44
- # Create the completer using the options
45
- def complete(text, state):
46
- results = [x for x in options if x.startswith(text)] + [None]
47
- return results[state]
48
- readline.set_completer(complete)
49
-
50
- # Insert the default when we launch
51
- def start():
52
- readline.insert_text(default)
53
- readline.set_startup_hook(start)
54
-
55
- # Actually perform the input
56
- try:
57
- value = input(prompt)
58
- finally:
59
- readline.set_startup_hook()
60
- readline.set_completer(null_complete)
61
- return value.strip()
62
-
63
-
64
- def tryit(): # pragma: nocover
65
- """Quick and dirty tester function"""
66
- return rlinput(prompt='>',
67
- options=['a-b', 'a-c', 'b-a'])
68
-
69
-
70
- if __name__ == '__main__':
71
- tryit()
File without changes