mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Make tab completion in console more useful
tab completion and dir() now show registered plugins in API name spaces. Signed-off-by: Christian Heimes <cheimes@redhat.com> Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
This commit is contained in:
@@ -949,6 +949,14 @@ class show_mappings(frontend.Command):
|
||||
print(to_cli(item[0]).ljust(mcl)+' : '+item[1])
|
||||
|
||||
|
||||
class IPACompleter(rlcompleter.Completer):
|
||||
def _callable_postfix(self, val, word):
|
||||
# Don't add '(' postfix for callable API objects
|
||||
if isinstance(val, (plugable.APINameSpace, plugable.API)):
|
||||
return word
|
||||
return super()._callable_postfix(val, word)
|
||||
|
||||
|
||||
class console(frontend.Command):
|
||||
"""Start the IPA interactive Python console, or run a script.
|
||||
|
||||
@@ -964,7 +972,7 @@ class console(frontend.Command):
|
||||
def _setup_tab_completion(self, local):
|
||||
readline.parse_and_bind("tab: complete")
|
||||
# completer with custom locals
|
||||
readline.set_completer(rlcompleter.Completer(local).complete)
|
||||
readline.set_completer(IPACompleter(local).complete)
|
||||
# load history
|
||||
history = os.path.join(api.env.dot_ipa, "console.history")
|
||||
try:
|
||||
|
||||
@@ -326,6 +326,14 @@ class APINameSpace(Mapping):
|
||||
self.__enumerate()
|
||||
return iter(self.__plugins)
|
||||
|
||||
def __dir__(self):
|
||||
# include plugins for readline tab completion and in dir()
|
||||
self.__enumerate()
|
||||
names = super().__dir__()
|
||||
names.extend(p.name for p in self)
|
||||
names.sort()
|
||||
return names
|
||||
|
||||
def get_plugin(self, key):
|
||||
self.__enumerate()
|
||||
return self.__plugins_by_key[key]
|
||||
|
||||
44
ipatests/test_cmdline/test_console.py
Normal file
44
ipatests/test_cmdline/test_console.py
Normal file
@@ -0,0 +1,44 @@
|
||||
#
|
||||
# Copyright (C) 2019 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
import inspect
|
||||
import io
|
||||
import pydoc
|
||||
|
||||
import pytest
|
||||
|
||||
from ipalib import api
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def api_obj():
|
||||
if not api.Backend.rpcclient.isconnected():
|
||||
api.Backend.rpcclient.connect()
|
||||
yield api
|
||||
|
||||
|
||||
@pytest.mark.tier0
|
||||
@pytest.mark.needs_ipaapi
|
||||
class TestIPAConsole:
|
||||
def run_pydoc(self, plugin):
|
||||
s = io.StringIO()
|
||||
# help() calls pydoc.doc() with pager
|
||||
pydoc.doc(plugin, "Help %s", output=s)
|
||||
return s.getvalue()
|
||||
|
||||
def test_dir(self, api_obj):
|
||||
assert "Command" in dir(api_obj)
|
||||
assert "group_add" in dir(api_obj.Command)
|
||||
|
||||
def test_signature(self, api_obj):
|
||||
sig = api_obj.Command.group_add.__signature__
|
||||
assert isinstance(sig, inspect.Signature)
|
||||
params = sig.parameters
|
||||
assert params['cn'].kind is inspect.Parameter.POSITIONAL_OR_KEYWORD
|
||||
assert params['cn'].annotation is str
|
||||
assert params['description'].kind is inspect.Parameter.KEYWORD_ONLY
|
||||
|
||||
def test_help(self, api_obj):
|
||||
s = self.run_pydoc(api_obj.Command.group_add)
|
||||
# check for __signature__ in help()
|
||||
assert "group_add(cn: str, *, description: str = None," in s
|
||||
Reference in New Issue
Block a user