Skip to content

Commit d21345f

Browse files
committed
API: Deprecate skip_footer in read_csv
1 parent cc216ad commit d21345f

File tree

8 files changed

+54
-41
lines changed

8 files changed

+54
-41
lines changed

doc/source/io.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ skiprows : list-like or integer, default ``None``
175175
of the file.
176176
skipfooter : int, default ``0``
177177
Number of lines at bottom of file to skip (unsupported with engine='c').
178+
skip_footer : int, default ``0``
179+
DEPRECATED: use the ``skipfooter`` parameter instead, as they are identical
178180
nrows : int, default ``None``
179181
Number of rows of file to read. Useful for reading pieces of large files.
180182
low_memory : boolean, default ``True``
@@ -1411,7 +1413,7 @@ back to python if C-unsupported options are specified. Currently, C-unsupported
14111413
options include:
14121414

14131415
- ``sep`` other than a single character (e.g. regex separators)
1414-
- ``skip_footer``
1416+
- ``skipfooter``
14151417
- ``sep=None`` with ``delim_whitespace=False``
14161418

14171419
Specifying any of the above options will produce a ``ParserWarning`` unless the

doc/source/whatsnew/v0.19.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ Deprecations
612612
- ``compact_ints`` and ``use_unsigned`` have been deprecated in ``pd.read_csv()`` and will be removed in a future version (:issue:`13320`)
613613
- ``buffer_lines`` has been deprecated in ``pd.read_csv()`` and will be removed in a future version (:issue:`13360`)
614614
- ``as_recarray`` has been deprecated in ``pd.read_csv()`` and will be removed in a future version (:issue:`13373`)
615+
- ``skip_footer`` has been deprecated in ``pd.read_csv()`` in favor of ``skipfooter`` and will be removed in a future version (:issue:`13349`)
615616
- top-level ``pd.ordered_merge()`` has been renamed to ``pd.merge_ordered()`` and the original name will be removed in a future version (:issue:`13358`)
616617
- ``Timestamp.offset`` property (and named arg in the constructor), has been deprecated in favor of ``freq`` (:issue:`12160`)
617618
- ``pd.tseries.util.pivot_annual`` is deprecated. Use ``pivot_table`` as alternative, an example is :ref:`here <cookbook.pivot>` (:issue:`736`)

pandas/io/excel.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ def _parse_cell(cell_contents, cell_typ):
473473
parse_dates=parse_dates,
474474
date_parser=date_parser,
475475
skiprows=skiprows,
476-
skip_footer=skip_footer,
476+
skipfooter=skip_footer,
477477
squeeze=squeeze,
478478
**kwds)
479479

pandas/io/parsers.py

+24-19
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@
125125
at the start of the file
126126
skipfooter : int, default 0
127127
Number of lines at bottom of file to skip (Unsupported with engine='c')
128+
skip_footer : int, default 0
129+
DEPRECATED: use the `skipfooter` parameter instead, as they are identical
128130
nrows : int, default None
129131
Number of rows of file to read. Useful for reading pieces of large files
130132
na_values : str or list-like or dict, default None
@@ -341,9 +343,6 @@ def _validate_nrows(nrows):
341343
def _read(filepath_or_buffer, kwds):
342344
"Generic reader of line files."
343345
encoding = kwds.get('encoding', None)
344-
skipfooter = kwds.pop('skipfooter', None)
345-
if skipfooter is not None:
346-
kwds['skip_footer'] = skipfooter
347346

348347
# If the input could be a filename, check for a recognizable compression
349348
# extension. If we're reading from a URL, the `get_filepath_or_buffer`
@@ -411,8 +410,8 @@ def _read(filepath_or_buffer, kwds):
411410
'na_values': None,
412411
'true_values': None,
413412
'false_values': None,
414-
'skip_footer': 0,
415413
'converters': None,
414+
'skipfooter': 0,
416415

417416
'keep_default_na': True,
418417
'thousands': None,
@@ -461,7 +460,7 @@ def _read(filepath_or_buffer, kwds):
461460
'widths': None,
462461
}
463462

464-
_c_unsupported = set(['skip_footer'])
463+
_c_unsupported = set(['skipfooter'])
465464
_python_unsupported = set([
466465
'low_memory',
467466
'buffer_lines',
@@ -503,7 +502,6 @@ def parser_f(filepath_or_buffer,
503502
false_values=None,
504503
skipinitialspace=False,
505504
skiprows=None,
506-
skipfooter=None,
507505
nrows=None,
508506

509507
# NA and Missing Data Handling
@@ -541,8 +539,8 @@ def parser_f(filepath_or_buffer,
541539
error_bad_lines=True,
542540
warn_bad_lines=True,
543541

544-
# Deprecated
545-
skip_footer=0,
542+
skipfooter=0,
543+
skip_footer=0, # deprecated
546544

547545
# Internal
548546
doublequote=True,
@@ -570,6 +568,13 @@ def parser_f(filepath_or_buffer,
570568
engine = 'c'
571569
engine_specified = False
572570

571+
if skip_footer != 0:
572+
warnings.warn("The 'skip_footer' argument has "
573+
"been deprecated and will be removed "
574+
"in a future version. Please use the "
575+
"'skipfooter' argument instead.",
576+
FutureWarning, stacklevel=2)
577+
573578
kwds = dict(delimiter=delimiter,
574579
engine=engine,
575580
dialect=dialect,
@@ -767,9 +772,9 @@ def _clean_options(self, options, engine):
767772

768773
# C engine not supported yet
769774
if engine == 'c':
770-
if options['skip_footer'] > 0:
775+
if options['skipfooter'] > 0:
771776
fallback_reason = "the 'c' engine does not support"\
772-
" skip_footer"
777+
" skipfooter"
773778
engine = 'python'
774779

775780
if sep is None and not delim_whitespace:
@@ -902,8 +907,8 @@ def _failover_to_python(self):
902907

903908
def read(self, nrows=None):
904909
if nrows is not None:
905-
if self.options.get('skip_footer'):
906-
raise ValueError('skip_footer not supported for iteration')
910+
if self.options.get('skipfooter'):
911+
raise ValueError('skipfooter not supported for iteration')
907912

908913
ret = self._engine.read(nrows)
909914

@@ -1578,7 +1583,7 @@ def TextParser(*args, **kwds):
15781583
date_parser : function, default None
15791584
skiprows : list of integers
15801585
Row numbers to skip
1581-
skip_footer : int
1586+
skipfooter : int
15821587
Number of line at bottom of file to skip
15831588
converters : dict, default None
15841589
Dict of functions for converting values in certain columns. Keys can
@@ -1691,7 +1696,7 @@ def __init__(self, f, **kwds):
16911696
self.memory_map = kwds['memory_map']
16921697
self.skiprows = kwds['skiprows']
16931698

1694-
self.skip_footer = kwds['skip_footer']
1699+
self.skipfooter = kwds['skipfooter']
16951700
self.delimiter = kwds['delimiter']
16961701

16971702
self.quotechar = kwds['quotechar']
@@ -2323,7 +2328,7 @@ def _rows_to_cols(self, content):
23232328
content, min_width=col_len).T)
23242329
zip_len = len(zipped_content)
23252330

2326-
if self.skip_footer < 0:
2331+
if self.skipfooter < 0:
23272332
raise ValueError('skip footer cannot be negative')
23282333

23292334
# Loop through rows to verify lengths are correct.
@@ -2336,8 +2341,8 @@ def _rows_to_cols(self, content):
23362341
break
23372342

23382343
footers = 0
2339-
if self.skip_footer:
2340-
footers = self.skip_footer
2344+
if self.skipfooter:
2345+
footers = self.skipfooter
23412346

23422347
row_num = self.pos - (len(content) - i + footers)
23432348

@@ -2423,8 +2428,8 @@ def _get_lines(self, rows=None):
24232428
else:
24242429
lines = new_rows
24252430

2426-
if self.skip_footer:
2427-
lines = lines[:-self.skip_footer]
2431+
if self.skipfooter:
2432+
lines = lines[:-self.skipfooter]
24282433

24292434
lines = self._check_comments(lines)
24302435
if self.skip_blank_lines:

pandas/io/tests/parser/common.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,9 @@ def test_malformed(self):
218218
skiprows=[2])
219219
it.read()
220220

221-
# skip_footer is not supported with the C parser yet
221+
# skipfooter is not supported with the C parser yet
222222
if self.engine == 'python':
223-
# skip_footer
223+
# skipfooter
224224
data = """ignore
225225
A,B,C
226226
1,2,3 # comment
@@ -232,7 +232,7 @@ def test_malformed(self):
232232
with tm.assertRaisesRegexp(Exception, msg):
233233
self.read_table(StringIO(data), sep=',',
234234
header=1, comment='#',
235-
skip_footer=1)
235+
skipfooter=1)
236236

237237
def test_quoting(self):
238238
bad_line_small = """printer\tresult\tvariant_name
@@ -524,11 +524,11 @@ def test_iterator(self):
524524
self.assertEqual(len(result), 3)
525525
tm.assert_frame_equal(pd.concat(result), expected)
526526

527-
# skip_footer is not supported with the C parser yet
527+
# skipfooter is not supported with the C parser yet
528528
if self.engine == 'python':
529-
# test bad parameter (skip_footer)
529+
# test bad parameter (skipfooter)
530530
reader = self.read_csv(StringIO(self.data1), index_col=0,
531-
iterator=True, skip_footer=True)
531+
iterator=True, skipfooter=True)
532532
self.assertRaises(ValueError, reader.read, 3)
533533

534534
def test_pass_names_with_index(self):

pandas/io/tests/parser/python_parser_only.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def test_single_line(self):
9898
finally:
9999
sys.stdout = sys.__stdout__
100100

101-
def test_skip_footer(self):
101+
def test_skipfooter(self):
102102
# see gh-6607
103103
data = """A,B,C
104104
1,2,3
@@ -107,7 +107,7 @@ def test_skip_footer(self):
107107
want to skip this
108108
also also skip this
109109
"""
110-
result = self.read_csv(StringIO(data), skip_footer=2)
110+
result = self.read_csv(StringIO(data), skipfooter=2)
111111
no_footer = '\n'.join(data.split('\n')[:-3])
112112
expected = self.read_csv(StringIO(no_footer))
113113
tm.assert_frame_equal(result, expected)

pandas/io/tests/parser/test_unsupported.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def test_c_engine(self):
5252
with tm.assertRaisesRegexp(ValueError, msg):
5353
read_table(StringIO(data), sep='\s', dtype={'a': float})
5454
with tm.assertRaisesRegexp(ValueError, msg):
55-
read_table(StringIO(data), skip_footer=1, dtype={'a': float})
55+
read_table(StringIO(data), skipfooter=1, dtype={'a': float})
5656

5757
# specify C engine with unsupported options (raise)
5858
with tm.assertRaisesRegexp(ValueError, msg):
@@ -61,15 +61,15 @@ def test_c_engine(self):
6161
with tm.assertRaisesRegexp(ValueError, msg):
6262
read_table(StringIO(data), engine='c', sep='\s')
6363
with tm.assertRaisesRegexp(ValueError, msg):
64-
read_table(StringIO(data), engine='c', skip_footer=1)
64+
read_table(StringIO(data), engine='c', skipfooter=1)
6565

6666
# specify C-unsupported options without python-unsupported options
6767
with tm.assert_produces_warning(parsers.ParserWarning):
6868
read_table(StringIO(data), sep=None, delim_whitespace=False)
6969
with tm.assert_produces_warning(parsers.ParserWarning):
7070
read_table(StringIO(data), sep='\s')
7171
with tm.assert_produces_warning(parsers.ParserWarning):
72-
read_table(StringIO(data), skip_footer=1)
72+
read_table(StringIO(data), skipfooter=1)
7373

7474
text = """ A B C D E
7575
one two three four
@@ -127,15 +127,20 @@ def test_deprecated_args(self):
127127
'as_recarray': True,
128128
'buffer_lines': True,
129129
'compact_ints': True,
130+
'skip_footer': True,
130131
'use_unsigned': True,
131132
}
132133

133134
engines = 'c', 'python'
134135

135136
for engine in engines:
136137
for arg, non_default_val in deprecated.items():
138+
if engine == 'c' and arg == 'skip_footer':
139+
# unsupported --> exception is raised
140+
continue
141+
137142
if engine == 'python' and arg == 'buffer_lines':
138-
# unsupported --> exception is raised first
143+
# unsupported --> exception is raised
139144
continue
140145

141146
with tm.assert_produces_warning(

pandas/parser.pyx

+8-8
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ cdef extern from "parser/tokenizer.h":
165165

166166
void *skipset
167167
int64_t skip_first_N_rows
168-
int skip_footer
168+
int skipfooter
169169
double (*converter)(const char *, char **, char, char, char, int) nogil
170170

171171
# error handling
@@ -270,7 +270,7 @@ cdef class TextReader:
270270
kh_str_t *true_set
271271

272272
cdef public:
273-
int leading_cols, table_width, skip_footer, buffer_lines
273+
int leading_cols, table_width, skipfooter, buffer_lines
274274
object allow_leading_cols
275275
object delimiter, converters, delim_whitespace
276276
object na_values
@@ -338,7 +338,7 @@ cdef class TextReader:
338338
low_memory=False,
339339
buffer_lines=None,
340340
skiprows=None,
341-
skip_footer=0,
341+
skipfooter=0,
342342
verbose=False,
343343
mangle_dupe_cols=True,
344344
tupleize_cols=False,
@@ -418,15 +418,15 @@ cdef class TextReader:
418418
if skiprows is not None:
419419
self._make_skiprow_set()
420420

421-
self.skip_footer = skip_footer
421+
self.skipfooter = skipfooter
422422

423423
# suboptimal
424424
if usecols is not None:
425425
self.has_usecols = 1
426426
self.usecols = set(usecols)
427427

428428
# XXX
429-
if skip_footer > 0:
429+
if skipfooter > 0:
430430
self.parser.error_bad_lines = 0
431431
self.parser.warn_bad_lines = 0
432432

@@ -912,8 +912,8 @@ cdef class TextReader:
912912
if buffered_lines < irows:
913913
self._tokenize_rows(irows - buffered_lines)
914914

915-
if self.skip_footer > 0:
916-
raise ValueError('skip_footer can only be used to read '
915+
if self.skipfooter > 0:
916+
raise ValueError('skipfooter can only be used to read '
917917
'the whole file')
918918
else:
919919
with nogil:
@@ -926,7 +926,7 @@ cdef class TextReader:
926926

927927
if status < 0:
928928
raise_parser_error('Error tokenizing data', self.parser)
929-
footer = self.skip_footer
929+
footer = self.skipfooter
930930

931931
if self.parser_start == self.parser.lines:
932932
raise StopIteration

0 commit comments

Comments
 (0)