From cdaa402d8014e689085a1d7dae3237a82d8b8af4 Mon Sep 17 00:00:00 2001 From: Douglas Burke Date: Thu, 7 Oct 2021 16:18:14 -0400 Subject: [PATCH 1/2] Tests: split up the test_export_method test Break up the test into a number of smaller checks (we could go more fine-grained but let's see how this works). --- sherpa/utils/tests/test_utils.py | 67 ++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/sherpa/utils/tests/test_utils.py b/sherpa/utils/tests/test_utils.py index 481e97c73..707281f13 100644 --- a/sherpa/utils/tests/test_utils.py +++ b/sherpa/utils/tests/test_utils.py @@ -75,34 +75,36 @@ def __init__(self): c.z = 5 -def test_export_method(): - class C(): +class C(): - def m(self, x, y=2): - 'Instance method m()' - return x * y + def m(self, x, y=2): + 'Instance method m()' + return x * y - def margs(self, x, y=2, *args): - 'Instance method margs() with *args' - return x * y + len(args) + def margs(self, x, y=2, *args): + 'Instance method margs() with *args' + return x * y + len(args) - def kwargs(self, x, y=2, **kwargs): - 'Instance method kwargs() with **kwargs' - return x * y + 2 * len(kwargs) + def kwargs(self, x, y=2, **kwargs): + 'Instance method kwargs() with **kwargs' + return x * y + 2 * len(kwargs) - def bargs(self, x, y=2, *args, **kwargs): - 'Instance method bargs() with *args and **kwargs' - return x * y + len(args) + 2 * len(kwargs) + def bargs(self, x, y=2, *args, **kwargs): + 'Instance method bargs() with *args and **kwargs' + return x * y + len(args) + 2 * len(kwargs) - @classmethod - def cm(klass, x, y=2): - 'Class method cm()' - return x * y + @classmethod + def cm(klass, x, y=2): + 'Class method cm()' + return x * y - @staticmethod - def sm(x, y=2): - 'Static method sm()' - return x * y + @staticmethod + def sm(x, y=2): + 'Static method sm()' + return x * y + + +def test_export_method_basic(): c = C() @@ -124,13 +126,26 @@ def sm(x, y=2): "missing 1 required positional argument: 'x'" assert str(exc.value) == emsg + +def test_export_method_args_call(): + # Check that *args/**kwargs are handled correctly for methods; # should perhaps be included above to avoid repeated calls # to export_method? # + c = C() meth = utils.export_method(c.margs) assert meth(3, 7, "a", "b") == 23 + meth = utils.export_method(c.bargs) + assert meth(3, 7, 14, 15, foo=None) == 25 + + +def test_export_method_args_errors(): + + c = C() + meth = utils.export_method(c.margs) + with pytest.raises(TypeError) as exc: meth(12, dummy=None) @@ -147,8 +162,8 @@ def sm(x, y=2): "but 3 were given" assert str(exc.value) in emsg - meth = utils.export_method(c.bargs) - assert meth(3, 7, 14, 15, foo=None) == 25 + +def test_export_method_non_method(): # Non-method argument def f(x): @@ -156,7 +171,11 @@ def f(x): assert utils.export_method(f) is f + +def test_export_method_names(): + # Name and module name + c = C() m = utils.export_method(c.m, 'foo', 'bar') assert m.__name__ == 'foo' assert m.__module__ == 'bar' From c189084bd620010bda0a23ab6e6499a598f53cdc Mon Sep 17 00:00:00 2001 From: Douglas Burke Date: Thu, 7 Oct 2021 16:37:48 -0400 Subject: [PATCH 2/2] Tests: update export_method tests for Python 3.10 There is a change to how an error message appears for a static method in Python 3.10 (it now includes the original class name). This is not ideal, but for now we adjust the test rather than try to work out whether the code can be changed. This is something of an edge case. --- sherpa/utils/tests/test_utils.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/sherpa/utils/tests/test_utils.py b/sherpa/utils/tests/test_utils.py index 707281f13..6fa32b7ff 100644 --- a/sherpa/utils/tests/test_utils.py +++ b/sherpa/utils/tests/test_utils.py @@ -108,7 +108,11 @@ def test_export_method_basic(): c = C() - # Basic usage + # Basic usage. The error message depends on + # a) Python version + # b) what method is being wrapped + # (before Python 3.10 it didn't). + # for meth in (c.m, c.margs, c.kwargs, c.bargs, c.cm, c.sm): m = utils.export_method(meth) @@ -122,9 +126,19 @@ def test_export_method_basic(): with pytest.raises(TypeError) as exc: m() - emsg = "{}() ".format(meth.__name__) + \ + emsg = f"{meth.__name__}() " + \ "missing 1 required positional argument: 'x'" - assert str(exc.value) == emsg + + if meth.__name__ == 'sm': + # In Python 3.10 we see C.sm rather than sm + # so we search for both. We could be more explicit + # and check on the Python version (e.g. for >= 3.10) + # but it doesn't seem worth it. It's interesting it's + # only for the static method. + # + assert str(exc.value) in [emsg, 'C.' + emsg] + else: + assert str(exc.value) == emsg def test_export_method_args_call():