declinate 0.0.1__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.
- declinate/__init__.py +3 -0
- declinate/check.py +30 -0
- declinate/cli.py +394 -0
- declinate/declinate.py +109 -0
- declinate/gen.py +951 -0
- declinate/py.typed +0 -0
- declinate-0.0.1.dist-info/LICENSE.txt +202 -0
- declinate-0.0.1.dist-info/METADATA +154 -0
- declinate-0.0.1.dist-info/RECORD +12 -0
- declinate-0.0.1.dist-info/WHEEL +5 -0
- declinate-0.0.1.dist-info/entry_points.txt +2 -0
- declinate-0.0.1.dist-info/top_level.txt +1 -0
declinate/__init__.py
ADDED
declinate/check.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Copyright 2022-2023 Ternaris.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""CLI generators."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import importlib
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from .gen import generate_code
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def check_package(package: str) -> str | None:
|
|
14
|
+
"""Check if package CLI is up to date.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
package: Name of package to check.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Instructions how to update package or None.
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
code = generate_code(package, write=False)
|
|
24
|
+
module = importlib.import_module(name=package)
|
|
25
|
+
assert module
|
|
26
|
+
assert module.__file__
|
|
27
|
+
clipath = Path(module.__file__).parent / 'cli.py'
|
|
28
|
+
if not clipath.exists() or clipath.read_text() != code:
|
|
29
|
+
return f'CLI is outdated, run "declinate generate -w {package}"'
|
|
30
|
+
return None
|
declinate/cli.py
ADDED
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
"""Generated declinate CLI."""
|
|
2
|
+
|
|
3
|
+
# DO NOT EDIT THIS FILE MANUALLY
|
|
4
|
+
# ruff: noqa
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
import os
|
|
10
|
+
import re
|
|
11
|
+
import sys
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from typing import Callable, NoReturn
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class HelpFormatter(argparse.HelpFormatter):
|
|
20
|
+
"""Help formatter."""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
prog: str,
|
|
25
|
+
indent_increment: int = 2,
|
|
26
|
+
max_help_position: int = 24,
|
|
27
|
+
width: int | None = None,
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Init."""
|
|
30
|
+
super().__init__(prog, indent_increment, max_help_position, width)
|
|
31
|
+
self._width = min(self._width, 78)
|
|
32
|
+
|
|
33
|
+
def _fill_text(self, text: str, width: int, indent: str) -> str:
|
|
34
|
+
"""Reformat individual paragraphs."""
|
|
35
|
+
parent = super()._fill_text
|
|
36
|
+
|
|
37
|
+
def idn(text: str) -> str:
|
|
38
|
+
if re.match(r'(?m)(^.*?:$)|(^ )', text):
|
|
39
|
+
return text
|
|
40
|
+
return parent(text, width, indent)
|
|
41
|
+
|
|
42
|
+
return '\n\n'.join(map(idn, text.split('\n\n')))
|
|
43
|
+
|
|
44
|
+
def _metavar_formatter(
|
|
45
|
+
self,
|
|
46
|
+
action: argparse.Action,
|
|
47
|
+
default_metavar: str,
|
|
48
|
+
) -> Callable[[int], tuple[str, ...]]:
|
|
49
|
+
if isinstance(action, argparse._SubParsersAction) and action.choices:
|
|
50
|
+
choice_strs = [
|
|
51
|
+
k for k, v in action.choices.items() if not v.description.startswith('SUPPRESS.')
|
|
52
|
+
]
|
|
53
|
+
result = f'{{{",".join(choice_strs)}}}'
|
|
54
|
+
return lambda x: (result,) * x
|
|
55
|
+
return super()._metavar_formatter(action, default_metavar)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ArgumentParser(argparse.ArgumentParser):
|
|
59
|
+
"""Argument parser."""
|
|
60
|
+
|
|
61
|
+
def _check_value(self, action: argparse.Action, value: str) -> None:
|
|
62
|
+
"""Filter suppressed actions."""
|
|
63
|
+
if isinstance(action, argparse._SubParsersAction):
|
|
64
|
+
if action.choices and value not in action.choices:
|
|
65
|
+
msg = f'invalid action: {value!r}'
|
|
66
|
+
raise argparse.ArgumentError(action, msg)
|
|
67
|
+
else:
|
|
68
|
+
super()._check_value(action, value)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
PARSER = ArgumentParser(
|
|
72
|
+
allow_abbrev=False,
|
|
73
|
+
argument_default=argparse.SUPPRESS,
|
|
74
|
+
formatter_class=HelpFormatter,
|
|
75
|
+
description='CLI generator for Python.',
|
|
76
|
+
)
|
|
77
|
+
PARSER.add_argument(
|
|
78
|
+
'--version',
|
|
79
|
+
help='Print version number.',
|
|
80
|
+
dest='version',
|
|
81
|
+
action='store_true',
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
SUBS = PARSER.add_subparsers(
|
|
85
|
+
title='sub commands',
|
|
86
|
+
dest='_command',
|
|
87
|
+
required=False,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
SUB = SUBS.add_parser(
|
|
91
|
+
'generate',
|
|
92
|
+
allow_abbrev=False,
|
|
93
|
+
argument_default=argparse.SUPPRESS,
|
|
94
|
+
formatter_class=HelpFormatter,
|
|
95
|
+
description=(
|
|
96
|
+
'Generate CLI code.\n'
|
|
97
|
+
'\n'
|
|
98
|
+
'This command parses the declarative CLI definition from a Python package\n'
|
|
99
|
+
'and generates the code for the CLI.'
|
|
100
|
+
),
|
|
101
|
+
help='Generate CLI code.',
|
|
102
|
+
)
|
|
103
|
+
SUB.add_argument(
|
|
104
|
+
'package',
|
|
105
|
+
help='Name of the Python package.',
|
|
106
|
+
type=str,
|
|
107
|
+
)
|
|
108
|
+
SUB.add_argument(
|
|
109
|
+
'-w',
|
|
110
|
+
'--write',
|
|
111
|
+
help='Write cli module into package.',
|
|
112
|
+
dest='write',
|
|
113
|
+
action='store_true',
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
SUB = SUBS.add_parser(
|
|
117
|
+
'check',
|
|
118
|
+
allow_abbrev=False,
|
|
119
|
+
argument_default=argparse.SUPPRESS,
|
|
120
|
+
formatter_class=HelpFormatter,
|
|
121
|
+
description='Check if generated cli is up to date.',
|
|
122
|
+
help='Check if generated cli is up to date.',
|
|
123
|
+
)
|
|
124
|
+
SUB.add_argument(
|
|
125
|
+
'package',
|
|
126
|
+
help='Name of the Python package.',
|
|
127
|
+
type=str,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def custom_complete(action: argparse.Action, args: list[str], arg: str) -> list[str]:
|
|
132
|
+
"""Complete action."""
|
|
133
|
+
ret: list[str] = []
|
|
134
|
+
addargs: dict[str, str] = {}
|
|
135
|
+
|
|
136
|
+
return ret
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
COMPLETER_BASH = """\
|
|
140
|
+
_completer__%(name)s() {
|
|
141
|
+
local IFS=$'\\n'
|
|
142
|
+
for reply in $(env _COMPLETER=bash COMP_LINE="$COMP_LINE" COMP_POINT=$COMP_POINT $1); do
|
|
143
|
+
IFS=',' read type value descr <<< "$reply"
|
|
144
|
+
if [[ $type == "directory" ]]; then
|
|
145
|
+
compopt -o dirnames
|
|
146
|
+
elif [[ $type == "file" ]]; then
|
|
147
|
+
compopt -o default
|
|
148
|
+
elif [[ $type == "string" ]]; then
|
|
149
|
+
COMPREPLY+=($value)
|
|
150
|
+
fi
|
|
151
|
+
done
|
|
152
|
+
return 0
|
|
153
|
+
}
|
|
154
|
+
complete -o nosort -F _completer__%(name)s %(name)s;
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
COMPLETER_ZSH = """\
|
|
158
|
+
#compdef %(name)s
|
|
159
|
+
_completer__%(name)s() {
|
|
160
|
+
local -a values values_descrs
|
|
161
|
+
(( ! $+commands[%(name)s] )) && return 1
|
|
162
|
+
for reply in "${(@f)$(env _COMPLETER=zsh COMP_LINE="$BUFFER" COMP_POINT=$CURSOR %(name)s)}"; do
|
|
163
|
+
IFS="," read type value descr <<< "$reply"
|
|
164
|
+
if [[ "$type" == "directory" ]]; then
|
|
165
|
+
_path_files -/
|
|
166
|
+
elif [[ "$type" == "file" ]]; then
|
|
167
|
+
_path_files -f
|
|
168
|
+
elif [[ "$type" == "string" ]]; then
|
|
169
|
+
if [[ -n "$descr" ]]; then
|
|
170
|
+
values_descrs+=("$value":"$descr")
|
|
171
|
+
else
|
|
172
|
+
values+=("$value")
|
|
173
|
+
fi
|
|
174
|
+
fi
|
|
175
|
+
done
|
|
176
|
+
if [ -n "$values_descrs" ]; then
|
|
177
|
+
_describe -V unsorted values_descrs -U
|
|
178
|
+
fi
|
|
179
|
+
if [ -n "$values" ]; then
|
|
180
|
+
compadd -U -V unsorted -a values
|
|
181
|
+
fi
|
|
182
|
+
}
|
|
183
|
+
compdef _completer__%(name)s %(name)s;
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def generate_source_completion() -> None:
|
|
188
|
+
"""Generate snippet for sourcing from shell."""
|
|
189
|
+
completer = os.getenv('_COMPLETER')
|
|
190
|
+
assert completer
|
|
191
|
+
completers = {
|
|
192
|
+
'bash': COMPLETER_BASH,
|
|
193
|
+
'zsh': COMPLETER_ZSH,
|
|
194
|
+
}
|
|
195
|
+
print(completers[completer] % {'name': Path(sys.argv[0]).name})
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def consume_action(action: argparse.Action, arg: str) -> None:
|
|
199
|
+
"""Consume arg in action."""
|
|
200
|
+
if action.choices and arg not in action.choices:
|
|
201
|
+
raise ValueError
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def consume_parser(
|
|
205
|
+
parser: ArgumentParser,
|
|
206
|
+
excluded: list[argparse.Action],
|
|
207
|
+
arg: str,
|
|
208
|
+
) -> tuple[ArgumentParser, argparse.Action | None]:
|
|
209
|
+
"""Consume parser."""
|
|
210
|
+
for action in parser._actions:
|
|
211
|
+
if isinstance(action, argparse._SubParsersAction):
|
|
212
|
+
for option, subaction in action.choices.items():
|
|
213
|
+
if option == arg:
|
|
214
|
+
return subaction, None
|
|
215
|
+
|
|
216
|
+
if arg.startswith('-'):
|
|
217
|
+
if any(x == arg for x in action.option_strings):
|
|
218
|
+
break
|
|
219
|
+
else:
|
|
220
|
+
if not action.option_strings:
|
|
221
|
+
break
|
|
222
|
+
else:
|
|
223
|
+
raise ValueError
|
|
224
|
+
|
|
225
|
+
if not isinstance(action, argparse._CountAction) and \
|
|
226
|
+
not (isinstance(action.nargs, str) and action.nargs in '*+'):
|
|
227
|
+
excluded.append(action)
|
|
228
|
+
for group in parser._mutually_exclusive_groups:
|
|
229
|
+
if action in group._group_actions:
|
|
230
|
+
for subaction in group._group_actions:
|
|
231
|
+
if subaction != action and subaction not in excluded:
|
|
232
|
+
excluded.append(subaction)
|
|
233
|
+
return parser, action if (
|
|
234
|
+
action.option_strings or action.choices
|
|
235
|
+
) and action.nargs != 0 else None
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def complete_actions(
|
|
239
|
+
actions: list[argparse.Action],
|
|
240
|
+
excluded: list[argparse.Action],
|
|
241
|
+
args: list[str],
|
|
242
|
+
arg: str,
|
|
243
|
+
) -> None:
|
|
244
|
+
"""Complete actions."""
|
|
245
|
+
completed: list[tuple[str, str]] = []
|
|
246
|
+
for action in sorted(actions, key=lambda x: not x.required):
|
|
247
|
+
if action in excluded:
|
|
248
|
+
continue
|
|
249
|
+
|
|
250
|
+
if isinstance(action, argparse._SubParsersAction):
|
|
251
|
+
completed += [
|
|
252
|
+
(k, v.description)
|
|
253
|
+
for k, v in action.choices.items()
|
|
254
|
+
if not v.description.startswith('SUPPRESS.')
|
|
255
|
+
]
|
|
256
|
+
|
|
257
|
+
elif action.option_strings:
|
|
258
|
+
completed += [(x, action.help or '') for x in action.option_strings]
|
|
259
|
+
|
|
260
|
+
elif action.choices:
|
|
261
|
+
completed += [(x, '') for x in action.choices]
|
|
262
|
+
|
|
263
|
+
else:
|
|
264
|
+
completed += [(x, '') for x in custom_complete(action, args, arg)]
|
|
265
|
+
|
|
266
|
+
if not arg and action.required:
|
|
267
|
+
break
|
|
268
|
+
|
|
269
|
+
have_positinal = any(not x.startswith('-') for x, _ in completed)
|
|
270
|
+
for option, descr in sorted(completed):
|
|
271
|
+
if have_positinal and not arg and option.startswith('-'):
|
|
272
|
+
continue
|
|
273
|
+
if option.startswith(arg):
|
|
274
|
+
print(f'string,{option},{descr}')
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def complete_action(action: argparse.Action, args: list[str], arg: str) -> None:
|
|
278
|
+
"""Complete action."""
|
|
279
|
+
completed: list[tuple[str, str]] = []
|
|
280
|
+
|
|
281
|
+
if action.type == Path:
|
|
282
|
+
print('file,,')
|
|
283
|
+
|
|
284
|
+
if action.choices:
|
|
285
|
+
if isinstance(action.choices, dict):
|
|
286
|
+
completed += action.choices.items()
|
|
287
|
+
else:
|
|
288
|
+
completed += [(x, '') for x in action.choices]
|
|
289
|
+
|
|
290
|
+
completed += [(x, '') for x in custom_complete(action, args, arg)]
|
|
291
|
+
|
|
292
|
+
for option, descr in sorted(completed):
|
|
293
|
+
if not arg and option.startswith('-'):
|
|
294
|
+
continue
|
|
295
|
+
if option.startswith(arg):
|
|
296
|
+
print(f'string,{option},{descr}')
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def generate_completion() -> None:
|
|
300
|
+
"""Generate snippet for sourcing from shell."""
|
|
301
|
+
import shlex
|
|
302
|
+
|
|
303
|
+
lexer = shlex.shlex(os.getenv('COMP_LINE'), posix=True)
|
|
304
|
+
pos = int(os.getenv('COMP_POINT', '0'))
|
|
305
|
+
lexer.whitespace_split = True
|
|
306
|
+
lexer.commenters = ""
|
|
307
|
+
args = []
|
|
308
|
+
cword = None
|
|
309
|
+
|
|
310
|
+
next(lexer)
|
|
311
|
+
laststate = lexer.state # type: ignore[attr-defined]
|
|
312
|
+
try:
|
|
313
|
+
for index, token in enumerate(lexer):
|
|
314
|
+
args.append(token)
|
|
315
|
+
laststate = lexer.state # type: ignore[attr-defined]
|
|
316
|
+
if cword is None and lexer.instream.tell() > pos:
|
|
317
|
+
cword = index
|
|
318
|
+
except ValueError:
|
|
319
|
+
args.append(lexer.token)
|
|
320
|
+
laststate = 'error'
|
|
321
|
+
if laststate == ' ':
|
|
322
|
+
args.append('')
|
|
323
|
+
if cword is None:
|
|
324
|
+
cword = len(args) - 1
|
|
325
|
+
|
|
326
|
+
parser = PARSER
|
|
327
|
+
action = None
|
|
328
|
+
excluded: list[argparse.Action] = []
|
|
329
|
+
|
|
330
|
+
# interpret_args(parser, action, excluded, args, cword)
|
|
331
|
+
for arg in args[:cword]:
|
|
332
|
+
# print('string,try', arg)
|
|
333
|
+
if action:
|
|
334
|
+
try:
|
|
335
|
+
consume_action(action, arg)
|
|
336
|
+
action = None
|
|
337
|
+
except ValueError:
|
|
338
|
+
sys.exit(0)
|
|
339
|
+
continue
|
|
340
|
+
|
|
341
|
+
try:
|
|
342
|
+
parser, action = consume_parser(parser, excluded, arg)
|
|
343
|
+
except ValueError:
|
|
344
|
+
sys.exit(0)
|
|
345
|
+
|
|
346
|
+
arg = args[cword]
|
|
347
|
+
|
|
348
|
+
if action:
|
|
349
|
+
complete_action(action, args, arg)
|
|
350
|
+
sys.exit(0)
|
|
351
|
+
|
|
352
|
+
complete_actions(parser._actions, excluded, args, arg)
|
|
353
|
+
sys.exit(0)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def main() -> NoReturn: # pragma: no cover
|
|
357
|
+
"""CLI entrypoint."""
|
|
358
|
+
if 'COMP_LINE' in os.environ:
|
|
359
|
+
generate_completion()
|
|
360
|
+
sys.exit(0)
|
|
361
|
+
|
|
362
|
+
if '_COMPLETER' in os.environ:
|
|
363
|
+
generate_source_completion()
|
|
364
|
+
sys.exit(0)
|
|
365
|
+
args = PARSER.parse_args().__dict__
|
|
366
|
+
|
|
367
|
+
from declinate.declinate import command
|
|
368
|
+
runargs = args
|
|
369
|
+
res = command(argparser=PARSER, **runargs)
|
|
370
|
+
|
|
371
|
+
_command = args.pop('_command')
|
|
372
|
+
_subaction = args['subaction'] if 'subaction' in args else None
|
|
373
|
+
if _command == 'generate':
|
|
374
|
+
from declinate.declinate import generate
|
|
375
|
+
runargs = {
|
|
376
|
+
k: v for k, v in args.items()
|
|
377
|
+
if k in {
|
|
378
|
+
'package',
|
|
379
|
+
'write',
|
|
380
|
+
}
|
|
381
|
+
} # yapf: disable
|
|
382
|
+
sys.exit(generate(**runargs))
|
|
383
|
+
|
|
384
|
+
if _command == 'check':
|
|
385
|
+
from declinate.declinate import check
|
|
386
|
+
runargs = {
|
|
387
|
+
k: v for k, v in args.items()
|
|
388
|
+
if k in {
|
|
389
|
+
'package',
|
|
390
|
+
}
|
|
391
|
+
} # yapf: disable
|
|
392
|
+
sys.exit(check(**runargs))
|
|
393
|
+
|
|
394
|
+
sys.exit(res)
|
declinate/declinate.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Copyright 2022-2023 Ternaris.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""CLI declaration."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import importlib.metadata
|
|
8
|
+
import sys
|
|
9
|
+
from typing import TYPE_CHECKING, TypedDict
|
|
10
|
+
|
|
11
|
+
from .check import check_package
|
|
12
|
+
from .gen import generate_code
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from argparse import ArgumentParser
|
|
16
|
+
from typing import Annotated
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Kwargs(TypedDict):
|
|
20
|
+
"""All keyword arg types."""
|
|
21
|
+
package: str
|
|
22
|
+
version: bool
|
|
23
|
+
write: bool
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def command(
|
|
27
|
+
argparser: ArgumentParser,
|
|
28
|
+
*,
|
|
29
|
+
version: Annotated[bool, {
|
|
30
|
+
'flags': ['--version'],
|
|
31
|
+
}] = False,
|
|
32
|
+
**kwargs: Kwargs,
|
|
33
|
+
) -> int:
|
|
34
|
+
"""CLI generator for Python.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
argparser: Argument parser,
|
|
38
|
+
with mnoew text.
|
|
39
|
+
version: Print version number.
|
|
40
|
+
kwargs: Rest of all CLI params.
|
|
41
|
+
|
|
42
|
+
Groups:
|
|
43
|
+
x: SUPPRESS
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
0 if success.
|
|
47
|
+
|
|
48
|
+
"""
|
|
49
|
+
if version:
|
|
50
|
+
print(importlib.metadata.version('declinate')) # noqa: T201
|
|
51
|
+
sys.exit(0)
|
|
52
|
+
|
|
53
|
+
if not kwargs.get('_command'):
|
|
54
|
+
argparser.print_help()
|
|
55
|
+
sys.exit(0)
|
|
56
|
+
|
|
57
|
+
return 1
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def generate(
|
|
61
|
+
package: str,
|
|
62
|
+
*,
|
|
63
|
+
write: Annotated[\
|
|
64
|
+
bool, {
|
|
65
|
+
'flags': ['-w', '--write'],
|
|
66
|
+
},
|
|
67
|
+
] = False,
|
|
68
|
+
) -> int:
|
|
69
|
+
"""Generate CLI code.
|
|
70
|
+
|
|
71
|
+
This command parses the declarative CLI definition from a Python package
|
|
72
|
+
and generates the code for the CLI.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
package: Name of the Python package.
|
|
76
|
+
write: Write cli module into package.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
0 if success.
|
|
80
|
+
|
|
81
|
+
"""
|
|
82
|
+
code = generate_code(package, write=write)
|
|
83
|
+
if not write:
|
|
84
|
+
print(code) # noqa: T201
|
|
85
|
+
return 0
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def check(package: str) -> int:
|
|
89
|
+
"""Check if generated cli is up to date.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
package: Name of the Python package.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
0 if success.
|
|
96
|
+
|
|
97
|
+
"""
|
|
98
|
+
if res := check_package(package):
|
|
99
|
+
print(res) # noqa: T201
|
|
100
|
+
return 1
|
|
101
|
+
return 0
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
COMMAND = command
|
|
105
|
+
|
|
106
|
+
SUBCOMMANDS = [
|
|
107
|
+
generate,
|
|
108
|
+
check,
|
|
109
|
+
]
|