docs: def _detect_circle(nodes=None, dependencies=None, traveled=None, path=None):
      """
          Recursively iterate over nodes checking
          if we've traveled to that node before.
      """
      # Verify nodes and traveled types
      if nodes is None:
          nodes = {}
      elif not isinstance(nodes, dict):
          raise TypeError('"nodes" must be a dictionary')
      if dependencies is None:
          return
      elif not isinstance(dependencies, set):
          raise TypeError('"dependencies" must be a set')
      if traveled is None:
          traveled = []
      elif not isinstance(traveled, list):
          raise TypeError('"traveled" must be a list')
      if path is None:
          path = []
  
      if not dependencies:
          # We're at the end of a dependency path.
          return []
  
      # Recursively iterate over nodes,
      # and gather dependency children nodes.
      children = []
      for name in dependencies:
          # Path is used for circular dependency exceptions
          # to display to the user the circular path.
          new_path = list(path)
          new_path.append(name)
  
          # Check if we've traveled to this node before.
          if name in traveled:
              raise CircularDependencyException(new_path)
  
          # Make recursive call
          node_children = _detect_circle(nodes=nodes,
                                         dependencies=nodes[name],
                                         traveled=traveled + list(name),
                                         path=new_path)
  
          # Create node for this dependency with children.
          node = DependencyNode(name)
          for child in node_children:
              child.parent = node
              node.add_child(child)
          children.append(node)
  
      return children