Commits

Andy Mikhailenko  committed 0eaaa19

Fix #33: enable custom per-argument shell completion (based on a patch by Marco Nenciarini)

  • Participants
  • Parent commits 49ba8d0

Comments (0)

Files changed (5)

 :thethomasw:          Python2.6 bug reports
 :Tuk Bredsdorff:      List of similar projects
 :Mike Gilbert:        Gentoo package; patch
+:Marco Nenciarini:    Patch for shell completion
 
 ...you? :-)
     Patches, ideas and any feedback is highly appreciated.

File argh/assembling.py

 import sys
 import argparse
 
+from argh.completion import COMPLETION_ENABLED
 from argh.constants import (ATTR_ALIASES, ATTR_ARGS, ATTR_NAME,
                             ATTR_INFER_ARGS_FROM_SIGNATURE,
                             ATTR_EXPECTS_NAMESPACE_OBJECT)
         dest_or_opt_strings = draft.pop('option_strings')
         if parser.add_help and '-h' in dest_or_opt_strings:
             dest_or_opt_strings = [x for x in dest_or_opt_strings if x != '-h']
+        completer = draft.pop('completer', None)
         try:
-            parser.add_argument(*dest_or_opt_strings, **draft)
+            action = parser.add_argument(*dest_or_opt_strings, **draft)
+            if COMPLETION_ENABLED and completer:
+                action.completer = completer
         except Exception as e:
             raise type(e)('{func}: cannot add arg {args}: {msg}'.format(
                 args='/'.join(dest_or_opt_strings), func=function.__name__, msg=e))

File argh/completion.py

 
 .. _argcomplete: https://github.com/kislyuk/argcomplete
 .. _python-selfcompletion: https://github.com/dbarnett/python-selfcompletion
+
+Argument-level completion
+-------------------------
+
+Argcomplete_ supports custom "completers".  The documentation suggests adding
+the completer as an attribute of the argument parser action::
+
+    parser.add_argument("--env-var1").completer = EnvironCompleter
+
+However, this doesn't fit the normal `Argh`-assisted workflow.
+It is recommended to use the :func:`~argh.decorators.arg` decorator::
+
+    @arg('--env-var1', completer=EnvironCompleter)
+    def func(...):
+        ...
+
 """
 
 COMPLETION_ENABLED = False

File test/test_assembling.py

     p.set_default_command(argh.command(cmd))
     prog_help = p.format_help()
     assert 'quux' in prog_help
+
+
+@mock.patch('argh.assembling.COMPLETION_ENABLED', True)
+def test_custom_argument_completer():
+    "Issue #33: Enable custom per-argument shell completion"
+
+    def func(foo):
+        pass
+
+    setattr(func, argh.constants.ATTR_ARGS, [
+        dict(option_strings=('foo',), completer='STUB')
+    ])
+
+    p = argh.ArghParser()
+    p.set_default_command(func)
+
+    assert p._actions[-1].completer == 'STUB'
+
+
+@mock.patch('argh.assembling.COMPLETION_ENABLED', False)
+def test_custom_argument_completer_no_backend():
+    "If completion backend is not available, nothing breaks"
+
+    def func(foo):
+        pass
+
+    setattr(func, argh.constants.ATTR_ARGS, [
+        dict(option_strings=('foo',), completer='STUB')
+    ])
+
+    p = argh.ArghParser()
+    p.set_default_command(func)
+
+    assert not hasattr(p._actions[-1], 'completer')

File test/test_integration.py

 import re
 import argparse
 
+import mock
 import pytest
 
 import argh
     p.set_default_command(cmd)
 
     assert run(p, 'hello') == 'hello\n'
+
+
+@mock.patch('argh.assembling.COMPLETION_ENABLED', True)
+def test_custom_argument_completer():
+    "Issue #33: Enable custom per-argument shell completion"
+
+    @argh.arg('foo', completer='STUB')
+    def func(foo):
+        pass
+
+    p = argh.ArghParser()
+    p.set_default_command(func)
+
+    assert p._actions[-1].completer == 'STUB'