xkits-command 0.2__tar.gz → 0.3__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.
- {xkits_command-0.2 → xkits_command-0.3}/PKG-INFO +2 -2
- {xkits_command-0.2 → xkits_command-0.3}/setup.py +17 -3
- {xkits_command-0.2 → xkits_command-0.3}/xkits_command/actuator.py +28 -28
- {xkits_command-0.2 → xkits_command-0.3}/xkits_command/attribute.py +2 -2
- {xkits_command-0.2 → xkits_command-0.3}/xkits_command/parser.py +17 -19
- {xkits_command-0.2 → xkits_command-0.3}/xkits_command.egg-info/PKG-INFO +2 -2
- {xkits_command-0.2 → xkits_command-0.3}/xkits_command.egg-info/requires.txt +1 -1
- {xkits_command-0.2 → xkits_command-0.3}/LICENSE +0 -0
- {xkits_command-0.2 → xkits_command-0.3}/README.md +0 -0
- {xkits_command-0.2 → xkits_command-0.3}/setup.cfg +0 -0
- {xkits_command-0.2 → xkits_command-0.3}/xkits_command/__init__.py +0 -0
- {xkits_command-0.2 → xkits_command-0.3}/xkits_command.egg-info/SOURCES.txt +0 -0
- {xkits_command-0.2 → xkits_command-0.3}/xkits_command.egg-info/dependency_links.txt +0 -0
- {xkits_command-0.2 → xkits_command-0.3}/xkits_command.egg-info/top_level.txt +0 -0
- {xkits_command-0.2 → xkits_command-0.3}/xkits_command.egg-info/zip-safe +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: xkits-command
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3
|
|
4
4
|
Summary: Command line module
|
|
5
5
|
Home-page: https://github.com/bondbox/xcommand/
|
|
6
6
|
Author: Mingzhe Zou
|
|
@@ -17,7 +17,7 @@ Requires-Python: >=3.8
|
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
Requires-Dist: argcomplete>=3.2.1
|
|
20
|
-
Requires-Dist:
|
|
20
|
+
Requires-Dist: xkits-logger>=0.2
|
|
21
21
|
|
|
22
22
|
# xcommand
|
|
23
23
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# coding=utf-8
|
|
2
2
|
|
|
3
|
+
from urllib.parse import urljoin
|
|
4
|
+
|
|
3
5
|
from setuptools import find_packages
|
|
4
6
|
from setuptools import setup
|
|
5
|
-
from
|
|
7
|
+
from setuptools.command.install import install
|
|
6
8
|
|
|
7
9
|
from xkits_command.attribute import __author__
|
|
8
10
|
from xkits_command.attribute import __author_email__
|
|
@@ -25,6 +27,14 @@ def all_requirements():
|
|
|
25
27
|
return requirements
|
|
26
28
|
|
|
27
29
|
|
|
30
|
+
class CustomInstallCommand(install):
|
|
31
|
+
"""Customized setuptools install command"""
|
|
32
|
+
|
|
33
|
+
def run(self):
|
|
34
|
+
install.run(self) # Run the standard installation
|
|
35
|
+
# Execute your custom code after installation
|
|
36
|
+
|
|
37
|
+
|
|
28
38
|
setup(
|
|
29
39
|
name=__project__,
|
|
30
40
|
version=__version__,
|
|
@@ -35,5 +45,9 @@ setup(
|
|
|
35
45
|
project_urls={"Source Code": __urlcode__,
|
|
36
46
|
"Bug Tracker": __urlbugs__,
|
|
37
47
|
"Documentation": __urldocs__},
|
|
38
|
-
packages=find_packages(include=["xkits_command*"], exclude=["xkits_command.unittest"]),
|
|
39
|
-
install_requires=all_requirements()
|
|
48
|
+
packages=find_packages(include=["xkits_command*"], exclude=["xkits_command.unittest"]), # noqa:E501
|
|
49
|
+
install_requires=all_requirements(),
|
|
50
|
+
cmdclass={
|
|
51
|
+
"install": CustomInstallCommand,
|
|
52
|
+
}
|
|
53
|
+
)
|
|
@@ -24,7 +24,7 @@ from xkits_command.parser import ArgParser
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class CommandArgument:
|
|
27
|
-
|
|
27
|
+
"""Define a new command-line node.
|
|
28
28
|
|
|
29
29
|
For example:
|
|
30
30
|
|
|
@@ -34,10 +34,10 @@ class CommandArgument:
|
|
|
34
34
|
>>> @CommandArgument("example")\n
|
|
35
35
|
>>> def cmd(_arg: ArgParser):\n
|
|
36
36
|
>>> _arg.add_opt_on("-t", "--test")\n
|
|
37
|
-
|
|
37
|
+
"""
|
|
38
38
|
|
|
39
39
|
def __init__(self, name: str, **kwargs):
|
|
40
|
-
|
|
40
|
+
"""Initialize the node.
|
|
41
41
|
|
|
42
42
|
@param name: Node name
|
|
43
43
|
@type name: str
|
|
@@ -53,7 +53,7 @@ class CommandArgument:
|
|
|
53
53
|
|
|
54
54
|
@param add_help: Add a -h/--help option to the node
|
|
55
55
|
@type add_help: bool (default: True)
|
|
56
|
-
|
|
56
|
+
"""
|
|
57
57
|
if "help" in kwargs and "description" not in kwargs:
|
|
58
58
|
kwargs["description"] = kwargs["help"]
|
|
59
59
|
if "description" in kwargs and "help" not in kwargs:
|
|
@@ -136,7 +136,7 @@ class CommandArgument:
|
|
|
136
136
|
|
|
137
137
|
|
|
138
138
|
class CommandExecutor:
|
|
139
|
-
|
|
139
|
+
"""Define the main callback function, and bind it to a node and
|
|
140
140
|
all subcommands.
|
|
141
141
|
|
|
142
142
|
For example:
|
|
@@ -147,11 +147,11 @@ class CommandExecutor:
|
|
|
147
147
|
>>> @CommandExecutor(cmd, cmd_get, cmd_set)\n
|
|
148
148
|
>>> def run(cmds: Command) -> int:\n
|
|
149
149
|
>>> return 0\n
|
|
150
|
-
|
|
150
|
+
"""
|
|
151
151
|
|
|
152
152
|
def __init__(self, cmd_bind: CommandArgument, *sub_cmds: CommandArgument,
|
|
153
153
|
skip: bool = False):
|
|
154
|
-
|
|
154
|
+
"""Initialize the node.
|
|
155
155
|
|
|
156
156
|
@param cmd_bind: Bind to a root command node
|
|
157
157
|
@type name: CommandArgument
|
|
@@ -163,7 +163,7 @@ class CommandExecutor:
|
|
|
163
163
|
CommandDeletion) does not run when a subcommand is specified,
|
|
164
164
|
run this node without any subcommands
|
|
165
165
|
@type skip: bool (default: False)
|
|
166
|
-
|
|
166
|
+
"""
|
|
167
167
|
assert isinstance(cmd_bind, CommandArgument)
|
|
168
168
|
assert isinstance(skip, bool)
|
|
169
169
|
cmd_bind.bind = self
|
|
@@ -215,7 +215,7 @@ class CommandExecutor:
|
|
|
215
215
|
|
|
216
216
|
|
|
217
217
|
class CommandCreation:
|
|
218
|
-
|
|
218
|
+
"""Define prepare callback function, and bind it with main callback.
|
|
219
219
|
|
|
220
220
|
For example:
|
|
221
221
|
|
|
@@ -230,14 +230,14 @@ class CommandCreation:
|
|
|
230
230
|
>>> @CommandCreation(run)\n
|
|
231
231
|
>>> def pre(cmds: Command) -> int:\n
|
|
232
232
|
>>> return 0\n
|
|
233
|
-
|
|
233
|
+
"""
|
|
234
234
|
|
|
235
235
|
def __init__(self, run_bind: CommandExecutor):
|
|
236
|
-
|
|
236
|
+
"""Initialize the node.
|
|
237
237
|
|
|
238
238
|
@param cmd_bind: Bind to a root command node
|
|
239
239
|
@type name: CommandArgument
|
|
240
|
-
|
|
240
|
+
"""
|
|
241
241
|
assert isinstance(run_bind, CommandExecutor)
|
|
242
242
|
run_bind.prep = self
|
|
243
243
|
self.__main: CommandExecutor = run_bind
|
|
@@ -259,7 +259,7 @@ class CommandCreation:
|
|
|
259
259
|
|
|
260
260
|
|
|
261
261
|
class CommandDeletion:
|
|
262
|
-
|
|
262
|
+
"""Define purge callback function, and bind it with main callback.
|
|
263
263
|
|
|
264
264
|
For example:
|
|
265
265
|
|
|
@@ -274,14 +274,14 @@ class CommandDeletion:
|
|
|
274
274
|
>>> @CommandDeletion(run)\n
|
|
275
275
|
>>> def end(cmds: Command) -> int:\n
|
|
276
276
|
>>> return 0\n
|
|
277
|
-
|
|
277
|
+
"""
|
|
278
278
|
|
|
279
279
|
def __init__(self, run_bind: CommandExecutor):
|
|
280
|
-
|
|
280
|
+
"""Initialize the node.
|
|
281
281
|
|
|
282
282
|
@param cmd_bind: Bind to a root command node
|
|
283
283
|
@type name: CommandArgument
|
|
284
|
-
|
|
284
|
+
"""
|
|
285
285
|
assert isinstance(run_bind, CommandExecutor)
|
|
286
286
|
run_bind.done = self
|
|
287
287
|
self.__main: CommandExecutor = run_bind
|
|
@@ -303,7 +303,7 @@ class CommandDeletion:
|
|
|
303
303
|
|
|
304
304
|
|
|
305
305
|
class Command(Log):
|
|
306
|
-
|
|
306
|
+
"""Singleton command-line tool based on argparse.
|
|
307
307
|
|
|
308
308
|
Define and bind all callback functions before calling run() or parse().
|
|
309
309
|
|
|
@@ -341,7 +341,7 @@ class Command(Log):
|
|
|
341
341
|
>>> argv=argv,\n
|
|
342
342
|
>>> prog="xkits-command-example",\n
|
|
343
343
|
>>> description="Simple command-line tool based on argparse.")\n
|
|
344
|
-
|
|
344
|
+
"""
|
|
345
345
|
|
|
346
346
|
LOGGER_ARGUMENT_GROUP = "logger options"
|
|
347
347
|
|
|
@@ -369,7 +369,7 @@ class Command(Log):
|
|
|
369
369
|
|
|
370
370
|
@property
|
|
371
371
|
def root(self) -> Optional[CommandArgument]:
|
|
372
|
-
|
|
372
|
+
"""Root Command."""
|
|
373
373
|
return self.__root
|
|
374
374
|
|
|
375
375
|
@root.setter
|
|
@@ -379,7 +379,7 @@ class Command(Log):
|
|
|
379
379
|
|
|
380
380
|
@property
|
|
381
381
|
def args(self) -> Namespace:
|
|
382
|
-
|
|
382
|
+
"""Namespace after parse arguments."""
|
|
383
383
|
assert isinstance(self.__args, Namespace)
|
|
384
384
|
return self.__args
|
|
385
385
|
|
|
@@ -390,7 +390,7 @@ class Command(Log):
|
|
|
390
390
|
|
|
391
391
|
@property
|
|
392
392
|
def version(self) -> Optional[str]:
|
|
393
|
-
|
|
393
|
+
"""Custom version for "-v" or "--version" output."""
|
|
394
394
|
return self.__version
|
|
395
395
|
|
|
396
396
|
@version.setter
|
|
@@ -410,7 +410,7 @@ class Command(Log):
|
|
|
410
410
|
|
|
411
411
|
@property
|
|
412
412
|
def logger(self) -> Logger:
|
|
413
|
-
|
|
413
|
+
"""Logger."""
|
|
414
414
|
return self.get_logger(self.prog)
|
|
415
415
|
|
|
416
416
|
def __add_optional_version(self, _arg: ArgParser):
|
|
@@ -590,15 +590,15 @@ class Command(Log):
|
|
|
590
590
|
|
|
591
591
|
@classmethod
|
|
592
592
|
def check_error(cls, value: Any) -> int:
|
|
593
|
-
|
|
593
|
+
"""Check value is an error.
|
|
594
594
|
|
|
595
595
|
Return True if value is an error, otherwise False.
|
|
596
|
-
|
|
596
|
+
"""
|
|
597
597
|
return value if isinstance(value, int) else 0 if value in (None, True) else EINVAL # noqa:E501
|
|
598
598
|
|
|
599
599
|
def parse(self, root: Optional[CommandArgument] = None,
|
|
600
600
|
argv: Optional[Sequence[str]] = None, **kwargs) -> Namespace:
|
|
601
|
-
|
|
601
|
+
"""Parse the command line."""
|
|
602
602
|
if root is None:
|
|
603
603
|
root = self.root
|
|
604
604
|
assert isinstance(root, CommandArgument)
|
|
@@ -620,7 +620,7 @@ class Command(Log):
|
|
|
620
620
|
|
|
621
621
|
def has_sub(self, root: CommandArgument,
|
|
622
622
|
args: Optional[Namespace] = None) -> bool:
|
|
623
|
-
|
|
623
|
+
"""If the root command node has any subcommand nodes, return true.
|
|
624
624
|
|
|
625
625
|
@param root: Command node
|
|
626
626
|
@type root: CommandArgument
|
|
@@ -629,7 +629,7 @@ class Command(Log):
|
|
|
629
629
|
@type args: Namespace or None (default self.args if None is specified)
|
|
630
630
|
|
|
631
631
|
@return: bool
|
|
632
|
-
|
|
632
|
+
"""
|
|
633
633
|
if args is None:
|
|
634
634
|
args = self.args
|
|
635
635
|
assert isinstance(root, CommandArgument)
|
|
@@ -692,7 +692,7 @@ class Command(Log):
|
|
|
692
692
|
root: Optional[CommandArgument] = None,
|
|
693
693
|
argv: Optional[Sequence[str]] = None,
|
|
694
694
|
**kwargs) -> int:
|
|
695
|
-
|
|
695
|
+
"""Parse and run the command line."""
|
|
696
696
|
if root is None:
|
|
697
697
|
root = self.root
|
|
698
698
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# coding:utf-8
|
|
2
2
|
|
|
3
3
|
__project__ = "xkits-command"
|
|
4
|
-
__version__ = "0.
|
|
5
|
-
__description__ = "Command line module"
|
|
4
|
+
__version__ = "0.3"
|
|
6
5
|
__urlhome__ = "https://github.com/bondbox/xcommand/"
|
|
6
|
+
__description__ = "Command line module"
|
|
7
7
|
|
|
8
8
|
# author
|
|
9
9
|
__author__ = "Mingzhe Zou"
|
|
@@ -12,11 +12,6 @@ from typing import Sequence
|
|
|
12
12
|
from typing import Set
|
|
13
13
|
from typing import Tuple
|
|
14
14
|
|
|
15
|
-
try:
|
|
16
|
-
from argcomplete import autocomplete
|
|
17
|
-
except ModuleNotFoundError: # pragma: no cover
|
|
18
|
-
pass # pragma: no cover
|
|
19
|
-
|
|
20
15
|
from xkits_command.attribute import __project__
|
|
21
16
|
from xkits_command.attribute import __urlhome__
|
|
22
17
|
|
|
@@ -27,7 +22,7 @@ class Checker():
|
|
|
27
22
|
|
|
28
23
|
@classmethod
|
|
29
24
|
def check_name_pos(cls, fn):
|
|
30
|
-
|
|
25
|
+
"""check positional argument name"""
|
|
31
26
|
|
|
32
27
|
def inner(self, name: str, **kwargs):
|
|
33
28
|
assert isinstance(name, str) and name[0] not in cls.prefix_chars, \
|
|
@@ -38,7 +33,7 @@ class Checker():
|
|
|
38
33
|
|
|
39
34
|
@classmethod
|
|
40
35
|
def check_name_opt(cls, fn):
|
|
41
|
-
|
|
36
|
+
"""check optional argument name"""
|
|
42
37
|
|
|
43
38
|
def inner(self, *name: str, **kwargs):
|
|
44
39
|
# 1. check short form optional argument ("-x")
|
|
@@ -54,13 +49,13 @@ class Checker():
|
|
|
54
49
|
|
|
55
50
|
@classmethod
|
|
56
51
|
def check_nargs_opt(cls, fn):
|
|
57
|
-
|
|
52
|
+
"""nargs hook function:
|
|
58
53
|
nargs < -1: using "?", 0 or 1 argument, default value
|
|
59
54
|
nargs = -1: using "+", arguments list, at least 1
|
|
60
55
|
nargs = 0: using "*", arguments list, allow to be empty
|
|
61
56
|
nargs = 1: redirect to "?", 0 or 1 argument
|
|
62
57
|
nargs > 1: N arguments list
|
|
63
|
-
|
|
58
|
+
"""
|
|
64
59
|
|
|
65
60
|
def inner(self, *args, **kwargs):
|
|
66
61
|
_nargs = kwargs.get("nargs", -2)
|
|
@@ -73,7 +68,7 @@ class Checker():
|
|
|
73
68
|
|
|
74
69
|
|
|
75
70
|
class ArgParser(ArgumentParser):
|
|
76
|
-
|
|
71
|
+
"""Simple command-line tool based on argparse."""
|
|
77
72
|
|
|
78
73
|
def __init__(self, # pylint: disable=R0913,R0917
|
|
79
74
|
argv: Optional[Sequence[str]] = None,
|
|
@@ -119,7 +114,7 @@ class ArgParser(ArgumentParser):
|
|
|
119
114
|
title: Optional[str] = None,
|
|
120
115
|
description: Optional[str] = None,
|
|
121
116
|
**kwargs) -> _ArgumentGroup:
|
|
122
|
-
|
|
117
|
+
"""Find the created argument group by title, create if not exist."""
|
|
123
118
|
for group in self._action_groups:
|
|
124
119
|
if title == group.title:
|
|
125
120
|
return group
|
|
@@ -127,7 +122,7 @@ class ArgParser(ArgumentParser):
|
|
|
127
122
|
|
|
128
123
|
@Checker.check_name_opt
|
|
129
124
|
def filter_optional_name(self, *name: str) -> Sequence[str]:
|
|
130
|
-
|
|
125
|
+
"""Filter defined optional argument name."""
|
|
131
126
|
option_strings: Set[str] = set()
|
|
132
127
|
for action in self._get_optional_actions():
|
|
133
128
|
option_strings.update(action.option_strings)
|
|
@@ -135,7 +130,7 @@ class ArgParser(ArgumentParser):
|
|
|
135
130
|
|
|
136
131
|
@Checker.check_name_pos
|
|
137
132
|
def add_pos(self, name: str, **kwargs) -> None:
|
|
138
|
-
|
|
133
|
+
"""Add positional argument."""
|
|
139
134
|
assert "dest" not in kwargs, \
|
|
140
135
|
"dest supplied twice for positional argument"
|
|
141
136
|
self.add_argument(name, **kwargs)
|
|
@@ -143,12 +138,12 @@ class ArgParser(ArgumentParser):
|
|
|
143
138
|
@Checker.check_name_opt
|
|
144
139
|
@Checker.check_nargs_opt
|
|
145
140
|
def add_opt(self, *name: str, **kwargs) -> None:
|
|
146
|
-
|
|
141
|
+
"""Add optional argument."""
|
|
147
142
|
self.add_argument(*name, **kwargs)
|
|
148
143
|
|
|
149
144
|
@Checker.check_name_opt
|
|
150
145
|
def add_opt_on(self, *name: str, **kwargs) -> None:
|
|
151
|
-
|
|
146
|
+
"""Add boolean optional argument, default value is False."""
|
|
152
147
|
kwargs.update({"action": "store_true"})
|
|
153
148
|
for key in ("type", "nargs", "const", "default", "choices"):
|
|
154
149
|
assert key not in kwargs, f"'{key}' is an invalid argument"
|
|
@@ -156,14 +151,14 @@ class ArgParser(ArgumentParser):
|
|
|
156
151
|
|
|
157
152
|
@Checker.check_name_opt
|
|
158
153
|
def add_opt_off(self, *name: str, **kwargs) -> None:
|
|
159
|
-
|
|
154
|
+
"""Add boolean optional argument, default value is True."""
|
|
160
155
|
kwargs.update({"action": "store_false"})
|
|
161
156
|
for key in ("type", "nargs", "const", "default", "choices"):
|
|
162
157
|
assert key not in kwargs, f"'{key}' is an invalid argument"
|
|
163
158
|
self.add_argument(*name, **kwargs)
|
|
164
159
|
|
|
165
160
|
def add_subparsers(self, *args, **kwargs) -> _SubParsersAction:
|
|
166
|
-
|
|
161
|
+
"""Add subparsers."""
|
|
167
162
|
# subparser: cannot have multiple subparser arguments
|
|
168
163
|
kwargs.setdefault("title", "subcommands")
|
|
169
164
|
kwargs.setdefault("description", None)
|
|
@@ -177,7 +172,10 @@ class ArgParser(ArgumentParser):
|
|
|
177
172
|
namespace: Optional[Namespace] = None
|
|
178
173
|
) -> Namespace:
|
|
179
174
|
try:
|
|
175
|
+
from argcomplete import autocomplete # pylint: disable=C0415
|
|
180
176
|
autocomplete(self) # For tab completion
|
|
177
|
+
except ModuleNotFoundError: # pragma: no cover
|
|
178
|
+
pass # pragma: no cover
|
|
181
179
|
except NameError: # pragma: no cover
|
|
182
180
|
pass # pragma: no cover
|
|
183
181
|
return super().parse_args(args, namespace) # type: ignore
|
|
@@ -203,7 +201,7 @@ class ArgParser(ArgumentParser):
|
|
|
203
201
|
self._option_string_actions.pop(option)
|
|
204
202
|
|
|
205
203
|
def preparse_from_sys_argv(self) -> Namespace:
|
|
206
|
-
|
|
204
|
+
"""Preparse some arguments from sys.argv for tab completion.
|
|
207
205
|
|
|
208
206
|
When arguments contain the help option, call parse_known_args()
|
|
209
207
|
will print help message and exit. The command line can parse
|
|
@@ -215,7 +213,7 @@ class ArgParser(ArgumentParser):
|
|
|
215
213
|
|
|
216
214
|
So, disable the help action before calling parse_known_args().
|
|
217
215
|
The help option will be stored, and restored after the call ends.
|
|
218
|
-
|
|
216
|
+
"""
|
|
219
217
|
|
|
220
218
|
def __dfs_enable_help_action(root: ArgParser):
|
|
221
219
|
root.__enable_help_action() # pylint: disable=protected-access
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: xkits-command
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3
|
|
4
4
|
Summary: Command line module
|
|
5
5
|
Home-page: https://github.com/bondbox/xcommand/
|
|
6
6
|
Author: Mingzhe Zou
|
|
@@ -17,7 +17,7 @@ Requires-Python: >=3.8
|
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
Requires-Dist: argcomplete>=3.2.1
|
|
20
|
-
Requires-Dist:
|
|
20
|
+
Requires-Dist: xkits-logger>=0.2
|
|
21
21
|
|
|
22
22
|
# xcommand
|
|
23
23
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
argcomplete>=3.2.1
|
|
2
|
-
|
|
2
|
+
xkits-logger>=0.2
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|