diff --git a/doc/source/release.rst b/doc/source/release.rst index 592d6804a04ee..57fbbf631fec4 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -71,6 +71,8 @@ pandas 0.13 when the key is a column - Support for using a ``DatetimeIndex/PeriodsIndex`` directly in a datelike calculation e.g. s-s.index (:issue:`4629`) + - Better/cleaned up exceptions in core/common, io/excel and core/format. + (:issue:`4721`, :issue:`3954`) **API Changes** diff --git a/pandas/core/common.py b/pandas/core/common.py index a995881d5c1e9..6fc006eae74fe 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -541,7 +541,7 @@ def take_nd(arr, indexer, axis=0, out=None, fill_value=np.nan, mask_info = mask, needs_masking if needs_masking: if out is not None and out.dtype != dtype: - raise Exception('Incompatible type for fill_value') + raise TypeError('Incompatible type for fill_value') else: # if not, then depromote, set fill_value to dummy # (it won't be used but we don't want the cython code @@ -612,7 +612,7 @@ def take_2d_multi(arr, indexer, out=None, fill_value=np.nan, mask_info = (row_mask, col_mask), (row_needs, col_needs) if row_needs or col_needs: if out is not None and out.dtype != dtype: - raise Exception('Incompatible type for fill_value') + raise TypeError('Incompatible type for fill_value') else: # if not, then depromote, set fill_value to dummy # (it won't be used but we don't want the cython code @@ -857,8 +857,8 @@ def changeit(): # if we are trying to do something unsafe # like put a bigger dtype in a smaller one, use the smaller one - if change.dtype.itemsize < r.dtype.itemsize: - raise Exception( + if change.dtype.itemsize < r.dtype.itemsize: # pragma: no cover + raise AssertionError( "cannot change dtype of input to smaller size") change.dtype = r.dtype change[:] = r @@ -1159,8 +1159,8 @@ def interpolate_2d(values, method='pad', axis=0, limit=None, fill_value=None): # reshape a 1 dim if needed ndim = values.ndim if values.ndim == 1: - if axis != 0: - raise Exception("cannot interpolate on a ndim == 1 with axis != 0") + if axis != 0: # pragma: no cover + raise AssertionError("cannot interpolate on a ndim == 1 with axis != 0") values = values.reshape(tuple((1,) + values.shape)) if fill_value is None: @@ -1434,13 +1434,17 @@ def ensure_float(arr): return arr -def _mut_exclusive(arg1, arg2): - if arg1 is not None and arg2 is not None: - raise Exception('mutually exclusive arguments') - elif arg1 is not None: - return arg1 +def _mut_exclusive(**kwargs): + item1, item2 = kwargs.items() + label1, val1 = item1 + label2, val2 = item2 + if val1 is not None and val2 is not None: + raise TypeError('mutually exclusive arguments: %r and %r' % + (label1, label2)) + elif val1 is not None: + return val1 else: - return arg2 + return val2 def _any_none(*args): diff --git a/pandas/core/format.py b/pandas/core/format.py index e84916009bbe1..8077254de47ff 100644 --- a/pandas/core/format.py +++ b/pandas/core/format.py @@ -1,13 +1,13 @@ from __future__ import print_function # pylint: disable=W0141 -from pandas import compat import sys -from pandas.compat import StringIO, lzip, range, map, zip, reduce, u, OrderedDict from pandas.core.common import adjoin, isnull, notnull from pandas.core.index import Index, MultiIndex, _ensure_index from pandas import compat +from pandas.compat import(StringIO, lzip, range, map, zip, reduce, u, + OrderedDict) from pandas.util.terminal import get_terminal_size from pandas.core.config import get_option, set_option, reset_option import pandas.core.common as com @@ -356,7 +356,7 @@ def get_col_type(dtype): column_format = 'l%s' % ''.join(map(get_col_type, dtypes)) else: column_format = '%s' % ''.join(map(get_col_type, dtypes)) - elif not isinstance(column_format, compat.string_types): + elif not isinstance(column_format, compat.string_types): # pragma: no cover raise AssertionError(('column_format must be str or unicode, not %s' % type(column_format))) @@ -820,8 +820,9 @@ def __init__(self, obj, path_or_buf, sep=",", na_rep='', float_format=None, # validate mi options if self.has_mi_columns: - if cols is not None: - raise Exception("cannot specify cols with a multi_index on the columns") + # guarded against in to_csv itself + if cols is not None: # pragma: no cover + raise AssertionError("cannot specify cols with a multi_index on the columns") if cols is not None: if isinstance(cols,Index): diff --git a/pandas/io/excel.py b/pandas/io/excel.py index 4f998b49260e6..5ff42c5cd12a6 100644 --- a/pandas/io/excel.py +++ b/pandas/io/excel.py @@ -73,7 +73,7 @@ def __init__(self, path_or_buf, **kwds): import xlrd # throw an ImportError if we need to ver = tuple(map(int, xlrd.__VERSION__.split(".")[:2])) - if ver < (0, 9): + if ver < (0, 9): # pragma: no cover raise ImportError("pandas requires xlrd >= 0.9.0 for excel " "support, current version " + xlrd.__VERSION__) @@ -382,8 +382,8 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0): if sheet_name is None: sheet_name = self.cur_sheet if sheet_name is None: # pragma: no cover - raise Exception('Must pass explicit sheet_name or set ' - 'cur_sheet property') + raise ValueError('Must pass explicit sheet_name or set ' + 'cur_sheet property') if self.use_xlsx: self._writecells_xlsx(cells, sheet_name, startrow, startcol) else: diff --git a/pandas/sparse/panel.py b/pandas/sparse/panel.py index ab946090c8ea8..261443a95b111 100644 --- a/pandas/sparse/panel.py +++ b/pandas/sparse/panel.py @@ -319,8 +319,8 @@ def reindex(self, major=None, items=None, minor=None, major_axis=None, ------- reindexed : SparsePanel """ - major = com._mut_exclusive(major, major_axis) - minor = com._mut_exclusive(minor, minor_axis) + major = com._mut_exclusive(major=major, major_axis=major_axis) + minor = com._mut_exclusive(minor=minor, minor_axis=minor_axis) if com._all_none(items, major, minor): raise ValueError('Must specify at least one axis') diff --git a/pandas/tests/test_common.py b/pandas/tests/test_common.py index 799cdd31c0a65..e2051eba7f42a 100644 --- a/pandas/tests/test_common.py +++ b/pandas/tests/test_common.py @@ -20,6 +20,14 @@ _multiprocess_can_split_ = True +def test_mut_exclusive(): + msg = "mutually exclusive arguments: '[ab]' and '[ab]'" + with tm.assertRaisesRegexp(TypeError, msg): + com._mut_exclusive(a=1, b=2) + assert com._mut_exclusive(a=1, b=None) == 1 + assert com._mut_exclusive(major=None, major_axis=None) is None + + def test_is_sequence(): is_seq = com._is_sequence assert(is_seq((1, 2))) @@ -360,6 +368,8 @@ def test_is_recompilable(): class TestTake(unittest.TestCase): + # standard incompatible fill error + fill_error = re.compile("Incompatible type for fill_value") _multiprocess_can_split_ = True @@ -381,8 +391,8 @@ def _test_dtype(dtype, can_hold_na): expected[3] = np.nan tm.assert_almost_equal(out, expected) else: - self.assertRaises(Exception, com.take_1d, data, - indexer, out=out) + with tm.assertRaisesRegexp(TypeError, self.fill_error): + com.take_1d(data, indexer, out=out) # no exception o/w data.take(indexer, out=out) @@ -466,13 +476,11 @@ def _test_dtype(dtype, can_hold_na): tm.assert_almost_equal(out0, expected0) tm.assert_almost_equal(out1, expected1) else: - self.assertRaises(Exception, com.take_nd, data, - indexer, out=out0, axis=0) - self.assertRaises(Exception, com.take_nd, data, - indexer, out=out1, axis=1) - # no exception o/w - data.take(indexer, out=out0, axis=0) - data.take(indexer, out=out1, axis=1) + for i, out in enumerate([out0, out1]): + with tm.assertRaisesRegexp(TypeError, self.fill_error): + com.take_nd(data, indexer, out=out, axis=i) + # no exception o/w + data.take(indexer, out=out, axis=i) _test_dtype(np.float64, True) _test_dtype(np.float32, True) @@ -572,16 +580,11 @@ def _test_dtype(dtype, can_hold_na): tm.assert_almost_equal(out1, expected1) tm.assert_almost_equal(out2, expected2) else: - self.assertRaises(Exception, com.take_nd, data, - indexer, out=out0, axis=0) - self.assertRaises(Exception, com.take_nd, data, - indexer, out=out1, axis=1) - self.assertRaises(Exception, com.take_nd, data, - indexer, out=out2, axis=2) - # no exception o/w - data.take(indexer, out=out0, axis=0) - data.take(indexer, out=out1, axis=1) - data.take(indexer, out=out2, axis=2) + for i, out in enumerate([out0, out1, out2]): + with tm.assertRaisesRegexp(TypeError, self.fill_error): + com.take_nd(data, indexer, out=out, axis=i) + # no exception o/w + data.take(indexer, out=out, axis=i) _test_dtype(np.float64, True) _test_dtype(np.float32, True)