Skip to content

Commit 931b7f9

Browse files
committed
Merge branch 'master' of https://github.com/pandas-dev/pandas into error-on-non-naive-datetime-strings
2 parents 577d742 + 774030c commit 931b7f9

File tree

15 files changed

+116
-70
lines changed

15 files changed

+116
-70
lines changed

ci/lint.sh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,13 @@ if [ "$LINT" ]; then
7272
echo "Linting *.c and *.h DONE"
7373

7474
echo "Check for invalid testing"
75-
grep -r -E --include '*.py' --exclude testing.py '(numpy|np)\.testing' pandas
75+
76+
# Check for the following code in testing:
77+
#
78+
# np.testing
79+
# np.array_equal
80+
grep -r -E --include '*.py' --exclude testing.py '(numpy|np)(\.testing|\.array_equal)' pandas/tests/
81+
7682
if [ $? = "0" ]; then
7783
RET=1
7884
fi

doc/source/whatsnew/v0.22.0.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,15 @@ Other API Changes
4646
- :class:`Timestamp` will no longer silently ignore invalid ``freq`` arguments (:issue:`5168`)
4747
- :class:`CacheableOffset` and :class:`WeekDay` are no longer available in the ``pandas.tseries.offsets`` module (:issue:`17830`)
4848
- `tseries.frequencies.get_freq_group()` and `tseries.frequencies.DAYS` are removed from the public API (:issue:`18034`)
49+
- :func:`Series.truncate` and :func:`DataFrame.truncate` will raise a ``ValueError`` if the index is not sorted instead of an unhelpful ``KeyError`` (:issue:`17935`)
50+
4951

5052
.. _whatsnew_0220.deprecations:
5153

5254
Deprecations
5355
~~~~~~~~~~~~
5456

55-
-
57+
- ``Series.from_array`` and ``SparseSeries.from_array`` are deprecated. Use the normal constructor ``Series(..)`` and ``SparseSeries(..)`` instead (:issue:`18213`).
5658
-
5759
-
5860

pandas/_libs/index.pyx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,11 @@ from pandas._libs.tslib import Timestamp, Timedelta
2222
from datetime import datetime, timedelta, date
2323

2424
from cpython cimport PyTuple_Check, PyList_Check
25+
from cpython.slice cimport PySlice_Check
2526

2627
cdef int64_t iNaT = util.get_nat()
2728

2829

29-
cdef extern from "Python.h":
30-
int PySlice_Check(object)
31-
32-
3330
cdef inline is_definitely_invalid_key(object val):
3431
if PyTuple_Check(val):
3532
try:

pandas/_libs/period.pyx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# -*- coding: utf-8 -*-
22
# cython: profile=False
33
from datetime import datetime, date, timedelta
4-
import operator
54

65
from cpython cimport (
76
PyUnicode_Check,
@@ -201,7 +200,7 @@ def period_asfreq_arr(ndarray[int64_t] arr, int freq1, int freq2, bint end):
201200
Py_ssize_t i, n
202201
freq_conv_func func
203202
asfreq_info finfo
204-
int64_t val, ordinal
203+
int64_t val
205204
char relation
206205

207206
n = len(arr)
@@ -236,9 +235,6 @@ def period_asfreq_arr(ndarray[int64_t] arr, int freq1, int freq2, bint end):
236235

237236
def period_ordinal(int y, int m, int d, int h, int min,
238237
int s, int us, int ps, int freq):
239-
cdef:
240-
int64_t ordinal
241-
242238
return get_period_ordinal(y, m, d, h, min, s, us, ps, freq)
243239

244240

pandas/_libs/tslib.pyx

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# distutils: define_macros=CYTHON_TRACE_NOGIL=0
66

77
cimport numpy as np
8-
from numpy cimport (int8_t, int32_t, int64_t, import_array, ndarray,
8+
from numpy cimport (int32_t, int64_t, import_array, ndarray,
99
float64_t, NPY_DATETIME, NPY_TIMEDELTA)
1010
import numpy as np
1111

@@ -24,8 +24,6 @@ from cpython cimport (
2424
cdef extern from "Python.h":
2525
cdef PyTypeObject *Py_TYPE(object)
2626

27-
from libc.stdlib cimport free
28-
2927
from util cimport (is_integer_object, is_float_object, is_string_object,
3028
is_datetime64_object, is_timedelta64_object,
3129
INT64_MAX)
@@ -51,7 +49,6 @@ from tslibs.np_datetime cimport (check_dts_bounds,
5149
PANDAS_DATETIMEUNIT, PANDAS_FR_ns,
5250
dt64_to_dtstruct, dtstruct_to_dt64,
5351
pydatetime_to_dt64, pydate_to_dt64,
54-
npy_datetime,
5552
get_datetime64_unit, get_datetime64_value,
5653
get_timedelta64_value,
5754
days_per_month_table,
@@ -75,12 +72,10 @@ from tslibs.timedeltas cimport cast_from_unit, delta_to_nanoseconds
7572
from tslibs.timedeltas import Timedelta
7673
from tslibs.timezones cimport (
7774
is_utc, is_tzlocal, is_fixed_offset,
78-
treat_tz_as_dateutil, treat_tz_as_pytz,
79-
get_timezone, get_utcoffset, maybe_get_tz,
75+
treat_tz_as_pytz,
76+
get_timezone, maybe_get_tz,
8077
get_dst_info)
81-
from tslibs.fields import (
82-
get_date_name_field, get_start_end_field, get_date_field,
83-
build_field_sarray)
78+
from tslibs.fields import get_start_end_field, get_date_field
8479
from tslibs.conversion cimport (tz_convert_single, _TSObject,
8580
convert_to_tsobject,
8681
convert_datetime_to_tsobject,
@@ -1763,13 +1758,6 @@ cpdef array_to_datetime(ndarray[object] values, errors='raise',
17631758
return oresult
17641759

17651760

1766-
cdef PyTypeObject* td_type = <PyTypeObject*> Timedelta
1767-
1768-
1769-
cdef inline bint is_timedelta(object o):
1770-
return Py_TYPE(o) == td_type # isinstance(o, Timedelta)
1771-
1772-
17731761
# ----------------------------------------------------------------------
17741762
# Conversion routines
17751763

pandas/core/frame.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2099,10 +2099,8 @@ def _ixs(self, i, axis=0):
20992099

21002100
if index_len and not len(values):
21012101
values = np.array([np.nan] * index_len, dtype=object)
2102-
result = self._constructor_sliced.from_array(values,
2103-
index=self.index,
2104-
name=label,
2105-
fastpath=True)
2102+
result = self._constructor_sliced._from_array(
2103+
values, index=self.index, name=label, fastpath=True)
21062104

21072105
# this is a cached value, mark it so
21082106
result._set_as_cached(label, self)
@@ -2497,8 +2495,8 @@ def _box_item_values(self, key, values):
24972495

24982496
def _box_col_values(self, values, items):
24992497
""" provide boxed values for a column """
2500-
return self._constructor_sliced.from_array(values, index=self.index,
2501-
name=items, fastpath=True)
2498+
return self._constructor_sliced._from_array(values, index=self.index,
2499+
name=items, fastpath=True)
25022500

25032501
def __setitem__(self, key, value):
25042502
key = com._apply_if_callable(key, self)
@@ -4939,8 +4937,8 @@ def _apply_standard(self, func, axis, ignore_failures=False, reduce=True):
49394937
res_index = self.index
49404938
res_columns = self.columns
49414939
values = self.values
4942-
series_gen = (Series.from_array(arr, index=res_columns, name=name,
4943-
dtype=dtype)
4940+
series_gen = (Series._from_array(arr, index=res_columns, name=name,
4941+
dtype=dtype)
49444942
for i, (arr, name) in enumerate(zip(values,
49454943
res_index)))
49464944
else: # pragma : no cover

pandas/core/generic.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6338,6 +6338,11 @@ def truncate(self, before=None, after=None, axis=None, copy=True):
63386338
axis = self._get_axis_number(axis)
63396339
ax = self._get_axis(axis)
63406340

6341+
# GH 17935
6342+
# Check that index is sorted
6343+
if not ax.is_monotonic_increasing and not ax.is_monotonic_decreasing:
6344+
raise ValueError("truncate requires a sorted index")
6345+
63416346
# if we have a date index, convert to dates, otherwise
63426347
# treat like a slice
63436348
if ax.is_all_dates:

pandas/core/indexes/datetimes.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
from pandas._libs import (lib, index as libindex, tslib as libts,
5656
algos as libalgos, join as libjoin,
5757
Timestamp, period as libperiod)
58-
from pandas._libs.tslibs import timezones, conversion
58+
from pandas._libs.tslibs import timezones, conversion, fields
5959

6060
# -------- some conversion wrapper functions
6161

@@ -75,20 +75,20 @@ def f(self):
7575
self.freq.kwds.get('month', 12))
7676
if self.freq else 12)
7777

78-
result = libts.get_start_end_field(values, field, self.freqstr,
79-
month_kw)
78+
result = fields.get_start_end_field(values, field,
79+
self.freqstr, month_kw)
8080
else:
81-
result = libts.get_date_field(values, field)
81+
result = fields.get_date_field(values, field)
8282

8383
# these return a boolean by-definition
8484
return result
8585

8686
if field in self._object_ops:
87-
result = libts.get_date_name_field(values, field)
87+
result = fields.get_date_name_field(values, field)
8888
result = self._maybe_mask_results(result)
8989

9090
else:
91-
result = libts.get_date_field(values, field)
91+
result = fields.get_date_field(values, field)
9292
result = self._maybe_mask_results(result, convert='float64')
9393

9494
return Index(result, name=self.name)

pandas/core/series.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,25 @@ def __init__(self, data=None, index=None, dtype=None, name=None,
273273
@classmethod
274274
def from_array(cls, arr, index=None, name=None, dtype=None, copy=False,
275275
fastpath=False):
276+
"""
277+
DEPRECATED: use the pd.Series(..) constructor instead.
278+
279+
"""
280+
warnings.warn("'from_array' is deprecated and will be removed in a "
281+
"future version. Please use the pd.Series(..) "
282+
"constructor instead.", FutureWarning, stacklevel=2)
283+
return cls._from_array(arr, index=index, name=name, dtype=dtype,
284+
copy=copy, fastpath=fastpath)
285+
286+
@classmethod
287+
def _from_array(cls, arr, index=None, name=None, dtype=None, copy=False,
288+
fastpath=False):
289+
"""
290+
Internal method used in DataFrame.__setitem__/__getitem__.
291+
Difference with Series(..) is that this method checks if a sparse
292+
array is passed.
293+
294+
"""
276295
# return a sparse series here
277296
if isinstance(arr, ABCSparseArray):
278297
from pandas.core.sparse.series import SparseSeries

pandas/core/sparse/series.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,18 @@ def npoints(self):
256256
def from_array(cls, arr, index=None, name=None, copy=False,
257257
fill_value=None, fastpath=False):
258258
"""
259-
Simplified alternate constructor
259+
DEPRECATED: use the pd.SparseSeries(..) constructor instead.
260+
260261
"""
262+
warnings.warn("'from_array' is deprecated and will be removed in a "
263+
"future version. Please use the pd.SparseSeries(..) "
264+
"constructor instead.", FutureWarning, stacklevel=2)
265+
return cls._from_array(arr, index=index, name=name, copy=copy,
266+
fill_value=fill_value, fastpath=fastpath)
267+
268+
@classmethod
269+
def _from_array(cls, arr, index=None, name=None, copy=False,
270+
fill_value=None, fastpath=False):
261271
return cls(arr, index=index, name=name, copy=copy,
262272
fill_value=fill_value, fastpath=fastpath)
263273

pandas/tests/frame/test_timeseries.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,33 @@ def test_truncate_copy(self):
377377
truncated.values[:] = 5.
378378
assert not (self.tsframe.values[5:11] == 5).any()
379379

380+
def test_truncate_nonsortedindex(self):
381+
# GH 17935
382+
383+
df = pd.DataFrame({'A': ['a', 'b', 'c', 'd', 'e']},
384+
index=[5, 3, 2, 9, 0])
385+
with tm.assert_raises_regex(ValueError,
386+
'truncate requires a sorted index'):
387+
df.truncate(before=3, after=9)
388+
389+
rng = pd.date_range('2011-01-01', '2012-01-01', freq='W')
390+
ts = pd.DataFrame({'A': np.random.randn(len(rng)),
391+
'B': np.random.randn(len(rng))},
392+
index=rng)
393+
with tm.assert_raises_regex(ValueError,
394+
'truncate requires a sorted index'):
395+
ts.sort_values('A', ascending=False).truncate(before='2011-11',
396+
after='2011-12')
397+
398+
df = pd.DataFrame({3: np.random.randn(5),
399+
20: np.random.randn(5),
400+
2: np.random.randn(5),
401+
0: np.random.randn(5)},
402+
columns=[3, 20, 2, 0])
403+
with tm.assert_raises_regex(ValueError,
404+
'truncate requires a sorted index'):
405+
df.truncate(before=2, after=20, axis=1)
406+
380407
def test_asfreq(self):
381408
offset_monthly = self.tsframe.asfreq(offsets.BMonthEnd())
382409
rule_monthly = self.tsframe.asfreq('BM')

pandas/tests/internals/test_internals.py

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -286,29 +286,6 @@ def test_delete(self):
286286
with pytest.raises(Exception):
287287
newb.delete(3)
288288

289-
def test_split_block_at(self):
290-
291-
# with dup column support this method was taken out
292-
# GH3679
293-
pytest.skip("skipping for now")
294-
295-
bs = list(self.fblock.split_block_at('a'))
296-
assert len(bs) == 1
297-
assert np.array_equal(bs[0].items, ['c', 'e'])
298-
299-
bs = list(self.fblock.split_block_at('c'))
300-
assert len(bs) == 2
301-
assert np.array_equal(bs[0].items, ['a'])
302-
assert np.array_equal(bs[1].items, ['e'])
303-
304-
bs = list(self.fblock.split_block_at('e'))
305-
assert len(bs) == 1
306-
assert np.array_equal(bs[0].items, ['a', 'c'])
307-
308-
# bblock = get_bool_ex(['f'])
309-
# bs = list(bblock.split_block_at('f'))
310-
# assert len(bs), 0)
311-
312289

313290
class TestDatetimeBlock(object):
314291

pandas/tests/series/test_api.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ def test_constructor_dict_timedelta_index(self):
195195
)
196196
self._assert_series_equal(result, expected)
197197

198+
def test_from_array_deprecated(self):
199+
200+
with tm.assert_produces_warning(FutureWarning):
201+
self.series_klass.from_array([1, 2, 3])
202+
198203

199204
class TestSeriesMisc(TestData, SharedWithSparse):
200205

pandas/tests/series/test_period.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,9 @@ def test_truncate(self):
272272
pd.Period('2017-09-03')
273273
])
274274
series2 = pd.Series([1, 2, 3], index=idx2)
275-
result2 = series2.truncate(after='2017-09-02')
275+
result2 = series2.sort_index().truncate(after='2017-09-02')
276276

277277
expected_idx2 = pd.PeriodIndex([
278-
pd.Period('2017-09-03'),
279278
pd.Period('2017-09-02')
280279
])
281-
tm.assert_series_equal(result2, pd.Series([1, 2], index=expected_idx2))
280+
tm.assert_series_equal(result2, pd.Series([2], index=expected_idx2))

pandas/tests/series/test_timeseries.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,22 @@ def test_truncate(self):
236236
before=self.ts.index[-1] + offset,
237237
after=self.ts.index[0] - offset)
238238

239+
def test_truncate_nonsortedindex(self):
240+
# GH 17935
241+
242+
s = pd.Series(['a', 'b', 'c', 'd', 'e'],
243+
index=[5, 3, 2, 9, 0])
244+
with tm.assert_raises_regex(ValueError,
245+
'truncate requires a sorted index'):
246+
s.truncate(before=3, after=9)
247+
248+
rng = pd.date_range('2011-01-01', '2012-01-01', freq='W')
249+
ts = pd.Series(np.random.randn(len(rng)), index=rng)
250+
with tm.assert_raises_regex(ValueError,
251+
'truncate requires a sorted index'):
252+
ts.sort_values(ascending=False).truncate(before='2011-11',
253+
after='2011-12')
254+
239255
def test_asfreq(self):
240256
ts = Series([0., 1., 2.], index=[datetime(2009, 10, 30), datetime(
241257
2009, 11, 30), datetime(2009, 12, 31)])
@@ -919,8 +935,9 @@ def test_from_M8_structured(self):
919935
assert isinstance(s[0], Timestamp)
920936
assert s[0] == dates[0][0]
921937

922-
s = Series.from_array(arr['Date'], Index([0]))
923-
assert s[0] == dates[0][0]
938+
with pytest.warns(FutureWarning):
939+
s = Series.from_array(arr['Date'], Index([0]))
940+
assert s[0] == dates[0][0]
924941

925942
def test_get_level_values_box(self):
926943
from pandas import MultiIndex

0 commit comments

Comments
 (0)