def rowstack(seq, mode='nulls', nullvals=None):
    '''
    Vertically stack a sequence of numpy ndarrays with structured dtype
    Analog of numpy.vstack
    Implemented by the tabarray method
    :func:`tabular.tab.tabarray.rowstack` which uses 
    :func:`tabular.tabarray.tab_rowstack`.
    **Parameters**
            **seq** :  sequence of numpy recarrays
                    List, tuple, etc. of numpy recarrays to stack vertically.
            **mode** :  string in ['nulls', 'commons', 'abort']
                    Denotes how to proceed if the recarrays have different
                    dtypes, e.g. different sets of named columns.
                    *   if `mode` == ``nulls``, the resulting set of columns is
                        determined by the union of the dtypes of all recarrays
                        to be stacked, and missing data is filled with null 
                        values as defined by 
                        :func:`tabular.spreadsheet.nullvalue`; this is the 
                        default mode.
                    *   elif `mode` == ``commons``, the resulting set of 
                        columns is determined by the intersection of the dtypes 
                        of all recarrays to be stacked, e.g. common columns.
                    *   elif `mode` == ``abort``, raise an error when the
                        recarrays to stack have different dtypes.
    **Returns**
            **out** :  numpy ndarray with structured dtype
                    Result of vertically stacking the arrays in `seq`.
    **See also:**  `numpy.vstack 
    <http://docs.scipy.org/doc/numpy/reference/generated/numpy.vstack.html>`_.
    '''
    if nullvals == None:
        nullvals = utils.DEFAULT_NULLVALUEFORMAT
    if len(seq) > 1:
        assert mode in ['commons','nulls','abort'], \
             ('"mode" argument must either by "commons", "abort", or "nulls".')
        if mode == 'abort':
            if not all([set(l.dtype.names) == set(seq[0].dtype.names) 
                        for l in seq]):
                raise ValueError('Some column names are different.')
            else:
                mode = 'commons'
        if mode == 'nulls':
            names =  utils.uniqify(utils.listunion([list(s.dtype.names) 
                                       for s in seq if s.dtype.names != None]))
            formats = [max([s.dtype[att] for s in seq if s.dtype.names != None 
                       and att in s.dtype.names]).str for att in names]         
            dtype = np.dtype(zip(names,formats))
            return utils.fromarrays([utils.listunion([s[att].tolist() 
                        if (s.dtype.names != None and att in s.dtype.names) 
                        else [nullvals(format)] * len(s) for s in seq]) 
                        for (att, format) in zip(names, formats)], type=np.ndarray,
                        dtype=dtype)
        elif mode == 'commons':
            names = [x for x in seq[0].dtype.names 
                     if all([x in l.dtype.names for l in seq[1:]])]
            formats = [max([a.dtype[att] for a in seq]).str for att in names]
            return utils.fromrecords(utils.listunion(
                    [ar.tolist() for ar in seq]), type=np.ndarray,
                          names=names, formats=formats)
    else:
        return seq[0]