aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/pure-eval/pure_eval/my_getattr_static.py
diff options
context:
space:
mode:
authorrobot-contrib <robot-contrib@yandex-team.ru>2022-05-18 00:43:36 +0300
committerrobot-contrib <robot-contrib@yandex-team.ru>2022-05-18 00:43:36 +0300
commit9e5f436a8b2a27bcc7802e443ea3ef3e41a82a75 (patch)
tree78b522cab9f76336e62064d4d8ff7c897659b20e /contrib/python/pure-eval/pure_eval/my_getattr_static.py
parent8113a823ffca6451bb5ff8f0334560885a939a24 (diff)
downloadydb-9e5f436a8b2a27bcc7802e443ea3ef3e41a82a75.tar.gz
Update contrib/python/ipython/py3 to 8.3.0
ref:e84342d4d30476f9148137f37fd0c6405fd36f55
Diffstat (limited to 'contrib/python/pure-eval/pure_eval/my_getattr_static.py')
-rw-r--r--contrib/python/pure-eval/pure_eval/my_getattr_static.py138
1 files changed, 138 insertions, 0 deletions
diff --git a/contrib/python/pure-eval/pure_eval/my_getattr_static.py b/contrib/python/pure-eval/pure_eval/my_getattr_static.py
new file mode 100644
index 0000000000..c750b1acc3
--- /dev/null
+++ b/contrib/python/pure-eval/pure_eval/my_getattr_static.py
@@ -0,0 +1,138 @@
+import types
+
+from pure_eval.utils import of_type, CannotEval
+
+_sentinel = object()
+
+
+def _static_getmro(klass):
+ return type.__dict__['__mro__'].__get__(klass)
+
+
+def _check_instance(obj, attr):
+ instance_dict = {}
+ try:
+ instance_dict = object.__getattribute__(obj, "__dict__")
+ except AttributeError:
+ pass
+ return dict.get(instance_dict, attr, _sentinel)
+
+
+def _check_class(klass, attr):
+ for entry in _static_getmro(klass):
+ if _shadowed_dict(type(entry)) is _sentinel:
+ try:
+ return entry.__dict__[attr]
+ except KeyError:
+ pass
+ else:
+ break
+ return _sentinel
+
+
+def _is_type(obj):
+ try:
+ _static_getmro(obj)
+ except TypeError:
+ return False
+ return True
+
+
+def _shadowed_dict(klass):
+ dict_attr = type.__dict__["__dict__"]
+ for entry in _static_getmro(klass):
+ try:
+ class_dict = dict_attr.__get__(entry)["__dict__"]
+ except KeyError:
+ pass
+ else:
+ if not (type(class_dict) is types.GetSetDescriptorType and
+ class_dict.__name__ == "__dict__" and
+ class_dict.__objclass__ is entry):
+ return class_dict
+ return _sentinel
+
+
+def getattr_static(obj, attr):
+ """Retrieve attributes without triggering dynamic lookup via the
+ descriptor protocol, __getattr__ or __getattribute__.
+
+ Note: this function may not be able to retrieve all attributes
+ that getattr can fetch (like dynamically created attributes)
+ and may find attributes that getattr can't (like descriptors
+ that raise AttributeError). It can also return descriptor objects
+ instead of instance members in some cases. See the
+ documentation for details.
+ """
+ instance_result = _sentinel
+ if not _is_type(obj):
+ klass = type(obj)
+ dict_attr = _shadowed_dict(klass)
+ if (dict_attr is _sentinel or
+ type(dict_attr) is types.MemberDescriptorType):
+ instance_result = _check_instance(obj, attr)
+ else:
+ raise CannotEval
+ else:
+ klass = obj
+
+ 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):
+ return _resolve_descriptor(klass_result, obj, klass)
+
+ if instance_result is not _sentinel:
+ return instance_result
+ if klass_result is not _sentinel:
+ get = _check_class(type(klass_result), '__get__')
+ if get is _sentinel:
+ return klass_result
+ else:
+ if obj is klass:
+ instance = None
+ else:
+ instance = obj
+ return _resolve_descriptor(klass_result, instance, klass)
+
+ if obj is klass:
+ # for types we check the metaclass too
+ for entry in _static_getmro(type(klass)):
+ if _shadowed_dict(type(entry)) is _sentinel:
+ try:
+ result = entry.__dict__[attr]
+ get = _check_class(type(result), '__get__')
+ if get is not _sentinel:
+ raise CannotEval
+ return result
+ except KeyError:
+ pass
+ raise CannotEval
+
+
+class _foo:
+ __slots__ = ['foo']
+ method = lambda: 0
+
+
+slot_descriptor = _foo.foo
+wrapper_descriptor = str.__dict__['__add__']
+method_descriptor = str.__dict__['startswith']
+user_method_descriptor = _foo.__dict__['method']
+
+safe_descriptors_raw = [
+ slot_descriptor,
+ wrapper_descriptor,
+ method_descriptor,
+ user_method_descriptor,
+]
+
+safe_descriptor_types = list(map(type, safe_descriptors_raw))
+
+
+def _resolve_descriptor(d, instance, owner):
+ try:
+ return type(of_type(d, *safe_descriptor_types)).__get__(d, instance, owner)
+ except AttributeError as e:
+ raise CannotEval from e