text: # -*- coding: utf-8 -*-
  """
      Copyright (C) 2017 Sebastian Golasch (plugin.video.netflix)
      Copyright (C) 2018 Caphm (original implementation module)
      Helper functions for retrieving values from nested dicts
  
      SPDX-License-Identifier: MIT
      See LICENSES/MIT.md for more information.
  """
  from __future__ import absolute_import, division, unicode_literals
  
  
  def get_path(path, search_space, include_key=False):
      """Retrieve a value from a nested dict by following the path.
      Throws KeyError if any key along the path does not exist"""
      if not isinstance(path, (tuple, list)):
          path = [path]
      current_value = search_space[path[0]]
      if len(path) == 1:
          return (path[0], current_value) if include_key else current_value
      return get_path(path[1:], current_value, include_key)
  
  
  def get_path_safe(path, search_space, include_key=False, default=None):
      """Retrieve a value from a nested dict by following the path.
      Returns default if any key in the path does not exist."""
      try:
          return get_path(path, search_space, include_key)
      except (KeyError, IndexError):
          return default
  
  
  def remove_path(path, search_space, is_empty, remove_remnants=True):
      """Remove a value from a nested dict by following a path.
      Also removes remaining empty dicts in the hierarchy if remove_remnants
      is True"""
      path = _ensure_listlike(path)
      if len(path) == 1:
          del search_space[path[0]]
      else:
          remove_path(path[1:], search_space[path[0]], is_empty)
          if remove_remnants and is_empty(search_space[path[0]]):
              del search_space[path[0]]
  
  
  def _ensure_listlike(path):
      return path if isinstance(path, (tuple, list)) else [path]
  
  
  def get_multiple_paths(path, search_space, default=None):
      """Retrieve multiple values from a nested dict by following the path.
      The path may branch into multiple paths at any point.
      A branch point is a list of different keys to follow down the path.
      Returns a nested dict structure with nested dicts for each branch point in
      the path. This essentially reduces the original nested dict by removing
      those layers that only have one key and keys not specified in the branch
      point. Keys specified in branch points that do not exist in the search
      space are silently ignored"""
      if not isinstance(search_space, (dict, list)):
          return default
      if isinstance(path[0], list):
          return _branch(path, search_space, default)
      current_value = search_space.get(path[0], default)
      return (current_value
              if len(path) == 1
              else get_multiple_paths(path[1:], current_value, default))
  
  
  def _branch(path, search_space, default):
      return {k: get_multiple_paths([k] + path[1:], search_space, default)
              for k in path[0]
              if k in search_space}
  
  
  def check_path_exists(path, search_space):
      """Return True if the path exists in search_space"""
      if not isinstance(search_space, dict):
          return False
      if path[0] in search_space:
          if len(path) > 1:
              current_value = search_space.get(path[0])
              return check_path_exists(path[1:], current_value)
          return True
      return False
  