docs: def _size_columns(self, container):
          """Calculate the table's column sizes constrained by:
  
          - requested (absolute, relative and automatic) column widths
          - container width (= available width)
          - cell contents
  
          """
          def calculate_column_widths(max_cell_width):
              """Calculate required column widths given a maximum cell width"""
              def cell_content_width(cell):
                  buffer = VirtualContainer(container, width=max_cell_width)
                  width, _, _ = cell.flow(buffer, None)
                  return float(width)
  
              widths = [0] * self.body.num_columns
              for row in chain(self.head or [], self.body):
                  for cell in (cell for cell in row if cell.colspan == 1):
                      col = int(cell.column_index)
                      widths[col] = max(widths[col], cell_content_width(cell))
              for row in chain(self.head or [], self.body):
                  for cell in (cell for cell in row if cell.colspan > 1):
                      c = int(cell.column_index)
                      c_end = c + cell.colspan
                      padding = cell_content_width(cell) - sum(widths[c:c_end])
                      if padding > 0:
                          per_column_padding = padding / cell.colspan
                          for i in range(cell.colspan):
                              widths[c + i] += per_column_padding
              return widths
  
          width = self._width(container)
          try:
              fixed_width = width.to_points(container.width)
          except AttributeError:
              fixed_width = width or FlowableWidth.AUTO
          min_column_widths = calculate_column_widths(0)
          max_column_widths = calculate_column_widths(float('+inf'))
  
          # calculate relative column widths for auto-sized columns
          auto_rel_colwidths = [sqrt(minimum * maximum) for minimum, maximum
                                in zip(min_column_widths, max_column_widths)]
          column_widths = self.column_widths or [None for _ in max_column_widths]
          try:          # TODO: max() instead of min()?
              relative_factor = min(auto_relative_width / width
                                    for width, auto_relative_width
                                    in zip(column_widths, auto_rel_colwidths)
                                    if width and not isinstance(width, DimBase))
          except ValueError:
              relative_factor = 1
          column_widths = [auto_relative_width * relative_factor
                           if width is None else width
                           for width, auto_relative_width
                           in zip(column_widths, auto_rel_colwidths)]
  
          # set min = max for columns with a fixed width
          total_fixed_cols_width = 0
          total_portions = 0
          for i, column_width in enumerate(column_widths):
              if isinstance(column_width, DimBase):
                  width_in_pt = column_width.to_points(container.width)
                  min_column_widths[i] = max_column_widths[i] = width_in_pt
                  total_fixed_cols_width += width_in_pt
              else:
                  total_portions += column_width
  
          # does the table fit within the available width without wrapping?
          if sum(max_column_widths) <= container.width:
              return max_column_widths
  
          # determine table width
          if fixed_width != FlowableWidth.AUTO:
              table_width = fixed_width
          elif total_portions:
              max_factor = max(maximum / width for width, maximum,
                               in zip(column_widths, max_column_widths)
                               if not isinstance(width, DimBase))
              no_wrap_rel_cols_width = total_portions * max_factor
              table_width = min(total_fixed_cols_width + no_wrap_rel_cols_width,
                                float(container.width))
          else:
              table_width = total_fixed_cols_width
  
          # TODO: warn when a column's fixed width < min width
  
          # determine absolute width of columns with relative widths
          if total_portions:
              total_relative_cols_width = table_width - total_fixed_cols_width
              portion_width = total_relative_cols_width / total_portions
              auto_widths = [width if isinstance(width, DimBase)
                             else width * portion_width
                             for width in column_widths]
              extra = [0 if isinstance(width, DimBase)
                       else auto_width - min_column_widths[index]
                       for index, auto_width in enumerate(auto_widths)]
              excess = [0 if isinstance(width, DimBase)
                        else auto_width - max_column_widths[index]
                        for index, auto_width in enumerate(auto_widths)]
              excess_pos = sum(x for x in excess if x > 0)
              extra_neg = sum(x for x in extra if x <= 0) + excess_pos
              extra_pos = (sum(x for x, c in zip(extra, excess)
                               if x > 0 and c <= 0))
              if extra_pos + extra_neg < 0:
                  self.warn('Table contents are too wide to fit within the '
                            'available width', container)
                  return [width.to_points(container.width)
                          if isinstance(width, DimBase) else width
                          for width in auto_widths]
  
              def final_column_width(index, width):
                  if isinstance(width, DimBase):
                      return width.to_points(container.width)
                  elif excess[index] > 0:
                      return max_column_widths[index]
                  elif extra[index] <= 0:
                      return min_column_widths[index]
                  else:
                      return width + (extra_neg * extra[index] / extra_pos)
  
              return [final_column_width(i, width)
                      for i, width in enumerate(auto_widths)]
          else:
              return [width.to_points(container.width)
                      for width in column_widths]