Skip to content

Commit

Permalink
allow switch abbrevations as an option
Browse files Browse the repository at this point in the history
  • Loading branch information
presto8 authored and henryiii committed Aug 8, 2018
1 parent 2b5a82a commit b2a5257
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 1 deletion.
21 changes: 21 additions & 0 deletions docs/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,27 @@ specify the validators. For example::

Annotations are ignored if the positional decorator is present.

Switch Abbreviations
^^^^^^^^^^^^^^^^^^^^

The cli supports switches which have been abbreviated by the user, for example, "--h", "--he", or
"--hel" would all match an actual switch name of"--help", as long as no ambiguity arises from
multiple switches that might match the same abbreviation. This behavior is disabled by default but
can be enabled by defining the class-level attribute ``ALLOW_ABBREV`` to True. For example::

class MyApp(cli.Application):
ALLOW_ABBREV = True
cheese = cli.Flag(["cheese"], help = "cheese, please")
chives = cli.Flag(["chives"], help = "chives, instead")

With the above definition, running the following will raise an error due to ambiguity::

$ python example.py --ch # error! matches --cheese and --chives

However, the following two lines are equivalent::

$ python example.py --che
$ python example.py --cheese


.. _guide-subcommands:
Expand Down
21 changes: 21 additions & 0 deletions plumbum/cli/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ def main(self, src, dst):
* ``SUBCOMMAND_HELPMSG`` - Controls the printing of extra "see subcommand -h" help message.
Default is a message, set to False to remove.
* ``ALLOW_ABBREV`` - Controls whether partial switch names are supported, for example '--ver' will match
'--verbose'. Default is False for backward consistency with previous plumbum releases. Note that ambiguous
abbreviations will not match, for example if --foothis and --foothat are defined, then --foo will not match.
A note on sub-commands: when an application is the root, its ``parent`` attribute is set to
``None``. When it is used as a nested-command, ``parent`` will point to its direct ancestor.
Likewise, when an application is invoked with a sub-command, its ``nested_command`` attribute
Expand All @@ -141,6 +145,7 @@ def main(self, src, dst):
COLOR_GROUPS = None
CALL_MAIN_IF_NESTED_COMMAND = True
SUBCOMMAND_HELPMSG = T_("see '{parent} {sub} --help' for more info")
ALLOW_ABBREV = False

parent = None
nested_command = None
Expand Down Expand Up @@ -259,6 +264,13 @@ def wrapper(subapp):

return wrapper(subapp) if subapp else wrapper

def _get_partial_matches(self, partialname):
matches = []
for switch in self._switches_by_name:
if switch.startswith(partialname):
matches += [switch, ]
return matches

def _parse_args(self, argv):
tailargs = []
swfuncs = {}
Expand Down Expand Up @@ -289,6 +301,15 @@ def _parse_args(self, argv):
argv.insert(0, a[eqsign:])
else:
name = a[2:]

if self.ALLOW_ABBREV:
partials = self._get_partial_matches(name)
if len(partials) == 1:
name = partials[0]
elif len(partials) > 1:
raise UnknownSwitch(
T_("Ambiguous partial switch {0}").format("--" + name))

swname = "--" + name
if name not in self._switches_by_name:
raise UnknownSwitch(
Expand Down
14 changes: 13 additions & 1 deletion tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ def bacon(self, param):
print ("!!b", param)

eggs = cli.SwitchAttr(["e"], str, help = "sets the eggs attribute", envname="PLUMBUM_TEST_EGGS")
cheese = cli.Flag(["--cheese"], help = "cheese, please")
chives = cli.Flag(["--chives"], help = "chives, instead")
verbose = cli.CountOf(["v"], help = "increases the verbosity level")
benedict = cli.CountOf(["--benedict"], help = """a very long help message with lots of
useless information that nobody would ever want to read, but heck, we need to test
Expand Down Expand Up @@ -291,5 +293,15 @@ def test_mandatory_env_var(self, capsys):
stdout, stderr = capsys.readouterr()
assert "bacon is mandatory" in stdout

def test_partial_switches(self, capsys):
app = SimpleApp
app.ALLOW_ABBREV = True
inst, rc = app.run(["foo", "--bacon=2", "--ch"], exit=False)
stdout, stderr = capsys.readouterr()
assert 'Ambiguous partial switch' in stdout
assert rc == 2


inst, rc = app.run(["foo", "--bacon=2", "--chee"], exit=False)
assert rc == 0
assert inst.cheese is True
assert inst.chives is False

0 comments on commit b2a5257

Please sign in to comment.