From f4486393ea0c0953769aa0237b6186324e85aa07 Mon Sep 17 00:00:00 2001 From: gfyoung Date: Sat, 12 Nov 2016 23:52:21 -0500 Subject: [PATCH] Standardize function signatures Standardize the following function signatures: 1) repeat(reps, *args, **kwargs) 2) searchsorted(value, side='left', sorter=None) Closes gh-12662. --- doc/source/whatsnew/v0.20.0.txt | 4 ++++ pandas/core/base.py | 15 ++++++++------- pandas/core/categorical.py | 7 ++++--- pandas/core/series.py | 16 +++++++++------- pandas/indexes/base.py | 7 ++++--- pandas/indexes/multi.py | 5 +++-- pandas/tests/indexes/test_base.py | 19 +++++++++++++++---- pandas/tests/indexes/test_multi.py | 4 ++++ pandas/tests/series/test_analytics.py | 17 +++++++++++++++++ pandas/tests/test_categorical.py | 5 +++++ pandas/tseries/index.py | 13 +++++++------ pandas/tseries/period.py | 22 ++++++++++++---------- pandas/tseries/tdi.py | 15 ++++++++------- pandas/tseries/tests/test_period.py | 3 +++ 14 files changed, 103 insertions(+), 49 deletions(-) diff --git a/doc/source/whatsnew/v0.20.0.txt b/doc/source/whatsnew/v0.20.0.txt index 65b62601c7022..985076880c87f 100644 --- a/doc/source/whatsnew/v0.20.0.txt +++ b/doc/source/whatsnew/v0.20.0.txt @@ -54,6 +54,10 @@ Other API Changes Deprecations ^^^^^^^^^^^^ +- ``Series.repeat()`` has deprecated the ``reps`` parameter in favor of ``repeats`` (:issue:`12662`) +- ``Index.repeat()`` and ``MultiIndex.repeat()`` have deprecated the ``n`` parameter in favor of ``repeats`` (:issue:`12662`) +- ``Categorical.searchsorted()`` and ``Series.searchsorted()`` have deprecated the ``v`` parameter in favor of ``value`` (:issue:`12662`) +- ``TimedeltaIndex.searchsorted()``, ``DatetimeIndex.searchsorted()``, and ``PeriodIndex.searchsorted()`` have deprecated the ``key`` parameter in favor of ``value`` (:issue:`12662`) diff --git a/pandas/core/base.py b/pandas/core/base.py index b9a70292498e4..d412349447794 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -1091,12 +1091,12 @@ def factorize(self, sort=False, na_sentinel=-1): """Find indices where elements should be inserted to maintain order. Find the indices into a sorted %(klass)s `self` such that, if the - corresponding elements in `v` were inserted before the indices, the - order of `self` would be preserved. + corresponding elements in `value` were inserted before the indices, + the order of `self` would be preserved. Parameters ---------- - %(value)s : array_like + value : array_like Values to insert into `self`. side : {'left', 'right'}, optional If 'left', the index of the first suitable location found is given. @@ -1109,7 +1109,7 @@ def factorize(self, sort=False, na_sentinel=-1): Returns ------- indices : array of ints - Array of insertion points with the same shape as `v`. + Array of insertion points with the same shape as `value`. See Also -------- @@ -1149,11 +1149,12 @@ def factorize(self, sort=False, na_sentinel=-1): array([3, 4]) # eggs before milk """) - @Substitution(klass='IndexOpsMixin', value='key') + @Substitution(klass='IndexOpsMixin') @Appender(_shared_docs['searchsorted']) - def searchsorted(self, key, side='left', sorter=None): + @deprecate_kwarg(old_arg_name='key', new_arg_name='value') + def searchsorted(self, value, side='left', sorter=None): # needs coercion on the key (DatetimeIndex does already) - return self.values.searchsorted(key, side=side, sorter=sorter) + return self.values.searchsorted(value, side=side, sorter=sorter) _shared_docs['drop_duplicates'] = ( """Return %(klass)s with duplicate values removed diff --git a/pandas/core/categorical.py b/pandas/core/categorical.py index fd1a23a5bab7f..922fb84684729 100644 --- a/pandas/core/categorical.py +++ b/pandas/core/categorical.py @@ -1076,9 +1076,10 @@ def memory_usage(self, deep=False): """ return self._codes.nbytes + self._categories.memory_usage(deep=deep) - @Substitution(klass='Categorical', value='v') + @Substitution(klass='Categorical') @Appender(_shared_docs['searchsorted']) - def searchsorted(self, v, side='left', sorter=None): + @deprecate_kwarg(old_arg_name='v', new_arg_name='value') + def searchsorted(self, value, side='left', sorter=None): if not self.ordered: raise ValueError("Categorical not ordered\nyou can use " ".as_ordered() to change the Categorical to an " @@ -1086,7 +1087,7 @@ def searchsorted(self, v, side='left', sorter=None): from pandas.core.series import Series values_as_codes = self.categories.values.searchsorted( - Series(v).values, side=side) + Series(value).values, side=side) return self.codes.searchsorted(values_as_codes, sorter=sorter) diff --git a/pandas/core/series.py b/pandas/core/series.py index 44d1703fb9b8a..56a3933bded3b 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -832,18 +832,19 @@ def _set_values(self, key, value): self._data = self._data.setitem(indexer=key, value=value) self._maybe_update_cacher() - def repeat(self, reps, *args, **kwargs): + @deprecate_kwarg(old_arg_name='reps', new_arg_name='repeats') + def repeat(self, repeats, *args, **kwargs): """ Repeat elements of an Series. Refer to `numpy.ndarray.repeat` - for more information about the `reps` argument. + for more information about the `repeats` argument. See also -------- numpy.ndarray.repeat """ nv.validate_repeat(args, kwargs) - new_index = self.index.repeat(reps) - new_values = self._values.repeat(reps) + new_index = self.index.repeat(repeats) + new_values = self._values.repeat(repeats) return self._constructor(new_values, index=new_index).__finalize__(self) @@ -1509,12 +1510,13 @@ def dot(self, other): else: # pragma: no cover raise TypeError('unsupported type: %s' % type(other)) - @Substitution(klass='Series', value='v') + @Substitution(klass='Series') @Appender(base._shared_docs['searchsorted']) - def searchsorted(self, v, side='left', sorter=None): + @deprecate_kwarg(old_arg_name='v', new_arg_name='value') + def searchsorted(self, value, side='left', sorter=None): if sorter is not None: sorter = _ensure_platform_int(sorter) - return self._values.searchsorted(Series(v)._values, + return self._values.searchsorted(Series(value)._values, side=side, sorter=sorter) # ------------------------------------------------------------------- diff --git a/pandas/indexes/base.py b/pandas/indexes/base.py index 54eaf86315a88..512abfd88c78c 100644 --- a/pandas/indexes/base.py +++ b/pandas/indexes/base.py @@ -535,17 +535,18 @@ def tolist(self): """ return list(self.values) - def repeat(self, n, *args, **kwargs): + @deprecate_kwarg(old_arg_name='n', new_arg_name='repeats') + def repeat(self, repeats, *args, **kwargs): """ Repeat elements of an Index. Refer to `numpy.ndarray.repeat` - for more information about the `n` argument. + for more information about the `repeats` argument. See also -------- numpy.ndarray.repeat """ nv.validate_repeat(args, kwargs) - return self._shallow_copy(self._values.repeat(n)) + return self._shallow_copy(self._values.repeat(repeats)) def where(self, cond, other=None): """ diff --git a/pandas/indexes/multi.py b/pandas/indexes/multi.py index f9576d92d8a49..45b6cad89d020 100644 --- a/pandas/indexes/multi.py +++ b/pandas/indexes/multi.py @@ -1166,10 +1166,11 @@ def append(self, other): def argsort(self, *args, **kwargs): return self.values.argsort(*args, **kwargs) - def repeat(self, n, *args, **kwargs): + @deprecate_kwarg(old_arg_name='n', new_arg_name='repeats') + def repeat(self, repeats, *args, **kwargs): nv.validate_repeat(args, kwargs) return MultiIndex(levels=self.levels, - labels=[label.view(np.ndarray).repeat(n) + labels=[label.view(np.ndarray).repeat(repeats) for label in self.labels], names=self.names, sortorder=self.sortorder, verify_integrity=False) diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 329e85d82122e..628095a2fcbd3 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -17,6 +17,7 @@ Float64Index, Int64Index, CategoricalIndex, DatetimeIndex, TimedeltaIndex, PeriodIndex) +from pandas.core.index import _get_combined_index from pandas.util.testing import assert_almost_equal from pandas.compat.numpy import np_datetime64_compat @@ -1976,8 +1977,18 @@ def test_dropna(self): with tm.assertRaisesRegexp(ValueError, msg): pd.Index([1, 2, 3]).dropna(how='xxx') + def test_get_combined_index(self): + result = _get_combined_index([]) + tm.assert_index_equal(result, Index([])) -def test_get_combined_index(): - from pandas.core.index import _get_combined_index - result = _get_combined_index([]) - tm.assert_index_equal(result, Index([])) + def test_repeat(self): + repeats = 2 + idx = pd.Index([1, 2, 3]) + expected = pd.Index([1, 1, 2, 2, 3, 3]) + + result = idx.repeat(repeats) + tm.assert_index_equal(result, expected) + + with tm.assert_produces_warning(FutureWarning): + result = idx.repeat(n=repeats) + tm.assert_index_equal(result, expected) diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py index 61a4ea53f06fb..e1e714719092a 100644 --- a/pandas/tests/indexes/test_multi.py +++ b/pandas/tests/indexes/test_multi.py @@ -97,6 +97,10 @@ def test_repeat(self): numbers, names.repeat(reps)], names=names) tm.assert_index_equal(m.repeat(reps), expected) + with tm.assert_produces_warning(FutureWarning): + result = m.repeat(n=reps) + tm.assert_index_equal(result, expected) + def test_numpy_repeat(self): reps = 2 numbers = [1, 2, 3] diff --git a/pandas/tests/series/test_analytics.py b/pandas/tests/series/test_analytics.py index 6de1a68464436..ad74b4a7e5cda 100644 --- a/pandas/tests/series/test_analytics.py +++ b/pandas/tests/series/test_analytics.py @@ -1363,6 +1363,10 @@ def test_repeat(self): exp = Series(s.values.repeat(5), index=s.index.values.repeat(5)) assert_series_equal(reps, exp) + with tm.assert_produces_warning(FutureWarning): + result = s.repeat(reps=5) + assert_series_equal(result, exp) + to_rep = [2, 3, 4] reps = s.repeat(to_rep) exp = Series(s.values.repeat(to_rep), @@ -1378,6 +1382,19 @@ def test_numpy_repeat(self): msg = "the 'axis' parameter is not supported" tm.assertRaisesRegexp(ValueError, msg, np.repeat, s, 2, axis=0) + def test_searchsorted(self): + s = Series([1, 2, 3]) + + idx = s.searchsorted(1, side='left') + tm.assert_numpy_array_equal(idx, np.array([0], dtype=np.intp)) + + idx = s.searchsorted(1, side='right') + tm.assert_numpy_array_equal(idx, np.array([1], dtype=np.intp)) + + with tm.assert_produces_warning(FutureWarning): + idx = s.searchsorted(v=1, side='left') + tm.assert_numpy_array_equal(idx, np.array([0], dtype=np.intp)) + def test_searchsorted_numeric_dtypes_scalar(self): s = Series([1, 2, 90, 1000, 3e9]) r = s.searchsorted(30) diff --git a/pandas/tests/test_categorical.py b/pandas/tests/test_categorical.py index f01fff035a3c5..5320b2216ee40 100644 --- a/pandas/tests/test_categorical.py +++ b/pandas/tests/test_categorical.py @@ -1593,6 +1593,11 @@ def test_searchsorted(self): self.assert_numpy_array_equal(res, exp) self.assert_numpy_array_equal(res, chk) + with tm.assert_produces_warning(FutureWarning): + res = c1.searchsorted(v=['bread']) + exp = np.array([1], dtype=np.intp) + tm.assert_numpy_array_equal(res, exp) + def test_deprecated_labels(self): # TODO: labels is deprecated and should be removed in 0.18 or 2017, # whatever is earlier diff --git a/pandas/tseries/index.py b/pandas/tseries/index.py index 024306edef2d8..0824072cc383f 100644 --- a/pandas/tseries/index.py +++ b/pandas/tseries/index.py @@ -1620,15 +1620,16 @@ def normalize(self): return DatetimeIndex(new_values, freq='infer', name=self.name, tz=self.tz) - @Substitution(klass='DatetimeIndex', value='key') + @Substitution(klass='DatetimeIndex') @Appender(_shared_docs['searchsorted']) - def searchsorted(self, key, side='left', sorter=None): - if isinstance(key, (np.ndarray, Index)): - key = np.array(key, dtype=_NS_DTYPE, copy=False) + @deprecate_kwarg(old_arg_name='key', new_arg_name='value') + def searchsorted(self, value, side='left', sorter=None): + if isinstance(value, (np.ndarray, Index)): + value = np.array(value, dtype=_NS_DTYPE, copy=False) else: - key = _to_m8(key, tz=self.tz) + value = _to_m8(value, tz=self.tz) - return self.values.searchsorted(key, side=side) + return self.values.searchsorted(value, side=side) def is_type_compatible(self, typ): return typ == self.inferred_type or typ == 'datetime' diff --git a/pandas/tseries/period.py b/pandas/tseries/period.py index d5d89c8dc2614..4bab3bc14461e 100644 --- a/pandas/tseries/period.py +++ b/pandas/tseries/period.py @@ -39,7 +39,8 @@ from pandas.indexes.base import _index_shared_docs, _ensure_index from pandas import compat -from pandas.util.decorators import Appender, cache_readonly, Substitution +from pandas.util.decorators import (Appender, Substitution, cache_readonly, + deprecate_kwarg) from pandas.lib import infer_dtype import pandas.tslib as tslib from pandas.compat import zip, u @@ -460,18 +461,19 @@ def astype(self, dtype, copy=True, how='start'): return self.asfreq(freq=dtype.freq) raise ValueError('Cannot cast PeriodIndex to dtype %s' % dtype) - @Substitution(klass='PeriodIndex', value='key') + @Substitution(klass='PeriodIndex') @Appender(_shared_docs['searchsorted']) - def searchsorted(self, key, side='left', sorter=None): - if isinstance(key, Period): - if key.freq != self.freq: - msg = _DIFFERENT_FREQ_INDEX.format(self.freqstr, key.freqstr) + @deprecate_kwarg(old_arg_name='key', new_arg_name='value') + def searchsorted(self, value, side='left', sorter=None): + if isinstance(value, Period): + if value.freq != self.freq: + msg = _DIFFERENT_FREQ_INDEX.format(self.freqstr, value.freqstr) raise IncompatibleFrequency(msg) - key = key.ordinal - elif isinstance(key, compat.string_types): - key = Period(key, freq=self.freq).ordinal + value = value.ordinal + elif isinstance(value, compat.string_types): + value = Period(value, freq=self.freq).ordinal - return self._values.searchsorted(key, side=side, sorter=sorter) + return self._values.searchsorted(value, side=side, sorter=sorter) @property def is_all_dates(self): diff --git a/pandas/tseries/tdi.py b/pandas/tseries/tdi.py index c1b0936edaff9..7e77d8baf3b2c 100644 --- a/pandas/tseries/tdi.py +++ b/pandas/tseries/tdi.py @@ -25,7 +25,7 @@ from pandas.indexes.base import _index_shared_docs import pandas.core.common as com import pandas.types.concat as _concat -from pandas.util.decorators import Appender, Substitution +from pandas.util.decorators import Appender, Substitution, deprecate_kwarg from pandas.tseries.base import TimelikeOps, DatetimeIndexOpsMixin from pandas.tseries.timedeltas import (to_timedelta, _coerce_scalar_to_timedelta_type) @@ -785,15 +785,16 @@ def _partial_td_slice(self, key, freq, use_lhs=True, use_rhs=True): # # try to find a the dates # return (lhs_mask & rhs_mask).nonzero()[0] - @Substitution(klass='TimedeltaIndex', value='key') + @Substitution(klass='TimedeltaIndex') @Appender(_shared_docs['searchsorted']) - def searchsorted(self, key, side='left', sorter=None): - if isinstance(key, (np.ndarray, Index)): - key = np.array(key, dtype=_TD_DTYPE, copy=False) + @deprecate_kwarg(old_arg_name='key', new_arg_name='value') + def searchsorted(self, value, side='left', sorter=None): + if isinstance(value, (np.ndarray, Index)): + value = np.array(value, dtype=_TD_DTYPE, copy=False) else: - key = _to_m8(key) + value = _to_m8(value) - return self.values.searchsorted(key, side=side, sorter=sorter) + return self.values.searchsorted(value, side=side, sorter=sorter) def is_type_compatible(self, typ): return typ == self.inferred_type or typ == 'timedelta' diff --git a/pandas/tseries/tests/test_period.py b/pandas/tseries/tests/test_period.py index 9bdf420ca6084..fe0d28dd9c508 100644 --- a/pandas/tseries/tests/test_period.py +++ b/pandas/tseries/tests/test_period.py @@ -3698,6 +3698,9 @@ def test_searchsorted(self): with self.assertRaisesRegexp(period.IncompatibleFrequency, msg): pidx.searchsorted(pd.Period('2014-01-01', freq='5D')) + with tm.assert_produces_warning(FutureWarning): + pidx.searchsorted(key=p2) + def test_round_trip(self): p = Period('2000Q1')