diff --git a/nltk/test/unit/test_util.py b/nltk/test/unit/test_util.py index 365452574b..64c422d8da 100644 --- a/nltk/test/unit/test_util.py +++ b/nltk/test/unit/test_util.py @@ -1,81 +1,130 @@ -""" -Unit tests for nltk.util. -""" - -import unittest - -from nltk.util import everygrams - - -class TestEverygrams(unittest.TestCase): - def setUp(self): - """Form test data for tests.""" - self.test_data = iter("a b c".split()) - - def test_everygrams_without_padding(self): - expected_output = [ - ("a",), - ("a", "b"), - ("a", "b", "c"), - ("b",), - ("b", "c"), - ("c",), - ] - output = everygrams(self.test_data) - self.assertCountEqual(output, expected_output) - - def test_everygrams_max_len(self): - expected_output = [ - ("a",), - ("a", "b"), - ("b",), - ("b", "c"), - ("c",), - ] - output = everygrams(self.test_data, max_len=2) - self.assertCountEqual(output, expected_output) - - def test_everygrams_min_len(self): - expected_output = [ - ("a", "b"), - ("b", "c"), - ("a", "b", "c"), - ] - output = everygrams(self.test_data, min_len=2) - self.assertCountEqual(output, expected_output) - - def test_everygrams_pad_right(self): - expected_output = [ - ("a",), - ("a", "b"), - ("a", "b", "c"), - ("b",), - ("b", "c"), - ("b", "c", None), - ("c",), - ("c", None), - ("c", None, None), - (None,), - (None, None), - (None,), - ] - output = everygrams(self.test_data, max_len=3, pad_right=True) - self.assertCountEqual(output, expected_output) - - def test_everygrams_pad_left(self): - expected_output = [ - (None,), - (None, None), - (None, None, "a"), - (None,), - (None, "a"), - (None, "a", "b"), - ("a",), - ("a", "b"), - ("a", "b", "c"), - ("b",), - ("b", "c"), - ("c",), - ] - output = everygrams(self.test_data, max_len=3, pad_left=True) - self.assertCountEqual(output, expected_output) +import pytest + +from nltk.util import everygrams, usage + + +def test_usage_with_self(capsys): + class MyClass: + # sorted alphabetically + def kwargs(self, a=1): + ... + + def no_args(self): + ... + + def pos_args(self, a, b): + ... + + def pos_args_and_kwargs(self, a, b, c=1): + ... + + usage(MyClass) + + captured = capsys.readouterr() + assert captured.out == ( + "MyClass supports the following operations:\n" + " - self.kwargs(a=1)\n" + " - self.no_args()\n" + " - self.pos_args(a, b)\n" + " - self.pos_args_and_kwargs(a, b, c=1)\n" + ) + + +def test_usage_with_cls(capsys): + class MyClass: + # sorted alphabetically + @classmethod + def clsmethod(cls): + ... + + @classmethod + def clsmethod_with_args(cls, a, b, c=1): + ... + + usage(MyClass) + + captured = capsys.readouterr() + assert captured.out == ( + "MyClass supports the following operations:\n" + " - cls.clsmethod()\n" + " - cls.clsmethod_with_args(a, b, c=1)\n" + ) + + +@pytest.fixture +def everygram_input(): + """Form test data for tests.""" + return iter(["a", "b", "c"]) + + +def test_everygrams_without_padding(everygram_input): + expected_output = [ + ("a",), + ("a", "b"), + ("a", "b", "c"), + ("b",), + ("b", "c"), + ("c",), + ] + output = list(everygrams(everygram_input)) + assert output == expected_output + + +def test_everygrams_max_len(everygram_input): + expected_output = [ + ("a",), + ("a", "b"), + ("b",), + ("b", "c"), + ("c",), + ] + output = list(everygrams(everygram_input, max_len=2)) + assert output == expected_output + + +def test_everygrams_min_len(everygram_input): + expected_output = [ + ("a", "b"), + ("a", "b", "c"), + ("b", "c"), + ] + output = list(everygrams(everygram_input, min_len=2)) + assert output == expected_output + + +def test_everygrams_pad_right(everygram_input): + expected_output = [ + ("a",), + ("a", "b"), + ("a", "b", "c"), + ("b",), + ("b", "c"), + ("b", "c", None), + ("c",), + ("c", None), + ("c", None, None), + (None,), + (None, None), + (None,), + ] + output = list(everygrams(everygram_input, max_len=3, pad_right=True)) + assert output == expected_output + + +def test_everygrams_pad_left(everygram_input): + expected_output = [ + (None,), + (None, None), + (None, None, "a"), + (None,), + (None, "a"), + (None, "a", "b"), + ("a",), + ("a", "b"), + ("a", "b", "c"), + ("b",), + ("b", "c"), + ("c",), + ] + output = list(everygrams(everygram_input, max_len=3, pad_left=True)) + assert output == expected_output diff --git a/nltk/util.py b/nltk/util.py index c25a8fb339..73885a3bf8 100644 --- a/nltk/util.py +++ b/nltk/util.py @@ -37,32 +37,30 @@ ###################################################################### -def usage(obj, selfname="self"): +def usage(obj): str(obj) # In case it's lazy, this will load it. if not isinstance(obj, type): obj = obj.__class__ - print("%s supports the following operations:" % obj.__name__) + print(f"{obj.__name__} supports the following operations:") for (name, method) in sorted(pydoc.allmethods(obj).items()): if name.startswith("_"): continue if getattr(method, "__deprecated__", False): continue - getargspec = inspect.getfullargspec - args, varargs, varkw, defaults = getargspec(method)[:4] - if ( - args - and args[0] == "self" - and (defaults is None or len(args) > len(defaults)) - ): - args = args[1:] - name = f"{selfname}.{name}" - argspec = inspect.formatargspec(args, varargs, varkw, defaults) + signature = inspect.signature(method) + args = str(signature).lstrip("(").rstrip(")").split(", ") + is_classmethod = isinstance(inspect.getattr_static(obj, name), classmethod) + if is_classmethod: + name = f"cls.{name}" + elif args and args[0] == "self": + name = f"self.{name}" + args.pop(0) print( textwrap.fill( - f"{name}{argspec}", + f"{name}({', '.join(args)})", initial_indent=" - ", subsequent_indent=" " * (len(name) + 5), )