docs: def union(self, other):
          """
          Merges this range with a given range.
  
              >>> intrange(1, 5).union(intrange(5, 10))
              intrange([1,10))
              >>> intrange(1, 10).union(intrange(5, 15))
              intrange([1,15))
  
          Two ranges can not be merged if the resulting range would be split in
          two. This happens when the two sets are neither adjacent nor overlaps.
  
              >>> intrange(1, 5).union(intrange(10, 15))
              Traceback (most recent call last):
                File "<stdin>", line 1, in <module>
              ValueError: Ranges must be either adjacent or overlapping
  
          This does not modify the range in place.
  
          This is the same as the ``+`` operator for two ranges in PostgreSQL.
  
          :param other: Range to merge with.
          :return: A new range that is the union of this and `other`.
          :raises ValueError: If `other` can not be merged with this range.
          """
  
          if not self.is_valid_range(other):
              msg = "Unsupported type to test for union '{.__class__.__name__}'"
              raise TypeError(msg.format(other))
  
          # Optimize empty ranges
          if not self:
              return other
          elif not other:
              return self
  
          # Order ranges to simplify checks
          if self < other:
              a, b = self, other
          else:
              a, b = other, self
  
          if (a.upper < b.lower or a.upper == b.lower and not
                  a.upper_inc and not b.lower_inc) and not a.adjacent(b):
              raise ValueError("Ranges must be either adjacent or overlapping")
  
          # a.lower is guaranteed to be the lower bound, but either a.upper or
          # b.upper can be the upper bound
          if a.upper == b.upper:
              upper = a.upper
              upper_inc = a.upper_inc or b.upper_inc
          elif a.upper < b.upper:
              upper = b.upper
              upper_inc = b.upper_inc
          else:
              upper = a.upper
              upper_inc = a.upper_inc
  
          return self.__class__(a.lower, upper, a.lower_inc, upper_inc)