Marco Ricci commited on 2024-12-13 14:25:44
Zeige 3 geänderte Dateien mit 50 Einfügungen und 70 Löschungen.
The three "verbosity" options `--debug`, `--verbose` and `--quiet` set the logging level for `derivepassphrase`, globally. Because `click` does not support mutually exclusive options by default, these options are implemented as boolean flags, and it is possible to override earlier verbosity settings with later options. The previous setup treated the three options as disjointed flags, so each callback was called once, irrespective of the others, so the aforementioned intended overriding behavior was not working properly. In addition, the callback was faulty, always enabling each of the flags. The new setup now links all three options to the same flag, with different flag values. We further expose the option objects at the top level, and unify the three callback functions to a single one. As a side effect, we also fix a misclassified diagnostic during configuration file migration ("vault" derivation scheme).
... | ... |
@@ -343,53 +343,25 @@ P = ParamSpec('P') |
343 | 343 |
R = TypeVar('R') |
344 | 344 |
|
345 | 345 |
|
346 |
-def log_debug( |
|
346 |
+def adjust_logging_level( |
|
347 | 347 |
ctx: click.Context, |
348 | 348 |
/, |
349 | 349 |
param: click.Parameter | None = None, |
350 |
- value: Any = None, # noqa: ANN401 |
|
350 |
+ value: int | None = None, |
|
351 | 351 |
) -> None: |
352 |
- """Request that DEBUG-level logs be emitted to standard error. |
|
352 |
+ """Change the logs that are emitted to standard error. |
|
353 | 353 |
|
354 | 354 |
This modifies the [`StandardCLILogging`][] settings such that log |
355 |
- records at level [`logging.DEBUG`][] and [`logging.INFO`][] are |
|
356 |
- emitted as well. |
|
355 |
+ records at the respective level are emitted, based on the `param` |
|
356 |
+ and the `value`. |
|
357 | 357 |
|
358 | 358 |
""" |
359 |
- del ctx, param, value |
|
360 |
- StandardCLILogging.cli_handler.setLevel(logging.DEBUG) |
|
361 |
- |
|
362 |
- |
|
363 |
-def log_info( |
|
364 |
- ctx: click.Context, |
|
365 |
- /, |
|
366 |
- param: click.Parameter | None = None, |
|
367 |
- value: Any = None, # noqa: ANN401 |
|
368 |
-) -> None: |
|
369 |
- """Request that INFO-level logs be emitted to standard error. |
|
370 |
- |
|
371 |
- This modifies the [`StandardCLILogging`][] settings such that log |
|
372 |
- records at level [`logging.INFO`][] are emitted as well. |
|
373 |
- |
|
374 |
- """ |
|
375 |
- del ctx, param, value |
|
376 |
- StandardCLILogging.cli_handler.setLevel(logging.INFO) |
|
377 |
- |
|
378 |
- |
|
379 |
-def silence_warnings( |
|
380 |
- ctx: click.Context, |
|
381 |
- /, |
|
382 |
- param: click.Parameter | None = None, |
|
383 |
- value: Any = None, # noqa: ANN401 |
|
384 |
-) -> None: |
|
385 |
- """Request that WARNING-level logs not be emitted to standard error. |
|
386 |
- |
|
387 |
- This modifies the [`StandardCLILogging`][] settings such that log |
|
388 |
- records at level [`logging.WARNING`][] and below are *not* emitted. |
|
389 |
- |
|
390 |
- """ |
|
391 |
- del ctx, param, value |
|
392 |
- StandardCLILogging.cli_handler.setLevel(logging.ERROR) |
|
359 |
+ # Note: If multiple options use this callback, then we will be |
|
360 |
+ # called multiple times. Ensure the runs are idempotent. |
|
361 |
+ if param is None or value is None or ctx.resilient_parsing: |
|
362 |
+ return |
|
363 |
+ StandardCLILogging.cli_handler.setLevel(value) |
|
364 |
+ logging.getLogger(StandardCLILogging.package_name).setLevel(value) |
|
393 | 365 |
|
394 | 366 |
|
395 | 367 |
# Option parsing and grouping |
... | ... |
@@ -498,50 +470,55 @@ class LoggingOption(OptionGroupOption): |
498 | 470 |
epilog = '' |
499 | 471 |
|
500 | 472 |
|
501 |
-def standard_logging_options(f: Callable[P, R]) -> Callable[P, R]: |
|
502 |
- """Decorate the function with standard logging click options. |
|
503 |
- |
|
504 |
- Adds the three click options `-v`/`--verbose`, `-q`/`--quiet` and |
|
505 |
- `--debug`, which issue callbacks to the [`log_info`][], |
|
506 |
- [`silence_warnings`][] and [`log_debug`][] functions, respectively. |
|
507 |
- |
|
508 |
- Args: |
|
509 |
- f: A callable to decorate. |
|
510 |
- |
|
511 |
- Returns: |
|
512 |
- The decorated callable. |
|
513 |
- |
|
514 |
- """ |
|
515 |
- dec1 = click.option( |
|
516 |
- '-q', |
|
517 |
- '--quiet', |
|
473 |
+debug_option = click.option( |
|
474 |
+ '--debug', |
|
475 |
+ 'logging_level', |
|
518 | 476 |
is_flag=True, |
519 |
- is_eager=True, |
|
477 |
+ flag_value=logging.DEBUG, |
|
520 | 478 |
expose_value=False, |
521 |
- callback=silence_warnings, |
|
522 |
- help='suppress even warnings, emit only errors', |
|
479 |
+ callback=adjust_logging_level, |
|
480 |
+ help='also emit debug information (implies --verbose)', |
|
523 | 481 |
cls=LoggingOption, |
524 | 482 |
) |
525 |
- dec2 = click.option( |
|
483 |
+verbose_option = click.option( |
|
526 | 484 |
'-v', |
527 | 485 |
'--verbose', |
486 |
+ 'logging_level', |
|
528 | 487 |
is_flag=True, |
529 |
- is_eager=True, |
|
488 |
+ flag_value=logging.INFO, |
|
530 | 489 |
expose_value=False, |
531 |
- callback=log_info, |
|
490 |
+ callback=adjust_logging_level, |
|
532 | 491 |
help='emit extra/progress information to standard error', |
533 | 492 |
cls=LoggingOption, |
534 | 493 |
) |
535 |
- dec3 = click.option( |
|
536 |
- '--debug', |
|
494 |
+quiet_option = click.option( |
|
495 |
+ '-q', |
|
496 |
+ '--quiet', |
|
497 |
+ 'logging_level', |
|
537 | 498 |
is_flag=True, |
538 |
- is_eager=True, |
|
499 |
+ flag_value=logging.ERROR, |
|
539 | 500 |
expose_value=False, |
540 |
- callback=log_debug, |
|
541 |
- help='also emit debug information (implies --verbose)', |
|
501 |
+ callback=adjust_logging_level, |
|
502 |
+ help='suppress even warnings, emit only errors', |
|
542 | 503 |
cls=LoggingOption, |
543 | 504 |
) |
544 |
- return dec1(dec2(dec3(f))) |
|
505 |
+ |
|
506 |
+ |
|
507 |
+def standard_logging_options(f: Callable[P, R]) -> Callable[P, R]: |
|
508 |
+ """Decorate the function with standard logging click options. |
|
509 |
+ |
|
510 |
+ Adds the three click options `-v`/`--verbose`, `-q`/`--quiet` and |
|
511 |
+ `--debug`, which issue callbacks to the [`log_info`][], |
|
512 |
+ [`silence_warnings`][] and [`log_debug`][] functions, respectively. |
|
513 |
+ |
|
514 |
+ Args: |
|
515 |
+ f: A callable to decorate. |
|
516 |
+ |
|
517 |
+ Returns: |
|
518 |
+ The decorated callable. |
|
519 |
+ |
|
520 |
+ """ |
|
521 |
+ return debug_option(verbose_option(quiet_option(f))) |
|
545 | 522 |
|
546 | 523 |
|
547 | 524 |
# Top-level |
... | ... |
@@ -1754,7 +1731,7 @@ def derivepassphrase_vault( # noqa: C901,PLR0912,PLR0913,PLR0914,PLR0915 |
1754 | 1731 |
exc.filename, |
1755 | 1732 |
) |
1756 | 1733 |
else: |
1757 |
- logger.info('Successfully migrated to %r.', new_name) |
|
1734 |
+ deprecation.info('Successfully migrated to %r.', new_name) |
|
1758 | 1735 |
return backup_config |
1759 | 1736 |
except OSError as e: |
1760 | 1737 |
err('Cannot load config: %s: %r', e.strerror, e.filename) |
... | ... |
@@ -1713,4 +1713,7 @@ warning_emitted = message_emitted_factory(logging.WARNING) |
1713 | 1713 |
deprecation_warning_emitted = message_emitted_factory( |
1714 | 1714 |
logging.WARNING, logger_name=f'{cli.PROG_NAME}.deprecation' |
1715 | 1715 |
) |
1716 |
+deprecation_info_emitted = message_emitted_factory( |
|
1717 |
+ logging.INFO, logger_name=f'{cli.PROG_NAME}.deprecation' |
|
1718 |
+) |
|
1716 | 1719 |
error_emitted = message_emitted_factory(logging.ERROR) |
... | ... |
@@ -2279,7 +2279,7 @@ class TestCLITransition: |
2279 | 2279 |
assert tests.deprecation_warning_emitted( |
2280 | 2280 |
'v0.1-style config file', caplog.record_tuples |
2281 | 2281 |
), 'expected known warning message in stderr' |
2282 |
- assert tests.info_emitted( |
|
2282 |
+ assert tests.deprecation_info_emitted( |
|
2283 | 2283 |
'Successfully migrated to ', caplog.record_tuples |
2284 | 2284 |
), 'expected known warning message in stderr' |
2285 | 2285 |
|
2286 | 2286 |