Skip to content

Commit ca3404b

Browse files
authored
Merge branch 'master' into bug16524
2 parents c3c4ffa + fb47ee5 commit ca3404b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+549
-127
lines changed

ci/build_docs.sh

+9
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ if [ "$DOC" ]; then
5959
git remote -v
6060

6161
git push origin gh-pages -f
62+
63+
echo "Running doctests"
64+
cd "$TRAVIS_BUILD_DIR"
65+
pytest --doctest-modules \
66+
pandas/core/reshape/concat.py \
67+
pandas/core/reshape/pivot.py \
68+
pandas/core/reshape/reshape.py \
69+
pandas/core/reshape/tile.py
70+
6271
fi
6372

6473
exit 0

doc/source/api.rst

+2
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,8 @@ Attributes
12861286
Index.is_monotonic
12871287
Index.is_monotonic_increasing
12881288
Index.is_monotonic_decreasing
1289+
Index.is_strictly_monotonic_increasing
1290+
Index.is_strictly_monotonic_decreasing
12891291
Index.is_unique
12901292
Index.has_duplicates
12911293
Index.dtype

doc/source/whatsnew/v0.20.2.txt

+13-6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Enhancements
2121

2222
- Unblocked access to additional compression types supported in pytables: 'blosc:blosclz, 'blosc:lz4', 'blosc:lz4hc', 'blosc:snappy', 'blosc:zlib', 'blosc:zstd' (:issue:`14478`)
2323
- ``Series`` provides a ``to_latex`` method (:issue:`16180`)
24+
- Added :attr:`Index.is_strictly_monotonic_increasing` and :attr:`Index.is_strictly_monotonic_decreasing` properties (:issue:`16515`)
2425

2526
.. _whatsnew_0202.performance:
2627

@@ -40,13 +41,14 @@ Bug Fixes
4041
- Silenced a warning on some Windows environments about "tput: terminal attributes: No such device or address" when
4142
detecting the terminal size. This fix only applies to python 3 (:issue:`16496`)
4243
- Bug in using ``pathlib.Path`` or ``py.path.local`` objects with io functions (:issue:`16291`)
44+
- Bug in ``Index.symmetric_difference()`` on two equal MultiIndex's, results in a TypeError (:issue `13490`)
4345
- Bug in ``DataFrame.update()`` with ``overwrite=False`` and ``NaN values`` (:issue:`15593`)
44-
- Bug in ``Series`` with dtype='category' (:issue:`16524`)
45-
46-
47-
46+
- Passing an invalid engine to :func:`read_csv` now raises an informative
47+
``ValueError`` rather than ``UnboundLocalError``. (:issue:`16511`)
48+
- Bug in :func:`unique` on an array of tuples (:issue:`16519`)
49+
- Bug in :func:`cut`` when ``labels`` are set, resulting in incorrect label ordering (:issue:`16459`)
4850
- Fixed a compatibility issue with IPython 6.0's tab completion showing deprecation warnings on Categoricals (:issue:`16409`)
49-
51+
- Bug in ``Series`` with dtype='category' (:issue:`16524`)
5052

5153
Conversion
5254
^^^^^^^^^^
@@ -59,15 +61,18 @@ Indexing
5961
^^^^^^^^
6062

6163
- Bug in ``DataFrame.reset_index(level=)`` with single level index (:issue:`16263`)
62-
64+
- Bug in partial string indexing with a monotonic, but not strictly-monotonic, index incorrectly reversing the slice bounds (:issue:`16515`)
6365

6466
I/O
6567
^^^
6668

6769
- Bug in pd.read_csv() when comment is passed in space deliminted text files (:issue:`16472`)
6870
- Bug that would force importing of the clipboard routines unnecessarily, potentially causing an import error on startup (:issue:`16288`)
6971
- Bug that raised IndexError HTML-rendering an empty DataFrame (:issue:`15953`)
72+
- Bug in ``pd.read_csv()`` in which tarfile object inputs were raising an error in Python 2.x for the C engine (:issue:`16530`)
73+
- Bug where ``DataFrame.to_html()`` ignored the ``index_names`` parameter (:issue:`16493`)
7074

75+
- Bug in ``HDFStore.select_as_multiple()`` where start/stop arguments were not respected (:issue:`16209`)
7176

7277
Plotting
7378
^^^^^^^^
@@ -84,6 +89,7 @@ Groupby/Resample/Rolling
8489

8590
- Bug creating datetime rolling window on an empty DataFrame (:issue:`15819`)
8691
- Bug in ``rolling.cov()`` with offset window (:issue:`16058`)
92+
- Bug in ``.resample()`` and ``.groupby()`` when aggregating on integers (:issue:`16361`)
8793

8894

8995
Sparse
@@ -98,6 +104,7 @@ Reshaping
98104
- Bug in ``pd.wide_to_long()`` where no error was raised when ``i`` was not a unique identifier (:issue:`16382`)
99105
- Bug in ``Series.isin(..)`` with a list of tuples (:issue:`16394`)
100106
- Bug in construction of a ``DataFrame`` with mixed dtypes including an all-NaT column. (:issue:`16395`)
107+
- Bug in ``DataFrame.agg()`` and ``Series.agg()`` with aggregating on non-callable attributes (:issue:`16405`)
101108

102109

103110
Numeric

pandas/_libs/index.pyx

+2-2
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ cdef class IndexEngine:
152152

153153
try:
154154
return self.mapping.get_item(val)
155-
except TypeError:
155+
except (TypeError, ValueError):
156156
raise KeyError(val)
157157

158158
cdef inline _get_loc_duplicates(self, object val):
@@ -470,7 +470,7 @@ cdef class DatetimeEngine(Int64Engine):
470470
try:
471471
val = _to_i8(val)
472472
return self.mapping.get_item(val)
473-
except TypeError:
473+
except (TypeError, ValueError):
474474
self._date_check_type(val)
475475
raise KeyError(val)
476476

pandas/core/algorithms.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def _ensure_arraylike(values):
163163
ABCIndexClass, ABCSeries)):
164164
inferred = lib.infer_dtype(values)
165165
if inferred in ['mixed', 'string', 'unicode']:
166-
values = np.asarray(values, dtype=object)
166+
values = lib.list_to_object_array(values)
167167
else:
168168
values = np.asarray(values)
169169
return values
@@ -328,6 +328,11 @@ def unique(values):
328328
[b, a, c]
329329
Categories (3, object): [a < b < c]
330330
331+
An array of tuples
332+
333+
>>> pd.unique([('a', 'b'), ('b', 'a'), ('a', 'c'), ('b', 'a')])
334+
array([('a', 'b'), ('b', 'a'), ('a', 'c')], dtype=object)
335+
331336
See Also
332337
--------
333338
pandas.Index.unique

pandas/core/base.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ def aggregate(self, func, *args, **kwargs):
378378
def _try_aggregate_string_function(self, arg, *args, **kwargs):
379379
"""
380380
if arg is a string, then try to operate on it:
381-
- try to find a function on ourselves
381+
- try to find a function (or attribute) on ourselves
382382
- try to find a numpy function
383383
- raise
384384
@@ -387,7 +387,15 @@ def _try_aggregate_string_function(self, arg, *args, **kwargs):
387387

388388
f = getattr(self, arg, None)
389389
if f is not None:
390-
return f(*args, **kwargs)
390+
if callable(f):
391+
return f(*args, **kwargs)
392+
393+
# people may try to aggregate on a non-callable attribute
394+
# but don't let them think they can pass args to it
395+
assert len(args) == 0
396+
assert len([kwarg for kwarg in kwargs
397+
if kwarg not in ['axis', '_level']]) == 0
398+
return f
391399

392400
f = getattr(np, arg, None)
393401
if f is not None:

pandas/core/dtypes/inference.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def is_file_like(obj):
171171
if not (hasattr(obj, 'read') or hasattr(obj, 'write')):
172172
return False
173173

174-
if not is_iterator(obj):
174+
if not hasattr(obj, "__iter__"):
175175
return False
176176

177177
return True

pandas/core/frame.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1918,7 +1918,7 @@ def get_value(self, index, col, takeable=False):
19181918

19191919
try:
19201920
return engine.get_value(series._values, index)
1921-
except TypeError:
1921+
except (TypeError, ValueError):
19221922

19231923
# we cannot handle direct indexing
19241924
# use positional

pandas/core/generic.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -2366,9 +2366,14 @@ def add_suffix(self, suffix):
23662366
1 A 1 1
23672367
"""
23682368

2369-
def sort_values(self, by, axis=0, ascending=True, inplace=False,
2369+
def sort_values(self, by=None, axis=0, ascending=True, inplace=False,
23702370
kind='quicksort', na_position='last'):
2371-
raise AbstractMethodError(self)
2371+
"""
2372+
NOT IMPLEMENTED: do not call this method, as sorting values is not
2373+
supported for Panel objects and will raise an error.
2374+
"""
2375+
raise NotImplementedError("sort_values has not been implemented "
2376+
"on Panel or Panel4D objects.")
23722377

23732378
_shared_docs['sort_index'] = """
23742379
Sort object by labels (along an axis)

pandas/core/groupby.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -3337,13 +3337,15 @@ def _cython_agg_blocks(self, how, alt=None, numeric_only=True):
33373337
obj = self.obj[data.items[locs]]
33383338
s = groupby(obj, self.grouper)
33393339
result = s.aggregate(lambda x: alt(x, axis=self.axis))
3340-
result = result._data.blocks[0]
3340+
newb = result._data.blocks[0]
33413341

3342-
# see if we can cast the block back to the original dtype
3343-
result = block._try_coerce_and_cast_result(result)
3342+
finally:
3343+
3344+
# see if we can cast the block back to the original dtype
3345+
result = block._try_coerce_and_cast_result(result)
3346+
newb = block.make_block(result)
33443347

33453348
new_items.append(locs)
3346-
newb = block.make_block_same_class(result)
33473349
new_blocks.append(newb)
33483350

33493351
if len(new_blocks) == 0:

pandas/core/indexes/base.py

+52-2
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,15 @@ def is_monotonic_increasing(self):
11911191
"""
11921192
return if the index is monotonic increasing (only equal or
11931193
increasing) values.
1194+
1195+
Examples
1196+
--------
1197+
>>> Index([1, 2, 3]).is_monotonic_increasing
1198+
True
1199+
>>> Index([1, 2, 2]).is_monotonic_increasing
1200+
True
1201+
>>> Index([1, 3, 2]).is_monotonic_increasing
1202+
False
11941203
"""
11951204
return self._engine.is_monotonic_increasing
11961205

@@ -1199,9 +1208,50 @@ def is_monotonic_decreasing(self):
11991208
"""
12001209
return if the index is monotonic decreasing (only equal or
12011210
decreasing) values.
1211+
1212+
Examples
1213+
--------
1214+
>>> Index([3, 2, 1]).is_monotonic_decreasing
1215+
True
1216+
>>> Index([3, 2, 2]).is_monotonic_decreasing
1217+
True
1218+
>>> Index([3, 1, 2]).is_monotonic_decreasing
1219+
False
12021220
"""
12031221
return self._engine.is_monotonic_decreasing
12041222

1223+
@property
1224+
def is_strictly_monotonic_increasing(self):
1225+
"""return if the index is strictly monotonic increasing
1226+
(only increasing) values
1227+
1228+
Examples
1229+
--------
1230+
>>> Index([1, 2, 3]).is_strictly_monotonic_increasing
1231+
True
1232+
>>> Index([1, 2, 2]).is_strictly_monotonic_increasing
1233+
False
1234+
>>> Index([1, 3, 2]).is_strictly_monotonic_increasing
1235+
False
1236+
"""
1237+
return self.is_unique and self.is_monotonic_increasing
1238+
1239+
@property
1240+
def is_strictly_monotonic_decreasing(self):
1241+
"""return if the index is strictly monotonic decreasing
1242+
(only decreasing) values
1243+
1244+
Examples
1245+
--------
1246+
>>> Index([3, 2, 1]).is_strictly_monotonic_decreasing
1247+
True
1248+
>>> Index([3, 2, 2]).is_strictly_monotonic_decreasing
1249+
False
1250+
>>> Index([3, 1, 2]).is_strictly_monotonic_decreasing
1251+
False
1252+
"""
1253+
return self.is_unique and self.is_monotonic_decreasing
1254+
12051255
def is_lexsorted_for_tuple(self, tup):
12061256
return True
12071257

@@ -1590,7 +1640,7 @@ def __contains__(self, key):
15901640
hash(key)
15911641
try:
15921642
return key in self._engine
1593-
except TypeError:
1643+
except (TypeError, ValueError):
15941644
return False
15951645

15961646
_index_shared_docs['contains'] = """
@@ -1610,7 +1660,7 @@ def contains(self, key):
16101660
hash(key)
16111661
try:
16121662
return key in self._engine
1613-
except TypeError:
1663+
except (TypeError, ValueError):
16141664
return False
16151665

16161666
def __hash__(self):

pandas/core/indexes/datetimes.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1472,7 +1472,7 @@ def _maybe_cast_slice_bound(self, label, side, kind):
14721472
# the bounds need swapped if index is reverse sorted and has a
14731473
# length > 1 (is_monotonic_decreasing gives True for empty
14741474
# and length 1 index)
1475-
if self.is_monotonic_decreasing and len(self) > 1:
1475+
if self.is_strictly_monotonic_decreasing and len(self) > 1:
14761476
return upper if side == 'left' else lower
14771477
return lower if side == 'left' else upper
14781478
else:

pandas/core/indexes/multi.py

+6
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,12 @@ def view(self, cls=None):
414414
return result
415415

416416
def _shallow_copy_with_infer(self, values=None, **kwargs):
417+
# On equal MultiIndexes the difference is empty.
418+
# Therefore, an empty MultiIndex is returned GH13490
419+
if len(values) == 0:
420+
return MultiIndex(levels=[[] for _ in range(self.nlevels)],
421+
labels=[[] for _ in range(self.nlevels)],
422+
**kwargs)
417423
return self._shallow_copy(values, **kwargs)
418424

419425
@Appender(_index_shared_docs['_shallow_copy'])

pandas/core/reshape/concat.py

+2
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ def concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,
197197
0
198198
a 2
199199
>>> pd.concat([df5, df6], verify_integrity=True)
200+
Traceback (most recent call last):
201+
...
200202
ValueError: Indexes have overlapping values: ['a']
201203
"""
202204
op = _Concatenator(objs, axis=axis, join_axes=join_axes,

0 commit comments

Comments
 (0)