From a64ac96513906eb76a03686a0658375b7fcb47be Mon Sep 17 00:00:00 2001 From: Danny Sepler Date: Fri, 10 Sep 2021 14:37:42 -0400 Subject: [PATCH 1/3] Final py39 deprecation --- nltk/test/unit/test_util.py | 225 +++++++++++++++++++++++------------- nltk/util.py | 32 ++--- 2 files changed, 163 insertions(+), 94 deletions(-) diff --git a/nltk/test/unit/test_util.py b/nltk/test/unit/test_util.py index 365452574b..2f8e4db4f1 100644 --- a/nltk/test/unit/test_util.py +++ b/nltk/test/unit/test_util.py @@ -1,81 +1,144 @@ -""" -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: + 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: + @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" + ) + + +def test_usage_on_builtin(capsys): + class MyClass(dict): + ... + + usage(MyClass) + + captured = capsys.readouterr() + assert captured.out == ( + "MyClass supports the following operations:\n" + " - fromkeys(iterable, value=None, /)\n" + " - self.get(key, default=None, /)\n" + " - self.popitem(/)\n" + " - self.setdefault(key, default=None, /)\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..383342a4e5 100644 --- a/nltk/util.py +++ b/nltk/util.py @@ -37,32 +37,38 @@ ###################################################################### -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) + try: + sig = str(inspect.signature(method)) + except ValueError as e: + # builtins sometimes don't support introspection + if "builtin" in str(e): + continue + else: + raise + + args = sig.lstrip("(").rstrip(")").split(", ") + meth = inspect.getattr_static(obj, name) + if isinstance(meth, (classmethod, staticmethod)): + 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), ) From 7740a517f7f63fcf6377177f45ebebdc6af54f7f Mon Sep 17 00:00:00 2001 From: Danny Sepler Date: Wed, 15 Sep 2021 23:07:48 -0400 Subject: [PATCH 2/3] acommodate multiple python versions --- nltk/test/unit/test_util.py | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/nltk/test/unit/test_util.py b/nltk/test/unit/test_util.py index 2f8e4db4f1..fd0136ce41 100644 --- a/nltk/test/unit/test_util.py +++ b/nltk/test/unit/test_util.py @@ -50,19 +50,9 @@ def clsmethod_with_args(cls, a, b, c=1): def test_usage_on_builtin(capsys): - class MyClass(dict): - ... - - usage(MyClass) - - captured = capsys.readouterr() - assert captured.out == ( - "MyClass supports the following operations:\n" - " - fromkeys(iterable, value=None, /)\n" - " - self.get(key, default=None, /)\n" - " - self.popitem(/)\n" - " - self.setdefault(key, default=None, /)\n" - ) + # just check the func passes, since + # builtins change each python version + usage(dict) @pytest.fixture From d77ea03285b98f46fc2cf099172e69daa4ff8619 Mon Sep 17 00:00:00 2001 From: Danny Sepler Date: Wed, 15 Sep 2021 23:18:17 -0400 Subject: [PATCH 3/3] dont need capsys import anymore --- nltk/test/unit/test_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nltk/test/unit/test_util.py b/nltk/test/unit/test_util.py index fd0136ce41..109a96b31b 100644 --- a/nltk/test/unit/test_util.py +++ b/nltk/test/unit/test_util.py @@ -49,7 +49,7 @@ def clsmethod_with_args(cls, a, b, c=1): ) -def test_usage_on_builtin(capsys): +def test_usage_on_builtin(): # just check the func passes, since # builtins change each python version usage(dict)