This method must NOT be called from outside the Section class.

        Do not override this method.

        If handle_not_found is set to False, hooks won't be called.
        This is needed when checking key existence -- the whole
        purpose of key existence checking is to avoid errors (and error handling).

def _get_item_or_section(self, key, handle_not_found=True):
        """
        This method must NOT be called from outside the Section class.

        Do not override this method.

        If handle_not_found is set to False, hooks won't be called.
        This is needed when checking key existence -- the whole
        purpose of key existence checking is to avoid errors (and error handling).
        """
        if isinstance(key, six.string_types):
            if self.settings.str_path_separator in key:
                return self._get_item_or_section(key.split(self.settings.str_path_separator))

            if key.endswith('_') and keyword.iskeyword(key[:-1]):
                key = key[:-1]

            if key in self._tree:
                resolution = self._tree[key]
            else:
                if handle_not_found:
                    result = self.dispatch_event(self.hooks.not_found, name=key, section=self)
                    if result is not None:
                        resolution = result
                    else:
                        raise NotFound(key, section=self)
                else:
                    raise NotFound(key, section=self)

        elif isinstance(key, (tuple, list)) and len(key) > 0:
            if len(key) == 1:
                resolution = self._get_item_or_section(key[0], handle_not_found=handle_not_found)
            else:
                resolution = self._get_item_or_section(
                    key[0], handle_not_found=handle_not_found
                )._get_item_or_section(key[1:], handle_not_found=handle_not_found)
        else:
            raise TypeError('Expected either a string or a tuple as key, got {!r}'.format(key))

        return resolution