duty 1.4.3__py3-none-any.whl → 1.5.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.
- duty/cli.py +29 -1
- duty/collection.py +29 -0
- duty/completions.bash +30 -0
- duty/tools/__init__.py +3 -3
- {duty-1.4.3.dist-info → duty-1.5.0.dist-info}/METADATA +1 -1
- {duty-1.4.3.dist-info → duty-1.5.0.dist-info}/RECORD +9 -8
- {duty-1.4.3.dist-info → duty-1.5.0.dist-info}/WHEEL +1 -1
- {duty-1.4.3.dist-info → duty-1.5.0.dist-info}/entry_points.txt +0 -0
- {duty-1.4.3.dist-info → duty-1.5.0.dist-info}/licenses/LICENSE +0 -0
duty/cli.py
CHANGED
|
@@ -17,6 +17,7 @@ import argparse
|
|
|
17
17
|
import inspect
|
|
18
18
|
import sys
|
|
19
19
|
import textwrap
|
|
20
|
+
from pathlib import Path
|
|
20
21
|
from typing import Any
|
|
21
22
|
|
|
22
23
|
from failprint.cli import ArgParser, add_flags
|
|
@@ -69,6 +70,18 @@ def get_parser() -> ArgParser:
|
|
|
69
70
|
metavar="DUTY",
|
|
70
71
|
help="Show this help message and exit. Pass duties names to print their help.",
|
|
71
72
|
)
|
|
73
|
+
parser.add_argument(
|
|
74
|
+
"--completion",
|
|
75
|
+
dest="completion",
|
|
76
|
+
action="store_true",
|
|
77
|
+
help=argparse.SUPPRESS,
|
|
78
|
+
)
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"--complete",
|
|
81
|
+
dest="complete",
|
|
82
|
+
action="store_true",
|
|
83
|
+
help=argparse.SUPPRESS,
|
|
84
|
+
)
|
|
72
85
|
parser.add_argument("-V", "--version", action="version", version=f"%(prog)s {debug.get_version()}")
|
|
73
86
|
parser.add_argument("--debug-info", action=_DebugInfo, help="Print debug information.")
|
|
74
87
|
|
|
@@ -261,6 +274,18 @@ def main(args: list[str] | None = None) -> int:
|
|
|
261
274
|
collection = Collection(opts.duties_file)
|
|
262
275
|
collection.load()
|
|
263
276
|
|
|
277
|
+
if opts.completion:
|
|
278
|
+
print(Path(__file__).parent.joinpath("completions.bash").read_text())
|
|
279
|
+
return 0
|
|
280
|
+
|
|
281
|
+
if opts.complete:
|
|
282
|
+
words = collection.completion_candidates(remainder)
|
|
283
|
+
words += sorted(
|
|
284
|
+
opt for opt, action in parser._option_string_actions.items() if action.help != argparse.SUPPRESS
|
|
285
|
+
)
|
|
286
|
+
print(*words, sep="\n")
|
|
287
|
+
return 0
|
|
288
|
+
|
|
264
289
|
if opts.help is not None:
|
|
265
290
|
print_help(parser, opts, collection)
|
|
266
291
|
return 0
|
|
@@ -279,7 +304,10 @@ def main(args: list[str] | None = None) -> int:
|
|
|
279
304
|
print_help(parser, opts, collection)
|
|
280
305
|
return 1
|
|
281
306
|
|
|
282
|
-
global_opts = specified_options(
|
|
307
|
+
global_opts = specified_options(
|
|
308
|
+
opts,
|
|
309
|
+
exclude={"duties_file", "list", "help", "remainder", "complete", "completion"},
|
|
310
|
+
)
|
|
283
311
|
try:
|
|
284
312
|
commands = parse_commands(arg_lists, global_opts, collection)
|
|
285
313
|
except TypeError as error:
|
duty/collection.py
CHANGED
|
@@ -143,6 +143,35 @@ class Collection:
|
|
|
143
143
|
"""
|
|
144
144
|
return list(self.duties.keys()) + list(self.aliases.keys())
|
|
145
145
|
|
|
146
|
+
def completion_candidates(self, args: tuple[str, ...]) -> list[str]:
|
|
147
|
+
"""Find shell completion candidates within this collection.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
The list of shell completion candidates, sorted alphabetically.
|
|
151
|
+
"""
|
|
152
|
+
# Find last duty name in args.
|
|
153
|
+
name = None
|
|
154
|
+
names = set(self.names())
|
|
155
|
+
for arg in reversed(args):
|
|
156
|
+
if arg in names:
|
|
157
|
+
name = arg
|
|
158
|
+
break
|
|
159
|
+
|
|
160
|
+
completion_names = sorted(names)
|
|
161
|
+
|
|
162
|
+
# If no duty found, return names.
|
|
163
|
+
if name is None:
|
|
164
|
+
return completion_names
|
|
165
|
+
|
|
166
|
+
params = [
|
|
167
|
+
f"{param.name}="
|
|
168
|
+
for param in inspect.signature(self.get(name).function).parameters.values()
|
|
169
|
+
if param.kind is not param.VAR_POSITIONAL
|
|
170
|
+
][1:]
|
|
171
|
+
|
|
172
|
+
# If duty found, return names *and* duty parameters.
|
|
173
|
+
return completion_names + sorted(params)
|
|
174
|
+
|
|
146
175
|
def get(self, name_or_alias: str) -> Duty:
|
|
147
176
|
"""Get a duty by its name or alias.
|
|
148
177
|
|
duty/completions.bash
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Invoke tab-completion script to be sourced with Bash shell.
|
|
2
|
+
# Known to work on Bash 3.x, untested on 4.x.
|
|
3
|
+
|
|
4
|
+
_complete_duty() {
|
|
5
|
+
local candidates
|
|
6
|
+
|
|
7
|
+
# COMP_WORDS contains the entire command string up til now (including
|
|
8
|
+
# program name).
|
|
9
|
+
# We hand it to Invoke so it can figure out the current context: spit back
|
|
10
|
+
# core options, task names, the current task's options, or some combo.
|
|
11
|
+
candidates=$(duty --complete -- "${COMP_WORDS[@]}")
|
|
12
|
+
|
|
13
|
+
# `compgen -W` takes list of valid options & a partial word & spits back
|
|
14
|
+
# possible matches. Necessary for any partial word completions (vs
|
|
15
|
+
# completions performed when no partial words are present).
|
|
16
|
+
#
|
|
17
|
+
# $2 is the current word or token being tabbed on, either empty string or a
|
|
18
|
+
# partial word, and thus wants to be compgen'd to arrive at some subset of
|
|
19
|
+
# our candidate list which actually matches.
|
|
20
|
+
#
|
|
21
|
+
# COMPREPLY is the list of valid completions handed back to `complete`.
|
|
22
|
+
COMPREPLY=( $(compgen -W "${candidates}" -- $2) )
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Tell shell builtin to use the above for completing our invocations.
|
|
27
|
+
# * -F: use given function name to generate completions.
|
|
28
|
+
# * -o default: when function generates no results, use filenames.
|
|
29
|
+
# * positional args: program names to complete for.
|
|
30
|
+
complete -F _complete_duty -o default duty
|
duty/tools/__init__.py
CHANGED
|
@@ -24,10 +24,9 @@ from duty.tools._ssort import ssort
|
|
|
24
24
|
from duty.tools._twine import twine
|
|
25
25
|
|
|
26
26
|
__all__ = [
|
|
27
|
-
"Tool",
|
|
28
|
-
"LazyStdout",
|
|
29
27
|
"LazyStderr",
|
|
30
|
-
"
|
|
28
|
+
"LazyStdout",
|
|
29
|
+
"Tool",
|
|
31
30
|
"autoflake",
|
|
32
31
|
"black",
|
|
33
32
|
"blacken_docs",
|
|
@@ -38,6 +37,7 @@ __all__ = [
|
|
|
38
37
|
"griffe",
|
|
39
38
|
"interrogate",
|
|
40
39
|
"isort",
|
|
40
|
+
"lazy",
|
|
41
41
|
"mkdocs",
|
|
42
42
|
"mypy",
|
|
43
43
|
"pytest",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
duty-1.
|
|
2
|
-
duty-1.
|
|
3
|
-
duty-1.
|
|
4
|
-
duty-1.
|
|
1
|
+
duty-1.5.0.dist-info/METADATA,sha256=CeSruNp_c1LB1AERsGqjy0UwRiww5pivOXdon_fRz7g,2710
|
|
2
|
+
duty-1.5.0.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
|
|
3
|
+
duty-1.5.0.dist-info/entry_points.txt,sha256=XZTh9yTgC9GDFmNoVeOqgKT6BCMifkCToilIj77B9ss,55
|
|
4
|
+
duty-1.5.0.dist-info/licenses/LICENSE,sha256=nQxdYSduhkgEpOTmg4yyIMmFPzcr2qrlUl8Tf9QZPug,754
|
|
5
5
|
duty/__init__.py,sha256=2fdBMNEBXYSCnV1GQm56VGe8VuvMp79-Hj3SHrAb5MM,144
|
|
6
6
|
duty/__main__.py,sha256=4YvloGDKmyVzOsE6ZdyCQyY0Jsl0LSlbqkO2UDExgmI,333
|
|
7
7
|
duty/callables/__init__.py,sha256=R42f1qpIy7m2MMbs6Xc_OnQiEARr4g2Pghpp9ry4JFI,1042
|
|
@@ -23,14 +23,15 @@ duty/callables/ruff.py,sha256=ZBjl1_MxaZ1-atHVB6YOFNf3QAm6GTw7Xj3hX8jnofo,13314
|
|
|
23
23
|
duty/callables/safety.py,sha256=ClwwAnDdZFG71_Fbh5X2XEGSPI8PZRy4-Jz6zq2amV4,2454
|
|
24
24
|
duty/callables/ssort.py,sha256=Lqak-xfJtKkj3AaI4_jPeaRkZ9SbvMCYhoUIVVHE6s8,842
|
|
25
25
|
duty/callables/twine.py,sha256=hsp8TcOYlbHCCqRwglDmNHS55LdnXFd-n2tFaJkMafs,9511
|
|
26
|
-
duty/cli.py,sha256=
|
|
27
|
-
duty/collection.py,sha256=
|
|
26
|
+
duty/cli.py,sha256=XnkVQAmHCf5QAykZ4foiLvBrsSD22dhSljXmLdFhWM4,9273
|
|
27
|
+
duty/collection.py,sha256=cg_rInuTErP7HTrUJsHenOSdtFZtzIw8cIIsr5g-0T8,7500
|
|
28
|
+
duty/completions.bash,sha256=xXtsZoF1bxhfG4vEuh8hwyYkzNBNlDRxKC9myHV4LPA,1311
|
|
28
29
|
duty/context.py,sha256=YVF68a2w3SMEM0AsN1mBCvlOZ5jTEZ9OYCxDZvv_soI,3250
|
|
29
30
|
duty/debug.py,sha256=9stdqxNJ9zA2HWsYfmy3C9BrWOXLlHYRGsQ6dHfCUfM,2813
|
|
30
31
|
duty/decorator.py,sha256=3puIe45Q_5vOVXlr71eFayHS1Swz6YdNANHOnDnHDk0,2984
|
|
31
32
|
duty/exceptions.py,sha256=gTtqtqOiMroP5-83kC5jakuwBfYKpzCQHE9RWfAGRv0,358
|
|
32
33
|
duty/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
|
-
duty/tools/__init__.py,sha256=
|
|
34
|
+
duty/tools/__init__.py,sha256=X-DqE9t47ybEhDf3eboxOEM0vVMQQsqKEOdmDafcuvc,1179
|
|
34
35
|
duty/tools/_autoflake.py,sha256=wDqNyfuC6rju9LqyTTimaQZs_8v7YvYECzdltO5rof0,5285
|
|
35
36
|
duty/tools/_base.py,sha256=MpjsSguxu_O6HAOkIy0hZdP2RkguS-NGVhYQHPnurWA,1474
|
|
36
37
|
duty/tools/_black.py,sha256=avo5-J2gHeXlOneYC0j1PSV7J-QFfPFUTdbwczsMvrA,7907
|
|
@@ -50,4 +51,4 @@ duty/tools/_safety.py,sha256=D0ID65aeSCx6ZG01jZVSik075YkojjoYb8DoRtaz4X8,3206
|
|
|
50
51
|
duty/tools/_ssort.py,sha256=xhh5eYq16BC8KTSKDCxA10mR8RZoQuN10-xUjhu3QlE,1097
|
|
51
52
|
duty/tools/_twine.py,sha256=9y7-X9fqZ6wbOddGtxBMePI7hgq9QldYyMHxRBy_JXg,10347
|
|
52
53
|
duty/validation.py,sha256=z0CLIsc-2AYbh-zqm3XMhWwE9JlVYmIJkrbo_bjmqVw,8241
|
|
53
|
-
duty-1.
|
|
54
|
+
duty-1.5.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|