Marco Ricci commited on 2024-12-31 22:30:36
Zeige 2 geänderte Dateien mit 137 Einfügungen und 8 Löschungen.
Reimplement the machinery for displaying help texts and version information, supporting translatable strings. Besides the one-line help texts for the `--help` and `--version` options, the version information text is a translatable string itself, in case the name and version number should be rearranged, or prefixed or suffixed, or whatever.
| ... | ... |
@@ -401,6 +401,11 @@ class Label(enum.Enum): |
| 401 | 401 |
""", |
| 402 | 402 |
context='help text (option one-line description)', |
| 403 | 403 |
) |
| 404 |
+ HELP_OPTION_HELP_TEXT = _prepare_translatable( |
|
| 405 |
+ 'show this help text, then exit', |
|
| 406 |
+ comments='', |
|
| 407 |
+ context='help text (option one-line description)', |
|
| 408 |
+ ) |
|
| 404 | 409 |
QUIET_OPTION_HELP_TEXT = _prepare_translatable( |
| 405 | 410 |
'suppress even warnings, emit only errors', |
| 406 | 411 |
comments='', |
| ... | ... |
@@ -411,6 +416,11 @@ class Label(enum.Enum): |
| 411 | 416 |
comments='', |
| 412 | 417 |
context='help text (option one-line description)', |
| 413 | 418 |
) |
| 419 |
+ VERSION_OPTION_HELP_TEXT = _prepare_translatable( |
|
| 420 |
+ 'show applicable version information, then exit', |
|
| 421 |
+ comments='', |
|
| 422 |
+ context='help text (option one-line description)', |
|
| 423 |
+ ) |
|
| 414 | 424 |
|
| 415 | 425 |
DERIVEPASSPHRASE_VAULT_PHRASE_HELP_TEXT = _prepare_translatable( |
| 416 | 426 |
msg='prompt for a master passphrase', |
| ... | ... |
@@ -675,6 +685,14 @@ class Label(enum.Enum): |
| 675 | 685 |
comments='', |
| 676 | 686 |
context='help text, option group name', |
| 677 | 687 |
) |
| 688 |
+ VERSION_INFO_TEXT = _prepare_translatable( |
|
| 689 |
+ msg=r""" |
|
| 690 |
+ {PROG_NAME!s} {__version__}
|
|
| 691 |
+ """, # noqa: RUF027 |
|
| 692 |
+ comments='', |
|
| 693 |
+ context='help text, version info text', |
|
| 694 |
+ flags='python-brace-format', |
|
| 695 |
+ ) |
|
| 678 | 696 |
CONFIRM_THIS_CHOICE_PROMPT_TEXT = _prepare_translatable( |
| 679 | 697 |
comments=r""" |
| 680 | 698 |
TRANSLATORS: There is no support for "yes" or "no" in other |
| ... | ... |
@@ -423,6 +423,10 @@ class OptionGroupOption(click.Option): |
| 423 | 423 |
self.help = help |
| 424 | 424 |
|
| 425 | 425 |
|
| 426 |
+class StandardOption(OptionGroupOption): |
|
| 427 |
+ pass |
|
| 428 |
+ |
|
| 429 |
+ |
|
| 426 | 430 |
class CommandWithHelpGroups(click.Command): |
| 427 | 431 |
"""A [`click.Command`][] with support for some help text customizations. |
| 428 | 432 |
|
| ... | ... |
@@ -498,6 +502,83 @@ class CommandWithHelpGroups(click.Command): |
| 498 | 502 |
rv.extend(str(x) for x in param.get_usage_pieces(ctx)) |
| 499 | 503 |
return rv |
| 500 | 504 |
|
| 505 |
+ def get_help_option( |
|
| 506 |
+ self, |
|
| 507 |
+ ctx: click.Context, |
|
| 508 |
+ ) -> click.Option | None: |
|
| 509 |
+ """Return a standard help option object. |
|
| 510 |
+ |
|
| 511 |
+ Based on code from click 8.1. Subject to the following license |
|
| 512 |
+ (3-clause BSD license): |
|
| 513 |
+ |
|
| 514 |
+ Copyright 2024 Pallets |
|
| 515 |
+ |
|
| 516 |
+ Redistribution and use in source and binary forms, with or |
|
| 517 |
+ without modification, are permitted provided that the |
|
| 518 |
+ following conditions are met: |
|
| 519 |
+ |
|
| 520 |
+ 1. Redistributions of source code must retain the above |
|
| 521 |
+ copyright notice, this list of conditions and the |
|
| 522 |
+ following disclaimer. |
|
| 523 |
+ |
|
| 524 |
+ 2. Redistributions in binary form must reproduce the above |
|
| 525 |
+ copyright notice, this list of conditions and the |
|
| 526 |
+ following disclaimer in the documentation and/or other |
|
| 527 |
+ materials provided with the distribution. |
|
| 528 |
+ |
|
| 529 |
+ 3. Neither the name of the copyright holder nor the names |
|
| 530 |
+ of its contributors may be used to endorse or promote |
|
| 531 |
+ products derived from this software without specific |
|
| 532 |
+ prior written permission. |
|
| 533 |
+ |
|
| 534 |
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
|
| 535 |
+ CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, |
|
| 536 |
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
|
| 537 |
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
| 538 |
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
|
| 539 |
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
| 540 |
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
| 541 |
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
| 542 |
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
| 543 |
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
| 544 |
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
|
| 545 |
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
| 546 |
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
| 547 |
+ |
|
| 548 |
+ Modifications are marked with respective comments. They too are |
|
| 549 |
+ released under the same license above. The original code did |
|
| 550 |
+ not contain any "noqa" or "pragma" comments. |
|
| 551 |
+ |
|
| 552 |
+ Args: |
|
| 553 |
+ ctx: |
|
| 554 |
+ The click context. |
|
| 555 |
+ |
|
| 556 |
+ """ |
|
| 557 |
+ help_options = self.get_help_option_names(ctx) |
|
| 558 |
+ |
|
| 559 |
+ if not help_options or not self.add_help_option: # pragma: no cover |
|
| 560 |
+ return None |
|
| 561 |
+ |
|
| 562 |
+ def show_help( |
|
| 563 |
+ ctx: click.Context, |
|
| 564 |
+ param: click.Parameter, # noqa: ARG001 |
|
| 565 |
+ value: str, |
|
| 566 |
+ ) -> None: |
|
| 567 |
+ if value and not ctx.resilient_parsing: |
|
| 568 |
+ click.echo(ctx.get_help(), color=ctx.color) |
|
| 569 |
+ ctx.exit() |
|
| 570 |
+ |
|
| 571 |
+ # Modified from click 8.1: We use StandardOption and a non-str |
|
| 572 |
+ # object as the help string. |
|
| 573 |
+ return StandardOption( |
|
| 574 |
+ help_options, |
|
| 575 |
+ is_flag=True, |
|
| 576 |
+ is_eager=True, |
|
| 577 |
+ expose_value=False, |
|
| 578 |
+ callback=show_help, |
|
| 579 |
+ help=_msg.TranslatedString(_msg.Label.HELP_OPTION_HELP_TEXT), |
|
| 580 |
+ ) |
|
| 581 |
+ |
|
| 501 | 582 |
def get_short_help_str( |
| 502 | 583 |
self, |
| 503 | 584 |
limit: int = 45, |
| ... | ... |
@@ -904,6 +985,37 @@ class CommandWithHelpGroups(click.Command): |
| 904 | 985 |
formatter.write_text(epilog) |
| 905 | 986 |
|
| 906 | 987 |
|
| 988 |
+def version_option_callback( |
|
| 989 |
+ ctx: click.Context, |
|
| 990 |
+ param: click.Parameter, |
|
| 991 |
+ value: bool, # noqa: FBT001 |
|
| 992 |
+) -> None: |
|
| 993 |
+ del param |
|
| 994 |
+ if value and not ctx.resilient_parsing: |
|
| 995 |
+ click.echo( |
|
| 996 |
+ str( |
|
| 997 |
+ _msg.TranslatedString( |
|
| 998 |
+ _msg.Label.VERSION_INFO_TEXT, |
|
| 999 |
+ PROG_NAME=PROG_NAME, |
|
| 1000 |
+ __version__=__version__, |
|
| 1001 |
+ ) |
|
| 1002 |
+ ), |
|
| 1003 |
+ ) |
|
| 1004 |
+ ctx.exit() |
|
| 1005 |
+ |
|
| 1006 |
+ |
|
| 1007 |
+def version_option(f: Callable[P, R]) -> Callable[P, R]: |
|
| 1008 |
+ return click.option( |
|
| 1009 |
+ '--version', |
|
| 1010 |
+ is_flag=True, |
|
| 1011 |
+ is_eager=True, |
|
| 1012 |
+ expose_value=False, |
|
| 1013 |
+ callback=version_option_callback, |
|
| 1014 |
+ cls=StandardOption, |
|
| 1015 |
+ help=_msg.TranslatedString(_msg.Label.VERSION_OPTION_HELP_TEXT), |
|
| 1016 |
+ )(f) |
|
| 1017 |
+ |
|
| 1018 |
+ |
|
| 907 | 1019 |
class LoggingOption(OptionGroupOption): |
| 908 | 1020 |
"""Logging options for the CLI.""" |
| 909 | 1021 |
|
| ... | ... |
@@ -1110,7 +1222,7 @@ class _TopLevelCLIEntryPoint(_DefaultToVaultGroup): |
| 1110 | 1222 |
_msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_03), |
| 1111 | 1223 |
), |
| 1112 | 1224 |
) |
| 1113 |
-@click.version_option(version=dpp.__version__, prog_name=PROG_NAME) |
|
| 1225 |
+@version_option |
|
| 1114 | 1226 |
@standard_logging_options |
| 1115 | 1227 |
@click.pass_context |
| 1116 | 1228 |
def derivepassphrase(ctx: click.Context, /) -> None: |
| ... | ... |
@@ -1159,7 +1271,7 @@ def derivepassphrase(ctx: click.Context, /) -> None: |
| 1159 | 1271 |
_msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_03), |
| 1160 | 1272 |
), |
| 1161 | 1273 |
) |
| 1162 |
-@click.version_option(version=dpp.__version__, prog_name=PROG_NAME) |
|
| 1274 |
+@version_option |
|
| 1163 | 1275 |
@standard_logging_options |
| 1164 | 1276 |
@click.pass_context |
| 1165 | 1277 |
def derivepassphrase_export(ctx: click.Context, /) -> None: |
| ... | ... |
@@ -1231,10 +1343,6 @@ def _load_data( |
| 1231 | 1343 |
assert_never(fmt) |
| 1232 | 1344 |
|
| 1233 | 1345 |
|
| 1234 |
-class StandardOption(OptionGroupOption): |
|
| 1235 |
- pass |
|
| 1236 |
- |
|
| 1237 |
- |
|
| 1238 | 1346 |
@derivepassphrase_export.command( |
| 1239 | 1347 |
'vault', |
| 1240 | 1348 |
context_settings={'help_option_names': ['-h', '--help']},
|
| ... | ... |
@@ -1255,7 +1363,6 @@ class StandardOption(OptionGroupOption): |
| 1255 | 1363 |
), |
| 1256 | 1364 |
), |
| 1257 | 1365 |
) |
| 1258 |
-@standard_logging_options |
|
| 1259 | 1366 |
@click.option( |
| 1260 | 1367 |
'-f', |
| 1261 | 1368 |
'--format', |
| ... | ... |
@@ -1288,6 +1395,8 @@ class StandardOption(OptionGroupOption): |
| 1288 | 1395 |
), |
| 1289 | 1396 |
cls=StandardOption, |
| 1290 | 1397 |
) |
| 1398 |
+@version_option |
|
| 1399 |
+@standard_logging_options |
|
| 1291 | 1400 |
@click.argument( |
| 1292 | 1401 |
'path', |
| 1293 | 1402 |
metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_METAVAR_PATH), |
| ... | ... |
@@ -2362,7 +2471,7 @@ DEFAULT_NOTES_MARKER = '# - - - - - >8 - - - - -' |
| 2362 | 2471 |
), |
| 2363 | 2472 |
cls=CompatibilityOption, |
| 2364 | 2473 |
) |
| 2365 |
-@click.version_option(version=dpp.__version__, prog_name=PROG_NAME) |
|
| 2474 |
+@version_option |
|
| 2366 | 2475 |
@standard_logging_options |
| 2367 | 2476 |
@click.argument( |
| 2368 | 2477 |
'service', |
| ... | ... |
@@ -2508,6 +2617,8 @@ def derivepassphrase_vault( # noqa: C901,PLR0912,PLR0913,PLR0914,PLR0915 |
| 2508 | 2617 |
group = LoggingOption |
| 2509 | 2618 |
elif isinstance(param, CompatibilityOption): |
| 2510 | 2619 |
group = CompatibilityOption |
| 2620 |
+ elif isinstance(param, StandardOption): |
|
| 2621 |
+ group = StandardOption |
|
| 2511 | 2622 |
elif isinstance(param, OptionGroupOption): |
| 2512 | 2623 |
raise AssertionError( # noqa: DOC501,TRY003,TRY004 |
| 2513 | 2624 |
f'Unknown option group for {param!r}' # noqa: EM102
|
| 2514 | 2625 |