Skip to main content
moving revision to gist
Source Link
Grozz
  • 135
  • 7
Rollback to Revision 1
Source Link
200_success
  • 145.6k
  • 22
  • 191
  • 481
# coding=utf-8
from __future__ import unicode_literals
import collections

_default_stub = object()


def deep_get(obj, path, default=_default_stub, separator='.'):
    """Get"""Gets arbitrarily nested attribute or item value.

    Args:
        obj: Object to search in.
        path (str, hashable, iterable of hashables): Arbitrarily nested path in obj hierarchy.
        default: Default value. When provided it is returned if the path doesn't exist.
            Otherwise the call raises a LookupError.
        separator: String to split path by.

    Returns:
        Value at path.

    Raises:
        LookupError: If object at path doesn't exist.

    Examples:
        >>> deep_get({'a': 1}, 'a')
        1

        >>> deep_get({'a': 1}, 'b')
        Traceback (most recent call last):
            ...
        LookupError: {u'a''a': 1} has no element at 'b'

        >>> deep_get(['a', 'b', 'c'], -1)
        u'c''c'

        >>> deep_get({'a': [{'b': [1, 2, 3]}, 'some string']}, 'a.0.b')
        [1, 2, 3]

        >>> class A(object):
        ...>>>     def __init__(self):
        ...>>>         self.x = self
        ...>>>         self.y = {'a': 10}
        ...>>>
        >>> deep_get(A(), 'x.x.x.x.x.x.y.a')
        10

        >>> deep_get({'a.b': {'c': 1}}, 'a.b.c')
        Traceback (most recent call last):
            ...
        LookupError: {u'a'a.b': {u'c''c': 1}} has no element at 'a'

        >>> deep_get({'a.b': {'Привет': 1}}, ['a.b', 'Привет'])
        1

        >>> deep_get({'a.b': {'Привет': 1}}, 'a.b/Привет', separator='/')
        1 

    """
    if isinstance(path, basestring):
        attributes = path.split(separator)
    elif isinstance(path, collections.Iterable):
        attributes = path
    else:
        attributes = [path]

    getattr_errorsfor =i (AttributeError,in TypeError,attributes:
 UnicodeEncodeError)       try:
    getitem_errors        success = (TypeError,False
 IndexError, KeyError)          # 1. access as attr
    conversion_errors        try:
                obj = getattr(UnicodeEncodeErrorobj, ValueErrori)
 
    lookups            success = [True
            except (getattrAttributeError, getattr_errors)TypeError, UnicodeEncodeError):
        (lambda o, i: o[i], getitem_errors),
    # 2. access as (lambdadict o,index
 i: o[int(i)], getitem_errors + conversion_errors),
    ]

       try:
        for attr in attributes:         obj = obj[i]
            for lookup       success = True
                except (TypeError, errorsAttributeError, inIndexError, lookupsKeyError):
                    # 3. access as list index
                    try:
                        obj = lookupobj[int(obj, attri)]
                    break    success = True
                    except errors(TypeError, AttributeError, IndexError, KeyError,
                            UnicodeEncodeError, ValueError):
                        pass 

            elseif not success:
                msg = "{obj} has no element at '{i}'".format(obj=obj, i=attri=i)
                raise LookupError(msg.encode('utf8')) 

        except Exception:
            if _default_stub != default:
                return default
            raise

    return obj
# coding=utf-8
from __future__ import unicode_literals
import collections

_default_stub = object()


def deep_get(obj, path, default=_default_stub, separator='.'):
    """Get arbitrarily nested attribute or item value.

    Args:
        obj: Object to search in.
        path (str, hashable, iterable of hashables): Arbitrarily nested path in obj hierarchy.
        default: Default value. When provided it is returned if the path doesn't exist.
            Otherwise the call raises a LookupError.
        separator: String to split path by.

    Returns:
        Value at path.

    Raises:
        LookupError: If object at path doesn't exist.

    Examples:
        >>> deep_get({'a': 1}, 'a')
        1

        >>> deep_get({'a': 1}, 'b')
        Traceback (most recent call last):
            ...
        LookupError: {u'a': 1} has no element at 'b'

        >>> deep_get(['a', 'b', 'c'], -1)
        u'c'

        >>> deep_get({'a': [{'b': [1, 2, 3]}, 'some string']}, 'a.0.b')
        [1, 2, 3]

        >>> class A(object):
        ...     def __init__(self):
        ...         self.x = self
        ...         self.y = {'a': 10}
        ...
        >>> deep_get(A(), 'x.x.x.x.x.x.y.a')
        10

        >>> deep_get({'a.b': {'c': 1}}, 'a.b.c')
        Traceback (most recent call last):
            ...
        LookupError: {u'a.b': {u'c': 1}} has no element at 'a'

        >>> deep_get({'a.b': {'Привет': 1}}, ['a.b', 'Привет'])
        1

        >>> deep_get({'a.b': {'Привет': 1}}, 'a.b/Привет', separator='/')
        1
    """
    if isinstance(path, basestring):
        attributes = path.split(separator)
    elif isinstance(path, collections.Iterable):
        attributes = path
    else:
        attributes = [path]

    getattr_errors = (AttributeError, TypeError, UnicodeEncodeError)
    getitem_errors = (TypeError, IndexError, KeyError)
    conversion_errors = (UnicodeEncodeError, ValueError)
 
    lookups = [
        (getattr, getattr_errors),
        (lambda o, i: o[i], getitem_errors),
        (lambda o, i: o[int(i)], getitem_errors + conversion_errors),
    ]

    try:
        for attr in attributes:
            for lookup, errors in lookups:
                try:
                    obj = lookup(obj, attr)
                    break
                except errors:
                    pass
            else:
                msg = "{obj} has no element at '{i}'".format(obj=obj, i=attr)
                raise LookupError(msg.encode('utf8'))
    except Exception:
        if _default_stub != default:
            return default
        raise

    return obj
# coding=utf-8
from __future__ import unicode_literals
import collections

_default_stub = object()


def deep_get(obj, path, default=_default_stub, separator='.'):
    """Gets arbitrarily nested attribute or item value.

    Args:
        obj: Object to search in.
        path (str, hashable, iterable of hashables): Arbitrarily nested path in obj hierarchy.
        default: Default value. When provided it is returned if the path doesn't exist.
            Otherwise the call raises a LookupError.
        separator: String to split path by.

    Returns:
        Value at path.

    Raises:
        LookupError: If object at path doesn't exist.

    Examples:
        >>> deep_get({'a': 1}, 'a')
        1

        >>> deep_get({'a': 1}, 'b')
        LookupError: {'a': 1} has no element at 'b'

        >>> deep_get(['a', 'b', 'c'], -1)
        'c'

        >>> deep_get({'a': [{'b': [1, 2, 3]}, 'some string']}, 'a.0.b')
        [1, 2, 3]

        >>> class A(object):
        >>>     def __init__(self):
        >>>         self.x = self
        >>>         self.y = {'a': 10}
        >>>
        >>> deep_get(A(), 'x.x.x.x.x.x.y.a')
        10

        >>> deep_get({'a.b': {'c': 1}}, 'a.b.c')
        LookupError: {'a.b': {'c': 1}} has no element at 'a'

        >>> deep_get({'a.b': {'Привет': 1}}, ['a.b', 'Привет'])
        1

        >>> deep_get({'a.b': {'Привет': 1}}, 'a.b/Привет', separator='/')
        1 

    """
    if isinstance(path, basestring):
        attributes = path.split(separator)
    elif isinstance(path, collections.Iterable):
        attributes = path
    else:
        attributes = [path]

    for i in attributes:
        try:
            success = False
            # 1. access as attr
            try:
                obj = getattr(obj, i)
                success = True
            except (AttributeError, TypeError, UnicodeEncodeError):
                # 2. access as dict index
                try:
                    obj = obj[i]
                    success = True
                except (TypeError, AttributeError, IndexError, KeyError):
                    # 3. access as list index
                    try:
                        obj = obj[int(i)]
                        success = True
                    except (TypeError, AttributeError, IndexError, KeyError,
                            UnicodeEncodeError, ValueError):
                        pass 

            if not success:
                msg = "{obj} has no element at '{i}'".format(obj=obj, i=i)
                raise LookupError(msg.encode('utf8')) 

        except Exception:
            if _default_stub != default:
                return default
            raise

    return obj
updated the code according to CR comments
Source Link
Grozz
  • 135
  • 7
# coding=utf-8
from __future__ import unicode_literals
import collections

_default_stub = object()


def deep_get(obj, path, default=_default_stub, separator='.'):
    """Gets"""Get arbitrarily nested attribute or item value.

    Args:
        obj: Object to search in.
        path (str, hashable, iterable of hashables): Arbitrarily nested path in obj hierarchy.
        default: Default value. When provided it is returned if the path doesn't exist.
            Otherwise the call raises a LookupError.
        separator: String to split path by.

    Returns:
        Value at path.

    Raises:
        LookupError: If object at path doesn't exist.

    Examples:
        >>> deep_get({'a': 1}, 'a')
        1

        >>> deep_get({'a': 1}, 'b')
        Traceback (most recent call last):
            ...
        LookupError: {'a'u'a': 1} has no element at 'b'

        >>> deep_get(['a', 'b', 'c'], -1)
        'c'u'c'

        >>> deep_get({'a': [{'b': [1, 2, 3]}, 'some string']}, 'a.0.b')
        [1, 2, 3]

        >>> class A(object):
        >>>...     def __init__(self):
        >>>...         self.x = self
        >>>...         self.y = {'a': 10}
        >>>...
        >>> deep_get(A(), 'x.x.x.x.x.x.y.a')
        10

        >>> deep_get({'a.b': {'c': 1}}, 'a.b.c')
        Traceback (most recent call last):
            ...
        LookupError: {'au'a.b': {'c'u'c': 1}} has no element at 'a'

        >>> deep_get({'a.b': {'Привет': 1}}, ['a.b', 'Привет'])
        1

        >>> deep_get({'a.b': {'Привет': 1}}, 'a.b/Привет', separator='/')
        1
 
    """
    if isinstance(path, basestring):
        attributes = path.split(separator)
    elif isinstance(path, collections.Iterable):
        attributes = path
    else:
        attributes = [path]
 
    for i in attributes:
        try:
            successgetattr_errors = False
            # 1. access(AttributeError, asTypeError, attrUnicodeEncodeError)
        getitem_errors = (TypeError, IndexError, try:KeyError)
                objconversion_errors = getattr(objUnicodeEncodeError, iValueError)
             
    successlookups = True[
            except (AttributeError, TypeErrorgetattr, UnicodeEncodeErrorgetattr_errors):,
                # 2.(lambda accesso, asi: dicto[i], indexgetitem_errors),
              (lambda o, tryi:
                   o[int(i)], objgetitem_errors =+ obj[i]conversion_errors),
                    success = True]
      
    try:
       except (TypeError,for AttributeError,attr IndexError,in KeyError)attributes:
                    # 3.for accesslookup, aserrors listin indexlookups:
                    try:
                        obj = obj[intlookup(iobj, attr)]
                        success = Truebreak
                    except (TypeError, AttributeError, IndexError, KeyError,
                            UnicodeEncodeError, ValueError)errors:
                        pass
 
            if not successelse:
                msg = "{obj} has no element at '{i}'".format(obj=obj, i=ii=attr)
                raise LookupError(msg.encode('utf8'))
 
        except Exception:
            if _default_stub != default:
                return default
            raise

    return obj
# coding=utf-8
from __future__ import unicode_literals
import collections

_default_stub = object()


def deep_get(obj, path, default=_default_stub, separator='.'):
    """Gets arbitrarily nested attribute or item value.

    Args:
        obj: Object to search in.
        path (str, hashable, iterable of hashables): Arbitrarily nested path in obj hierarchy.
        default: Default value. When provided it is returned if the path doesn't exist.
            Otherwise the call raises a LookupError.
        separator: String to split path by.

    Returns:
        Value at path.

    Raises:
        LookupError: If object at path doesn't exist.

    Examples:
        >>> deep_get({'a': 1}, 'a')
        1

        >>> deep_get({'a': 1}, 'b')
        LookupError: {'a': 1} has no element at 'b'

        >>> deep_get(['a', 'b', 'c'], -1)
        'c'

        >>> deep_get({'a': [{'b': [1, 2, 3]}, 'some string']}, 'a.0.b')
        [1, 2, 3]

        >>> class A(object):
        >>>     def __init__(self):
        >>>         self.x = self
        >>>         self.y = {'a': 10}
        >>>
        >>> deep_get(A(), 'x.x.x.x.x.x.y.a')
        10

        >>> deep_get({'a.b': {'c': 1}}, 'a.b.c')
        LookupError: {'a.b': {'c': 1}} has no element at 'a'

        >>> deep_get({'a.b': {'Привет': 1}}, ['a.b', 'Привет'])
        1

        >>> deep_get({'a.b': {'Привет': 1}}, 'a.b/Привет', separator='/')
        1
 
    """
    if isinstance(path, basestring):
        attributes = path.split(separator)
    elif isinstance(path, collections.Iterable):
        attributes = path
    else:
        attributes = [path]
 
    for i in attributes:
        try:
            success = False
            # 1. access as attr
            try:
                obj = getattr(obj, i)
                success = True
            except (AttributeError, TypeError, UnicodeEncodeError):
                # 2. access as dict index
                try:
                    obj = obj[i]
                    success = True
                except (TypeError, AttributeError, IndexError, KeyError):
                    # 3. access as list index
                    try:
                        obj = obj[int(i)]
                        success = True
                    except (TypeError, AttributeError, IndexError, KeyError,
                            UnicodeEncodeError, ValueError):
                        pass
 
            if not success:
                msg = "{obj} has no element at '{i}'".format(obj=obj, i=i)
                raise LookupError(msg.encode('utf8'))
 
        except Exception:
            if _default_stub != default:
                return default
            raise

    return obj
# coding=utf-8
from __future__ import unicode_literals
import collections

_default_stub = object()


def deep_get(obj, path, default=_default_stub, separator='.'):
    """Get arbitrarily nested attribute or item value.

    Args:
        obj: Object to search in.
        path (str, hashable, iterable of hashables): Arbitrarily nested path in obj hierarchy.
        default: Default value. When provided it is returned if the path doesn't exist.
            Otherwise the call raises a LookupError.
        separator: String to split path by.

    Returns:
        Value at path.

    Raises:
        LookupError: If object at path doesn't exist.

    Examples:
        >>> deep_get({'a': 1}, 'a')
        1

        >>> deep_get({'a': 1}, 'b')
        Traceback (most recent call last):
            ...
        LookupError: {u'a': 1} has no element at 'b'

        >>> deep_get(['a', 'b', 'c'], -1)
        u'c'

        >>> deep_get({'a': [{'b': [1, 2, 3]}, 'some string']}, 'a.0.b')
        [1, 2, 3]

        >>> class A(object):
        ...     def __init__(self):
        ...         self.x = self
        ...         self.y = {'a': 10}
        ...
        >>> deep_get(A(), 'x.x.x.x.x.x.y.a')
        10

        >>> deep_get({'a.b': {'c': 1}}, 'a.b.c')
        Traceback (most recent call last):
            ...
        LookupError: {u'a.b': {u'c': 1}} has no element at 'a'

        >>> deep_get({'a.b': {'Привет': 1}}, ['a.b', 'Привет'])
        1

        >>> deep_get({'a.b': {'Привет': 1}}, 'a.b/Привет', separator='/')
        1
    """
    if isinstance(path, basestring):
        attributes = path.split(separator)
    elif isinstance(path, collections.Iterable):
        attributes = path
    else:
        attributes = [path]

    getattr_errors = (AttributeError, TypeError, UnicodeEncodeError)
    getitem_errors = (TypeError, IndexError, KeyError)
    conversion_errors = (UnicodeEncodeError, ValueError)
 
    lookups = [
        (getattr, getattr_errors),
        (lambda o, i: o[i], getitem_errors),
        (lambda o, i: o[int(i)], getitem_errors + conversion_errors),
    ]
 
    try:
        for attr in attributes:
            for lookup, errors in lookups:
                try:
                    obj = lookup(obj, attr)
                    break
                except errors:
                    pass
            else:
                msg = "{obj} has no element at '{i}'".format(obj=obj, i=attr)
                raise LookupError(msg.encode('utf8'))
    except Exception:
        if _default_stub != default:
            return default
        raise

    return obj
Source Link
Grozz
  • 135
  • 7
Loading