From 8bbf64adefdb9ce46c430359b69a2fd72de6ac92 Mon Sep 17 00:00:00 2001 From: Paolo Lammens Date: Sun, 13 Dec 2020 17:00:02 +0100 Subject: [PATCH 1/2] feat: Add is_bound_method utility --- six.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/six.py b/six.py index 83f69783d..f3f012fb2 100644 --- a/six.py +++ b/six.py @@ -541,6 +541,9 @@ def callable(obj): if PY3: + def is_bound_method(func): + return callable(func) and hasattr(func, _meth_self) + def get_unbound_function(unbound): return unbound @@ -551,6 +554,15 @@ def create_unbound_method(func, cls): Iterator = object else: + _builtin_bound_method_type = type((0).bit_length) + _method_wrapper_type = type((0).__abs__) + + def is_bound_method(func): + return ( + callable(func) and getattr(func, _meth_self, None) is not None + or isinstance(func, (_builtin_bound_method_type, _method_wrapper_type)) + ) + def get_unbound_function(unbound): return unbound.im_func From 2c237db8e5f6f718612fdaecdaa47700428e5589 Mon Sep 17 00:00:00 2001 From: Paolo Lammens Date: Sun, 13 Dec 2020 17:40:36 +0100 Subject: [PATCH 2/2] tests: Test is_bound_method --- test_six.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test_six.py b/test_six.py index 7b8b03b5e..07f89e789 100644 --- a/test_six.py +++ b/test_six.py @@ -471,6 +471,57 @@ def f(self): assert f(x) is x +class TestIsBoundMethod: + class DummyClass: + @staticmethod + def static(): + pass + + @classmethod + def class_meth(cls): + pass + + def meth(self): + pass + + def a_free_function(self): + pass + + @pytest.mark.parametrize( + "meth", + [ + DummyClass().meth, + DummyClass.class_meth, + DummyClass().class_meth, + (0).bit_length, + "".join, + "foo".__lt__, + (0).__abs__, + ] + ) + def test_is_bound_method_true(self, meth): + assert six.is_bound_method(meth) + + @pytest.mark.parametrize( + "obj", + [ + lambda x: x, + a_free_function, + DummyClass.meth, + DummyClass.static, + DummyClass().static, + int.bit_length, + str.join, + str.__lt__, + ] + ) + def test_is_bound_method_false(self, obj): + assert not six.is_bound_method(obj) + + del DummyClass + del a_free_function + + if six.PY3: def test_b():