wizlib 3.0.1__tar.gz → 3.1.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.
Potentially problematic release.
This version of wizlib might be problematic. Click here for more details.
- {wizlib-3.0.1 → wizlib-3.1.1}/PKG-INFO +1 -1
- {wizlib-3.0.1 → wizlib-3.1.1}/pyproject.toml +1 -1
- wizlib-3.1.1/wizlib/app.py +112 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/command.py +0 -1
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/parser.py +2 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/ui/shell_ui.py +0 -1
- wizlib-3.0.1/wizlib/app.py +0 -98
- wizlib-3.0.1/wizlib/rlinput.py +0 -71
- {wizlib-3.0.1 → wizlib-3.1.1}/README.md +0 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/__init__.py +0 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/class_family.py +0 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/config_handler.py +0 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/error.py +0 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/handler.py +0 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/stream_handler.py +0 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/super_wrapper.py +0 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/ui/__init__.py +0 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/ui/shell/__init__.py +0 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/ui/shell/line_editor.py +0 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/ui_handler.py +0 -0
- {wizlib-3.0.1 → wizlib-3.1.1}/wizlib/util.py +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from argparse import ArgumentError
|
|
2
|
+
import sys
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from wizlib.class_family import ClassFamily
|
|
8
|
+
from wizlib.command import WizHelpCommand
|
|
9
|
+
from wizlib.super_wrapper import SuperWrapper
|
|
10
|
+
from wizlib.parser import WizArgumentError, WizParser
|
|
11
|
+
from wizlib.ui import UI
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
RED = '\033[91m'
|
|
15
|
+
RESET = '\033[0m'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AppCancellation(BaseException):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class WizApp:
|
|
23
|
+
"""Root of all WizLib-based CLI applications. Subclass it. Can be
|
|
24
|
+
instantiated and then run multiple commands."""
|
|
25
|
+
|
|
26
|
+
# Name of this app, used in argparse (override)
|
|
27
|
+
name = ''
|
|
28
|
+
|
|
29
|
+
# Base command class, typically defined in command/__init__.py (override)
|
|
30
|
+
base = None
|
|
31
|
+
|
|
32
|
+
# List of Handler classes used by this app (override)
|
|
33
|
+
handlers = []
|
|
34
|
+
|
|
35
|
+
# Set some default types so linting works
|
|
36
|
+
ui: UI
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def main(cls): # pragma: nocover
|
|
40
|
+
"""Call this from a __main__ entrypoint"""
|
|
41
|
+
cls.start(*sys.argv[1:], debug=os.getenv('DEBUG'))
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
def start(cls, *args, debug=False):
|
|
45
|
+
"""Call this from a Python entrypoint"""
|
|
46
|
+
try:
|
|
47
|
+
cls.initialize()
|
|
48
|
+
try:
|
|
49
|
+
ns = cls.parser.parse_args(args)
|
|
50
|
+
if (ns.command is None) and (not hasattr(ns, 'help')):
|
|
51
|
+
ns = cls.dparser.parse_args(args)
|
|
52
|
+
except ArgumentError as e:
|
|
53
|
+
ns = cls.dparser.parse_args(args)
|
|
54
|
+
app = cls(**vars(ns))
|
|
55
|
+
app.run(**vars(ns))
|
|
56
|
+
except AppCancellation as cancellation:
|
|
57
|
+
if str(cancellation):
|
|
58
|
+
print(str(cancellation), file=sys.stderr)
|
|
59
|
+
except BaseException as error:
|
|
60
|
+
if debug:
|
|
61
|
+
raise error
|
|
62
|
+
else:
|
|
63
|
+
name = type(error).__name__
|
|
64
|
+
print(f"\n{RED}{name}{': ' if str(error) else ''}" +
|
|
65
|
+
f"{error}{RESET}", file=sys.stderr)
|
|
66
|
+
sys.exit(1)
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def initialize(cls):
|
|
70
|
+
"""Set up the parser for the app class"""
|
|
71
|
+
cls.parser = WizParser(prog=cls.name)
|
|
72
|
+
subparsers = cls.parser.add_subparsers(dest='command')
|
|
73
|
+
for command in cls.base.family_members('name'):
|
|
74
|
+
key = command.get_member_attr('key')
|
|
75
|
+
aliases = [key] if key else []
|
|
76
|
+
subparser = subparsers.add_parser(command.name, aliases=aliases)
|
|
77
|
+
if command.name == cls.base.default:
|
|
78
|
+
cls.dparser = subparser
|
|
79
|
+
command.add_args(subparser)
|
|
80
|
+
for handler in cls.handlers:
|
|
81
|
+
handler.add_args(cls.parser)
|
|
82
|
+
handler.add_args(cls.dparser)
|
|
83
|
+
|
|
84
|
+
def __init__(self, **vals):
|
|
85
|
+
"""Create the app. Only interested in the handlers from the parsed
|
|
86
|
+
values passed in"""
|
|
87
|
+
for hcls in self.handlers:
|
|
88
|
+
val = vals[hcls.name] if (hcls.name in vals) else hcls.default
|
|
89
|
+
handler = hcls.setup(val)
|
|
90
|
+
handler.app = self
|
|
91
|
+
setattr(self, hcls.name, handler)
|
|
92
|
+
|
|
93
|
+
def run(self, **vals):
|
|
94
|
+
"""Perform a command. May be called more than once. Only interested in
|
|
95
|
+
the command itself and its specific arguments from the values passed
|
|
96
|
+
in."""
|
|
97
|
+
if 'help' in vals:
|
|
98
|
+
ccls = WizHelpCommand
|
|
99
|
+
else:
|
|
100
|
+
c = 'command'
|
|
101
|
+
cname = (vals.pop(c) if c in vals else None) or self.base.default
|
|
102
|
+
ccls = self.base.family_member('name', cname)
|
|
103
|
+
if not ccls:
|
|
104
|
+
raise Exception(f"Unknown command {cname}")
|
|
105
|
+
command = ccls(self, **vals)
|
|
106
|
+
result = command.execute()
|
|
107
|
+
if result:
|
|
108
|
+
print(result, end='')
|
|
109
|
+
if sys.stdout.isatty(): # pragma: nocover
|
|
110
|
+
print()
|
|
111
|
+
if command.status:
|
|
112
|
+
print(command.status, file=sys.stderr)
|
wizlib-3.0.1/wizlib/app.py
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
from dataclasses import dataclass
|
|
3
|
-
import os
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
from wizlib.class_family import ClassFamily
|
|
7
|
-
from wizlib.command import WizHelpCommand
|
|
8
|
-
from wizlib.super_wrapper import SuperWrapper
|
|
9
|
-
from wizlib.parser import WizParser
|
|
10
|
-
from wizlib.ui import UI
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
RED = '\033[91m'
|
|
14
|
-
RESET = '\033[0m'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class AppCancellation(BaseException):
|
|
18
|
-
pass
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class WizApp:
|
|
22
|
-
"""Root of all WizLib-based CLI applications. Subclass it. Can be
|
|
23
|
-
instantiated and then run multiple commands."""
|
|
24
|
-
|
|
25
|
-
base_command = None
|
|
26
|
-
name = ''
|
|
27
|
-
|
|
28
|
-
# Set some default types so linting works
|
|
29
|
-
ui: UI
|
|
30
|
-
|
|
31
|
-
@classmethod
|
|
32
|
-
def main(cls): # pragma: nocover
|
|
33
|
-
"""Call this from a __main__ entrypoint"""
|
|
34
|
-
cls.start(*sys.argv[1:], debug=os.getenv('DEBUG'))
|
|
35
|
-
|
|
36
|
-
@classmethod
|
|
37
|
-
def start(cls, *args, debug=False):
|
|
38
|
-
"""Call this from a Python entrypoint"""
|
|
39
|
-
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)
|
|
47
|
-
except AppCancellation as cancellation:
|
|
48
|
-
if str(cancellation):
|
|
49
|
-
print(str(cancellation), file=sys.stderr)
|
|
50
|
-
except BaseException as error:
|
|
51
|
-
if debug:
|
|
52
|
-
raise error
|
|
53
|
-
else:
|
|
54
|
-
name = type(error).__name__
|
|
55
|
-
print(f"\n{RED}{name}{': ' if str(error) else ''}" +
|
|
56
|
-
f"{error}{RESET}", file=sys.stderr)
|
|
57
|
-
sys.exit(1)
|
|
58
|
-
|
|
59
|
-
@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'):
|
|
77
|
-
key = command.get_member_attr('key')
|
|
78
|
-
aliases = [key] if key else []
|
|
79
|
-
subparser = subparsers.add_parser(command.name, aliases=aliases)
|
|
80
|
-
command.add_args(subparser)
|
|
81
|
-
|
|
82
|
-
def run(self, *args):
|
|
83
|
-
vals = vars(self.parser.parse_args(args))
|
|
84
|
-
if 'help' in vals:
|
|
85
|
-
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)
|
|
92
|
-
result = command.execute()
|
|
93
|
-
if result:
|
|
94
|
-
print(result, end='')
|
|
95
|
-
if sys.stdout.isatty(): # pragma: nocover
|
|
96
|
-
print()
|
|
97
|
-
if command.status:
|
|
98
|
-
print(command.status, file=sys.stderr)
|
wizlib-3.0.1/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
|
|
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
|