123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- 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
- or _check_class(type(klass_result), "__delete__") 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
|