Added completer.py and tests for FileDisplay

This commit is contained in:
Brad Warren
2016-03-22 18:07:51 -07:00
parent 95a4a2ca60
commit 74a7d2bed9
2 changed files with 115 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
"""Provides tab autocompletion when prompting users for a path."""
import glob
import readline
class Completer(object):
"""Provides tab autocompletion when prompting users for a path.
This class is meant to be used with readline to provide tab
autocompletion for users entering paths. The complete method can
be passed to readline.set_completer directly, however, this function
works best as a context manager. For example:
with Completer():
raw_input()
In this example, tab autocompletion will be available during
the call to raw_input above, however, readline will be restored to
its previous state when exiting the body of the with statement.
"""
def __init__(self):
self._completer = self._delims = self._iter = None
def complete(self, text, state):
"""Provides path autocompletion for use with readline.
:param str text: text to offer completions for
:param int state: which completion to return
:returns: possible completion for text or ``None`` if all
completions have been returned
:rtype: str
"""
if state == 0:
self._iter = glob.iglob(text + '*')
return next(self._iter, None)
def __enter__(self):
self._completer = readline.get_completer()
self._delims = readline.get_completer_delims()
readline.set_completer(self.complete)
readline.set_completer_delims(' \t\n;')
readline.parse_and_bind('tab: complete')
def __exit__(self, unused_type, unused_value, unused_traceback):
readline.set_completer_delims(self._delims)
readline.set_completer(self._completer)
@@ -0,0 +1,64 @@
"""Test letsencrypt.display.completer."""
import os
import readline
import shutil
import string
import tempfile
import unittest
class CompleterTest(unittest.TestCase):
"""Test letsencrypt.display.completer.Completer."""
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
# directories must end with os.sep for completer to
# search inside the directory for possible completions
if self.temp_dir[-1] != os.sep:
self.temp_dir += os.sep
self.paths = []
# create some files and directories in temp_dir
for c in string.ascii_lowercase:
path = os.path.join(self.temp_dir, c)
self.paths.append(path)
if ord(c) % 2:
os.mkdir(path)
else:
with open(path, 'w'):
pass
def tearDown(self):
shutil.rmtree(self.temp_dir)
def test_context_manager(self):
from letsencrypt.display import completer
original_completer = readline.get_completer()
original_delims = readline.get_completer_delims()
with completer.Completer():
pass
self.assertEqual(readline.get_completer(), original_completer)
self.assertEqual(readline.get_completer_delims(), original_delims)
def test_complete(self):
from letsencrypt.display import completer
my_completer = completer.Completer()
num_paths = len(self.paths)
for i in range(num_paths):
completion = my_completer.complete(self.temp_dir, i)
self.assertTrue(completion in self.paths)
self.paths.remove(completion)
self.assertFalse(self.paths)
completion = my_completer.complete(self.temp_dir, num_paths)
self.assertEqual(completion, None)
if __name__ == "__main__":
unittest.main() # pragma: no cover