"""
Module containing Dict and ODict classes

These classes reproduce normal Dict and ODict behavior, but add support for object-like dot notation (e.g. cell.secs.soma.geom)

"""

from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import

from builtins import range
from builtins import dict
from builtins import super
from future import standard_library

standard_library.install_aliases()
from collections import OrderedDict

# ----------------------------------------------------------------------------
# Dict class (allows dot notation for dicts)
# ----------------------------------------------------------------------------


class Dict(dict):
    """
    Class for/to <short description of `netpyne.specs.dicts.Dict`>


    """

    __slots__ = []

    def __init__(*args, **kwargs):
        self = args[0]
        args = args[1:]
        if len(args) > 1:
            raise TypeError('expected at most 1 arguments, got %d' % len(args))
        if args:
            self.update(self.dotify(args[0]))
        if len(kwargs):
            self.update(self.dotify(kwargs))

    # only called if k not found in normal places
    def __getattr__(self, k):
        try:
            # Throws exception if not in prototype chain
            return object.__getattribute__(self, k)
        except AttributeError:
            try:
                return self[k]
            except KeyError:
                raise AttributeError(k)

    def __setattr__(self, k, v):
        try:
            # Throws exception if not in prototype chain
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                self[k] = v
            except:
                raise AttributeError(k)
        else:
            object.__setattr__(self, k, v)

    def __delattr__(self, k):
        try:
            # Throws exception if not in prototype chain
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                del self[k]
            except KeyError:
                raise AttributeError(k)
        else:
            object.__delattr__(self, k)

    def todict(self):
        return self.undotify(self)

    def fromdict(self, d):
        d = self.dotify(d)
        for k, v in d.items():
            self[k] = v

    def __repr__(self):
        keys = list(self.keys())
        args = ', '.join(['%s: %r' % (key, self[key]) for key in keys])
        return '{%s}' % (args)

    def dotify(self, x):
        if isinstance(x, dict):
            return Dict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.dotify(v) for v in x)
        else:
            return x

    def undotify(self, x):
        if isinstance(x, dict):
            return dict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.undotify(v) for v in x)
        else:
            return x

    def __rename__(self, old, new, label=None):
        """
        old (string): old dict key
        new (string): new dict key
        label (list/tuple of strings): nested keys pointing to dict with key to be replaced;
            e.g. ('PYR', 'secs'); use None to replace root key; defaults to None

        returns: True if successful, False otherwse
        """

        obj = self
        if isinstance(label, (tuple, list)):
            for ip in range(len(label)):
                try:
                    obj = obj[label[ip]]
                except:
                    return False

        if old in obj:
            obj[new] = obj.pop(old)  # replace
            return True
        else:
            return False

    def rename(self, *args, **kwargs):
        self.__rename__(*args, **kwargs)

    def __missing__(self, key):
        if key and not key.startswith('_ipython'):
            value = self[key] = Dict()
            return value

    def __getstate__(self):
        return self.todict()

    def __setstate__(self, d):
        self = self.fromdict(d)


# ----------------------------------------------------------------------------
# ODict class (allows dot notation for ordered dicts)
# ----------------------------------------------------------------------------


class ODict(OrderedDict):
    """
    Class for/to <short description of `netpyne.specs.dicts.ODict`>


    """

    __slots__ = []

    def __init__(self, *args, **kwargs):
        super(ODict, self).__init__(*args, **kwargs)

    def __contains__(self, k):
        try:
            return hasattr(self, k) or dict.__contains__(self, k)
        except:
            return False

    # only called if k not found in normal places
    def __getattr__(self, k):
        try:
            # Throws exception if not in prototype chain
            return super(ODict, self).__getattr__(k)
        except AttributeError:
            try:
                return super(ODict, self).__getitem__(k)
            except KeyError:
                raise AttributeError(k)

    def __setattr__(self, k, v):
        if k.startswith('_OrderedDict'):
            super(ODict, self).__setattr__(k, v)
        else:
            try:
                super(ODict, self).__setitem__(k, v)
            except:
                raise AttributeError(k)

    def __getitem__(self, k):
        return super(ODict, self).__getitem__(k)

    def __setitem__(self, k, v):
        super(ODict, self).__setitem__(k, v)

    def __delattr__(self, k):
        try:
            # Throws exception if not in prototype chain
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                super(ODict, self).__delattr__(k)
            except KeyError:
                raise AttributeError(k)
        else:
            object.__delattr__(self, k)

    def toOrderedDict(self):
        return self.undotify(self)

    def fromOrderedDict(self, d):
        d = self.dotify(d)
        for k, v in d.items():
            self[k] = v

    def __repr__(self):
        keys = list(self.keys())
        args = ', '.join(['%s: %r' % (key, self[key]) for key in keys])
        return '{%s}' % (args)

    def dotify(self, x):
        if isinstance(x, OrderedDict):
            return ODict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, dict):
            return Dict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.dotify(v) for v in x)
        else:
            return x

    def undotify(self, x):
        if isinstance(x, OrderedDict):
            return OrderedDict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, dict):
            return dict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.undotify(v) for v in x)
        else:
            return x

    def __rename__(self, old, new, label=None):
        """
        old (string): old dict key
        new (string): new dict key
        label (list/tuple of strings): nested keys pointing to dict with key to be replaced;
            e.g. ('PYR', 'secs'); use None to replace root key; defaults to None

        returns: True if successful, False otherwse
        """

        obj = self
        if isinstance(label, (tuple, list)):
            for ip in range(len(label)):
                try:
                    obj = obj[label[ip]]
                except:
                    return False

        if old in obj:
            obj[new] = obj.pop(old)  # replace
            return True
        else:
            return False

    def rename(self, *args, **kwargs):
        self.__rename__(*args, **kwargs)

    def __getstate__(self):
        return self.toOrderedDict()

    def __setstate__(self, d):
        self = self.fromOrderedDict(d)

13056b54c55b68eab1b90974d496861d4da2b5da
<mask token>


class ODict(OrderedDict):
    <mask token>
    __slots__ = []

    def __init__(self, *args, **kwargs):
        super(ODict, self).__init__(*args, **kwargs)

    def __contains__(self, k):
        try:
            return hasattr(self, k) or dict.__contains__(self, k)
        except:
            return False

    def __getattr__(self, k):
        try:
            return super(ODict, self).__getattr__(k)
        except AttributeError:
            try:
                return super(ODict, self).__getitem__(k)
            except KeyError:
                raise AttributeError(k)

    def __setattr__(self, k, v):
        if k.startswith('_OrderedDict'):
            super(ODict, self).__setattr__(k, v)
        else:
            try:
                super(ODict, self).__setitem__(k, v)
            except:
                raise AttributeError(k)

    def __getitem__(self, k):
        return super(ODict, self).__getitem__(k)

    def __setitem__(self, k, v):
        super(ODict, self).__setitem__(k, v)

    def __delattr__(self, k):
        try:
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                super(ODict, self).__delattr__(k)
            except KeyError:
                raise AttributeError(k)
        else:
            object.__delattr__(self, k)

    def toOrderedDict(self):
        return self.undotify(self)

    def fromOrderedDict(self, d):
        d = self.dotify(d)
        for k, v in d.items():
            self[k] = v

    def __repr__(self):
        keys = list(self.keys())
        args = ', '.join([('%s: %r' % (key, self[key])) for key in keys])
        return '{%s}' % args

    def dotify(self, x):
        if isinstance(x, OrderedDict):
            return ODict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, dict):
            return Dict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.dotify(v) for v in x)
        else:
            return x

    def undotify(self, x):
        if isinstance(x, OrderedDict):
            return OrderedDict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, dict):
            return dict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.undotify(v) for v in x)
        else:
            return x

    def __rename__(self, old, new, label=None):
        """
        old (string): old dict key
        new (string): new dict key
        label (list/tuple of strings): nested keys pointing to dict with key to be replaced;
            e.g. ('PYR', 'secs'); use None to replace root key; defaults to None

        returns: True if successful, False otherwse
        """
        obj = self
        if isinstance(label, (tuple, list)):
            for ip in range(len(label)):
                try:
                    obj = obj[label[ip]]
                except:
                    return False
        if old in obj:
            obj[new] = obj.pop(old)
            return True
        else:
            return False

    def rename(self, *args, **kwargs):
        self.__rename__(*args, **kwargs)

    def __getstate__(self):
        return self.toOrderedDict()

    def __setstate__(self, d):
        self = self.fromOrderedDict(d)

<mask token>


class Dict(dict):
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>

    def todict(self):
        return self.undotify(self)
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>


class ODict(OrderedDict):
    """
    Class for/to <short description of `netpyne.specs.dicts.ODict`>


    """
    __slots__ = []

    def __init__(self, *args, **kwargs):
        super(ODict, self).__init__(*args, **kwargs)

    def __contains__(self, k):
        try:
            return hasattr(self, k) or dict.__contains__(self, k)
        except:
            return False

    def __getattr__(self, k):
        try:
            return super(ODict, self).__getattr__(k)
        except AttributeError:
            try:
                return super(ODict, self).__getitem__(k)
            except KeyError:
                raise AttributeError(k)

    def __setattr__(self, k, v):
        if k.startswith('_OrderedDict'):
            super(ODict, self).__setattr__(k, v)
        else:
            try:
                super(ODict, self).__setitem__(k, v)
            except:
                raise AttributeError(k)

    def __getitem__(self, k):
        return super(ODict, self).__getitem__(k)

    def __setitem__(self, k, v):
        super(ODict, self).__setitem__(k, v)

    def __delattr__(self, k):
        try:
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                super(ODict, self).__delattr__(k)
            except KeyError:
                raise AttributeError(k)
        else:
            object.__delattr__(self, k)

    def toOrderedDict(self):
        return self.undotify(self)

    def fromOrderedDict(self, d):
        d = self.dotify(d)
        for k, v in d.items():
            self[k] = v

    def __repr__(self):
        keys = list(self.keys())
        args = ', '.join([('%s: %r' % (key, self[key])) for key in keys])
        return '{%s}' % args

    def dotify(self, x):
        if isinstance(x, OrderedDict):
            return ODict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, dict):
            return Dict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.dotify(v) for v in x)
        else:
            return x

    def undotify(self, x):
        if isinstance(x, OrderedDict):
            return OrderedDict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, dict):
            return dict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.undotify(v) for v in x)
        else:
            return x

    def __rename__(self, old, new, label=None):
        """
        old (string): old dict key
        new (string): new dict key
        label (list/tuple of strings): nested keys pointing to dict with key to be replaced;
            e.g. ('PYR', 'secs'); use None to replace root key; defaults to None

        returns: True if successful, False otherwse
        """
        obj = self
        if isinstance(label, (tuple, list)):
            for ip in range(len(label)):
                try:
                    obj = obj[label[ip]]
                except:
                    return False
        if old in obj:
            obj[new] = obj.pop(old)
            return True
        else:
            return False

    def rename(self, *args, **kwargs):
        self.__rename__(*args, **kwargs)

    def __getstate__(self):
        return self.toOrderedDict()

    def __setstate__(self, d):
        self = self.fromOrderedDict(d)

<mask token>


class Dict(dict):
    <mask token>
    <mask token>

    def __init__(*args, **kwargs):
        self = args[0]
        args = args[1:]
        if len(args) > 1:
            raise TypeError('expected at most 1 arguments, got %d' % len(args))
        if args:
            self.update(self.dotify(args[0]))
        if len(kwargs):
            self.update(self.dotify(kwargs))

    def __getattr__(self, k):
        try:
            return object.__getattribute__(self, k)
        except AttributeError:
            try:
                return self[k]
            except KeyError:
                raise AttributeError(k)

    def __setattr__(self, k, v):
        try:
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                self[k] = v
            except:
                raise AttributeError(k)
        else:
            object.__setattr__(self, k, v)

    def __delattr__(self, k):
        try:
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                del self[k]
            except KeyError:
                raise AttributeError(k)
        else:
            object.__delattr__(self, k)

    def todict(self):
        return self.undotify(self)

    def fromdict(self, d):
        d = self.dotify(d)
        for k, v in d.items():
            self[k] = v

    def __repr__(self):
        keys = list(self.keys())
        args = ', '.join([('%s: %r' % (key, self[key])) for key in keys])
        return '{%s}' % args

    def dotify(self, x):
        if isinstance(x, dict):
            return Dict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.dotify(v) for v in x)
        else:
            return x

    def undotify(self, x):
        if isinstance(x, dict):
            return dict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.undotify(v) for v in x)
        else:
            return x

    def __rename__(self, old, new, label=None):
        """
        old (string): old dict key
        new (string): new dict key
        label (list/tuple of strings): nested keys pointing to dict with key to be replaced;
            e.g. ('PYR', 'secs'); use None to replace root key; defaults to None

        returns: True if successful, False otherwse
        """
        obj = self
        if isinstance(label, (tuple, list)):
            for ip in range(len(label)):
                try:
                    obj = obj[label[ip]]
                except:
                    return False
        if old in obj:
            obj[new] = obj.pop(old)
            return True
        else:
            return False

    def rename(self, *args, **kwargs):
        self.__rename__(*args, **kwargs)

    def __missing__(self, key):
        if key and not key.startswith('_ipython'):
            value = self[key] = Dict()
            return value

    def __getstate__(self):
        return self.todict()

    def __setstate__(self, d):
        self = self.fromdict(d)


class ODict(OrderedDict):
    """
    Class for/to <short description of `netpyne.specs.dicts.ODict`>


    """
    __slots__ = []

    def __init__(self, *args, **kwargs):
        super(ODict, self).__init__(*args, **kwargs)

    def __contains__(self, k):
        try:
            return hasattr(self, k) or dict.__contains__(self, k)
        except:
            return False

    def __getattr__(self, k):
        try:
            return super(ODict, self).__getattr__(k)
        except AttributeError:
            try:
                return super(ODict, self).__getitem__(k)
            except KeyError:
                raise AttributeError(k)

    def __setattr__(self, k, v):
        if k.startswith('_OrderedDict'):
            super(ODict, self).__setattr__(k, v)
        else:
            try:
                super(ODict, self).__setitem__(k, v)
            except:
                raise AttributeError(k)

    def __getitem__(self, k):
        return super(ODict, self).__getitem__(k)

    def __setitem__(self, k, v):
        super(ODict, self).__setitem__(k, v)

    def __delattr__(self, k):
        try:
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                super(ODict, self).__delattr__(k)
            except KeyError:
                raise AttributeError(k)
        else:
            object.__delattr__(self, k)

    def toOrderedDict(self):
        return self.undotify(self)

    def fromOrderedDict(self, d):
        d = self.dotify(d)
        for k, v in d.items():
            self[k] = v

    def __repr__(self):
        keys = list(self.keys())
        args = ', '.join([('%s: %r' % (key, self[key])) for key in keys])
        return '{%s}' % args

    def dotify(self, x):
        if isinstance(x, OrderedDict):
            return ODict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, dict):
            return Dict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.dotify(v) for v in x)
        else:
            return x

    def undotify(self, x):
        if isinstance(x, OrderedDict):
            return OrderedDict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, dict):
            return dict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.undotify(v) for v in x)
        else:
            return x

    def __rename__(self, old, new, label=None):
        """
        old (string): old dict key
        new (string): new dict key
        label (list/tuple of strings): nested keys pointing to dict with key to be replaced;
            e.g. ('PYR', 'secs'); use None to replace root key; defaults to None

        returns: True if successful, False otherwse
        """
        obj = self
        if isinstance(label, (tuple, list)):
            for ip in range(len(label)):
                try:
                    obj = obj[label[ip]]
                except:
                    return False
        if old in obj:
            obj[new] = obj.pop(old)
            return True
        else:
            return False

    def rename(self, *args, **kwargs):
        self.__rename__(*args, **kwargs)

    def __getstate__(self):
        return self.toOrderedDict()

    def __setstate__(self, d):
        self = self.fromOrderedDict(d)

<mask token>


class Dict(dict):
    <mask token>
    __slots__ = []

    def __init__(*args, **kwargs):
        self = args[0]
        args = args[1:]
        if len(args) > 1:
            raise TypeError('expected at most 1 arguments, got %d' % len(args))
        if args:
            self.update(self.dotify(args[0]))
        if len(kwargs):
            self.update(self.dotify(kwargs))

    def __getattr__(self, k):
        try:
            return object.__getattribute__(self, k)
        except AttributeError:
            try:
                return self[k]
            except KeyError:
                raise AttributeError(k)

    def __setattr__(self, k, v):
        try:
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                self[k] = v
            except:
                raise AttributeError(k)
        else:
            object.__setattr__(self, k, v)

    def __delattr__(self, k):
        try:
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                del self[k]
            except KeyError:
                raise AttributeError(k)
        else:
            object.__delattr__(self, k)

    def todict(self):
        return self.undotify(self)

    def fromdict(self, d):
        d = self.dotify(d)
        for k, v in d.items():
            self[k] = v

    def __repr__(self):
        keys = list(self.keys())
        args = ', '.join([('%s: %r' % (key, self[key])) for key in keys])
        return '{%s}' % args

    def dotify(self, x):
        if isinstance(x, dict):
            return Dict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.dotify(v) for v in x)
        else:
            return x

    def undotify(self, x):
        if isinstance(x, dict):
            return dict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.undotify(v) for v in x)
        else:
            return x

    def __rename__(self, old, new, label=None):
        """
        old (string): old dict key
        new (string): new dict key
        label (list/tuple of strings): nested keys pointing to dict with key to be replaced;
            e.g. ('PYR', 'secs'); use None to replace root key; defaults to None

        returns: True if successful, False otherwse
        """
        obj = self
        if isinstance(label, (tuple, list)):
            for ip in range(len(label)):
                try:
                    obj = obj[label[ip]]
                except:
                    return False
        if old in obj:
            obj[new] = obj.pop(old)
            return True
        else:
            return False

    def rename(self, *args, **kwargs):
        self.__rename__(*args, **kwargs)

    def __missing__(self, key):
        if key and not key.startswith('_ipython'):
            value = self[key] = Dict()
            return value

    def __getstate__(self):
        return self.todict()

    def __setstate__(self, d):
        self = self.fromdict(d)


class ODict(OrderedDict):
    """
    Class for/to <short description of `netpyne.specs.dicts.ODict`>


    """
    __slots__ = []

    def __init__(self, *args, **kwargs):
        super(ODict, self).__init__(*args, **kwargs)

    def __contains__(self, k):
        try:
            return hasattr(self, k) or dict.__contains__(self, k)
        except:
            return False

    def __getattr__(self, k):
        try:
            return super(ODict, self).__getattr__(k)
        except AttributeError:
            try:
                return super(ODict, self).__getitem__(k)
            except KeyError:
                raise AttributeError(k)

    def __setattr__(self, k, v):
        if k.startswith('_OrderedDict'):
            super(ODict, self).__setattr__(k, v)
        else:
            try:
                super(ODict, self).__setitem__(k, v)
            except:
                raise AttributeError(k)

    def __getitem__(self, k):
        return super(ODict, self).__getitem__(k)

    def __setitem__(self, k, v):
        super(ODict, self).__setitem__(k, v)

    def __delattr__(self, k):
        try:
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                super(ODict, self).__delattr__(k)
            except KeyError:
                raise AttributeError(k)
        else:
            object.__delattr__(self, k)

    def toOrderedDict(self):
        return self.undotify(self)

    def fromOrderedDict(self, d):
        d = self.dotify(d)
        for k, v in d.items():
            self[k] = v

    def __repr__(self):
        keys = list(self.keys())
        args = ', '.join([('%s: %r' % (key, self[key])) for key in keys])
        return '{%s}' % args

    def dotify(self, x):
        if isinstance(x, OrderedDict):
            return ODict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, dict):
            return Dict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.dotify(v) for v in x)
        else:
            return x

    def undotify(self, x):
        if isinstance(x, OrderedDict):
            return OrderedDict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, dict):
            return dict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.undotify(v) for v in x)
        else:
            return x

    def __rename__(self, old, new, label=None):
        """
        old (string): old dict key
        new (string): new dict key
        label (list/tuple of strings): nested keys pointing to dict with key to be replaced;
            e.g. ('PYR', 'secs'); use None to replace root key; defaults to None

        returns: True if successful, False otherwse
        """
        obj = self
        if isinstance(label, (tuple, list)):
            for ip in range(len(label)):
                try:
                    obj = obj[label[ip]]
                except:
                    return False
        if old in obj:
            obj[new] = obj.pop(old)
            return True
        else:
            return False

    def rename(self, *args, **kwargs):
        self.__rename__(*args, **kwargs)

    def __getstate__(self):
        return self.toOrderedDict()

    def __setstate__(self, d):
        self = self.fromOrderedDict(d)

"""
Module containing Dict and ODict classes

These classes reproduce normal Dict and ODict behavior, but add support for object-like dot notation (e.g. cell.secs.soma.geom)

"""

from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import

from builtins import range
from builtins import dict
from builtins import super
from future import standard_library

standard_library.install_aliases()
from collections import OrderedDict

# ----------------------------------------------------------------------------
# Dict class (allows dot notation for dicts)
# ----------------------------------------------------------------------------


class Dict(dict):
    """
    Class for/to <short description of `netpyne.specs.dicts.Dict`>


    """

    __slots__ = []

    def __init__(*args, **kwargs):
        self = args[0]
        args = args[1:]
        if len(args) > 1:
            raise TypeError('expected at most 1 arguments, got %d' % len(args))
        if args:
            self.update(self.dotify(args[0]))
        if len(kwargs):
            self.update(self.dotify(kwargs))

    # only called if k not found in normal places
    def __getattr__(self, k):
        try:
            # Throws exception if not in prototype chain
            return object.__getattribute__(self, k)
        except AttributeError:
            try:
                return self[k]
            except KeyError:
                raise AttributeError(k)

    def __setattr__(self, k, v):
        try:
            # Throws exception if not in prototype chain
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                self[k] = v
            except:
                raise AttributeError(k)
        else:
            object.__setattr__(self, k, v)

    def __delattr__(self, k):
        try:
            # Throws exception if not in prototype chain
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                del self[k]
            except KeyError:
                raise AttributeError(k)
        else:
            object.__delattr__(self, k)

    def todict(self):
        return self.undotify(self)

    def fromdict(self, d):
        d = self.dotify(d)
        for k, v in d.items():
            self[k] = v

    def __repr__(self):
        keys = list(self.keys())
        args = ', '.join(['%s: %r' % (key, self[key]) for key in keys])
        return '{%s}' % (args)

    def dotify(self, x):
        if isinstance(x, dict):
            return Dict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.dotify(v) for v in x)
        else:
            return x

    def undotify(self, x):
        if isinstance(x, dict):
            return dict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.undotify(v) for v in x)
        else:
            return x

    def __rename__(self, old, new, label=None):
        """
        old (string): old dict key
        new (string): new dict key
        label (list/tuple of strings): nested keys pointing to dict with key to be replaced;
            e.g. ('PYR', 'secs'); use None to replace root key; defaults to None

        returns: True if successful, False otherwse
        """

        obj = self
        if isinstance(label, (tuple, list)):
            for ip in range(len(label)):
                try:
                    obj = obj[label[ip]]
                except:
                    return False

        if old in obj:
            obj[new] = obj.pop(old)  # replace
            return True
        else:
            return False

    def rename(self, *args, **kwargs):
        self.__rename__(*args, **kwargs)

    def __missing__(self, key):
        if key and not key.startswith('_ipython'):
            value = self[key] = Dict()
            return value

    def __getstate__(self):
        return self.todict()

    def __setstate__(self, d):
        self = self.fromdict(d)


# ----------------------------------------------------------------------------
# ODict class (allows dot notation for ordered dicts)
# ----------------------------------------------------------------------------


class ODict(OrderedDict):
    """
    Class for/to <short description of `netpyne.specs.dicts.ODict`>


    """

    __slots__ = []

    def __init__(self, *args, **kwargs):
        super(ODict, self).__init__(*args, **kwargs)

    def __contains__(self, k):
        try:
            return hasattr(self, k) or dict.__contains__(self, k)
        except:
            return False

    # only called if k not found in normal places
    def __getattr__(self, k):
        try:
            # Throws exception if not in prototype chain
            return super(ODict, self).__getattr__(k)
        except AttributeError:
            try:
                return super(ODict, self).__getitem__(k)
            except KeyError:
                raise AttributeError(k)

    def __setattr__(self, k, v):
        if k.startswith('_OrderedDict'):
            super(ODict, self).__setattr__(k, v)
        else:
            try:
                super(ODict, self).__setitem__(k, v)
            except:
                raise AttributeError(k)

    def __getitem__(self, k):
        return super(ODict, self).__getitem__(k)

    def __setitem__(self, k, v):
        super(ODict, self).__setitem__(k, v)

    def __delattr__(self, k):
        try:
            # Throws exception if not in prototype chain
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                super(ODict, self).__delattr__(k)
            except KeyError:
                raise AttributeError(k)
        else:
            object.__delattr__(self, k)

    def toOrderedDict(self):
        return self.undotify(self)

    def fromOrderedDict(self, d):
        d = self.dotify(d)
        for k, v in d.items():
            self[k] = v

    def __repr__(self):
        keys = list(self.keys())
        args = ', '.join(['%s: %r' % (key, self[key]) for key in keys])
        return '{%s}' % (args)

    def dotify(self, x):
        if isinstance(x, OrderedDict):
            return ODict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, dict):
            return Dict((k, self.dotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.dotify(v) for v in x)
        else:
            return x

    def undotify(self, x):
        if isinstance(x, OrderedDict):
            return OrderedDict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, dict):
            return dict((k, self.undotify(v)) for k, v in x.items())
        elif isinstance(x, (list, tuple)):
            return type(x)(self.undotify(v) for v in x)
        else:
            return x

    def __rename__(self, old, new, label=None):
        """
        old (string): old dict key
        new (string): new dict key
        label (list/tuple of strings): nested keys pointing to dict with key to be replaced;
            e.g. ('PYR', 'secs'); use None to replace root key; defaults to None

        returns: True if successful, False otherwse
        """

        obj = self
        if isinstance(label, (tuple, list)):
            for ip in range(len(label)):
                try:
                    obj = obj[label[ip]]
                except:
                    return False

        if old in obj:
            obj[new] = obj.pop(old)  # replace
            return True
        else:
            return False

    def rename(self, *args, **kwargs):
        self.__rename__(*args, **kwargs)

    def __getstate__(self):
        return self.toOrderedDict()

    def __setstate__(self, d):
        self = self.fromOrderedDict(d)
