Marco Ricci commited on 2024-12-07 08:50:03
Zeige 1 geänderte Dateien mit 99 Einfügungen und 95 Löschungen.
We expect to add new option categories that apply to multiple super- and subcommands, not just the "vault" subcommand.
... | ... |
@@ -57,6 +57,105 @@ _NO_USABLE_KEYS = 'No usable SSH keys were found' |
57 | 57 |
_EMPTY_SELECTION = 'Empty selection' |
58 | 58 |
|
59 | 59 |
|
60 |
+# Option parsing and grouping |
|
61 |
+# =========================== |
|
62 |
+ |
|
63 |
+ |
|
64 |
+class OptionGroupOption(click.Option): |
|
65 |
+ """A [`click.Option`][] with an associated group name and group epilog. |
|
66 |
+ |
|
67 |
+ Used by [`CommandWithHelpGroups`][] to print help sections. Each |
|
68 |
+ subclass contains its own group name and epilog. |
|
69 |
+ |
|
70 |
+ Attributes: |
|
71 |
+ option_group_name: |
|
72 |
+ The name of the option group. Used as a heading on the help |
|
73 |
+ text for options in this section. |
|
74 |
+ epilog: |
|
75 |
+ An epilog to print after listing the options in this |
|
76 |
+ section. |
|
77 |
+ |
|
78 |
+ """ |
|
79 |
+ |
|
80 |
+ option_group_name: str = '' |
|
81 |
+ """""" |
|
82 |
+ epilog: str = '' |
|
83 |
+ """""" |
|
84 |
+ |
|
85 |
+ def __init__(self, *args: Any, **kwargs: Any) -> None: # noqa: ANN401 |
|
86 |
+ if self.__class__ == __class__: # type: ignore[name-defined] |
|
87 |
+ raise NotImplementedError |
|
88 |
+ super().__init__(*args, **kwargs) |
|
89 |
+ |
|
90 |
+ |
|
91 |
+class CommandWithHelpGroups(click.Command): |
|
92 |
+ """A [`click.Command`][] with support for help/option groups. |
|
93 |
+ |
|
94 |
+ Inspired by [a comment on `pallets/click#373`][CLICK_ISSUE], and |
|
95 |
+ further modified to support group epilogs. |
|
96 |
+ |
|
97 |
+ [CLICK_ISSUE]: https://github.com/pallets/click/issues/373#issuecomment-515293746 |
|
98 |
+ |
|
99 |
+ """ |
|
100 |
+ |
|
101 |
+ def format_options( |
|
102 |
+ self, |
|
103 |
+ ctx: click.Context, |
|
104 |
+ formatter: click.HelpFormatter, |
|
105 |
+ ) -> None: |
|
106 |
+ r"""Format options on the help listing, grouped into sections. |
|
107 |
+ |
|
108 |
+ This is a callback for [`click.Command.get_help`][] that |
|
109 |
+ implements the `--help` listing, by calling appropriate methods |
|
110 |
+ of the `formatter`. We list all options (like the base |
|
111 |
+ implementation), but grouped into sections according to the |
|
112 |
+ concrete [`click.Option`][] subclass being used. If the option |
|
113 |
+ is an instance of some subclass of [`OptionGroupOption`][], then |
|
114 |
+ the section heading and the epilog are taken from the |
|
115 |
+ [`option_group_name`] [OptionGroupOption.option_group_name] and |
|
116 |
+ [`epilog`] [OptionGroupOption.epilog] attributes; otherwise, the |
|
117 |
+ section heading is "Options" (or "Other options" if there are |
|
118 |
+ other option groups) and the epilog is empty. |
|
119 |
+ |
|
120 |
+ Args: |
|
121 |
+ ctx: |
|
122 |
+ The click context. |
|
123 |
+ formatter: |
|
124 |
+ The formatter for the `--help` listing. |
|
125 |
+ |
|
126 |
+ """ |
|
127 |
+ help_records: dict[str, list[tuple[str, str]]] = {} |
|
128 |
+ epilogs: dict[str, str] = {} |
|
129 |
+ params = self.params[:] |
|
130 |
+ if ( # pragma: no branch |
|
131 |
+ (help_opt := self.get_help_option(ctx)) is not None |
|
132 |
+ and help_opt not in params |
|
133 |
+ ): |
|
134 |
+ params.append(help_opt) |
|
135 |
+ for param in params: |
|
136 |
+ rec = param.get_help_record(ctx) |
|
137 |
+ if rec is not None: |
|
138 |
+ if isinstance(param, OptionGroupOption): |
|
139 |
+ group_name = param.option_group_name |
|
140 |
+ epilogs.setdefault(group_name, param.epilog) |
|
141 |
+ else: |
|
142 |
+ group_name = '' |
|
143 |
+ help_records.setdefault(group_name, []).append(rec) |
|
144 |
+ default_group = help_records.pop('') |
|
145 |
+ default_group_name = ( |
|
146 |
+ 'Other Options' if len(default_group) > 1 else 'Options' |
|
147 |
+ ) |
|
148 |
+ help_records[default_group_name] = default_group |
|
149 |
+ for group_name, records in help_records.items(): |
|
150 |
+ with formatter.section(group_name): |
|
151 |
+ formatter.write_dl(records) |
|
152 |
+ epilog = inspect.cleandoc(epilogs.get(group_name, '')) |
|
153 |
+ if epilog: |
|
154 |
+ formatter.write_paragraph() |
|
155 |
+ with formatter.indentation(): |
|
156 |
+ formatter.write_text(epilog) |
|
157 |
+ |
|
158 |
+ |
|
60 | 159 |
# Top-level |
61 | 160 |
# ========= |
62 | 161 |
|
... | ... |
@@ -767,101 +866,6 @@ def _check_for_misleading_passphrase( |
767 | 866 |
) |
768 | 867 |
|
769 | 868 |
|
770 |
-class OptionGroupOption(click.Option): |
|
771 |
- """A [`click.Option`][] with an associated group name and group epilog. |
|
772 |
- |
|
773 |
- Used by [`CommandWithHelpGroups`][] to print help sections. Each |
|
774 |
- subclass contains its own group name and epilog. |
|
775 |
- |
|
776 |
- Attributes: |
|
777 |
- option_group_name: |
|
778 |
- The name of the option group. Used as a heading on the help |
|
779 |
- text for options in this section. |
|
780 |
- epilog: |
|
781 |
- An epilog to print after listing the options in this |
|
782 |
- section. |
|
783 |
- |
|
784 |
- """ |
|
785 |
- |
|
786 |
- option_group_name: str = '' |
|
787 |
- """""" |
|
788 |
- epilog: str = '' |
|
789 |
- """""" |
|
790 |
- |
|
791 |
- def __init__(self, *args: Any, **kwargs: Any) -> None: # noqa: ANN401 |
|
792 |
- if self.__class__ == __class__: # type: ignore[name-defined] |
|
793 |
- raise NotImplementedError |
|
794 |
- super().__init__(*args, **kwargs) |
|
795 |
- |
|
796 |
- |
|
797 |
-class CommandWithHelpGroups(click.Command): |
|
798 |
- """A [`click.Command`][] with support for help/option groups. |
|
799 |
- |
|
800 |
- Inspired by [a comment on `pallets/click#373`][CLICK_ISSUE], and |
|
801 |
- further modified to support group epilogs. |
|
802 |
- |
|
803 |
- [CLICK_ISSUE]: https://github.com/pallets/click/issues/373#issuecomment-515293746 |
|
804 |
- |
|
805 |
- """ |
|
806 |
- |
|
807 |
- def format_options( |
|
808 |
- self, |
|
809 |
- ctx: click.Context, |
|
810 |
- formatter: click.HelpFormatter, |
|
811 |
- ) -> None: |
|
812 |
- r"""Format options on the help listing, grouped into sections. |
|
813 |
- |
|
814 |
- This is a callback for [`click.Command.get_help`][] that |
|
815 |
- implements the `--help` listing, by calling appropriate methods |
|
816 |
- of the `formatter`. We list all options (like the base |
|
817 |
- implementation), but grouped into sections according to the |
|
818 |
- concrete [`click.Option`][] subclass being used. If the option |
|
819 |
- is an instance of some subclass of [`OptionGroupOption`][], then |
|
820 |
- the section heading and the epilog are taken from the |
|
821 |
- [`option_group_name`] [OptionGroupOption.option_group_name] and |
|
822 |
- [`epilog`] [OptionGroupOption.epilog] attributes; otherwise, the |
|
823 |
- section heading is "Options" (or "Other options" if there are |
|
824 |
- other option groups) and the epilog is empty. |
|
825 |
- |
|
826 |
- Args: |
|
827 |
- ctx: |
|
828 |
- The click context. |
|
829 |
- formatter: |
|
830 |
- The formatter for the `--help` listing. |
|
831 |
- |
|
832 |
- """ |
|
833 |
- help_records: dict[str, list[tuple[str, str]]] = {} |
|
834 |
- epilogs: dict[str, str] = {} |
|
835 |
- params = self.params[:] |
|
836 |
- if ( # pragma: no branch |
|
837 |
- (help_opt := self.get_help_option(ctx)) is not None |
|
838 |
- and help_opt not in params |
|
839 |
- ): |
|
840 |
- params.append(help_opt) |
|
841 |
- for param in params: |
|
842 |
- rec = param.get_help_record(ctx) |
|
843 |
- if rec is not None: |
|
844 |
- if isinstance(param, OptionGroupOption): |
|
845 |
- group_name = param.option_group_name |
|
846 |
- epilogs.setdefault(group_name, param.epilog) |
|
847 |
- else: |
|
848 |
- group_name = '' |
|
849 |
- help_records.setdefault(group_name, []).append(rec) |
|
850 |
- default_group = help_records.pop('') |
|
851 |
- default_group_name = ( |
|
852 |
- 'Other Options' if len(default_group) > 1 else 'Options' |
|
853 |
- ) |
|
854 |
- help_records[default_group_name] = default_group |
|
855 |
- for group_name, records in help_records.items(): |
|
856 |
- with formatter.section(group_name): |
|
857 |
- formatter.write_dl(records) |
|
858 |
- epilog = inspect.cleandoc(epilogs.get(group_name, '')) |
|
859 |
- if epilog: |
|
860 |
- formatter.write_paragraph() |
|
861 |
- with formatter.indentation(): |
|
862 |
- formatter.write_text(epilog) |
|
863 |
- |
|
864 |
- |
|
865 | 869 |
# Concrete option groups used by this command-line interface. |
866 | 870 |
class PasswordGenerationOption(OptionGroupOption): |
867 | 871 |
"""Password generation options for the CLI.""" |
868 | 872 |