Skip to content

Commit

Permalink
parser/CliBoundArguments: [breaking] use attrs and put parsing in method
Browse files Browse the repository at this point in the history
The preferred method for invoking the parser remains
CliSignature#parse_arguments.  If you were using:

    CliBoundArguments(csig, in_args, name)

Please add a call to CliBoundArguments#process_arguments:

    ba = CliBoundArguments(csig, in_args, name)
    ba.process_arguments()

The advantage now is that you can more easily set up instances of
CliBoundArguments for testing:

    myparam = ...
    csig = CliSignature([myparam])
    ba = CliBoundArguments(csig, ['arg'], 'test', kwargs={'myparam':'1'}
    myparam.read_argument(ba, 0)
    self.assertEqual(ba.kwargs['myparam'], 2)
  • Loading branch information
epsy committed Apr 8, 2017
1 parent 10c5a72 commit 60e0316
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 21 deletions.
41 changes: 29 additions & 12 deletions clize/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import six
from sigtools import modifiers
import attr

from clize import errors, util

Expand Down Expand Up @@ -971,7 +972,9 @@ def read_arguments(self, args, name):
:param sequence args: The CLI arguments, minus the script name.
:param str name: The script name.
"""
return CliBoundArguments(self, args, name)
ba = CliBoundArguments(self, args, name)
ba.process_arguments()
return ba

def __str__(self):
return ' '.join(
Expand Down Expand Up @@ -1007,6 +1010,7 @@ def __exit__(self, typ, exc, tb):
return True


@attr.s
class CliBoundArguments(object):
"""Command line arguments bound to a `.CliSignature` instance.
Expand Down Expand Up @@ -1092,22 +1096,35 @@ class CliBoundArguments(object):
"""
threshold = 0.75

def __init__(self, sig, args, name):
self.sig = sig
self.name = name
self.in_args = tuple(args)
self.func = None
self.post_name = []
self.args = []
self.kwargs = {}
self.meta = {}

sig = attr.ib()
in_args = attr.ib(convert=tuple)
name = attr.ib()

func = attr.ib(default=None)
post_name = attr.ib(default=attr.Factory(list))
args = attr.ib(default=attr.Factory(list))
kwargs = attr.ib(default=attr.Factory(dict))
meta = attr.ib(default=attr.Factory(dict))

posparam = attr.ib(init=False)
namedparam = attr.ib(init=False)
unsatisfied = attr.ib(init=False)
posarg_only = attr.ib(init=False)
skip = attr.ib(init=False)

def process_arguments(self):
"""Process the arguments in `.in_args`, setting the `.func`,
`.post_name`, `.args` and `.kwargs` attributes as a result.
This methods reads `str`s from `.in_args`. For each one, it finds the
relevant `Parameter` instance in `.posparam` or `.namedparam` and
delegates processing to it """
self.posparam = iter(self.sig.positional)
self.namedparams = dict(self.sig.aliases)
self.unsatisfied = set(self.sig.required)
self.sticky = None
self.posarg_only = False
self.skip = 0
self.unsatisfied = set(self.sig.required)

with _SeekFallbackCommand():
for i, arg in enumerate(self.in_args):
Expand Down
15 changes: 6 additions & 9 deletions clize/tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,50 +341,47 @@ def test_posparam_set_value_parameter_not_present(self):
param = parser.PositionalParameter(argument_name='two', display_name='two')
sig = support.s('one, two')
csig = parser.CliSignature.from_signature(sig)
ba = parser.CliBoundArguments(csig, ['one', 'two'], 'func')
ba = parser.CliBoundArguments(csig, [], 'func', args=['one', 'two'])
with self.assertRaises(ValueError):
param.set_value(ba, 'inserted')

def test_posparam_set_value_only(self):
param = parser.PositionalParameter(argument_name='one', display_name='one')
sig = support.s('one:par', locals={'par': param})
csig = parser.CliSignature.from_signature(sig)
ba = parser.CliBoundArguments(csig, ['one'], 'func')
ba.args[:] = []
ba = parser.CliBoundArguments(csig, [], 'func', args=[])
param.set_value(ba, 'inserted')
self.assertEqual(ba.args, ['inserted'])

def test_posparam_set_value_already_set(self):
param = parser.PositionalParameter(argument_name='two', display_name='two')
sig = support.s('one, two:par', locals={'par': param})
csig = parser.CliSignature.from_signature(sig)
ba = parser.CliBoundArguments(csig, ['one', 'two'], 'func')
ba = parser.CliBoundArguments(csig, [], 'func', args=['one', 'two'])
param.set_value(ba, 'inserted')
self.assertEqual(ba.args, ['one', 'inserted'])

def test_posparam_set_value_after_set(self):
param = parser.PositionalParameter(argument_name='two', display_name='two')
sig = support.s('one, two:par', locals={'par': param})
csig = parser.CliSignature.from_signature(sig)
ba = parser.CliBoundArguments(csig, ['one', 'two'], 'func')
ba.args[1:] = []
ba = parser.CliBoundArguments(csig, [], 'func', args=['one'])
param.set_value(ba, 'inserted')
self.assertEqual(ba.args, ['one', 'inserted'])

def test_posparam_set_value_after_default(self):
param = parser.PositionalParameter(argument_name='two', display_name='two', default="two")
sig = support.s('one="one", two:par="two"', locals={'par': param})
csig = parser.CliSignature.from_signature(sig)
ba = parser.CliBoundArguments(csig, [], 'func')
ba = parser.CliBoundArguments(csig, [], 'func', args=[])
param.set_value(ba, 'inserted')
self.assertEqual(ba.args, ['one', 'inserted'])

def test_posparam_set_value_after_missing(self):
param = parser.PositionalParameter(argument_name='two', display_name='two')
sig = support.s('one, two:par', locals={'par': param})
csig = parser.CliSignature.from_signature(sig)
ba = parser.CliBoundArguments(csig, ['one', 'two'], 'func')
ba.args[:] = []
ba = parser.CliBoundArguments(csig, [], 'func', args=[])
with self.assertRaises(ValueError):
param.set_value(ba, 'inserted')

Expand Down

0 comments on commit 60e0316

Please sign in to comment.