# Source code for odict

    #
    ##
    ##  This file is part of pyFormex 1.0.5  (Sat Feb 16 10:40:32 CET 2019)
    ##  pyFormex is a tool for generating, manipulating and transforming 3D
    ##  geometrical models by sequences of mathematical operations.
    ##  Home page: http://pyformex.org
    ##  Project page:  http://savannah.nongnu.org/projects/pyformex/
    ##  Copyright 2004-2018 (C) Benedict Verhegghe (benedict.verhegghe@ugent.be)
    ##  Distributed under the GNU General Public License version 3 or later.
    ##
    ##  This program is free software: you can redistribute it and/or modify
    ##  it under the terms of the GNU General Public License as published by
    ##  the Free Software Foundation, either version 3 of the License, or
    ##  (at your option) any later version.
    ##
    ##  This program is distributed in the hope that it will be useful,
    ##  but WITHOUT ANY WARRANTY; without even the implied warranty of
    ##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ##  GNU General Public License for more details.
    ##
    ##  You should have received a copy of the GNU General Public License
    ##  along with this program.  If not, see http://www.gnu.org/licenses/.
    ##

    """Specialized dictionary types.

    """
    from __future__ import absolute_import, division, print_function

    from collections import OrderedDict

    class DDict(dict):
        """A dict with multiple ways to set the default values.

        This is equivalent to the dict class, except that if a key is not found
        it's value may be found from calling a function or from looking it up
        in another dict.

        This differs in two ways from the :class:`collections.defaultdict` class:

        - the default function takes the missing key as a parameter,
        - the value looked up through the default function is not stored in
          the DDict itself, but will be looked up againe with the default
          function on each subsequent access of the same key.
          See :class:`EDict` for an analog class that stores the looked up values
          in itself.

        Parameters:

        - `default`: either None, a function. If it is a function, it should take
          the key as parameter and return the value for that key. It can
          appropriately be set to the get method of another dict, to have
          missing keys being looked up in another dict. The default None will
          cause a KeyError on missing keys.

        - all other parameters are passed to the dict initialisation.

        Examples:

        >>> d = DDict(lambda x:-x)
        >>> print(d)
        {}
        >>> print(d[1],d[2],d[3])
        -1 -2 -3
        >>> d[2] = 2
        >>> e = DDict(d.get,{1:1})
        >>> print(e)
        {1: 1}
        >>> print(e[1],e[2],e[3])
        1 2 None

        """

        def __init__(self, default=None, *args, **kargs):
            """Initialize the CascadingDict"""
            self.default_factory = default
            dict.__init__(self, *args, **kargs)

        def __missing__(self,key):
            if self.default_factory is None:
                raise KeyError
            else:
                return self.default_factory(key)

    class EDict(dict):
        """An extensible DDict

        This class is like DDict, but it installs missing keys in itself,
        with the value of the first default lookup.

        Examples (compare with DDict):

        >>> d = EDict(lambda x:-x)
        >>> print(d)
        {}
        >>> print(d[1],d[2],d[3])
        -1 -2 -3
        >>> d[2] = 2
        >>> e = EDict(d.get,{1:1})
        >>> print(e)
        {1: 1}
        >>> print(e[1],e[2],e[3])
        1 2 -3

        """

        def __init__(self, factory=None, *args, **kargs):
            """Initialize the CascadingDict"""
            self.default_factory = factory
            dict.__init__(self, *args, **kargs)

        def __missing__(self, key):
            if self.default_factory is None:
                raise KeyError
            else:
                self[key] = self.default_factory(key)
                return self[key]

    # End