Will traverse the configuration data looking for attr_name provided.  It will know where to look for the
        attribute based on the *args that are passed to the method.  It treats the args as ancestors starting with the
        oldest `root -> grandparent -> parent -> attr_name`.  The findings will be updated with the last found object.
        The properties in the last found object will overwrite those in the previous.  If the attribute isn't found
        will return None

        Usage::
            >>> attr = self._get_cascading_attr('attribute_name', 'root', 'grandparent', 'parent')
            >>> if attr is not None:
            >>>  do_thing(attr)

        :param attr_name: A string, the configuration attribute name
        :param *args: A list, A list of strings that that represent the attributes ancestry. (how to find the obj)
        :rtype: Any defined configuration value :dict:, :string:, :int:, :list:, :float: `attr`

def _get_cascading_attr(self, attr_name, *args):
        """ Will traverse the configuration data looking for attr_name provided.  It will know where to look for the
        attribute based on the *args that are passed to the method.  It treats the args as ancestors starting with the
        oldest `root -> grandparent -> parent -> attr_name`.  The findings will be updated with the last found object.
        The properties in the last found object will overwrite those in the previous.  If the attribute isn't found
        will return None

        Usage::
            >>> attr = self._get_cascading_attr('attribute_name', 'root', 'grandparent', 'parent')
            >>> if attr is not None:
            >>>  do_thing(attr)

        :param attr_name: A string, the configuration attribute name
        :param *args: A list, A list of strings that that represent the attributes ancestry. (how to find the obj)
        :rtype: Any defined configuration value :dict:, :string:, :int:, :list:, :float: `attr`
        """
        attr = self._data.get(attr_name, None)
        if isinstance(attr, ConfigDict):
            attr = ConfigDict(attr, attr.start_mark, attr.end_mark)
        elif isinstance(attr, dict):
            attr = attr.copy()

        cascading = self._data
        if args:

            for key in args:
                if not isinstance(key, six.string_types):
                    raise TypeError('Every key in args must be a string.')

                if key in cascading:
                    config_object = cascading.get(key)

                    if config_object:
                        if attr_name in config_object:
                            if isinstance(attr, dict):
                                value = config_object[attr_name]

                                if value is None:
                                    attr = value
                                elif isinstance(value, dict):
                                    attr.update(config_object[attr_name])
                                else:
                                    raise LookupError(
                                        "Unable to find '{0}'. Obj structure: {1}".format(
                                            attr_name, " -> ".join(args)
                                        )
                                    )
                            else:
                                attr = config_object[attr_name]

                        cascading = config_object
                        continue
                else:
                    break

        return attr