1""" 
    2A static version of getattr. 
    3This is a backport of the Python 3 code with a little bit of additional 
    4information returned to enable Jedi to make decisions. 
    5""" 
    6 
    7import types 
    8 
    9from jedi import debug 
    10 
    11_sentinel = object() 
    12 
    13 
    14def _check_instance(obj, attr): 
    15    instance_dict = {} 
    16    try: 
    17        instance_dict = object.__getattribute__(obj, "__dict__") 
    18    except AttributeError: 
    19        pass 
    20    return dict.get(instance_dict, attr, _sentinel) 
    21 
    22 
    23def _check_class(klass, attr): 
    24    for entry in _static_getmro(klass): 
    25        if _shadowed_dict(type(entry)) is _sentinel: 
    26            try: 
    27                return entry.__dict__[attr] 
    28            except KeyError: 
    29                pass 
    30    return _sentinel 
    31 
    32 
    33def _is_type(obj): 
    34    try: 
    35        _static_getmro(obj) 
    36    except TypeError: 
    37        return False 
    38    return True 
    39 
    40 
    41def _shadowed_dict(klass): 
    42    dict_attr = type.__dict__["__dict__"] 
    43    for entry in _static_getmro(klass): 
    44        try: 
    45            class_dict = dict_attr.__get__(entry)["__dict__"] 
    46        except KeyError: 
    47            pass 
    48        else: 
    49            if not (type(class_dict) is types.GetSetDescriptorType 
    50                    and class_dict.__name__ == "__dict__" 
    51                    and class_dict.__objclass__ is entry): 
    52                return class_dict 
    53    return _sentinel 
    54 
    55 
    56def _static_getmro(klass): 
    57    mro = type.__dict__['__mro__'].__get__(klass) 
    58    if not isinstance(mro, (tuple, list)): 
    59        # There are unfortunately no tests for this, I was not able to 
    60        # reproduce this in pure Python. However should still solve the issue 
    61        # raised in GH #1517. 
    62        debug.warning('mro of %s returned %s, should be a tuple' % (klass, mro)) 
    63        return () 
    64    return mro 
    65 
    66 
    67def _safe_hasattr(obj, name): 
    68    return _check_class(type(obj), name) is not _sentinel 
    69 
    70 
    71def _safe_is_data_descriptor(obj): 
    72    return _safe_hasattr(obj, '__set__') or _safe_hasattr(obj, '__delete__') 
    73 
    74 
    75def getattr_static(obj, attr, default=_sentinel): 
    76    """Retrieve attributes without triggering dynamic lookup via the 
    77       descriptor protocol,  __getattr__ or __getattribute__. 
    78 
    79       Note: this function may not be able to retrieve all attributes 
    80       that getattr can fetch (like dynamically created attributes) 
    81       and may find attributes that getattr can't (like descriptors 
    82       that raise AttributeError). It can also return descriptor objects 
    83       instead of instance members in some cases. See the 
    84       documentation for details. 
    85 
    86       Returns a tuple `(attr, is_get_descriptor)`. is_get_descripter means that 
    87       the attribute is a descriptor that has a `__get__` attribute. 
    88    """ 
    89    instance_result = _sentinel 
    90    if not _is_type(obj): 
    91        klass = type(obj) 
    92        dict_attr = _shadowed_dict(klass) 
    93        if (dict_attr is _sentinel or type(dict_attr) is types.MemberDescriptorType): 
    94            instance_result = _check_instance(obj, attr) 
    95    else: 
    96        klass = obj 
    97 
    98    klass_result = _check_class(klass, attr) 
    99 
    100    if instance_result is not _sentinel and klass_result is not _sentinel: 
    101        if _safe_hasattr(klass_result, '__get__') \ 
    102                and _safe_is_data_descriptor(klass_result): 
    103            # A get/set descriptor has priority over everything. 
    104            return klass_result, True 
    105 
    106    if instance_result is not _sentinel: 
    107        return instance_result, False 
    108    if klass_result is not _sentinel: 
    109        return klass_result, _safe_hasattr(klass_result, '__get__') 
    110 
    111    if obj is klass: 
    112        # for types we check the metaclass too 
    113        for entry in _static_getmro(type(klass)): 
    114            if _shadowed_dict(type(entry)) is _sentinel: 
    115                try: 
    116                    return entry.__dict__[attr], False 
    117                except KeyError: 
    118                    pass 
    119    if default is not _sentinel: 
    120        return default, False 
    121    raise AttributeError(attr)