From 4b73663ea85787d5f083998232fcffd6f2d17ff7 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Fri, 11 Aug 2017 16:49:18 +0200 Subject: [PATCH] Fix data descriptor detection in inspect.getattr_static. Data descriptors are defined by having a __get__ attribute and at least one of the __set__ and __delete__ attributes. Implementation detail: Both __delete__ and __get__ set the same slot called tp_descr_set in CPython. --- Lib/inspect.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py index 9a843d6..e16c8c3 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1544,6 +1544,9 @@ def _shadowed_dict(klass): return class_dict return _sentinel +def _safe_hasattr(obj, name): + return _check_class(type(obj), name) is not _sentinel + def getattr_static(obj, attr, default=_sentinel): """Retrieve attributes without triggering dynamic lookup via the descriptor protocol, __getattr__ or __getattribute__. @@ -1568,8 +1571,10 @@ def getattr_static(obj, attr, default=_sentinel): klass_result = _check_class(klass, attr) if instance_result is not _sentinel and klass_result is not _sentinel: - if (_check_class(type(klass_result), '__get__') is not _sentinel and - _check_class(type(klass_result), '__set__') is not _sentinel): + if _safe_hasattr(klass_result, '__get__') \ + and (_safe_hasattr(klass_result, '__set__') + or _safe_hasattr(klass_result, '__delete__')): + # Is a data descriptor. return klass_result if instance_result is not _sentinel: -- 2.7.4