Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / argument / __init__.py @ 6893e31c

History | View | Annotate | Download (22.1 kB)

1 e3f01d64 Stavros Sachtouris
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2 b9331a9f Stavros Sachtouris
#
3 b9331a9f Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
4 b9331a9f Stavros Sachtouris
# without modification, are permitted provided that the following
5 b9331a9f Stavros Sachtouris
# conditions are met:
6 b9331a9f Stavros Sachtouris
#
7 b9331a9f Stavros Sachtouris
#   1. Redistributions of source code must retain the above
8 b9331a9f Stavros Sachtouris
#     copyright notice, this list of conditions and the following
9 b9331a9f Stavros Sachtouris
#     disclaimer.
10 b9331a9f Stavros Sachtouris
#
11 b9331a9f Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
12 b9331a9f Stavros Sachtouris
#     copyright notice, this list of conditions and the following
13 b9331a9f Stavros Sachtouris
#     disclaimer in the documentation and/or other materials
14 b9331a9f Stavros Sachtouris
#     provided with the distribution.
15 b9331a9f Stavros Sachtouris
#
16 b9331a9f Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 b9331a9f Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 b9331a9f Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 b9331a9f Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 b9331a9f Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 b9331a9f Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 b9331a9f Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 b9331a9f Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 b9331a9f Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 b9331a9f Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 b9331a9f Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 b9331a9f Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
28 b9331a9f Stavros Sachtouris
#
29 b9331a9f Stavros Sachtouris
# The views and conclusions contained in the software and
30 b9331a9f Stavros Sachtouris
# documentation are those of the authors and should not be
31 b9331a9f Stavros Sachtouris
# interpreted as representing official policies, either expressed
32 b9331a9f Stavros Sachtouris
# or implied, of GRNET S.A.
33 9bdc89da Stavros Sachtouris
34 c270fe96 Stavros Sachtouris
from kamaki.cli.config import Config
35 b696ed2c Stavros Sachtouris
from kamaki.cli.errors import CLISyntaxError, raiseCLIError
36 7b109aa7 Stavros Sachtouris
from kamaki.cli.utils import split_input, to_bytes
37 7637d600 Stavros Sachtouris
38 04d01cd4 Stavros Sachtouris
from datetime import datetime as dtm
39 ea4a21b8 Stavros Sachtouris
from time import mktime
40 56d84a4e Stavros Sachtouris
from sys import stderr
41 db8d1766 Stavros Sachtouris
42 7637d600 Stavros Sachtouris
from logging import getLogger
43 af6de846 Stavros Sachtouris
from argparse import ArgumentParser, ArgumentError
44 2703cceb Stavros Sachtouris
from argparse import RawDescriptionHelpFormatter
45 67083ca0 Stavros Sachtouris
from progress.bar import ShadyBar as KamakiProgressBar
46 fd1f1d96 Stavros Sachtouris
47 7637d600 Stavros Sachtouris
log = getLogger(__name__)
48 db8d1766 Stavros Sachtouris
49 fd5db045 Stavros Sachtouris
50 dfee2caf Stavros Sachtouris
class Argument(object):
51 edb7fc1a Stavros Sachtouris
    """An argument that can be parsed from command line or otherwise.
52 5286e2c3 Stavros Sachtouris
    This is the top-level Argument class. It is suggested to extent this
53 edb7fc1a Stavros Sachtouris
    class into more specific argument types.
54 edb7fc1a Stavros Sachtouris
    """
55 eb647cfe Stavros Sachtouris
    lvalue_delimiter = '/'
56 dfee2caf Stavros Sachtouris
57 dfee2caf Stavros Sachtouris
    def __init__(self, arity, help=None, parsed_name=None, default=None):
58 606fe15f Stavros Sachtouris
        self.arity = int(arity)
59 5286e2c3 Stavros Sachtouris
        self.help = '%s' % help or ''
60 dfee2caf Stavros Sachtouris
61 f17d6cb5 Stavros Sachtouris
        assert parsed_name, 'No parsed name for argument %s' % self
62 f17d6cb5 Stavros Sachtouris
        self.parsed_name = list(parsed_name) if isinstance(
63 f17d6cb5 Stavros Sachtouris
            parsed_name, list) or isinstance(parsed_name, tuple) else (
64 f17d6cb5 Stavros Sachtouris
                '%s' % parsed_name).split()
65 f17d6cb5 Stavros Sachtouris
        for name in self.parsed_name:
66 f17d6cb5 Stavros Sachtouris
            assert name.count(' ') == 0, '%s: Invalid parse name "%s"' % (
67 f17d6cb5 Stavros Sachtouris
                self, name)
68 f17d6cb5 Stavros Sachtouris
            msg = '%s: Invalid parse name "%s" should start with a "-"' % (
69 f17d6cb5 Stavros Sachtouris
                    self, name)
70 f17d6cb5 Stavros Sachtouris
            assert name.startswith('-'), msg
71 f17d6cb5 Stavros Sachtouris
72 a6d2ad78 Stavros Sachtouris
        self.default = default or None
73 dfee2caf Stavros Sachtouris
74 fd5db045 Stavros Sachtouris
    @property
75 dfee2caf Stavros Sachtouris
    def value(self):
76 dfee2caf Stavros Sachtouris
        return getattr(self, '_value', self.default)
77 fd5db045 Stavros Sachtouris
78 dfee2caf Stavros Sachtouris
    @value.setter
79 dfee2caf Stavros Sachtouris
    def value(self, newvalue):
80 dfee2caf Stavros Sachtouris
        self._value = newvalue
81 dfee2caf Stavros Sachtouris
82 dfee2caf Stavros Sachtouris
    def update_parser(self, parser, name):
83 edb7fc1a Stavros Sachtouris
        """Update argument parser with self info"""
84 f17d6cb5 Stavros Sachtouris
        action = 'append' if self.arity < 0 else (
85 f17d6cb5 Stavros Sachtouris
            'store' if self.arity else 'store_true')
86 de73876b Stavros Sachtouris
        parser.add_argument(
87 de73876b Stavros Sachtouris
            *self.parsed_name,
88 f17d6cb5 Stavros Sachtouris
            dest=name, action=action, default=self.default, help=self.help)
89 dfee2caf Stavros Sachtouris
90 eb647cfe Stavros Sachtouris
    @property
91 eb647cfe Stavros Sachtouris
    def lvalue(self):
92 eb647cfe Stavros Sachtouris
        """A printable form of the left value when calling an argument e.g.,
93 eb647cfe Stavros Sachtouris
        --left-value=right-value"""
94 eb647cfe Stavros Sachtouris
        return (self.lvalue_delimiter or ' ').join(self.parsed_name or [])
95 eb647cfe Stavros Sachtouris
96 fd5db045 Stavros Sachtouris
97 9bdc89da Stavros Sachtouris
class ConfigArgument(Argument):
98 439926dd Stavros Sachtouris
    """Manage a kamaki configuration (file)"""
99 edb7fc1a Stavros Sachtouris
100 a7aacf12 Stavros Sachtouris
    def __init__(self, help, parsed_name=('-c', '--config')):
101 a7aacf12 Stavros Sachtouris
        super(ConfigArgument, self).__init__(1, help, parsed_name, None)
102 a7aacf12 Stavros Sachtouris
        self.file_path = None
103 e9a92550 Stavros Sachtouris
104 fd5db045 Stavros Sachtouris
    @property
105 c41a86b2 Stavros Sachtouris
    def value(self):
106 c22183b9 Stavros Sachtouris
        return getattr(self, '_value', None)
107 fd5db045 Stavros Sachtouris
108 c41a86b2 Stavros Sachtouris
    @value.setter
109 c41a86b2 Stavros Sachtouris
    def value(self, config_file):
110 e9a92550 Stavros Sachtouris
        if config_file:
111 e9a92550 Stavros Sachtouris
            self._value = Config(config_file)
112 a7aacf12 Stavros Sachtouris
            self.file_path = config_file
113 a7aacf12 Stavros Sachtouris
        elif self.file_path:
114 a7aacf12 Stavros Sachtouris
            self._value = Config(self.file_path)
115 e9a92550 Stavros Sachtouris
        else:
116 e9a92550 Stavros Sachtouris
            self._value = Config()
117 9bdc89da Stavros Sachtouris
118 c41a86b2 Stavros Sachtouris
    def get(self, group, term):
119 439926dd Stavros Sachtouris
        """Get a configuration setting from the Config object"""
120 c41a86b2 Stavros Sachtouris
        return self.value.get(group, term)
121 c41a86b2 Stavros Sachtouris
122 a7aacf12 Stavros Sachtouris
    @property
123 a7aacf12 Stavros Sachtouris
    def groups(self):
124 362adf50 Stavros Sachtouris
        suffix = '_cli'
125 362adf50 Stavros Sachtouris
        slen = len(suffix)
126 362adf50 Stavros Sachtouris
        return [term[:-slen] for term in self.value.keys('global') if (
127 362adf50 Stavros Sachtouris
            term.endswith(suffix))]
128 f724cd35 Stavros Sachtouris
129 a7aacf12 Stavros Sachtouris
    @property
130 a7aacf12 Stavros Sachtouris
    def cli_specs(self):
131 362adf50 Stavros Sachtouris
        suffix = '_cli'
132 362adf50 Stavros Sachtouris
        slen = len(suffix)
133 362adf50 Stavros Sachtouris
        return [(k[:-slen], v) for k, v in self.value.items('global') if (
134 362adf50 Stavros Sachtouris
            k.endswith(suffix))]
135 362adf50 Stavros Sachtouris
136 362adf50 Stavros Sachtouris
    def get_global(self, option):
137 534e7bbb Stavros Sachtouris
        return self.value.get('global', option)
138 362adf50 Stavros Sachtouris
139 144b3551 Stavros Sachtouris
    def get_cloud(self, cloud, option):
140 144b3551 Stavros Sachtouris
        return self.value.get_cloud(cloud, option)
141 017d37ce Stavros Sachtouris
142 f17d6cb5 Stavros Sachtouris
143 a7aacf12 Stavros Sachtouris
_config_arg = ConfigArgument('Path to config file')
144 017d37ce Stavros Sachtouris
145 fd5db045 Stavros Sachtouris
146 1bd4f765 Stavros Sachtouris
class RuntimeConfigArgument(Argument):
147 edb7fc1a Stavros Sachtouris
    """Set a run-time setting option (not persistent)"""
148 edb7fc1a Stavros Sachtouris
149 c41a86b2 Stavros Sachtouris
    def __init__(self, config_arg, help='', parsed_name=None, default=None):
150 c41a86b2 Stavros Sachtouris
        super(self.__class__, self).__init__(1, help, parsed_name, default)
151 c41a86b2 Stavros Sachtouris
        self._config_arg = config_arg
152 c41a86b2 Stavros Sachtouris
153 fd5db045 Stavros Sachtouris
    @property
154 c41a86b2 Stavros Sachtouris
    def value(self):
155 34c480f2 Stavros Sachtouris
        return super(RuntimeConfigArgument, self).value
156 fd5db045 Stavros Sachtouris
157 c41a86b2 Stavros Sachtouris
    @value.setter
158 c41a86b2 Stavros Sachtouris
    def value(self, options):
159 c41a86b2 Stavros Sachtouris
        if options == self.default:
160 c41a86b2 Stavros Sachtouris
            return
161 fd5db045 Stavros Sachtouris
        if not isinstance(options, list):
162 a517ff50 Stavros Sachtouris
            options = ['%s' % options]
163 c41a86b2 Stavros Sachtouris
        for option in options:
164 c41a86b2 Stavros Sachtouris
            keypath, sep, val = option.partition('=')
165 c41a86b2 Stavros Sachtouris
            if not sep:
166 de73876b Stavros Sachtouris
                raiseCLIError(
167 de73876b Stavros Sachtouris
                    CLISyntaxError('Argument Syntax Error '),
168 24ff0a35 Stavros Sachtouris
                    details=[
169 24ff0a35 Stavros Sachtouris
                        '%s is missing a "="',
170 24ff0a35 Stavros Sachtouris
                        ' (usage: -o section.key=val)' % option])
171 c41a86b2 Stavros Sachtouris
            section, sep, key = keypath.partition('.')
172 0a0b9fb6 Stavros Sachtouris
        if not sep:
173 0a0b9fb6 Stavros Sachtouris
            key = section
174 0a0b9fb6 Stavros Sachtouris
            section = 'global'
175 0a0b9fb6 Stavros Sachtouris
        self._config_arg.value.override(
176 0a0b9fb6 Stavros Sachtouris
            section.strip(),
177 fd5db045 Stavros Sachtouris
            key.strip(),
178 fd5db045 Stavros Sachtouris
            val.strip())
179 fd5db045 Stavros Sachtouris
180 c41a86b2 Stavros Sachtouris
181 c41a86b2 Stavros Sachtouris
class FlagArgument(Argument):
182 edb7fc1a Stavros Sachtouris
    """
183 439926dd Stavros Sachtouris
    :value: true if set, false otherwise
184 edb7fc1a Stavros Sachtouris
    """
185 edb7fc1a Stavros Sachtouris
186 a6d2ad78 Stavros Sachtouris
    def __init__(self, help='', parsed_name=None, default=None):
187 c41a86b2 Stavros Sachtouris
        super(FlagArgument, self).__init__(0, help, parsed_name, default)
188 c41a86b2 Stavros Sachtouris
189 fd5db045 Stavros Sachtouris
190 c41a86b2 Stavros Sachtouris
class ValueArgument(Argument):
191 edb7fc1a Stavros Sachtouris
    """
192 edb7fc1a Stavros Sachtouris
    :value type: string
193 edb7fc1a Stavros Sachtouris
    :value returns: given value or default
194 edb7fc1a Stavros Sachtouris
    """
195 edb7fc1a Stavros Sachtouris
196 c41a86b2 Stavros Sachtouris
    def __init__(self, help='', parsed_name=None, default=None):
197 c41a86b2 Stavros Sachtouris
        super(ValueArgument, self).__init__(1, help, parsed_name, default)
198 c41a86b2 Stavros Sachtouris
199 fd5db045 Stavros Sachtouris
200 0155548b Stavros Sachtouris
class CommaSeparatedListArgument(ValueArgument):
201 0155548b Stavros Sachtouris
    """
202 0155548b Stavros Sachtouris
    :value type: string
203 0155548b Stavros Sachtouris
    :value returns: list of the comma separated values
204 0155548b Stavros Sachtouris
    """
205 0155548b Stavros Sachtouris
206 0155548b Stavros Sachtouris
    @property
207 0155548b Stavros Sachtouris
    def value(self):
208 0155548b Stavros Sachtouris
        return self._value or list()
209 0155548b Stavros Sachtouris
210 0155548b Stavros Sachtouris
    @value.setter
211 0155548b Stavros Sachtouris
    def value(self, newvalue):
212 0155548b Stavros Sachtouris
        self._value = newvalue.split(',') if newvalue else list()
213 0155548b Stavros Sachtouris
214 0155548b Stavros Sachtouris
215 e3d4d442 Stavros Sachtouris
class IntArgument(ValueArgument):
216 edb7fc1a Stavros Sachtouris
217 fd5db045 Stavros Sachtouris
    @property
218 e3d4d442 Stavros Sachtouris
    def value(self):
219 439926dd Stavros Sachtouris
        """integer (type checking)"""
220 e3d4d442 Stavros Sachtouris
        return getattr(self, '_value', self.default)
221 fd5db045 Stavros Sachtouris
222 e3d4d442 Stavros Sachtouris
    @value.setter
223 e3d4d442 Stavros Sachtouris
    def value(self, newvalue):
224 4a25486d Stavros Sachtouris
        if newvalue == self.default:
225 4a25486d Stavros Sachtouris
            self._value = newvalue
226 4a25486d Stavros Sachtouris
            return
227 e3d4d442 Stavros Sachtouris
        try:
228 4a25486d Stavros Sachtouris
            if int(newvalue) == float(newvalue):
229 4a25486d Stavros Sachtouris
                self._value = int(newvalue)
230 4a25486d Stavros Sachtouris
            else:
231 4a25486d Stavros Sachtouris
                raise ValueError('Raise int argument error')
232 e3d4d442 Stavros Sachtouris
        except ValueError:
233 24ff0a35 Stavros Sachtouris
            raiseCLIError(CLISyntaxError(
234 24ff0a35 Stavros Sachtouris
                'IntArgument Error',
235 c8e17a67 Stavros Sachtouris
                details=['Value %s not an int' % newvalue]))
236 fd5db045 Stavros Sachtouris
237 e3d4d442 Stavros Sachtouris
238 7b109aa7 Stavros Sachtouris
class DataSizeArgument(ValueArgument):
239 7b109aa7 Stavros Sachtouris
    """Input: a string of the form <number><unit>
240 7b109aa7 Stavros Sachtouris
    Output: the number of bytes
241 7b109aa7 Stavros Sachtouris
    Units: B, KiB, KB, MiB, MB, GiB, GB, TiB, TB
242 7b109aa7 Stavros Sachtouris
    """
243 7b109aa7 Stavros Sachtouris
244 7b109aa7 Stavros Sachtouris
    @property
245 7b109aa7 Stavros Sachtouris
    def value(self):
246 7b109aa7 Stavros Sachtouris
        return getattr(self, '_value', self.default)
247 7b109aa7 Stavros Sachtouris
248 7b109aa7 Stavros Sachtouris
    def _calculate_limit(self, user_input):
249 7b109aa7 Stavros Sachtouris
        limit = 0
250 7b109aa7 Stavros Sachtouris
        try:
251 7b109aa7 Stavros Sachtouris
            limit = int(user_input)
252 7b109aa7 Stavros Sachtouris
        except ValueError:
253 7b109aa7 Stavros Sachtouris
            index = 0
254 7b109aa7 Stavros Sachtouris
            digits = [str(num) for num in range(0, 10)] + ['.']
255 7b109aa7 Stavros Sachtouris
            while user_input[index] in digits:
256 7b109aa7 Stavros Sachtouris
                index += 1
257 7b109aa7 Stavros Sachtouris
            limit = user_input[:index]
258 7b109aa7 Stavros Sachtouris
            format = user_input[index:]
259 7b109aa7 Stavros Sachtouris
            try:
260 7b109aa7 Stavros Sachtouris
                return to_bytes(limit, format)
261 7b109aa7 Stavros Sachtouris
            except Exception as qe:
262 7b109aa7 Stavros Sachtouris
                msg = 'Failed to convert %s to bytes' % user_input,
263 7b109aa7 Stavros Sachtouris
                raiseCLIError(qe, msg, details=[
264 7b109aa7 Stavros Sachtouris
                    'Syntax: containerlimit set <limit>[format] [container]',
265 7b109aa7 Stavros Sachtouris
                    'e.g.,: containerlimit set 2.3GB mycontainer',
266 7b109aa7 Stavros Sachtouris
                    'Valid formats:',
267 7b109aa7 Stavros Sachtouris
                    '(*1024): B, KiB, MiB, GiB, TiB',
268 7b109aa7 Stavros Sachtouris
                    '(*1000): B, KB, MB, GB, TB'])
269 7b109aa7 Stavros Sachtouris
        return limit
270 7b109aa7 Stavros Sachtouris
271 7b109aa7 Stavros Sachtouris
    @value.setter
272 7b109aa7 Stavros Sachtouris
    def value(self, new_value):
273 7b109aa7 Stavros Sachtouris
        if new_value:
274 7b109aa7 Stavros Sachtouris
            self._value = self._calculate_limit(new_value)
275 7b109aa7 Stavros Sachtouris
276 7b109aa7 Stavros Sachtouris
277 04d01cd4 Stavros Sachtouris
class DateArgument(ValueArgument):
278 04d01cd4 Stavros Sachtouris
279 b7ff6e0c Stavros Sachtouris
    DATE_FORMAT = '%a %b %d %H:%M:%S %Y'
280 04d01cd4 Stavros Sachtouris
281 b7ff6e0c Stavros Sachtouris
    INPUT_FORMATS = [DATE_FORMAT, '%d-%m-%Y', '%H:%M:%S %d-%m-%Y']
282 04d01cd4 Stavros Sachtouris
283 04d01cd4 Stavros Sachtouris
    @property
284 ea4a21b8 Stavros Sachtouris
    def timestamp(self):
285 ea4a21b8 Stavros Sachtouris
        v = getattr(self, '_value', self.default)
286 ea4a21b8 Stavros Sachtouris
        return mktime(v.timetuple()) if v else None
287 ea4a21b8 Stavros Sachtouris
288 ea4a21b8 Stavros Sachtouris
    @property
289 ea4a21b8 Stavros Sachtouris
    def formated(self):
290 ea4a21b8 Stavros Sachtouris
        v = getattr(self, '_value', self.default)
291 b7ff6e0c Stavros Sachtouris
        return v.strftime(self.DATE_FORMAT) if v else None
292 ea4a21b8 Stavros Sachtouris
293 ea4a21b8 Stavros Sachtouris
    @property
294 04d01cd4 Stavros Sachtouris
    def value(self):
295 ea4a21b8 Stavros Sachtouris
        return self.timestamp
296 04d01cd4 Stavros Sachtouris
297 04d01cd4 Stavros Sachtouris
    @value.setter
298 04d01cd4 Stavros Sachtouris
    def value(self, newvalue):
299 2af87afc Stavros Sachtouris
        self._value = self.format_date(newvalue) if newvalue else self.default
300 04d01cd4 Stavros Sachtouris
301 04d01cd4 Stavros Sachtouris
    def format_date(self, datestr):
302 04d01cd4 Stavros Sachtouris
        for format in self.INPUT_FORMATS:
303 04d01cd4 Stavros Sachtouris
            try:
304 04d01cd4 Stavros Sachtouris
                t = dtm.strptime(datestr, format)
305 04d01cd4 Stavros Sachtouris
            except ValueError:
306 04d01cd4 Stavros Sachtouris
                continue
307 b7ff6e0c Stavros Sachtouris
            return t  # .strftime(self.DATE_FORMAT)
308 b7ff6e0c Stavros Sachtouris
        raiseCLIError(None, 'Date Argument Error', details=[
309 b7ff6e0c Stavros Sachtouris
            '%s not a valid date' % datestr,
310 b7ff6e0c Stavros Sachtouris
            'Correct formats:\n\t%s' % self.INPUT_FORMATS])
311 04d01cd4 Stavros Sachtouris
312 04d01cd4 Stavros Sachtouris
313 c41a86b2 Stavros Sachtouris
class VersionArgument(FlagArgument):
314 edb7fc1a Stavros Sachtouris
    """A flag argument with that prints current version"""
315 edb7fc1a Stavros Sachtouris
316 fd5db045 Stavros Sachtouris
    @property
317 c41a86b2 Stavros Sachtouris
    def value(self):
318 439926dd Stavros Sachtouris
        """bool"""
319 c41a86b2 Stavros Sachtouris
        return super(self.__class__, self).value
320 fd5db045 Stavros Sachtouris
321 c41a86b2 Stavros Sachtouris
    @value.setter
322 c41a86b2 Stavros Sachtouris
    def value(self, newvalue):
323 c41a86b2 Stavros Sachtouris
        self._value = newvalue
324 f17d6cb5 Stavros Sachtouris
        if newvalue:
325 c41a86b2 Stavros Sachtouris
            import kamaki
326 fd5db045 Stavros Sachtouris
            print('kamaki %s' % kamaki.__version__)
327 fd5db045 Stavros Sachtouris
328 9bdc89da Stavros Sachtouris
329 ca5528f1 Stavros Sachtouris
class RepeatableArgument(Argument):
330 ca5528f1 Stavros Sachtouris
    """A value argument that can be repeated"""
331 ca5528f1 Stavros Sachtouris
332 a6d2ad78 Stavros Sachtouris
    def __init__(self, help='', parsed_name=None, default=None):
333 ca5528f1 Stavros Sachtouris
        super(RepeatableArgument, self).__init__(
334 ca5528f1 Stavros Sachtouris
            -1, help, parsed_name, default)
335 ca5528f1 Stavros Sachtouris
336 a6d2ad78 Stavros Sachtouris
    @property
337 a6d2ad78 Stavros Sachtouris
    def value(self):
338 a6d2ad78 Stavros Sachtouris
        return getattr(self, '_value', [])
339 a6d2ad78 Stavros Sachtouris
340 a6d2ad78 Stavros Sachtouris
    @value.setter
341 a6d2ad78 Stavros Sachtouris
    def value(self, newvalue):
342 a6d2ad78 Stavros Sachtouris
        self._value = newvalue
343 a6d2ad78 Stavros Sachtouris
344 ca5528f1 Stavros Sachtouris
345 0a0b9fb6 Stavros Sachtouris
class KeyValueArgument(Argument):
346 ca5528f1 Stavros Sachtouris
    """A Key=Value Argument that can be repeated
347 edb7fc1a Stavros Sachtouris

348 439926dd Stavros Sachtouris
    :syntax: --<arg> key1=value1 --<arg> key2=value2 ...
349 edb7fc1a Stavros Sachtouris
    """
350 edb7fc1a Stavros Sachtouris
351 a6d2ad78 Stavros Sachtouris
    def __init__(self, help='', parsed_name=None, default=None):
352 0a0b9fb6 Stavros Sachtouris
        super(KeyValueArgument, self).__init__(-1, help, parsed_name, default)
353 f3e94e06 Stavros Sachtouris
354 fd5db045 Stavros Sachtouris
    @property
355 f3e94e06 Stavros Sachtouris
    def value(self):
356 439926dd Stavros Sachtouris
        """
357 8d427cb9 Stavros Sachtouris
        :returns: (dict) {key1: val1, key2: val2, ...}
358 439926dd Stavros Sachtouris
        """
359 a6d2ad78 Stavros Sachtouris
        return getattr(self, '_value', {})
360 fd5db045 Stavros Sachtouris
361 fd5db045 Stavros Sachtouris
    @value.setter
362 f3e94e06 Stavros Sachtouris
    def value(self, keyvalue_pairs):
363 8d427cb9 Stavros Sachtouris
        """
364 8d427cb9 Stavros Sachtouris
        :param keyvalue_pairs: (str) ['key1=val1', 'key2=val2', ...]
365 8d427cb9 Stavros Sachtouris
        """
366 a6d2ad78 Stavros Sachtouris
        if keyvalue_pairs:
367 a6d2ad78 Stavros Sachtouris
            self._value = self.value
368 a6d2ad78 Stavros Sachtouris
            try:
369 a6d2ad78 Stavros Sachtouris
                for pair in keyvalue_pairs:
370 a6d2ad78 Stavros Sachtouris
                    key, sep, val = pair.partition('=')
371 a6d2ad78 Stavros Sachtouris
                    assert sep, ' %s misses a "=" (usage: key1=val1 )\n' % (
372 a6d2ad78 Stavros Sachtouris
                        pair)
373 a6d2ad78 Stavros Sachtouris
                    self._value[key] = val
374 a6d2ad78 Stavros Sachtouris
            except Exception as e:
375 a6d2ad78 Stavros Sachtouris
                raiseCLIError(e, 'KeyValueArgument Syntax Error')
376 f3e94e06 Stavros Sachtouris
377 fd1f1d96 Stavros Sachtouris
378 fd1f1d96 Stavros Sachtouris
class ProgressBarArgument(FlagArgument):
379 439926dd Stavros Sachtouris
    """Manage a progress bar"""
380 fd1f1d96 Stavros Sachtouris
381 fd1f1d96 Stavros Sachtouris
    def __init__(self, help='', parsed_name='', default=True):
382 fd1f1d96 Stavros Sachtouris
        self.suffix = '%(percent)d%%'
383 fd1f1d96 Stavros Sachtouris
        super(ProgressBarArgument, self).__init__(help, parsed_name, default)
384 fd1f1d96 Stavros Sachtouris
385 852a22e7 Stavros Sachtouris
    def clone(self):
386 439926dd Stavros Sachtouris
        """Get a modifiable copy of this bar"""
387 852a22e7 Stavros Sachtouris
        newarg = ProgressBarArgument(
388 c0fbf04c Stavros Sachtouris
            self.help, self.parsed_name, self.default)
389 852a22e7 Stavros Sachtouris
        newarg._value = self._value
390 852a22e7 Stavros Sachtouris
        return newarg
391 852a22e7 Stavros Sachtouris
392 8547cd19 Stavros Sachtouris
    def get_generator(
393 8547cd19 Stavros Sachtouris
            self, message, message_len=25, countdown=False, timeout=100):
394 439926dd Stavros Sachtouris
        """Get a generator to handle progress of the bar (gen.next())"""
395 fd1f1d96 Stavros Sachtouris
        if self.value:
396 fd1f1d96 Stavros Sachtouris
            return None
397 fd1f1d96 Stavros Sachtouris
        try:
398 1d329d27 Stavros Sachtouris
            self.bar = KamakiProgressBar()
399 fd1f1d96 Stavros Sachtouris
        except NameError:
400 329753ae Stavros Sachtouris
            self.value = None
401 329753ae Stavros Sachtouris
            return self.value
402 8547cd19 Stavros Sachtouris
        if countdown:
403 e9c73313 Stavros Sachtouris
            bar_phases = list(self.bar.phases)
404 8547cd19 Stavros Sachtouris
            self.bar.empty_fill, bar_phases[0] = bar_phases[-1], ''
405 8547cd19 Stavros Sachtouris
            bar_phases.reverse()
406 e9c73313 Stavros Sachtouris
            self.bar.phases = bar_phases
407 8547cd19 Stavros Sachtouris
            self.bar.bar_prefix = ' '
408 e9c73313 Stavros Sachtouris
            self.bar.bar_suffix = ' '
409 8547cd19 Stavros Sachtouris
            self.bar.max = timeout or 100
410 8547cd19 Stavros Sachtouris
            self.bar.suffix = '%(remaining)ds to timeout'
411 e9c73313 Stavros Sachtouris
        else:
412 e9c73313 Stavros Sachtouris
            self.bar.suffix = '%(percent)d%% - %(eta)ds'
413 8547cd19 Stavros Sachtouris
        self.bar.eta = timeout or 100
414 329753ae Stavros Sachtouris
        self.bar.message = message.ljust(message_len)
415 a10f5561 Stavros Sachtouris
        self.bar.start()
416 fd1f1d96 Stavros Sachtouris
417 852a22e7 Stavros Sachtouris
        def progress_gen(n):
418 852a22e7 Stavros Sachtouris
            for i in self.bar.iter(range(int(n))):
419 852a22e7 Stavros Sachtouris
                yield
420 852a22e7 Stavros Sachtouris
            yield
421 852a22e7 Stavros Sachtouris
        return progress_gen
422 fd1f1d96 Stavros Sachtouris
423 852a22e7 Stavros Sachtouris
    def finish(self):
424 439926dd Stavros Sachtouris
        """Stop progress bar, return terminal cursor to user"""
425 852a22e7 Stavros Sachtouris
        if self.value:
426 852a22e7 Stavros Sachtouris
            return
427 852a22e7 Stavros Sachtouris
        mybar = getattr(self, 'bar', None)
428 852a22e7 Stavros Sachtouris
        if mybar:
429 852a22e7 Stavros Sachtouris
            mybar.finish()
430 fd1f1d96 Stavros Sachtouris
431 fd1f1d96 Stavros Sachtouris
432 de73876b Stavros Sachtouris
_arguments = dict(
433 de73876b Stavros Sachtouris
    config=_config_arg,
434 144b3551 Stavros Sachtouris
    cloud=ValueArgument('Chose a cloud to connect to', ('--cloud')),
435 fd5db045 Stavros Sachtouris
    help=Argument(0, 'Show help message', ('-h', '--help')),
436 fd5db045 Stavros Sachtouris
    debug=FlagArgument('Include debug output', ('-d', '--debug')),
437 f6822a26 Stavros Sachtouris
    #include=FlagArgument(
438 f6822a26 Stavros Sachtouris
    #    'Include raw connection data in the output', ('-i', '--include')),
439 fd5db045 Stavros Sachtouris
    silent=FlagArgument('Do not output anything', ('-s', '--silent')),
440 fd5db045 Stavros Sachtouris
    verbose=FlagArgument('More info at response', ('-v', '--verbose')),
441 fd5db045 Stavros Sachtouris
    version=VersionArgument('Print current version', ('-V', '--version')),
442 1bd4f765 Stavros Sachtouris
    options=RuntimeConfigArgument(
443 cb4a5d9c Stavros Sachtouris
        _config_arg, 'Override a config value', ('-o', '--options'))
444 9bdc89da Stavros Sachtouris
)
445 cb4a5d9c Stavros Sachtouris
446 cb4a5d9c Stavros Sachtouris
447 cb4a5d9c Stavros Sachtouris
#  Initial command line interface arguments
448 439926dd Stavros Sachtouris
449 439926dd Stavros Sachtouris
450 7c2247a0 Stavros Sachtouris
class ArgumentParseManager(object):
451 e0da0f90 Stavros Sachtouris
    """Manage (initialize and update) an ArgumentParser object"""
452 e0da0f90 Stavros Sachtouris
453 49e85ee2 Stavros Sachtouris
    def __init__(
454 49e85ee2 Stavros Sachtouris
            self, exe,
455 9b3c8fd9 Stavros Sachtouris
            arguments=None, required=None, syntax=None, description=None,
456 9b3c8fd9 Stavros Sachtouris
            check_required=True):
457 e0da0f90 Stavros Sachtouris
        """
458 e0da0f90 Stavros Sachtouris
        :param exe: (str) the basic command (e.g. 'kamaki')
459 e0da0f90 Stavros Sachtouris

460 e0da0f90 Stavros Sachtouris
        :param arguments: (dict) if given, overrides the global _argument as
461 e0da0f90 Stavros Sachtouris
            the parsers arguments specification
462 56d84a4e Stavros Sachtouris
        :param required: (list or tuple) an iterable of argument keys, denoting
463 56d84a4e Stavros Sachtouris
            which arguments are required. A tuple denoted an AND relation,
464 56d84a4e Stavros Sachtouris
            while a list denotes an OR relation e.g., ['a', 'b'] means that
465 56d84a4e Stavros Sachtouris
            either 'a' or 'b' is required, while ('a', 'b') means that both 'a'
466 56d84a4e Stavros Sachtouris
            and 'b' ar required.
467 56d84a4e Stavros Sachtouris
            Nesting is allowed e.g., ['a', ('b', 'c'), ['d', 'e']] means that
468 56d84a4e Stavros Sachtouris
            this command required either 'a', or both 'b' and 'c', or one of
469 56d84a4e Stavros Sachtouris
            'd', 'e'.
470 56d84a4e Stavros Sachtouris
            Repeated arguments are also allowed e.g., [('a', 'b'), ('a', 'c'),
471 56d84a4e Stavros Sachtouris
            ['b', 'c']] means that the command required either 'a' and 'b' or
472 56d84a4e Stavros Sachtouris
            'a' and 'c' or at least one of 'b', 'c' and could be written as
473 56d84a4e Stavros Sachtouris
            [('a', ['b', 'c']), ['b', 'c']]
474 49e85ee2 Stavros Sachtouris
        :param syntax: (str) The basic syntax of the arguments. Default:
475 49e85ee2 Stavros Sachtouris
            exe <cmd_group> [<cmd_subbroup> ...] <cmd>
476 49e85ee2 Stavros Sachtouris
        :param description: (str) The description of the commands or ''
477 9b3c8fd9 Stavros Sachtouris
        :param check_required: (bool) Set to False inorder not to check for
478 9b3c8fd9 Stavros Sachtouris
            required argument values while parsing
479 e0da0f90 Stavros Sachtouris
        """
480 de73876b Stavros Sachtouris
        self.parser = ArgumentParser(
481 320aac17 Stavros Sachtouris
            add_help=False, formatter_class=RawDescriptionHelpFormatter)
482 56d84a4e Stavros Sachtouris
        self._exe = exe
483 49e85ee2 Stavros Sachtouris
        self.syntax = syntax or (
484 49e85ee2 Stavros Sachtouris
            '%s <cmd_group> [<cmd_subbroup> ...] <cmd>' % exe)
485 9b3c8fd9 Stavros Sachtouris
        self.required, self.check_required = required, check_required
486 49e85ee2 Stavros Sachtouris
        self.parser.description = description or ''
487 e0da0f90 Stavros Sachtouris
        if arguments:
488 e0da0f90 Stavros Sachtouris
            self.arguments = arguments
489 e0da0f90 Stavros Sachtouris
        else:
490 e0da0f90 Stavros Sachtouris
            global _arguments
491 e0da0f90 Stavros Sachtouris
            self.arguments = _arguments
492 631b7c35 Stavros Sachtouris
        self._parser_modified, self._parsed, self._unparsed = False, None, None
493 7c2247a0 Stavros Sachtouris
        self.parse()
494 e0da0f90 Stavros Sachtouris
495 56d84a4e Stavros Sachtouris
    @staticmethod
496 56d84a4e Stavros Sachtouris
    def required2list(required):
497 56d84a4e Stavros Sachtouris
        if isinstance(required, list) or isinstance(required, tuple):
498 56d84a4e Stavros Sachtouris
            terms = []
499 56d84a4e Stavros Sachtouris
            for r in required:
500 56d84a4e Stavros Sachtouris
                terms.append(ArgumentParseManager.required2list(r))
501 56d84a4e Stavros Sachtouris
            return list(set(terms).union())
502 56d84a4e Stavros Sachtouris
        return required
503 56d84a4e Stavros Sachtouris
504 56d84a4e Stavros Sachtouris
    @staticmethod
505 56d84a4e Stavros Sachtouris
    def required2str(required, arguments, tab=''):
506 56d84a4e Stavros Sachtouris
        if isinstance(required, list):
507 a6d2ad78 Stavros Sachtouris
            return ' %sat least one of the following:\n%s' % (tab, ''.join(
508 56d84a4e Stavros Sachtouris
                [ArgumentParseManager.required2str(
509 56d84a4e Stavros Sachtouris
                    r, arguments, tab + '  ') for r in required]))
510 56d84a4e Stavros Sachtouris
        elif isinstance(required, tuple):
511 a6d2ad78 Stavros Sachtouris
            return ' %sall of the following:\n%s' % (tab, ''.join(
512 56d84a4e Stavros Sachtouris
                [ArgumentParseManager.required2str(
513 56d84a4e Stavros Sachtouris
                    r, arguments, tab + '  ') for r in required]))
514 56d84a4e Stavros Sachtouris
        else:
515 56d84a4e Stavros Sachtouris
            lt_pn, lt_all, arg = 23, 80, arguments[required]
516 56d84a4e Stavros Sachtouris
            tab2 = ' ' * lt_pn
517 56d84a4e Stavros Sachtouris
            ret = '%s%s' % (tab, ', '.join(arg.parsed_name))
518 56d84a4e Stavros Sachtouris
            if arg.arity != 0:
519 56d84a4e Stavros Sachtouris
                ret += ' %s' % required.upper()
520 56d84a4e Stavros Sachtouris
            ret = ('{:<%s}' % lt_pn).format(ret)
521 264a13f7 Stavros Sachtouris
            prefix = ('\n%s' % tab2) if len(ret) > lt_pn else ' '
522 264a13f7 Stavros Sachtouris
            cur = 0
523 56d84a4e Stavros Sachtouris
            while arg.help[cur:]:
524 264a13f7 Stavros Sachtouris
                next = cur + lt_all - lt_pn
525 56d84a4e Stavros Sachtouris
                ret += prefix
526 56d84a4e Stavros Sachtouris
                ret += ('{:<%s}' % (lt_all - lt_pn)).format(arg.help[cur:next])
527 56d84a4e Stavros Sachtouris
                cur, finish = next, '\n%s' % tab2
528 56d84a4e Stavros Sachtouris
            return ret + '\n'
529 56d84a4e Stavros Sachtouris
530 320af781 Stavros Sachtouris
    @staticmethod
531 320af781 Stavros Sachtouris
    def _patch_with_required_args(arguments, required):
532 320af781 Stavros Sachtouris
        if isinstance(required, tuple):
533 320af781 Stavros Sachtouris
            return ' '.join([ArgumentParseManager._patch_with_required_args(
534 320af781 Stavros Sachtouris
                arguments, k) for k in required])
535 320af781 Stavros Sachtouris
        elif isinstance(required, list):
536 320af781 Stavros Sachtouris
            return '< %s >' % ' | '.join([
537 320af781 Stavros Sachtouris
                ArgumentParseManager._patch_with_required_args(
538 320af781 Stavros Sachtouris
                    arguments, k) for k in required])
539 320af781 Stavros Sachtouris
        arg = arguments[required]
540 320af781 Stavros Sachtouris
        return '/'.join(arg.parsed_name) + (
541 320af781 Stavros Sachtouris
            ' %s [...]' % required.upper() if arg.arity < 0 else (
542 320af781 Stavros Sachtouris
                ' %s' % required.upper() if arg.arity else ''))
543 320af781 Stavros Sachtouris
544 56d84a4e Stavros Sachtouris
    def print_help(self, out=stderr):
545 56d84a4e Stavros Sachtouris
        if self.required:
546 56d84a4e Stavros Sachtouris
            tmp_args = dict(self.arguments)
547 56d84a4e Stavros Sachtouris
            for term in self.required2list(self.required):
548 56d84a4e Stavros Sachtouris
                tmp_args.pop(term)
549 56d84a4e Stavros Sachtouris
            tmp_parser = ArgumentParseManager(self._exe, tmp_args)
550 320af781 Stavros Sachtouris
            tmp_parser.syntax = self.syntax + self._patch_with_required_args(
551 320af781 Stavros Sachtouris
                self.arguments, self.required)
552 56d84a4e Stavros Sachtouris
            tmp_parser.parser.description = '%s\n\nrequired arguments:\n%s' % (
553 56d84a4e Stavros Sachtouris
                self.parser.description,
554 56d84a4e Stavros Sachtouris
                self.required2str(self.required, self.arguments))
555 56d84a4e Stavros Sachtouris
            tmp_parser.update_parser()
556 56d84a4e Stavros Sachtouris
            tmp_parser.parser.print_help()
557 56d84a4e Stavros Sachtouris
        else:
558 56d84a4e Stavros Sachtouris
            self.parser.print_help()
559 56d84a4e Stavros Sachtouris
560 e0da0f90 Stavros Sachtouris
    @property
561 e0da0f90 Stavros Sachtouris
    def syntax(self):
562 b3dd8f4b Stavros Sachtouris
        """The command syntax (useful for help messages, descriptions, etc)"""
563 e0da0f90 Stavros Sachtouris
        return self.parser.prog
564 e0da0f90 Stavros Sachtouris
565 e0da0f90 Stavros Sachtouris
    @syntax.setter
566 e0da0f90 Stavros Sachtouris
    def syntax(self, new_syntax):
567 e0da0f90 Stavros Sachtouris
        self.parser.prog = new_syntax
568 e0da0f90 Stavros Sachtouris
569 b3dd8f4b Stavros Sachtouris
    @property
570 b3dd8f4b Stavros Sachtouris
    def arguments(self):
571 631b7c35 Stavros Sachtouris
        """:returns: (dict) arguments the parser should be aware of"""
572 b3dd8f4b Stavros Sachtouris
        return self._arguments
573 b3dd8f4b Stavros Sachtouris
574 b3dd8f4b Stavros Sachtouris
    @arguments.setter
575 b3dd8f4b Stavros Sachtouris
    def arguments(self, new_arguments):
576 631b7c35 Stavros Sachtouris
        assert isinstance(new_arguments, dict), 'Arguments must be in a dict'
577 b3dd8f4b Stavros Sachtouris
        self._arguments = new_arguments
578 b3dd8f4b Stavros Sachtouris
        self.update_parser()
579 b3dd8f4b Stavros Sachtouris
580 7c2247a0 Stavros Sachtouris
    @property
581 b3dd8f4b Stavros Sachtouris
    def parsed(self):
582 7c2247a0 Stavros Sachtouris
        """(Namespace) parser-matched terms"""
583 b3dd8f4b Stavros Sachtouris
        if self._parser_modified:
584 b3dd8f4b Stavros Sachtouris
            self.parse()
585 b3dd8f4b Stavros Sachtouris
        return self._parsed
586 b3dd8f4b Stavros Sachtouris
587 b3dd8f4b Stavros Sachtouris
    @property
588 b3dd8f4b Stavros Sachtouris
    def unparsed(self):
589 b3dd8f4b Stavros Sachtouris
        """(list) parser-unmatched terms"""
590 b3dd8f4b Stavros Sachtouris
        if self._parser_modified:
591 b3dd8f4b Stavros Sachtouris
            self.parse()
592 b3dd8f4b Stavros Sachtouris
        return self._unparsed
593 b3dd8f4b Stavros Sachtouris
594 e0da0f90 Stavros Sachtouris
    def update_parser(self, arguments=None):
595 e0da0f90 Stavros Sachtouris
        """Load argument specifications to parser
596 e0da0f90 Stavros Sachtouris

597 e0da0f90 Stavros Sachtouris
        :param arguments: if not given, update self.arguments instead
598 e0da0f90 Stavros Sachtouris
        """
599 631b7c35 Stavros Sachtouris
        arguments = arguments or self._arguments
600 e0da0f90 Stavros Sachtouris
601 e0da0f90 Stavros Sachtouris
        for name, arg in arguments.items():
602 e0da0f90 Stavros Sachtouris
            try:
603 e0da0f90 Stavros Sachtouris
                arg.update_parser(self.parser, name)
604 b3dd8f4b Stavros Sachtouris
                self._parser_modified = True
605 e0da0f90 Stavros Sachtouris
            except ArgumentError:
606 e0da0f90 Stavros Sachtouris
                pass
607 e0da0f90 Stavros Sachtouris
608 7c2247a0 Stavros Sachtouris
    def update_arguments(self, new_arguments):
609 7c2247a0 Stavros Sachtouris
        """Add to / update existing arguments
610 7c2247a0 Stavros Sachtouris

611 7c2247a0 Stavros Sachtouris
        :param new_arguments: (dict)
612 7c2247a0 Stavros Sachtouris
        """
613 7c2247a0 Stavros Sachtouris
        if new_arguments:
614 56d84a4e Stavros Sachtouris
            assert isinstance(new_arguments, dict), 'Arguments not in dict !!!'
615 7c2247a0 Stavros Sachtouris
            self._arguments.update(new_arguments)
616 7c2247a0 Stavros Sachtouris
            self.update_parser()
617 7c2247a0 Stavros Sachtouris
618 0b052394 Stavros Sachtouris
    def _parse_required_arguments(self, required, parsed_args):
619 9b3c8fd9 Stavros Sachtouris
        if not (self.check_required and required):
620 0b052394 Stavros Sachtouris
            return True
621 0b052394 Stavros Sachtouris
        if isinstance(required, tuple):
622 0b052394 Stavros Sachtouris
            for item in required:
623 0b052394 Stavros Sachtouris
                if not self._parse_required_arguments(item, parsed_args):
624 0b052394 Stavros Sachtouris
                    return False
625 0b052394 Stavros Sachtouris
            return True
626 0b052394 Stavros Sachtouris
        if isinstance(required, list):
627 0b052394 Stavros Sachtouris
            for item in required:
628 0b052394 Stavros Sachtouris
                if self._parse_required_arguments(item, parsed_args):
629 0b052394 Stavros Sachtouris
                    return True
630 0b052394 Stavros Sachtouris
            return False
631 0b052394 Stavros Sachtouris
        return required in parsed_args
632 0b052394 Stavros Sachtouris
633 120126f1 Stavros Sachtouris
    def parse(self, new_args=None):
634 320aac17 Stavros Sachtouris
        """Parse user input"""
635 c8e17a67 Stavros Sachtouris
        try:
636 320aac17 Stavros Sachtouris
            pkargs = (new_args,) if new_args else ()
637 320aac17 Stavros Sachtouris
            self._parsed, unparsed = self.parser.parse_known_args(*pkargs)
638 0b052394 Stavros Sachtouris
            parsed_args = [
639 0b052394 Stavros Sachtouris
                k for k, v in vars(self._parsed).items() if v not in (None, )]
640 0b052394 Stavros Sachtouris
            if not self._parse_required_arguments(self.required, parsed_args):
641 56d84a4e Stavros Sachtouris
                self.print_help()
642 0b052394 Stavros Sachtouris
                raise CLISyntaxError('Missing required arguments')
643 c8e17a67 Stavros Sachtouris
        except SystemExit:
644 c8e17a67 Stavros Sachtouris
            raiseCLIError(CLISyntaxError('Argument Syntax Error'))
645 b3dd8f4b Stavros Sachtouris
        for name, arg in self.arguments.items():
646 b3dd8f4b Stavros Sachtouris
            arg.value = getattr(self._parsed, name, arg.default)
647 b3dd8f4b Stavros Sachtouris
        self._unparsed = []
648 b3dd8f4b Stavros Sachtouris
        for term in unparsed:
649 b3dd8f4b Stavros Sachtouris
            self._unparsed += split_input(' \'%s\' ' % term)
650 b3dd8f4b Stavros Sachtouris
        self._parser_modified = False