|
28 | 28 | import sys |
29 | 29 | import tempfile |
30 | 30 | import textwrap |
31 | | -from collections.abc import Iterable, Sequence |
| 31 | +from collections.abc import Callable, Iterable, Sequence |
32 | 32 | from re import Match, Pattern |
33 | 33 | from typing import ( |
34 | 34 | Any, |
@@ -176,6 +176,44 @@ class QuietLevels: |
176 | 176 | CONFIG_FILES = 32 |
177 | 177 |
|
178 | 178 |
|
| 179 | +_INTERACTIVE_NAMES = {"ask": 1, "choose": 2} |
| 180 | +_QUIET_LEVEL_NAMES = { |
| 181 | + "encoding": QuietLevels.ENCODING, |
| 182 | + "binary-file": QuietLevels.BINARY_FILE, |
| 183 | + "disabled-fixes": QuietLevels.DISABLED_FIXES, |
| 184 | + "non-automatic-fixes": QuietLevels.NON_AUTOMATIC_FIXES, |
| 185 | + "fixes": QuietLevels.FIXES, |
| 186 | + "config-files": QuietLevels.CONFIG_FILES, |
| 187 | +} |
| 188 | + |
| 189 | + |
| 190 | +def _bitmask(names: dict[str, int]) -> Callable[[str], int]: |
| 191 | + """Return an argparse type for a bitmask option. |
| 192 | +
|
| 193 | + The value is either the number as before (``3``) or a comma-separated |
| 194 | + list of names (``ask,choose``) that are ORed together (GH-2526). |
| 195 | + """ |
| 196 | + all_bits = sum(names.values()) |
| 197 | + |
| 198 | + def parse(value: str) -> int: |
| 199 | + if value.isdigit(): |
| 200 | + level = int(value) |
| 201 | + if level > all_bits: |
| 202 | + msg = f"invalid choice: {value} (choose from 0-{all_bits})" |
| 203 | + raise argparse.ArgumentTypeError(msg) |
| 204 | + return level |
| 205 | + level = 0 |
| 206 | + for name in value.split(","): |
| 207 | + try: |
| 208 | + level |= names[name.strip()] |
| 209 | + except KeyError: |
| 210 | + msg = f"invalid choice: {name!r} (choose from {', '.join(names)})" |
| 211 | + raise argparse.ArgumentTypeError(msg) from None |
| 212 | + return level |
| 213 | + |
| 214 | + return parse |
| 215 | + |
| 216 | + |
179 | 217 | class GlobMatch: |
180 | 218 | def __init__(self, pattern: list[str]) -> None: |
181 | 219 | self.pattern_list: list[str] = pattern |
@@ -592,35 +630,35 @@ def convert_arg_line_to_args(self, arg_line: str) -> list[str]: |
592 | 630 | "-i", |
593 | 631 | "--interactive", |
594 | 632 | action="store", |
595 | | - type=int, |
| 633 | + type=_bitmask(_INTERACTIVE_NAMES), |
596 | 634 | default=0, |
597 | | - choices=range(0, 4), |
598 | | - help="set interactive mode when writing changes:\n" |
| 635 | + help="set interactive mode when writing changes, as a number " |
| 636 | + "or as a comma-separated list of names:\n" |
599 | 637 | "- 0: no interactivity.\n" |
600 | | - "- 1: ask for confirmation; 'a'/'s' answer for the rest of the file.\n" |
601 | | - "- 2: ask user to choose one fix when more than one is available;" |
| 638 | + "- 1 or ask: ask for confirmation; 'a'/'s' answer for the rest of the file.\n" |
| 639 | + "- 2 or choose: ask user to choose one fix when more than one is available;" |
602 | 640 | " 'Na'/'s' answer for the rest of the file.\n" |
603 | | - "- 3: both 1 and 2", |
| 641 | + "- 3 or ask,choose: both 1 and 2", |
604 | 642 | metavar="MODE", |
605 | 643 | ) |
606 | 644 |
|
607 | 645 | parser.add_argument( |
608 | 646 | "-q", |
609 | 647 | "--quiet-level", |
610 | 648 | action="store", |
611 | | - type=int, |
| 649 | + type=_bitmask(_QUIET_LEVEL_NAMES), |
612 | 650 | default=34, |
613 | | - choices=range(0, 64), |
614 | | - help="bitmask that allows suppressing messages:\n" |
| 651 | + help="bitmask that allows suppressing messages, as a number " |
| 652 | + "or as a comma-separated list of names:\n" |
615 | 653 | "- 0: print all messages.\n" |
616 | | - "- 1: disable warnings about wrong encoding.\n" |
617 | | - "- 2: disable warnings about binary files.\n" |
618 | | - "- 4: omit warnings about automatic fixes that were disabled in the dictionary.\n" # noqa: E501 |
619 | | - "- 8: don't print anything for non-automatic fixes.\n" |
620 | | - "- 16: don't print the list of fixed files.\n" |
621 | | - "- 32: don't print configuration files.\n" |
| 654 | + "- 1 or encoding: disable warnings about wrong encoding.\n" |
| 655 | + "- 2 or binary-file: disable warnings about binary files.\n" |
| 656 | + "- 4 or disabled-fixes: omit warnings about automatic fixes that were disabled in the dictionary.\n" # noqa: E501 |
| 657 | + "- 8 or non-automatic-fixes: don't print anything for non-automatic fixes.\n" |
| 658 | + "- 16 or fixes: don't print the list of fixed files.\n" |
| 659 | + "- 32 or config-files: don't print configuration files.\n" |
622 | 660 | "As usual with bitmasks, these levels can be " |
623 | | - "combined; e.g. use 3 for levels 1+2, 7 for " |
| 661 | + "combined; e.g. use 3 or encoding,binary-file for levels 1+2, 7 for " |
624 | 662 | "1+2+4, 23 for 1+2+4+16, etc. " |
625 | 663 | "The default mask is %(default)s.", |
626 | 664 | metavar="LEVEL", |
|
0 commit comments