diff --git a/doc/source/whatsnew/v0.18.0.txt b/doc/source/whatsnew/v0.18.0.txt index 8fe7a5753f1d1..cc2bb47dea3bd 100644 --- a/doc/source/whatsnew/v0.18.0.txt +++ b/doc/source/whatsnew/v0.18.0.txt @@ -196,3 +196,4 @@ Bug Fixes - Bug in ``pd.rolling_median`` where memory allocation failed even with sufficient memory (:issue:`11696`) - Bug in ``df.replace`` while replacing value in mixed dtype ``Dataframe`` (:issue:`11698`) +- Bug in ``to_numeric`` where it does not raise if input is more than one dimension (:issue:`11776`) diff --git a/pandas/tools/tests/test_util.py b/pandas/tools/tests/test_util.py index 72ce7d8659157..a00b27c81e668 100644 --- a/pandas/tools/tests/test_util.py +++ b/pandas/tools/tests/test_util.py @@ -113,7 +113,6 @@ def test_error(self): expected = pd.Series([1, -3.14, np.nan]) tm.assert_series_equal(res, expected) - def test_list(self): s = ['1', '-3.14', '7'] res = to_numeric(s) @@ -136,6 +135,14 @@ def test_all_nan(self): expected = pd.Series([np.nan, np.nan, np.nan]) tm.assert_series_equal(res, expected) + def test_type_check(self): + # GH 11776 + df = pd.DataFrame({'a': [1, -3.14, 7], 'b': ['4', '5', '6']}) + with tm.assertRaisesRegexp(TypeError, "1-d array"): + to_numeric(df) + for errors in ['ignore', 'raise', 'coerce']: + with tm.assertRaisesRegexp(TypeError, "1-d array"): + to_numeric(df, errors=errors) if __name__ == '__main__': nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'], diff --git a/pandas/tools/util.py b/pandas/tools/util.py index 925c23255b5f5..c3ebadfdb9e0b 100644 --- a/pandas/tools/util.py +++ b/pandas/tools/util.py @@ -56,7 +56,7 @@ def to_numeric(arg, errors='raise'): Parameters ---------- - arg : list, tuple or array of objects, or Series + arg : list, tuple, 1-d array, or Series errors : {'ignore', 'raise', 'coerce'}, default 'raise' - If 'raise', then invalid parsing will raise an exception - If 'coerce', then invalid parsing will be set as NaN @@ -84,6 +84,8 @@ def to_numeric(arg, errors='raise'): index, name = arg.index, arg.name elif isinstance(arg, (list, tuple)): arg = np.array(arg, dtype='O') + elif getattr(arg, 'ndim', 1) > 1: + raise TypeError('arg must be a list, tuple, 1-d array, or Series') conv = arg arg = com._ensure_object(arg) diff --git a/pandas/tseries/tests/test_period.py b/pandas/tseries/tests/test_period.py index c6fb54ceec644..db0ee4696d289 100644 --- a/pandas/tseries/tests/test_period.py +++ b/pandas/tseries/tests/test_period.py @@ -2984,6 +2984,16 @@ def test_to_datetime_1703(self): result = index.to_datetime() self.assertEqual(result[0], Timestamp('1/1/2012')) + def test_to_datetime_dimensions(self): + # GH 11776 + df = DataFrame({'a': ['1/1/2012', '1/2/2012'], + 'b': ['12/30/2012', '12/31/2012']}) + with tm.assertRaisesRegexp(TypeError, "1-d array"): + to_datetime(df) + for errors in ['ignore', 'raise', 'coerce']: + with tm.assertRaisesRegexp(TypeError, "1-d array"): + to_datetime(df, errors=errors) + def test_get_loc_msg(self): idx = period_range('2000-1-1', freq='A', periods=10) bad_period = Period('2012', 'A') diff --git a/pandas/tseries/tests/test_timedeltas.py b/pandas/tseries/tests/test_timedeltas.py index 4bff2e3c5c2cd..67f1b12ec8ead 100644 --- a/pandas/tseries/tests/test_timedeltas.py +++ b/pandas/tseries/tests/test_timedeltas.py @@ -444,26 +444,36 @@ def check(value): def test_timedelta_range(self): - expected = to_timedelta(np.arange(5),unit='D') - result = timedelta_range('0 days',periods=5,freq='D') + expected = to_timedelta(np.arange(5), unit='D') + result = timedelta_range('0 days', periods=5, freq='D') tm.assert_index_equal(result, expected) - expected = to_timedelta(np.arange(11),unit='D') - result = timedelta_range('0 days','10 days',freq='D') + expected = to_timedelta(np.arange(11), unit='D') + result = timedelta_range('0 days', '10 days', freq='D') tm.assert_index_equal(result, expected) - expected = to_timedelta(np.arange(5),unit='D') + Second(2) + Day() - result = timedelta_range('1 days, 00:00:02','5 days, 00:00:02',freq='D') + expected = to_timedelta(np.arange(5), unit='D') + Second(2) + Day() + result = timedelta_range('1 days, 00:00:02', '5 days, 00:00:02', freq='D') tm.assert_index_equal(result, expected) - expected = to_timedelta([1,3,5,7,9],unit='D') + Second(2) - result = timedelta_range('1 days, 00:00:02',periods=5,freq='2D') + expected = to_timedelta([1,3,5,7,9], unit='D') + Second(2) + result = timedelta_range('1 days, 00:00:02', periods=5, freq='2D') tm.assert_index_equal(result, expected) - expected = to_timedelta(np.arange(50),unit='T')*30 - result = timedelta_range('0 days',freq='30T',periods=50) + expected = to_timedelta(np.arange(50), unit='T') * 30 + result = timedelta_range('0 days', freq='30T', periods=50) tm.assert_index_equal(result, expected) + # GH 11776 + arr = np.arange(10).reshape(2, 5) + df = pd.DataFrame(np.arange(10).reshape(2, 5)) + for arg in (arr, df): + with tm.assertRaisesRegexp(TypeError, "1-d array"): + to_timedelta(arg) + for errors in ['ignore', 'raise', 'coerce']: + with tm.assertRaisesRegexp(TypeError, "1-d array"): + to_timedelta(arg, errors=errors) + # issue10583 df = pd.DataFrame(np.random.normal(size=(10,4))) df.index = pd.timedelta_range(start='0s', periods=10, freq='s') diff --git a/pandas/tseries/timedeltas.py b/pandas/tseries/timedeltas.py index 11200bb2540cd..9a21d426c3aab 100644 --- a/pandas/tseries/timedeltas.py +++ b/pandas/tseries/timedeltas.py @@ -19,7 +19,7 @@ def to_timedelta(arg, unit='ns', box=True, errors='raise', coerce=None): Parameters ---------- - arg : string, timedelta, array of strings (with possible NAs) + arg : string, timedelta, list, tuple, 1-d array, or Series unit : unit of the arg (D,h,m,s,ms,us,ns) denote the unit, which is an integer/float number box : boolean, default True - If True returns a Timedelta/TimedeltaIndex of the results @@ -37,7 +37,7 @@ def to_timedelta(arg, unit='ns', box=True, errors='raise', coerce=None): def _convert_listlike(arg, box, unit, name=None): - if isinstance(arg, (list,tuple)) or ((hasattr(arg,'__iter__') and not hasattr(arg,'dtype'))): + if isinstance(arg, (list, tuple)) or not hasattr(arg, 'dtype'): arg = np.array(list(arg), dtype='O') # these are shortcutable @@ -62,8 +62,10 @@ def _convert_listlike(arg, box, unit, name=None): return Series(values, index=arg.index, name=arg.name, dtype='m8[ns]') elif isinstance(arg, ABCIndexClass): return _convert_listlike(arg, box=box, unit=unit, name=arg.name) - elif is_list_like(arg): + elif is_list_like(arg) and getattr(arg, 'ndim', 1) == 1: return _convert_listlike(arg, box=box, unit=unit) + elif getattr(arg, 'ndim', 1) > 1: + raise TypeError('arg must be a string, timedelta, list, tuple, 1-d array, or Series') # ...so it must be a scalar value. Return scalar. return _coerce_scalar_to_timedelta_type(arg, unit=unit, box=box, errors=errors) diff --git a/pandas/tseries/tools.py b/pandas/tseries/tools.py index c38878fe398e4..995c920358b9f 100644 --- a/pandas/tseries/tools.py +++ b/pandas/tseries/tools.py @@ -188,7 +188,7 @@ def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, Parameters ---------- - arg : string, datetime, array of strings (with possible NAs) + arg : string, datetime, list, tuple, 1-d array, or Series errors : {'ignore', 'raise', 'coerce'}, default 'raise' - If 'raise', then invalid parsing will raise an exception - If 'coerce', then invalid parsing will be set as NaT @@ -288,7 +288,7 @@ def _to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, def _convert_listlike(arg, box, format, name=None): - if isinstance(arg, (list,tuple)): + if isinstance(arg, (list, tuple)): arg = np.array(arg, dtype='O') # these are shortcutable @@ -312,8 +312,9 @@ def _convert_listlike(arg, box, format, name=None): result = arg.astype('datetime64[ns]') if box: return DatetimeIndex(result, tz='utc' if utc else None, name=name) - return result + elif getattr(arg, 'ndim', 1) > 1: + raise TypeError('arg must be a string, datetime, list, tuple, 1-d array, or Series') arg = com._ensure_object(arg) require_iso8601 = False