1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Overrides of standard argparse behavior."""
from __future__ import absolute_import
import argparse
import sys
import warnings
class ArgumentParser(argparse.ArgumentParser):
if sys.version_info < (3, 5):
def __init__(self, *args, **kwargs):
self.allow_abbrev = kwargs.pop("allow_abbrev", True)
super(ArgumentParser, self).__init__(*args, **kwargs)
def _get_option_tuples(self, option_string):
if self.allow_abbrev:
return super(ArgumentParser, self)._get_option_tuples(
option_string)
return ()
# NOTE(dhellmann): We have to override the methods for creating
# groups to return our objects that know how to deal with the
# special conflict handler.
def add_argument_group(self, *args, **kwargs):
group = _ArgumentGroup(self, *args, **kwargs)
self._action_groups.append(group)
return group
def add_mutually_exclusive_group(self, **kwargs):
group = _MutuallyExclusiveGroup(self, **kwargs)
self._mutually_exclusive_groups.append(group)
return group
def _handle_conflict_ignore(self, action, conflicting_actions):
_handle_conflict_ignore(
self,
self._option_string_actions,
action,
conflicting_actions,
)
def _handle_conflict_ignore(container, option_string_actions,
new_action, conflicting_actions):
# Remember the option strings the new action starts with so we can
# restore them as part of error reporting if we need to.
original_option_strings = new_action.option_strings
# Remove all of the conflicting option strings from the new action
# and report an error if none are left at the end.
for option_string, action in conflicting_actions:
# remove the conflicting option from the new action
new_action.option_strings.remove(option_string)
warnings.warn(
('Ignoring option string {} for new action '
'because it conflicts with an existing option.').format(
option_string))
# if the option now has no option string, remove it from the
# container holding it
if not new_action.option_strings:
new_action.option_strings = original_option_strings
raise argparse.ArgumentError(
new_action,
('Cannot resolve conflicting option string, '
'all names conflict.'),
)
class _ArgumentGroup(argparse._ArgumentGroup):
def _handle_conflict_ignore(self, action, conflicting_actions):
_handle_conflict_ignore(
self,
self._option_string_actions,
action,
conflicting_actions,
)
class _MutuallyExclusiveGroup(argparse._MutuallyExclusiveGroup):
def _handle_conflict_ignore(self, action, conflicting_actions):
_handle_conflict_ignore(
self,
self._option_string_actions,
action,
conflicting_actions,
)
class SmartHelpFormatter(argparse.HelpFormatter):
"""Smart help formatter to output raw help message if help contain \n.
Some command help messages maybe have multiple line content, the built-in
argparse.HelpFormatter wrap and split the content according to width, and
ignore \n in the raw help message, it merge multiple line content in one
line to output, that looks messy. SmartHelpFormatter keep the raw help
message format if it contain \n, and wrap long line like HelpFormatter
behavior.
"""
def _split_lines(self, text, width):
lines = text.splitlines() if '\n' in text else [text]
wrap_lines = []
for each_line in lines:
wrap_lines.extend(
super(SmartHelpFormatter, self)._split_lines(each_line, width)
)
return wrap_lines
|