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