# Path: trtools/tools/attrdict.py
# class attrdict(OrderedDict):
#     """A dict whose items can also be accessed as member variables.
# 
#     >>> d = attrdict(a=1, b=2)
#     >>> d['c'] = 3
#     >>> print d.a, d.b, d.c
#     1 2 3
#     >>> d.b = 10
#     >>> print d['b']
#     10
# 
#     # but be careful, it's easy to hide methods
#     >>> print d.get('c')
#     3
#     >>> d['get'] = 4
#     >>> print d.get('a')
#     Traceback (most recent call last):
#     TypeError: 'int' object is not callable
#     """
#     def __init__(self, *args, **kwargs):
#         OrderedDict.__init__(self, *args, **kwargs)
# 
#     def __getattr__(self, name):
#         try:
#              return self[name]
#         except:
#             pass
#         return OrderedDict.__getattribute__(self, name)
# 
#     def __getitem__(self, name):
#         """
#             A regular key in dict will match on hash. 
# 
#             This version matches on __eq__ if the hash doesn't match.
# 
#             # NOTE: This can possibly lead to both perf hits and situations
#             # where two keys match the same other. 
#         """
#         # regular ole dict check
#         if name in self:
#             return dict.__getitem__(self, name)
# 
#         # list.__contains__ uses eq() to check membership
#         keys = list(self.keys())
#         if name in keys:
#             ind = keys.index(name)
#             return self[keys[ind]]
#         raise KeyError()
# 
#     def __repr__(self):
#         out = 'Keys:\n'
#         out += '\n'.join([str(k) for k in list(self.keys())])
#         return out
# 
#     def foreach(self, key=None, func=missing):
#         """
#         A convenient way to get a subset of results. 
# 
#         I often use attrdict to store DataFrames with a common
#         column indexes. This allows me to quickly get a subset
#         """
#         if func is None and key is None:
#             raise ValueError('invalid number of arguments')
# 
#         if func is missing:
#             func = lambda dct, key: dct[key]
# 
#         res = attrdict()
#         for k, v in self.items():
#             try:
#                 res[k] = func(v, key)
#             except:
#                 pass
#         return res


import inspect
from trtools.tools.attrdict import attrdict

def locals_ns(skip=[]):
    """
    Useful for returning all the locals() in a function as an attrdict

    Parameters
    ----------
    skip : iterable
        list of keys to skip including in return dict

    Usage:
        def test():
            test = '123'
            test_int = 222
            return locals_ns()
        ret = test()
        assert ret.test == '123'
    """
    caller_globals = inspect.stack()[1][0].f_locals
    # remove skip items
    for k in skip:
        caller_globals.pop(k, None)

# Path: trtools/tools/attrdict.py
# class attrdict(OrderedDict):
#     """A dict whose items can also be accessed as member variables.
# 
#     >>> d = attrdict(a=1, b=2)
#     >>> d['c'] = 3
#     >>> print d.a, d.b, d.c
#     1 2 3
#     >>> d.b = 10
#     >>> print d['b']
#     10
# 
#     # but be careful, it's easy to hide methods
#     >>> print d.get('c')
#     3
#     >>> d['get'] = 4
#     >>> print d.get('a')
#     Traceback (most recent call last):
#     TypeError: 'int' object is not callable
#     """
#     def __init__(self, *args, **kwargs):
#         OrderedDict.__init__(self, *args, **kwargs)
# 
#     def __getattr__(self, name):
#         try:
#              return self[name]
#         except:
#             pass
#         return OrderedDict.__getattribute__(self, name)
# 
#     def __getitem__(self, name):
#         """
#             A regular key in dict will match on hash. 
# 
#             This version matches on __eq__ if the hash doesn't match.
# 
#             # NOTE: This can possibly lead to both perf hits and situations
#             # where two keys match the same other. 
#         """
#         # regular ole dict check
#         if name in self:
#             return dict.__getitem__(self, name)
# 
#         # list.__contains__ uses eq() to check membership
#         keys = list(self.keys())
#         if name in keys:
#             ind = keys.index(name)
#             return self[keys[ind]]
#         raise KeyError()
# 
#     def __repr__(self):
#         out = 'Keys:\n'
#         out += '\n'.join([str(k) for k in list(self.keys())])
#         return out
# 
#     def foreach(self, key=None, func=missing):
#         """
#         A convenient way to get a subset of results. 
# 
#         I often use attrdict to store DataFrames with a common
#         column indexes. This allows me to quickly get a subset
#         """
#         if func is None and key is None:
#             raise ValueError('invalid number of arguments')
# 
#         if func is missing:
#             func = lambda dct, key: dct[key]
# 
#         res = attrdict()
#         for k, v in self.items():
#             try:
#                 res[k] = func(v, key)
#             except:
#                 pass
#         return res


# Path: trtools/tools/func_ns.py
import inspect
from trtools.tools.attrdict import attrdict


def locals_ns(skip=[]):
    """
    Useful for returning all the locals() in a function as an attrdict

    Parameters
    ----------
    skip : iterable
        list of keys to skip including in return dict

    Usage:
        def test():
            test = '123'
            test_int = 222
            return locals_ns()
        ret = test()
        assert ret.test == '123'
    """
    caller_globals = inspect.stack()[1][0].f_locals
    # remove skip items
    for k in skip:
        caller_globals.pop(k, None)

    return attrdict(caller_globals)