Skip to content

Commit 38aebd0

Browse files
committed
DEPR: Warn about Series.to_csv signature alignment
Warns about aligning Series.to_csv's signature with that of DataFrame.to_csv's. In anticipation, we have moved DataFrame.to_csv to generic.py so that we can later delete the Series.to_csv implementation, and allow it to automatically adopt DataFrame's to_csv due to inheritance. Closes pandas-devgh-19745.
1 parent bdb6168 commit 38aebd0

File tree

7 files changed

+219
-140
lines changed

7 files changed

+219
-140
lines changed

doc/source/whatsnew/v0.24.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ Deprecations
245245
- :meth:`DataFrame.to_stata`, :meth:`read_stata`, :class:`StataReader` and :class:`StataWriter` have deprecated the ``encoding`` argument. The encoding of a Stata dta file is determined by the file type and cannot be changed (:issue:`21244`).
246246
- :meth:`MultiIndex.to_hierarchical` is deprecated and will be removed in a future version (:issue:`21613`)
247247
- :meth:`Series.ptp` is deprecated. Use ``numpy.ptp`` instead (:issue:`21614`)
248-
-
248+
- The signature in :meth:`Series.to_csv` has been deprecated. Please follow the signature in :meth:`DataFrame.to_csv` instead (:issue:`19745`)
249249

250250
.. _whatsnew_0240.prior_deprecations:
251251

pandas/core/frame.py

-97
Original file line numberDiff line numberDiff line change
@@ -1710,103 +1710,6 @@ def to_panel(self):
17101710

17111711
return self._constructor_expanddim(new_mgr)
17121712

1713-
def to_csv(self, path_or_buf=None, sep=",", na_rep='', float_format=None,
1714-
columns=None, header=True, index=True, index_label=None,
1715-
mode='w', encoding=None, compression=None, quoting=None,
1716-
quotechar='"', line_terminator='\n', chunksize=None,
1717-
tupleize_cols=None, date_format=None, doublequote=True,
1718-
escapechar=None, decimal='.'):
1719-
r"""Write DataFrame to a comma-separated values (csv) file
1720-
1721-
Parameters
1722-
----------
1723-
path_or_buf : string or file handle, default None
1724-
File path or object, if None is provided the result is returned as
1725-
a string.
1726-
sep : character, default ','
1727-
Field delimiter for the output file.
1728-
na_rep : string, default ''
1729-
Missing data representation
1730-
float_format : string, default None
1731-
Format string for floating point numbers
1732-
columns : sequence, optional
1733-
Columns to write
1734-
header : boolean or list of string, default True
1735-
Write out the column names. If a list of strings is given it is
1736-
assumed to be aliases for the column names
1737-
index : boolean, default True
1738-
Write row names (index)
1739-
index_label : string or sequence, or False, default None
1740-
Column label for index column(s) if desired. If None is given, and
1741-
`header` and `index` are True, then the index names are used. A
1742-
sequence should be given if the DataFrame uses MultiIndex. If
1743-
False do not print fields for index names. Use index_label=False
1744-
for easier importing in R
1745-
mode : str
1746-
Python write mode, default 'w'
1747-
encoding : string, optional
1748-
A string representing the encoding to use in the output file,
1749-
defaults to 'ascii' on Python 2 and 'utf-8' on Python 3.
1750-
compression : {'infer', 'gzip', 'bz2', 'xz', None}, default None
1751-
If 'infer' and `path_or_buf` is path-like, then detect compression
1752-
from the following extensions: '.gz', '.bz2' or '.xz'
1753-
(otherwise no compression).
1754-
line_terminator : string, default ``'\n'``
1755-
The newline character or character sequence to use in the output
1756-
file
1757-
quoting : optional constant from csv module
1758-
defaults to csv.QUOTE_MINIMAL. If you have set a `float_format`
1759-
then floats are converted to strings and thus csv.QUOTE_NONNUMERIC
1760-
will treat them as non-numeric
1761-
quotechar : string (length 1), default '\"'
1762-
character used to quote fields
1763-
doublequote : boolean, default True
1764-
Control quoting of `quotechar` inside a field
1765-
escapechar : string (length 1), default None
1766-
character used to escape `sep` and `quotechar` when appropriate
1767-
chunksize : int or None
1768-
rows to write at a time
1769-
tupleize_cols : boolean, default False
1770-
.. deprecated:: 0.21.0
1771-
This argument will be removed and will always write each row
1772-
of the multi-index as a separate row in the CSV file.
1773-
1774-
Write MultiIndex columns as a list of tuples (if True) or in
1775-
the new, expanded format, where each MultiIndex column is a row
1776-
in the CSV (if False).
1777-
date_format : string, default None
1778-
Format string for datetime objects
1779-
decimal: string, default '.'
1780-
Character recognized as decimal separator. E.g. use ',' for
1781-
European data
1782-
1783-
"""
1784-
1785-
if tupleize_cols is not None:
1786-
warnings.warn("The 'tupleize_cols' parameter is deprecated and "
1787-
"will be removed in a future version",
1788-
FutureWarning, stacklevel=2)
1789-
else:
1790-
tupleize_cols = False
1791-
1792-
from pandas.io.formats.csvs import CSVFormatter
1793-
formatter = CSVFormatter(self, path_or_buf,
1794-
line_terminator=line_terminator, sep=sep,
1795-
encoding=encoding,
1796-
compression=compression, quoting=quoting,
1797-
na_rep=na_rep, float_format=float_format,
1798-
cols=columns, header=header, index=index,
1799-
index_label=index_label, mode=mode,
1800-
chunksize=chunksize, quotechar=quotechar,
1801-
tupleize_cols=tupleize_cols,
1802-
date_format=date_format,
1803-
doublequote=doublequote,
1804-
escapechar=escapechar, decimal=decimal)
1805-
formatter.save()
1806-
1807-
if path_or_buf is None:
1808-
return formatter.path_or_buf.getvalue()
1809-
18101713
@Appender(_shared_docs['to_excel'] % _shared_doc_kwargs)
18111714
def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='',
18121715
float_format=None, columns=None, header=True, index=True,

pandas/core/generic.py

+101
Original file line numberDiff line numberDiff line change
@@ -9161,6 +9161,107 @@ def first_valid_index(self):
91619161
def last_valid_index(self):
91629162
return self._find_valid_index('last')
91639163

9164+
def to_csv(self, path_or_buf=None, sep=",", na_rep='', float_format=None,
9165+
columns=None, header=True, index=True, index_label=None,
9166+
mode='w', encoding=None, compression=None, quoting=None,
9167+
quotechar='"', line_terminator='\n', chunksize=None,
9168+
tupleize_cols=None, date_format=None, doublequote=True,
9169+
escapechar=None, decimal='.'):
9170+
r"""Export to a comma-separated values (CSV) file
9171+
9172+
Parameters
9173+
----------
9174+
path_or_buf : string or file handle, default None
9175+
File path or object, if None is provided the result is returned as
9176+
a string.
9177+
sep : character, default ','
9178+
Field delimiter for the output file.
9179+
na_rep : string, default ''
9180+
Missing data representation
9181+
float_format : string, default None
9182+
Format string for floating point numbers
9183+
columns : sequence, optional
9184+
Columns to write
9185+
header : boolean or list of string, default True
9186+
Write out the column names. If a list of strings is given it is
9187+
assumed to be aliases for the column names
9188+
index : boolean, default True
9189+
Write row names (index)
9190+
index_label : string or sequence, or False, default None
9191+
Column label for index column(s) if desired. If None is given, and
9192+
`header` and `index` are True, then the index names are used. A
9193+
sequence should be given if the DataFrame uses MultiIndex. If
9194+
False do not print fields for index names. Use index_label=False
9195+
for easier importing in R
9196+
mode : str
9197+
Python write mode, default 'w'
9198+
encoding : string, optional
9199+
A string representing the encoding to use in the output file,
9200+
defaults to 'ascii' on Python 2 and 'utf-8' on Python 3.
9201+
compression : {'infer', 'gzip', 'bz2', 'xz', None}, default None
9202+
If 'infer' and `path_or_buf` is path-like, then detect compression
9203+
from the following extensions: '.gz', '.bz2' or '.xz'
9204+
(otherwise no compression).
9205+
line_terminator : string, default ``'\n'``
9206+
The newline character or character sequence to use in the output
9207+
file
9208+
quoting : optional constant from csv module
9209+
defaults to csv.QUOTE_MINIMAL. If you have set a `float_format`
9210+
then floats are converted to strings and thus csv.QUOTE_NONNUMERIC
9211+
will treat them as non-numeric
9212+
quotechar : string (length 1), default '\"'
9213+
character used to quote fields
9214+
doublequote : boolean, default True
9215+
Control quoting of `quotechar` inside a field
9216+
escapechar : string (length 1), default None
9217+
character used to escape `sep` and `quotechar` when appropriate
9218+
chunksize : int or None
9219+
rows to write at a time
9220+
tupleize_cols : boolean, default False
9221+
.. deprecated:: 0.21.0
9222+
This argument will be removed and will always write each row
9223+
of the multi-index as a separate row in the CSV file.
9224+
9225+
Write MultiIndex columns as a list of tuples (if True) or in
9226+
the new, expanded format, where each MultiIndex column is a row
9227+
in the CSV (if False).
9228+
date_format : string, default None
9229+
Format string for datetime objects
9230+
decimal: string, default '.'
9231+
Character recognized as decimal separator. E.g. use ',' for
9232+
European data
9233+
9234+
"""
9235+
9236+
from pandas.core.frame import DataFrame
9237+
from pandas.io.formats.csvs import CSVFormatter
9238+
9239+
df = self if isinstance(self, DataFrame) else DataFrame(self)
9240+
9241+
if tupleize_cols is not None:
9242+
warnings.warn("The 'tupleize_cols' parameter is deprecated and "
9243+
"will be removed in a future version",
9244+
FutureWarning, stacklevel=2)
9245+
else:
9246+
tupleize_cols = False
9247+
9248+
formatter = CSVFormatter(df, path_or_buf,
9249+
line_terminator=line_terminator, sep=sep,
9250+
encoding=encoding,
9251+
compression=compression, quoting=quoting,
9252+
na_rep=na_rep, float_format=float_format,
9253+
cols=columns, header=header, index=index,
9254+
index_label=index_label, mode=mode,
9255+
chunksize=chunksize, quotechar=quotechar,
9256+
tupleize_cols=tupleize_cols,
9257+
date_format=date_format,
9258+
doublequote=doublequote,
9259+
escapechar=escapechar, decimal=decimal)
9260+
formatter.save()
9261+
9262+
if path_or_buf is None:
9263+
return formatter.path_or_buf.getvalue()
9264+
91649265

91659266
def _doc_parms(cls):
91669267
"""Return a tuple of the doc parms."""

pandas/core/series.py

+53-15
Original file line numberDiff line numberDiff line change
@@ -3760,24 +3760,30 @@ def from_csv(cls, path, sep=',', parse_dates=True, header=None,
37603760

37613761
return result
37623762

3763-
def to_csv(self, path=None, index=True, sep=",", na_rep='',
3764-
float_format=None, header=False, index_label=None,
3763+
def to_csv(self, path_or_buf=None, index=True, sep=",", na_rep='',
3764+
float_format=None, header=None, index_label=None,
37653765
mode='w', encoding=None, compression=None, date_format=None,
3766-
decimal='.'):
3767-
"""
3768-
Write Series to a comma-separated values (csv) file
3766+
decimal='.', **kwargs):
3767+
"""Export to a comma-separated values (CSV) file
3768+
3769+
.. deprecated:: 0.24.0
3770+
The signature will aligned to that of :func:`DataFrame.to_csv`.
3771+
3772+
:func:`Series.to_csv` will align its signature with that of
3773+
`DataFrame.to_csv`. Please pass in keyword arguments in accordance
3774+
with that signature instead.
37693775
37703776
Parameters
37713777
----------
3772-
path : string or file handle, default None
3778+
path_or_buf : string or file handle, default None
37733779
File path or object, if None is provided the result is returned as
37743780
a string.
37753781
na_rep : string, default ''
37763782
Missing data representation
37773783
float_format : string, default None
37783784
Format string for floating point numbers
3779-
header : boolean, default False
3780-
Write out series name
3785+
header : boolean, default None
3786+
Write out Series name. By default, the name will be omitted.
37813787
index : boolean, default True
37823788
Write row names (index)
37833789
index_label : string or sequence, default None
@@ -3800,15 +3806,47 @@ def to_csv(self, path=None, index=True, sep=",", na_rep='',
38003806
Character recognized as decimal separator. E.g. use ',' for
38013807
European data
38023808
"""
3809+
38033810
from pandas.core.frame import DataFrame
38043811
df = DataFrame(self)
3805-
# result is only a string if no path provided, otherwise None
3806-
result = df.to_csv(path, index=index, sep=sep, na_rep=na_rep,
3807-
float_format=float_format, header=header,
3808-
index_label=index_label, mode=mode,
3809-
encoding=encoding, compression=compression,
3810-
date_format=date_format, decimal=decimal)
3811-
if path is None:
3812+
3813+
new_path_key = "path_or_buf"
3814+
old_path_key = "path"
3815+
emit_warning = False
3816+
3817+
# For backwards compatibility, override the `path_of_buf`
3818+
# argument if a `path` keyword argument is provided.
3819+
if kwargs.get(old_path_key, None) is not None:
3820+
kwargs[new_path_key] = kwargs.pop(old_path_key)
3821+
emit_warning = True
3822+
3823+
if header is None:
3824+
emit_warning = True
3825+
header = False
3826+
3827+
if emit_warning:
3828+
warnings.warn("The signature of `Series.to_csv` will be "
3829+
"aligned to that of `DataFrame.to_csv` in the "
3830+
"future. Note that some of the default arguments "
3831+
"and argument names are different, so please refer "
3832+
"to the documentation for `DataFrame.to_csv` when "
3833+
"changing your function calls.",
3834+
FutureWarning, stacklevel=2)
3835+
header = False
3836+
3837+
to_csv_kwargs = dict(path_or_buf=path_or_buf, index=index, sep=sep,
3838+
na_rep=na_rep, float_format=float_format,
3839+
header=header, index_label=index_label,
3840+
mode=mode, encoding=encoding,
3841+
compression=compression,
3842+
date_format=date_format,
3843+
decimal=decimal)
3844+
to_csv_kwargs.update(**kwargs)
3845+
3846+
# Result is only a string if no path provided, otherwise None.
3847+
result = df.to_csv(**to_csv_kwargs)
3848+
3849+
if to_csv_kwargs[new_path_key] is None:
38123850
return result
38133851

38143852
@Appender(generic._shared_docs['to_excel'] % _shared_doc_kwargs)

pandas/tests/frame/test_to_csv.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -893,14 +893,16 @@ def test_to_csv_line_terminators(self):
893893

894894
def test_to_csv_from_csv_categorical(self):
895895

896-
# CSV with categoricals should result in the same output as when one
897-
# would add a "normal" Series/DataFrame.
896+
# CSV with Categoricals should result in the same output
897+
# as when one would add a "normal" Series/DataFrame.
898898
s = Series(pd.Categorical(['a', 'b', 'b', 'a', 'a', 'c', 'c', 'c']))
899899
s2 = Series(['a', 'b', 'b', 'a', 'a', 'c', 'c', 'c'])
900900
res = StringIO()
901-
s.to_csv(res)
901+
902+
s.to_csv(res, header=False)
902903
exp = StringIO()
903-
s2.to_csv(exp)
904+
905+
s2.to_csv(exp, header=False)
904906
assert res.getvalue() == exp.getvalue()
905907

906908
df = DataFrame({"s": s})

0 commit comments

Comments
 (0)