code: def connected_components(self) -> (dict, dict):
          
          inclusions = utils.completed_graph(self.inclusions)  # allow bottom-up movement
          edges = utils.completed_graph(self.edges) if self.oriented else self.edges
          cc = {}  # maps cc root with nodes in the cc
          subroots = defaultdict(set)  # maps cc root with other roots of the cc
          walked_roots = set()  # all roots that have been walked already
          for root in self.roots:
              if root in walked_roots: continue  # this cc have been done already
              # walk in the graph starting at root
              cc[root] = set([root])
              walked = cc[root]
              stack = list(edges.get(root, ())) + list(inclusions.get(root, ()))
              while len(stack) > 0:
                  *stack, curr = stack
                  walked.add(curr)
                  if curr in self.roots:  # don't do the walk for already found roots
                      walked_roots.add(curr)
                      subroots[root].add(curr)
                  for succ in it.chain(edges.get(curr, ()), inclusions.get(curr, ())):
                      if succ not in walked:
                          stack.append(succ)
          return cc, dict(subroots)
docs: Return for one root of each connected component all
          the linked objects, and the mapping linking a connected component
          root with the roots that it contains.