docs: def neighbors(self, type=None, direction="to", failed=None):
          """Get a node's neighbors - nodes that are directly connected to it.
  
          Type specifies the class of neighbour and must be a subclass of
          Node (default is Node).
          Connection is the direction of the connections and can be "to"
          (default), "from", "either", or "both".
          """
          # get type
          if type is None:
              type = Node
          if not issubclass(type, Node):
              raise ValueError(
                  "{} is not a valid neighbor type,"
                  "needs to be a subclass of Node.".format(type)
              )
  
          # get direction
          if direction not in ["both", "either", "from", "to"]:
              raise ValueError(
                  "{} not a valid neighbor connection."
                  "Should be both, either, to or from.".format(direction)
              )
  
          if failed is not None:
              raise ValueError(
                  "You should not pass a failed argument to neighbors(). "
                  "Neighbors is "
                  "unusual in that a failed argument cannot be passed. This is "
                  "because there is inherent uncertainty in what it means for a "
                  "neighbor to be failed. The neighbors function will only ever "
                  "return not-failed nodes connected to you via not-failed "
                  "vectors. If you want to do more elaborate queries, for "
                  "example, getting not-failed nodes connected to you via failed"
                  " vectors, you should do so via sql queries."
              )
  
          neighbors = []
          # get the neighbours
          if direction == "to":
              outgoing_vectors = (
                  Vector.query.with_entities(Vector.destination_id)
                  .filter_by(origin_id=self.id, failed=False)
                  .all()
              )
  
              neighbor_ids = [v.destination_id for v in outgoing_vectors]
              if neighbor_ids:
                  neighbors = Node.query.filter(Node.id.in_(neighbor_ids)).all()
                  neighbors = [n for n in neighbors if isinstance(n, type)]
  
          if direction == "from":
              incoming_vectors = (
                  Vector.query.with_entities(Vector.origin_id)
                  .filter_by(destination_id=self.id, failed=False)
                  .all()
              )
  
              neighbor_ids = [v.origin_id for v in incoming_vectors]
              if neighbor_ids:
                  neighbors = Node.query.filter(Node.id.in_(neighbor_ids)).all()
                  neighbors = [n for n in neighbors if isinstance(n, type)]
  
          if direction == "either":
              neighbors = list(
                  set(
                      self.neighbors(type=type, direction="to")
                      + self.neighbors(type=type, direction="from")
                  )
              )
  
          if direction == "both":
              neighbors = list(
                  set(self.neighbors(type=type, direction="to"))
                  & set(self.neighbors(type=type, direction="from"))
              )
  
          return neighbors