'Given a `ColDefs` object of unknown origin, initialize a new `FITS_rec`
object.
.. note::
This was originally part of the ``new_table`` function in the table
module but was moved into a class method since most of its
functionality always had more to do with initializing a `FITS_rec`
object than anything else, and much of it also overlapped with
``FITS_rec._scale_back``.
Parameters
columns : sequence of `Column` or a `ColDefs`
The columns from which to create the table data.  If these
columns have data arrays attached that data may be used in
initializing the new table.  Otherwise the input columns
will be used as a template for a new table with the requested
number of rows.
nrows : int
Number of rows in the new table.  If the input columns have data
associated with them, the size of the largest input column is used.
Otherwise the default is 0.
fill : bool
If `True`, will fill all cells with zeros or blanks.  If
`False`, copy the data from input, undefined cells will still
be filled with zeros/blanks.'

@classmethod
def from_columns(cls, columns, nrows=0, fill=False):

    if (not isinstance(columns, ColDefs)):
        columns = ColDefs(columns)
    for column in columns:
        arr = column.array
        if isinstance(arr, Delayed):
            if (arr.hdu.data is None):
                column.array = None
            else:
                column.array = _get_recarray_field(arr.hdu.data, arr.field)
    del columns._arrays
    if (nrows == 0):
        for arr in columns._arrays:
            if (arr is not None):
                dim = arr.shape[0]
            else:
                dim = 0
            if (dim > nrows):
                nrows = dim
    raw_data = np.empty((columns.dtype.itemsize * nrows), dtype=np.uint8)
    raw_data.fill(ord(columns._padding_byte))
    data = np.recarray(nrows, dtype=columns.dtype, buf=raw_data).view(cls)
    columns._add_listener(data)
    data._coldefs = columns
    if fill:
        return data
    for (idx, column) in enumerate(columns):
        arr = column.array
        if (arr is None):
            array_size = 0
        else:
            array_size = len(arr)
        n = min(array_size, nrows)
        if (not n):
            continue
        field = _get_recarray_field(data, idx)
        name = column.name
        fitsformat = column.format
        recformat = fitsformat.recformat
        outarr = field[:n]
        inarr = arr[:n]
        if isinstance(recformat, _FormatX):
            if (inarr.shape[(-1)] == recformat.repeat):
                _wrapx(inarr, outarr, recformat.repeat)
                continue
        elif isinstance(recformat, _FormatP):
            data._cache_field(name, _makep(inarr, field, recformat, nrows=nrows))
            continue
        elif ((recformat[(-2):] == FITS2NUMPY['L']) and (inarr.dtype == bool)):
            field[:] = ord('F')
            converted = np.zeros(field.shape, dtype=bool)
            converted[:n] = inarr
            data._cache_field(name, converted)
            inarr = np.where((inarr == np.False_), ord('F'), ord('T'))
        elif (columns[idx]._physical_values and columns[idx]._pseudo_unsigned_ints):
            bzero = column.bzero
            converted = np.zeros(field.shape, dtype=inarr.dtype)
            converted[:n] = inarr
            data._cache_field(name, converted)
            if (n < nrows):
                field[n:] = (- bzero)
            inarr = (inarr - bzero)
        elif isinstance(columns, _AsciiColDefs):
            if fitsformat._pseudo_logical:
                outarr = field.view(np.uint8, np.ndarray)[:n]
            elif (arr.dtype.kind not in ('S', 'U')):
                data._cache_field(name, np.zeros(nrows, dtype=arr.dtype))
                outarr = data._converted[name][:n]
            outarr[:] = inarr
            continue
        if (inarr.shape != outarr.shape):
            if ((inarr.dtype.kind == outarr.dtype.kind) and (inarr.dtype.kind in ('U', 'S')) and (inarr.dtype != outarr.dtype)):
                inarr_rowsize = inarr[0].size
                inarr = inarr.flatten().view(outarr.dtype)
            if (outarr.ndim > 1):
                inarr_rowsize = inarr[0].size
                inarr = inarr.reshape((n, inarr_rowsize))
                outarr[:, :inarr_rowsize] = inarr
            else:
                outarr[:n] = inarr.ravel()
        else:
            outarr[:] = inarr
    for idx in range(len(columns)):
        columns._arrays[idx] = data.field(idx)
    return data
