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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
|
from spec import Spec, eq_, raises
from invoke.parser import Parser, Context, Argument, ParseError
class Parser_(Spec):
def can_take_initial_context(self):
c = Context()
p = Parser(initial=c)
eq_(p.initial, c)
def can_take_initial_and_other_contexts(self):
c1 = Context('foo')
c2 = Context('bar')
p = Parser(initial=Context(), contexts=[c1, c2])
eq_(p.contexts['foo'], c1)
eq_(p.contexts['bar'], c2)
def can_take_just_other_contexts(self):
c = Context('foo')
p = Parser(contexts=[c])
eq_(p.contexts['foo'], c)
def can_take_just_contexts_as_non_keyword_arg(self):
c = Context('foo')
p = Parser([c])
eq_(p.contexts['foo'], c)
@raises(ValueError)
def raises_ValueError_for_unnamed_Contexts_in_contexts(self):
Parser(initial=Context(), contexts=[Context()])
@raises(ValueError)
def raises_error_for_context_name_clashes(self):
Parser(contexts=(Context('foo'), Context('foo')))
@raises(ValueError)
def raises_error_for_context_alias_and_name_clashes(self):
Parser((Context('foo', aliases=('bar',)), Context('bar')))
@raises(ValueError)
def raises_error_for_context_name_and_alias_clashes(self):
# I.e. inverse of the above, which is a different code path.
Parser((Context('foo'), Context('bar', aliases=('foo',))))
def takes_ignore_unknown_kwarg(self):
Parser(ignore_unknown=True)
def ignore_unknown_defaults_to_False(self):
eq_(Parser().ignore_unknown, False)
class parse_argv:
def parses_sys_argv_style_list_of_strings(self):
"parses sys.argv-style list of strings"
# Doesn't-blow-up tests FTL
mytask = Context(name='mytask')
mytask.add_arg('arg')
p = Parser(contexts=[mytask])
p.parse_argv(['mytask', '--arg', 'value'])
def returns_only_contexts_mentioned(self):
task1 = Context('mytask')
task2 = Context('othertask')
result = Parser((task1, task2)).parse_argv(['othertask'])
eq_(len(result), 1)
eq_(result[0].name, 'othertask')
@raises(ParseError)
def raises_error_if_unknown_contexts_found(self):
Parser().parse_argv(['foo', 'bar'])
def unparsed_does_not_share_state(self):
r = Parser(ignore_unknown=True).parse_argv(['self'])
eq_(r.unparsed, ['self'])
r2 = Parser(ignore_unknown=True).parse_argv(['contained'])
eq_(r.unparsed, ['self']) # NOT ['self', 'contained']
eq_(r2.unparsed, ['contained']) # NOT ['self', 'contained']
def ignore_unknown_returns_unparsed_argv_instead(self):
r = Parser(ignore_unknown=True).parse_argv(['foo', 'bar', '--baz'])
eq_(r.unparsed, ['foo', 'bar', '--baz'])
def ignore_unknown_does_not_mutate_rest_of_argv(self):
p = Parser([Context('ugh')], ignore_unknown=True)
r = p.parse_argv(['ugh', 'what', '-nowai'])
# NOT: ['what', '-n', '-w', '-a', '-i']
eq_(r.unparsed, ['what', '-nowai'])
def always_includes_initial_context_if_one_was_given(self):
# Even if no core/initial flags were seen
t1 = Context('t1')
init = Context()
result = Parser((t1,), initial=init).parse_argv(['t1'])
eq_(result[0].name, None)
eq_(result[1].name, 't1')
def returned_contexts_are_in_order_given(self):
t1, t2 = Context('t1'), Context('t2')
r = Parser((t1, t2)).parse_argv(['t2', 't1'])
eq_([x.name for x in r], ['t2', 't1'])
def returned_context_member_arguments_contain_given_values(self):
c = Context('mytask', args=(Argument('boolean', kind=bool),))
result = Parser((c,)).parse_argv(['mytask', '--boolean'])
eq_(result[0].args['boolean'].value, True)
def inverse_bools_get_set_correctly(self):
arg = Argument('myarg', kind=bool, default=True)
c = Context('mytask', args=(arg,))
r = Parser((c,)).parse_argv(['mytask', '--no-myarg'])
eq_(r[0].args['myarg'].value, False)
def arguments_which_take_values_get_defaults_overridden_correctly(self): # noqa
args = (Argument('arg', kind=str), Argument('arg2', kind=int))
c = Context('mytask', args=args)
argv = ['mytask', '--arg', 'myval', '--arg2', '25']
result = Parser((c,)).parse_argv(argv)
eq_(result[0].args['arg'].value, 'myval')
eq_(result[0].args['arg2'].value, 25)
def returned_arguments_not_given_contain_default_values(self):
# I.e. a Context with args A and B, invoked with no mention of B,
# should result in B existing in the result, with its default value
# intact, and not e.g. None, or the arg not existing.
a = Argument('name', kind=str)
b = Argument('age', default=7)
c = Context('mytask', args=(a, b))
Parser((c,)).parse_argv(['mytask', '--name', 'blah'])
eq_(c.args['age'].value, 7)
def returns_remainder(self):
"returns -- style remainder string chunk"
r = Parser((Context('foo'),)).parse_argv(
['foo', '--', 'bar', 'biz']
)
eq_(r.remainder, "bar biz")
def clones_initial_context(self):
a = Argument('foo', kind=bool)
eq_(a.value, None)
c = Context(args=(a,))
p = Parser(initial=c)
assert p.initial is c
r = p.parse_argv(['--foo'])
assert p.initial is c
c2 = r[0]
assert c2 is not c
a2 = c2.args['foo']
assert a2 is not a
eq_(a.value, None)
eq_(a2.value, True)
def clones_noninitial_contexts(self):
a = Argument('foo')
eq_(a.value, None)
c = Context(name='mytask', args=(a,))
p = Parser(contexts=(c,))
assert p.contexts['mytask'] is c
r = p.parse_argv(['mytask', '--foo', 'val'])
assert p.contexts['mytask'] is c
c2 = r[0]
assert c2 is not c
a2 = c2.args['foo']
assert a2 is not a
eq_(a.value, None)
eq_(a2.value, 'val')
class parsing_errors:
def setup(self):
self.p = Parser([Context(name='foo', args=[Argument('bar')])])
@raises(ParseError)
def missing_flag_values_raise_ParseError(self):
self.p.parse_argv(['foo', '--bar'])
def attaches_context_to_ParseErrors(self):
try:
self.p.parse_argv(['foo', '--bar'])
except ParseError as e:
assert e.context is not None
def attached_context_is_None_outside_contexts(self):
try:
Parser().parse_argv(['wat'])
except ParseError as e:
assert e.context is None
class positional_arguments:
def _basic(self):
arg = Argument('pos', positional=True)
mytask = Context(name='mytask', args=[arg])
return Parser(contexts=[mytask])
def single_positional_arg(self):
r = self._basic().parse_argv(['mytask', 'posval'])
eq_(r[0].args['pos'].value, 'posval')
@raises(ParseError)
def omitted_positional_arg_raises_ParseError(self):
self._basic().parse_argv(['mytask'])
def positional_args_eat_otherwise_valid_context_names(self):
mytask = Context('mytask', args=[
Argument('pos', positional=True),
Argument('nonpos', default='default')
])
Context('lolwut')
result = Parser([mytask]).parse_argv(['mytask', 'lolwut'])
r = result[0]
eq_(r.args['pos'].value, 'lolwut')
eq_(r.args['nonpos'].value, 'default')
eq_(len(result), 1) # Not 2
def positional_args_can_still_be_given_as_flags(self):
# AKA "positional args can come anywhere in the context"
pos1 = Argument('pos1', positional=True)
pos2 = Argument('pos2', positional=True)
nonpos = Argument('nonpos', positional=False, default='lol')
mytask = Context('mytask', args=[pos1, pos2, nonpos])
eq_(mytask.positional_args, [pos1, pos2])
r = Parser([mytask]).parse_argv([
'mytask',
'--nonpos', 'wut',
'--pos2', 'pos2val',
'pos1val',
])[0]
eq_(r.args['pos1'].value, 'pos1val')
eq_(r.args['pos2'].value, 'pos2val')
eq_(r.args['nonpos'].value, 'wut')
class equals_signs:
def _compare(self, argname, invoke, value):
c = Context('mytask', args=(Argument(argname, kind=str),))
r = Parser((c,)).parse_argv(['mytask', invoke])
eq_(r[0].args[argname].value, value)
def handles_equals_style_long_flags(self):
self._compare('foo', '--foo=bar', 'bar')
def handles_equals_style_short_flags(self):
self._compare('f', '-f=bar', 'bar')
def does_not_require_escaping_equals_signs_in_value(self):
self._compare('f', '-f=biz=baz', 'biz=baz')
def handles_multiple_boolean_flags_per_context(self):
c = Context('mytask', args=(
Argument('foo', kind=bool), Argument('bar', kind=bool)
))
r = Parser([c]).parse_argv(['mytask', '--foo', '--bar'])
a = r[0].args
eq_(a.foo.value, True)
eq_(a.bar.value, True)
class optional_arg_values:
def setup(self):
self.parser = self._parser()
def _parser(self, arguments=None):
if arguments is None:
arguments = (
Argument(
names=('foo', 'f'),
optional=True,
default='mydefault'
),
)
self.context = Context('mytask', args=arguments)
return Parser([self.context])
def _parse(self, argstr, parser=None):
parser = parser or self.parser
return parser.parse_argv(['mytask'] + argstr.split())
def _expect(self, argstr, expected, parser=None):
result = self._parse(argstr, parser)
eq_(result[0].args.foo.value, expected)
def no_value_becomes_True_not_default_value(self):
self._expect('--foo', True)
self._expect('-f', True)
def value_given_gets_preserved_normally(self):
for argstr in (
'--foo whatever',
'--foo=whatever',
'-f whatever',
'-f=whatever',
):
self._expect(argstr, 'whatever')
def not_given_at_all_uses_default_value(self):
self._expect('', 'mydefault')
def _test_for_ambiguity(self, invoke, parser=None):
msg = "is ambiguous"
try:
self._parse(invoke, parser or self.parser)
# Expected result
except ParseError as e:
assert msg in str(e)
# No exception occurred at all? Bollocks.
else:
assert False
# Any other exceptions will naturally cause failure here.
def ambiguity_with_unfilled_posargs(self):
p = self._parser((
Argument('foo', optional=True),
Argument('bar', positional=True)
))
self._test_for_ambiguity("--foo uhoh", p)
def ambiguity_with_flaglike_value(self):
self._test_for_ambiguity("--foo --bar")
def ambiguity_with_actual_other_flag(self):
self._parser((
Argument('foo', optional=True),
Argument('bar')
))
self._test_for_ambiguity("--foo --bar")
def ambiguity_with_task_name(self):
# mytask --foo myothertask
c1 = Context('mytask', args=(Argument('foo', optional=True),))
c2 = Context('othertask')
p = Parser([c1, c2])
self._test_for_ambiguity("--foo othertask", p)
class task_repetition:
def is_happy_to_handle_same_task_multiple_times(self):
task1 = Context('mytask')
result = Parser((task1,)).parse_argv(['mytask', 'mytask'])
eq_(len(result), 2)
[eq_(x.name, 'mytask') for x in result]
def task_args_work_correctly(self):
task1 = Context('mytask', args=(Argument('meh'),))
result = Parser((task1,)).parse_argv(
['mytask', '--meh', 'mehval1', 'mytask', '--meh', 'mehval2']
)
eq_(result[0].args.meh.value, 'mehval1')
eq_(result[1].args.meh.value, 'mehval2')
class ParseResult_(Spec):
"ParseResult"
def setup(self):
self.context = Context('mytask',
args=(Argument('foo', kind=str), Argument('bar')))
argv = ['mytask', '--foo', 'foo-val', '--', 'my', 'remainder']
self.result = Parser((self.context,)).parse_argv(argv)
def acts_as_a_list_of_parsed_contexts(self):
eq_(len(self.result), 1)
eq_(self.result[0].name, 'mytask')
def exhibits_remainder_attribute(self):
eq_(self.result.remainder, 'my remainder')
|