diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 89aca9c9df864a..bbc1d1301d2c2a 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -155,6 +155,14 @@ Standard names are defined for the following types: .. versionadded:: 3.7 +.. data:: ClassMethodDescriptorType + + The type of *unbound* class methods of some built-in data types such as + ``dict.__dict__['fromkeys']``. + + .. versionadded:: 3.7 + + .. class:: ModuleType(name, doc=None) The type of :term:`modules `. Constructor takes the name of the diff --git a/Lib/inspect.py b/Lib/inspect.py index 8c121ce96c4158..b7551878b74994 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -457,10 +457,10 @@ def classify_class_attrs(cls): continue obj = get_obj if get_obj is not None else dict_obj # Classify the object or its descriptor. - if isinstance(dict_obj, staticmethod): + if isinstance(dict_obj, (staticmethod, types.BuiltinMethodType)): kind = "static method" obj = dict_obj - elif isinstance(dict_obj, classmethod): + elif isinstance(dict_obj, (classmethod, types.ClassMethodDescriptorType)): kind = "class method" obj = dict_obj elif isinstance(dict_obj, property): diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 13a86b12dd3d51..7d118970c4371d 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -858,7 +858,8 @@ def m1(self): pass attrs = attrs_wo_objs(A) - self.assertIn(('__new__', 'method', object), attrs, 'missing __new__') + self.assertIn(('__new__', 'static method', object), attrs, + 'missing __new__') self.assertIn(('__init__', 'method', object), attrs, 'missing __init__') self.assertIn(('s', 'static method', A), attrs, 'missing static method') @@ -923,6 +924,18 @@ def test_classify_builtin_types(self): if isinstance(builtin, type): inspect.classify_class_attrs(builtin) + attrs = attrs_wo_objs(bool) + self.assertIn(('__new__', 'static method', bool), attrs, + 'missing __new__') + self.assertIn(('from_bytes', 'class method', int), attrs, + 'missing class method') + self.assertIn(('to_bytes', 'method', int), attrs, + 'missing plain method') + self.assertIn(('__add__', 'method', int), attrs, + 'missing plain method') + self.assertIn(('__and__', 'method', bool), attrs, + 'missing plain method') + def test_classify_DynamicClassAttribute(self): class Meta(type): def __getattr__(self, name): diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 28133a3560f3c5..658e549d89a282 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -594,6 +594,10 @@ def test_method_descriptor_types(self): self.assertIsInstance(''.join, types.BuiltinMethodType) self.assertIsInstance([].append, types.BuiltinMethodType) + self.assertIsInstance(int.__dict__['from_bytes'], types.ClassMethodDescriptorType) + self.assertIsInstance(int.from_bytes, types.BuiltinMethodType) + self.assertIsInstance(int.__new__, types.BuiltinMethodType) + class MappingProxyTests(unittest.TestCase): mappingproxy = types.MappingProxyType diff --git a/Lib/types.py b/Lib/types.py index 336918fea09d4a..b299fc7b1b19db 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -39,6 +39,7 @@ def _m(self): pass WrapperDescriptorType = type(object.__init__) MethodWrapperType = type(object().__str__) MethodDescriptorType = type(str.join) +ClassMethodDescriptorType = type(dict.__dict__['fromkeys']) ModuleType = type(sys) diff --git a/Misc/NEWS.d/next/Library/2017-12-10-00-57-51.bpo-32265.kELtTE.rst b/Misc/NEWS.d/next/Library/2017-12-10-00-57-51.bpo-32265.kELtTE.rst new file mode 100644 index 00000000000000..16686c1b418657 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-12-10-00-57-51.bpo-32265.kELtTE.rst @@ -0,0 +1,3 @@ +All class and static methods of builtin types now are correctly classified +by inspect.classify_class_attrs() and grouped in pydoc ouput. Added +types.ClassMethodDescriptorType for unbound class methods of builtin types.