Skip to content

Commit 58199c5

Browse files
gfyoungjorisvandenbossche
authored andcommitted
API: Raise FileNotFoundError for nonexistent files (pandas-dev#14116)
For a nonexistent file, raise the more specific FileNotFoundError for Python >= 3.3 in read_csv, read_table, and read_hdf. This error is backported to Python 2.x as IOError. Closes pandas-devgh-14086.
1 parent 306e647 commit 58199c5

File tree

6 files changed

+16
-6
lines changed

6 files changed

+16
-6
lines changed

doc/source/whatsnew/v0.19.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ API changes
455455
- ``Timestamp.to_pydatetime`` will issue a ``UserWarning`` when ``warn=True``, and the instance has a non-zero number of nanoseconds (:issue:`14101`)
456456
- ``Panel.to_sparse`` will raise a ``NotImplementedError`` exception when called (:issue:`13778`)
457457
- ``Index.reshape`` will raise a ``NotImplementedError`` exception when called (:issue:`12882`)
458+
- ``pd.read_csv()``, ``pd.read_table()``, and ``pd.read_hdf()`` raise the builtin ``FileNotFoundError`` exception for Python 3.x when called on a nonexistent file, and this is back-ported as IOError in Python 2.x (:issue:`14086`)
458459
- Non-convertible dates in an excel date column will be returned without conversion and the column will be ``object`` dtype, rather than raising an exception (:issue:`10001`)
459460
- ``eval``'s upcasting rules for ``float32`` types have been updated to be more consistent with NumPy's rules. New behavior will not upcast to ``float64`` if you multiply a pandas ``float32`` object by a scalar float64. (:issue:`12388`)
460461
- An ``UnsupportedFunctionCall`` error is now raised if NumPy ufuncs like ``np.mean`` are called on groupby or resample objects (:issue:`12811`)

pandas/compat/__init__.py

+6
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ def signature(f):
107107
long = int
108108
unichr = chr
109109

110+
# This was introduced in Python 3.3, but we don't support
111+
# Python 3.x < 3.4, so checking PY3 is safe.
112+
FileNotFoundError = FileNotFoundError
113+
110114
# list-producing versions of the major Python iterating functions
111115
def lrange(*args, **kwargs):
112116
return list(range(*args, **kwargs))
@@ -125,6 +129,8 @@ def lfilter(*args, **kwargs):
125129
import re
126130
_name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
127131

132+
FileNotFoundError = IOError
133+
128134
def isidentifier(s, dotted=False):
129135
return bool(_name_re.match(s))
130136

pandas/io/pytables.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,8 @@ def read_hdf(path_or_buf, key=None, **kwargs):
322322
exists = False
323323

324324
if not exists:
325-
raise IOError('File %s does not exist' % path_or_buf)
325+
raise compat.FileNotFoundError(
326+
'File %s does not exist' % path_or_buf)
326327

327328
# can't auto open/close if we are using an iterator
328329
# so delegate to the iterator

pandas/io/tests/parser/common.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -654,9 +654,10 @@ def test_file(self):
654654
tm.assert_frame_equal(url_table, local_table)
655655

656656
def test_nonexistent_path(self):
657-
# don't segfault pls #2428
657+
# gh-2428: pls no segfault
658+
# gh-14086: raise more helpful FileNotFoundError
658659
path = '%s.csv' % tm.rands(10)
659-
self.assertRaises(IOError, self.read_csv, path)
660+
self.assertRaises(compat.FileNotFoundError, self.read_csv, path)
660661

661662
def test_missing_trailing_delimiters(self):
662663
data = """A,B,C,D

pandas/io/tests/test_pytables.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,8 @@ def test_api(self):
339339

340340
# File path doesn't exist
341341
path = ""
342-
self.assertRaises(IOError, read_hdf, path, 'df')
342+
self.assertRaises(compat.FileNotFoundError,
343+
read_hdf, path, 'df')
343344

344345
def test_api_default_format(self):
345346

pandas/parser.pyx

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import numpy as np
3434
cimport util
3535

3636
import pandas.lib as lib
37+
import pandas.compat as compat
3738
from pandas.types.common import (is_categorical_dtype, CategoricalDtype,
3839
is_integer_dtype, is_float_dtype,
3940
is_bool_dtype, is_object_dtype,
@@ -631,7 +632,6 @@ cdef class TextReader:
631632
raise ValueError('Multiple files found in compressed '
632633
'zip file %s', str(zip_names))
633634
elif self.compression == 'xz':
634-
from pandas import compat
635635
lzma = compat.import_lzma()
636636

637637
if isinstance(source, basestring):
@@ -663,7 +663,7 @@ cdef class TextReader:
663663

664664
if ptr == NULL:
665665
if not os.path.exists(source):
666-
raise IOError('File %s does not exist' % source)
666+
raise compat.FileNotFoundError('File %s does not exist' % source)
667667
raise IOError('Initializing from file failed')
668668

669669
self.parser.source = ptr

0 commit comments

Comments
 (0)