def saveSV(fname, X, comments=None, metadata=None, printmetadict=None,<EOL>dialect=None, delimiter=None, doublequote=True, <EOL>lineterminator='<STR_LIT:\n>', escapechar = None, <EOL>quoting=csv.QUOTE_MINIMAL, quotechar='<STR_LIT:">', <EOL>skipinitialspace=False, stringifier=None,<EOL>verbosity=DEFAULT_VERBOSITY):
if metadata is None:<EOL><INDENT>metakeys = ['<STR_LIT>']<EOL>if printmetadict is None:<EOL><INDENT>printmetadict = False<EOL>if verbosity > <NUM_LIT:8>:<EOL><INDENT>print('''<STR_LIT>''')<EOL><DEDENT><DEDENT>if comments is None:<EOL><INDENT>comments = '<STR_LIT>'<EOL>if verbosity > <NUM_LIT:8>:<EOL><INDENT>print('<STR_LIT>')<EOL><DEDENT><DEDENT>if verbosity > <NUM_LIT:7>:<EOL><INDENT>print('<STR_LIT>')<EOL><DEDENT><DEDENT>elif metadata is True:<EOL><INDENT>metakeys = defaultmetadatakeys(X)<EOL>if printmetadict is None:<EOL><INDENT>printmetadict = True<EOL>if verbosity > <NUM_LIT:8>:<EOL><INDENT>print('''<STR_LIT>''')<EOL><DEDENT><DEDENT>if comments is None:<EOL><INDENT>comments = '<STR_LIT>'<EOL>if verbosity > <NUM_LIT:8>:<EOL><INDENT>print('<STR_LIT>')            <EOL><DEDENT><DEDENT>if verbosity >= <NUM_LIT:5>:<EOL><INDENT>print('<STR_LIT>')<EOL><DEDENT><DEDENT>elif metadata is False:<EOL><INDENT>metakeys = []<EOL>printmetadict = False<EOL>comments = '<STR_LIT>'<EOL>if verbosity >= <NUM_LIT:5>:<EOL><INDENT>print('<STR_LIT>')<EOL><DEDENT><DEDENT>else:<EOL><INDENT>metakeys = metadata<EOL>if printmetadict is None:<EOL><INDENT>if metakeys == []:<EOL><INDENT>printmetadict = False<EOL><DEDENT>else:<EOL><INDENT>printmetadict = True<EOL><DEDENT><DEDENT>if comments is None:<EOL><INDENT>comments = '<STR_LIT>'<EOL><DEDENT>if verbosity >= <NUM_LIT:5>:<EOL><INDENT>print('''<STR_LIT>''')<EOL><DEDENT><DEDENT>assert lineterminator in ['<STR_LIT:\r>','<STR_LIT:\n>','<STR_LIT:\r\n>'], '''<STR_LIT>''' + repr( ['<STR_LIT:\r>','<STR_LIT:\n>','<STR_LIT:\r\n>'])<EOL>dialect = getdialect(fname, dialect, delimiter, lineterminator, doublequote, <EOL>escapechar, quoting, quotechar, skipinitialspace)<EOL>delimiter = dialect.delimiter     <EOL>if <NUM_LIT:6> > verbosity > <NUM_LIT:2>:<EOL><INDENT>print('<STR_LIT>', repr(delimiter))<EOL><DEDENT>elif verbosity >= <NUM_LIT:6>:<EOL><INDENT>print('<STR_LIT>', repr(printdialect(dialect)))<EOL><DEDENT>metadata = getstringmetadata(X,metakeys,dialect)<EOL>metametadata = {}<EOL>v = <NUM_LIT:1><EOL>for k in metakeys:<EOL><INDENT>if k in list(metadata.keys()):<EOL><INDENT>nl = len(metadata[k].split(lineterminator))<EOL>metametadata[k] = v if nl == <NUM_LIT:1> else (v, v + nl)<EOL>v = v + nl<EOL><DEDENT><DEDENT>F = open(fname,'<STR_LIT:wb>')<EOL>if printmetadict is True:<EOL><INDENT>line = "<STR_LIT>" + repr(metametadata)<EOL>F.write(comments + line + lineterminator)<EOL><DEDENT>for k in metakeys:<EOL><INDENT>if k in list(metadata.keys()):<EOL><INDENT>for line in metadata[k].split(lineterminator):<EOL><INDENT>F.write(comments + line + lineterminator)<EOL><DEDENT><DEDENT><DEDENT>Write(X, F, dialect, stringifier=stringifier)<EOL>F.close()<EOL>
Save a tabarray to a separated-variable (CSV) file.

**Parameters**

    **fname** :  string

        Path to a separated variable (CSV) text file.

    **X** :  tabarray

        The actual data in a :class:`tabular.tab.tabarray`.

    **comments** :  string, optional

        The character to be used to denote the start of a header (non-data) 
        line, e.g. '#'.  If not specified, it is determined according to the 
        following rule:  '#' if `metadata` argument is set, otherwise ''.

    **delimiter** :  string, optional

        The character to beused to separate values in each line of text, 
        e.g. ','.  If not specified, by default, this is inferred from 
        the file extension: if the file ends in `.csv`, the delimiter is 
        ',', otherwise it is '\\t.'

    **linebreak** :  string, optional

        The string separating lines of text.  By default, this is assumed to 
        be '\\n', and can also be set to be '\\r' or '\\r\\n'.

    **metadata** :  list of strings or Boolean, optional

        Allowed values are True, False, or any sublists of the list 
        `['names', 'formats', 'types', 'coloring', 'dialect']`.  These 
        keys indicate what special metadata is printed in the header.

        * If a sublist of 
         `['names', 'formats', 'types', 'coloring', 'dialect']`, then the 
         indicated types of metadata are written out.  

        * If `True`, this is the same as 
          `metadata = ['coloring', 'types', 'names','dialect']`, e.g. as 
           many types of metadata as this algorithm currently knows how to 
           write out. 

        * If 'False', no metadata is printed at all, e.g. just the data.

        * If `metadata` is not specified, the default is `['names']`, that 
          is, just column names are written out.

    **printmetadict** :  Boolean, optional

        Whether or not to print a string representation of the 
        `metadatadict` in the first line of the header.

        If `printmetadict` is not specified, then:

        * If `metadata` is specified and is not `False`, then
          `printmetadata` defaults to `True`.

        * Else if `metadata` is `False`, then `printmetadata` defaults 
          to `False`.

        * Else `metadata` is not specified, and `printmetadata` defaults 
          to `False`.

        See the :func:`tabular.io.loadSV` for more information about 
        `metadatadict`.

    **stringifier** : callable 

        Callable taking 1-d numpy array and returning Python list of strings 
        of same length, or dictionary or tuple of such callables.  

        If specified, the callable will be applied to each column, and the 
        resulting list of strings will be written to the file.  If 
        specified as a list or dictionary of callables, the functions will 
        be applied to correponding columns.  The default used if 
        **stringifier** is not specified, is `tb.utils.DEFAULT_STRINGIFIER`, 
        which merely passes through string-type columns, and converts 
        numerical-type columns directly to corresponding strings with NaNs 
        replaced with blank values.  The main purpose of specifying a 
        non-default value is to encode numerical values in various string 
        encodings that might be used required for other applications like 
        databases.                    

        NOTE:  In certain special circumstances (e.g. when the 
        lineterminator or delimiter character appears in a field of the 
        data), the Python CSV writer is used to write out data.  To allow 
        for control of the operation of the writer in these circumstances, 
        the following other parameters replicating the interface of the CSV 
        module are also valid, and values will be passed through:  
        **doublequote**, **escapechar**, **quoting**, **quotechar**, and 
        **skipinitialspace**.  (See Python CSV module documentation for more 
        information.)     

**See Also:**

        :func:`tabular.io.loadSV`