Mercurial > repos > shellac > sam_consensus_v3
comparison env/lib/python3.9/site-packages/pip/_internal/cli/parser.py @ 0:4f3585e2f14b draft default tip
"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author | shellac |
---|---|
date | Mon, 22 Mar 2021 18:12:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4f3585e2f14b |
---|---|
1 """Base option parser setup""" | |
2 | |
3 # The following comment should be removed at some point in the future. | |
4 # mypy: disallow-untyped-defs=False | |
5 | |
6 import logging | |
7 import optparse | |
8 import shutil | |
9 import sys | |
10 import textwrap | |
11 | |
12 from pip._vendor.contextlib2 import suppress | |
13 | |
14 from pip._internal.cli.status_codes import UNKNOWN_ERROR | |
15 from pip._internal.configuration import Configuration, ConfigurationError | |
16 from pip._internal.utils.misc import redact_auth_from_url, strtobool | |
17 | |
18 logger = logging.getLogger(__name__) | |
19 | |
20 | |
21 class PrettyHelpFormatter(optparse.IndentedHelpFormatter): | |
22 """A prettier/less verbose help formatter for optparse.""" | |
23 | |
24 def __init__(self, *args, **kwargs): | |
25 # help position must be aligned with __init__.parseopts.description | |
26 kwargs['max_help_position'] = 30 | |
27 kwargs['indent_increment'] = 1 | |
28 kwargs['width'] = shutil.get_terminal_size()[0] - 2 | |
29 super().__init__(*args, **kwargs) | |
30 | |
31 def format_option_strings(self, option): | |
32 return self._format_option_strings(option) | |
33 | |
34 def _format_option_strings(self, option, mvarfmt=' <{}>', optsep=', '): | |
35 """ | |
36 Return a comma-separated list of option strings and metavars. | |
37 | |
38 :param option: tuple of (short opt, long opt), e.g: ('-f', '--format') | |
39 :param mvarfmt: metavar format string | |
40 :param optsep: separator | |
41 """ | |
42 opts = [] | |
43 | |
44 if option._short_opts: | |
45 opts.append(option._short_opts[0]) | |
46 if option._long_opts: | |
47 opts.append(option._long_opts[0]) | |
48 if len(opts) > 1: | |
49 opts.insert(1, optsep) | |
50 | |
51 if option.takes_value(): | |
52 metavar = option.metavar or option.dest.lower() | |
53 opts.append(mvarfmt.format(metavar.lower())) | |
54 | |
55 return ''.join(opts) | |
56 | |
57 def format_heading(self, heading): | |
58 if heading == 'Options': | |
59 return '' | |
60 return heading + ':\n' | |
61 | |
62 def format_usage(self, usage): | |
63 """ | |
64 Ensure there is only one newline between usage and the first heading | |
65 if there is no description. | |
66 """ | |
67 msg = '\nUsage: {}\n'.format( | |
68 self.indent_lines(textwrap.dedent(usage), " ")) | |
69 return msg | |
70 | |
71 def format_description(self, description): | |
72 # leave full control over description to us | |
73 if description: | |
74 if hasattr(self.parser, 'main'): | |
75 label = 'Commands' | |
76 else: | |
77 label = 'Description' | |
78 # some doc strings have initial newlines, some don't | |
79 description = description.lstrip('\n') | |
80 # some doc strings have final newlines and spaces, some don't | |
81 description = description.rstrip() | |
82 # dedent, then reindent | |
83 description = self.indent_lines(textwrap.dedent(description), " ") | |
84 description = f'{label}:\n{description}\n' | |
85 return description | |
86 else: | |
87 return '' | |
88 | |
89 def format_epilog(self, epilog): | |
90 # leave full control over epilog to us | |
91 if epilog: | |
92 return epilog | |
93 else: | |
94 return '' | |
95 | |
96 def indent_lines(self, text, indent): | |
97 new_lines = [indent + line for line in text.split('\n')] | |
98 return "\n".join(new_lines) | |
99 | |
100 | |
101 class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter): | |
102 """Custom help formatter for use in ConfigOptionParser. | |
103 | |
104 This is updates the defaults before expanding them, allowing | |
105 them to show up correctly in the help listing. | |
106 | |
107 Also redact auth from url type options | |
108 """ | |
109 | |
110 def expand_default(self, option): | |
111 default_values = None | |
112 if self.parser is not None: | |
113 self.parser._update_defaults(self.parser.defaults) | |
114 default_values = self.parser.defaults.get(option.dest) | |
115 help_text = super().expand_default(option) | |
116 | |
117 if default_values and option.metavar == 'URL': | |
118 if isinstance(default_values, str): | |
119 default_values = [default_values] | |
120 | |
121 # If its not a list, we should abort and just return the help text | |
122 if not isinstance(default_values, list): | |
123 default_values = [] | |
124 | |
125 for val in default_values: | |
126 help_text = help_text.replace( | |
127 val, redact_auth_from_url(val)) | |
128 | |
129 return help_text | |
130 | |
131 | |
132 class CustomOptionParser(optparse.OptionParser): | |
133 | |
134 def insert_option_group(self, idx, *args, **kwargs): | |
135 """Insert an OptionGroup at a given position.""" | |
136 group = self.add_option_group(*args, **kwargs) | |
137 | |
138 self.option_groups.pop() | |
139 self.option_groups.insert(idx, group) | |
140 | |
141 return group | |
142 | |
143 @property | |
144 def option_list_all(self): | |
145 """Get a list of all options, including those in option groups.""" | |
146 res = self.option_list[:] | |
147 for i in self.option_groups: | |
148 res.extend(i.option_list) | |
149 | |
150 return res | |
151 | |
152 | |
153 class ConfigOptionParser(CustomOptionParser): | |
154 """Custom option parser which updates its defaults by checking the | |
155 configuration files and environmental variables""" | |
156 | |
157 def __init__(self, *args, **kwargs): | |
158 self.name = kwargs.pop('name') | |
159 | |
160 isolated = kwargs.pop("isolated", False) | |
161 self.config = Configuration(isolated) | |
162 | |
163 assert self.name | |
164 super().__init__(*args, **kwargs) | |
165 | |
166 def check_default(self, option, key, val): | |
167 try: | |
168 return option.check_value(key, val) | |
169 except optparse.OptionValueError as exc: | |
170 print(f"An error occurred during configuration: {exc}") | |
171 sys.exit(3) | |
172 | |
173 def _get_ordered_configuration_items(self): | |
174 # Configuration gives keys in an unordered manner. Order them. | |
175 override_order = ["global", self.name, ":env:"] | |
176 | |
177 # Pool the options into different groups | |
178 section_items = {name: [] for name in override_order} | |
179 for section_key, val in self.config.items(): | |
180 # ignore empty values | |
181 if not val: | |
182 logger.debug( | |
183 "Ignoring configuration key '%s' as it's value is empty.", | |
184 section_key | |
185 ) | |
186 continue | |
187 | |
188 section, key = section_key.split(".", 1) | |
189 if section in override_order: | |
190 section_items[section].append((key, val)) | |
191 | |
192 # Yield each group in their override order | |
193 for section in override_order: | |
194 for key, val in section_items[section]: | |
195 yield key, val | |
196 | |
197 def _update_defaults(self, defaults): | |
198 """Updates the given defaults with values from the config files and | |
199 the environ. Does a little special handling for certain types of | |
200 options (lists).""" | |
201 | |
202 # Accumulate complex default state. | |
203 self.values = optparse.Values(self.defaults) | |
204 late_eval = set() | |
205 # Then set the options with those values | |
206 for key, val in self._get_ordered_configuration_items(): | |
207 # '--' because configuration supports only long names | |
208 option = self.get_option('--' + key) | |
209 | |
210 # Ignore options not present in this parser. E.g. non-globals put | |
211 # in [global] by users that want them to apply to all applicable | |
212 # commands. | |
213 if option is None: | |
214 continue | |
215 | |
216 if option.action in ('store_true', 'store_false'): | |
217 try: | |
218 val = strtobool(val) | |
219 except ValueError: | |
220 self.error( | |
221 '{} is not a valid value for {} option, ' # noqa | |
222 'please specify a boolean value like yes/no, ' | |
223 'true/false or 1/0 instead.'.format(val, key) | |
224 ) | |
225 elif option.action == 'count': | |
226 with suppress(ValueError): | |
227 val = strtobool(val) | |
228 with suppress(ValueError): | |
229 val = int(val) | |
230 if not isinstance(val, int) or val < 0: | |
231 self.error( | |
232 '{} is not a valid value for {} option, ' # noqa | |
233 'please instead specify either a non-negative integer ' | |
234 'or a boolean value like yes/no or false/true ' | |
235 'which is equivalent to 1/0.'.format(val, key) | |
236 ) | |
237 elif option.action == 'append': | |
238 val = val.split() | |
239 val = [self.check_default(option, key, v) for v in val] | |
240 elif option.action == 'callback': | |
241 late_eval.add(option.dest) | |
242 opt_str = option.get_opt_string() | |
243 val = option.convert_value(opt_str, val) | |
244 # From take_action | |
245 args = option.callback_args or () | |
246 kwargs = option.callback_kwargs or {} | |
247 option.callback(option, opt_str, val, self, *args, **kwargs) | |
248 else: | |
249 val = self.check_default(option, key, val) | |
250 | |
251 defaults[option.dest] = val | |
252 | |
253 for key in late_eval: | |
254 defaults[key] = getattr(self.values, key) | |
255 self.values = None | |
256 return defaults | |
257 | |
258 def get_default_values(self): | |
259 """Overriding to make updating the defaults after instantiation of | |
260 the option parser possible, _update_defaults() does the dirty work.""" | |
261 if not self.process_default_values: | |
262 # Old, pre-Optik 1.5 behaviour. | |
263 return optparse.Values(self.defaults) | |
264 | |
265 # Load the configuration, or error out in case of an error | |
266 try: | |
267 self.config.load() | |
268 except ConfigurationError as err: | |
269 self.exit(UNKNOWN_ERROR, str(err)) | |
270 | |
271 defaults = self._update_defaults(self.defaults.copy()) # ours | |
272 for option in self._get_all_options(): | |
273 default = defaults.get(option.dest) | |
274 if isinstance(default, str): | |
275 opt_str = option.get_opt_string() | |
276 defaults[option.dest] = option.check_value(opt_str, default) | |
277 return optparse.Values(defaults) | |
278 | |
279 def error(self, msg): | |
280 self.print_usage(sys.stderr) | |
281 self.exit(UNKNOWN_ERROR, f"{msg}\n") |