Skip to content

Commit 517abf3

Browse files
authored
Merge pull request #36 from pandas-dev/master
Sync Fork from Upstream Repo
2 parents 96ccda8 + 4b142ef commit 517abf3

33 files changed

+420
-466
lines changed

ci/code_checks.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then
113113

114114
# Imports - Check formatting using isort see setup.cfg for settings
115115
MSG='Check import format using isort' ; echo $MSG
116-
ISORT_CMD="isort --recursive --check-only pandas asv_bench"
116+
ISORT_CMD="isort --quiet --recursive --check-only pandas asv_bench"
117117
if [[ "$GITHUB_ACTIONS" == "true" ]]; then
118118
eval $ISORT_CMD | awk '{print "##[error]" $0}'; RET=$(($RET + ${PIPESTATUS[0]}))
119119
else

doc/source/whatsnew/v1.0.2.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ including other versions of pandas.
1515
Fixed regressions
1616
~~~~~~~~~~~~~~~~~
1717

18-
-
18+
- Fixed regression in :meth:`DataFrame.to_excel` when ``columns`` kwarg is passed (:issue:`31677`)
1919
-
2020

2121
.. ---------------------------------------------------------------------------

doc/source/whatsnew/v1.1.0.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ Backwards incompatible API changes
6363
- :meth:`DataFrameGroupby.mean` and :meth:`SeriesGroupby.mean` (and similarly for :meth:`~DataFrameGroupby.median`, :meth:`~DataFrameGroupby.std`` and :meth:`~DataFrameGroupby.var``)
6464
now raise a ``TypeError`` if a not-accepted keyword argument is passed into it.
6565
Previously a ``UnsupportedFunctionCall`` was raised (``AssertionError`` if ``min_count`` passed into :meth:`~DataFrameGroupby.median``) (:issue:`31485`)
66-
66+
- :meth:`DataFrame.at` and :meth:`Series.at` will raise a ``TypeError`` instead of a ``ValueError`` if an incompatible key is passed, and ``KeyError`` if a missing key is passed, matching the behavior of ``.loc[]`` (:issue:`31722`)
67+
-
6768

6869
.. ---------------------------------------------------------------------------
6970

pandas/_libs/index.pyx

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
1-
from datetime import datetime, timedelta, date
21
import warnings
32

4-
import cython
5-
63
import numpy as np
74
cimport numpy as cnp
85
from numpy cimport (ndarray, intp_t,
96
float64_t, float32_t,
107
int64_t, int32_t, int16_t, int8_t,
11-
uint64_t, uint32_t, uint16_t, uint8_t,
12-
# Note: NPY_DATETIME, NPY_TIMEDELTA are only available
13-
# for cimport in cython>=0.27.3
14-
NPY_DATETIME, NPY_TIMEDELTA)
8+
uint64_t, uint32_t, uint16_t, uint8_t
9+
)
1510
cnp.import_array()
1611

1712

@@ -23,7 +18,7 @@ from pandas._libs.tslibs.c_timestamp cimport _Timestamp
2318
from pandas._libs.hashtable cimport HashTable
2419

2520
from pandas._libs import algos, hashtable as _hash
26-
from pandas._libs.tslibs import Timestamp, Timedelta, period as periodlib
21+
from pandas._libs.tslibs import Timedelta, period as periodlib
2722
from pandas._libs.missing import checknull
2823

2924

@@ -35,16 +30,6 @@ cdef inline bint is_definitely_invalid_key(object val):
3530
return False
3631

3732

38-
cpdef get_value_at(ndarray arr, object loc, object tz=None):
39-
obj = util.get_value_at(arr, loc)
40-
41-
if arr.descr.type_num == NPY_DATETIME:
42-
return Timestamp(obj, tz=tz)
43-
elif arr.descr.type_num == NPY_TIMEDELTA:
44-
return Timedelta(obj)
45-
return obj
46-
47-
4833
# Don't populate hash tables in monotonic indexes larger than this
4934
_SIZE_CUTOFF = 1_000_000
5035

@@ -72,21 +57,6 @@ cdef class IndexEngine:
7257
self._ensure_mapping_populated()
7358
return val in self.mapping
7459

75-
cpdef get_value(self, ndarray arr, object key, object tz=None):
76-
"""
77-
Parameters
78-
----------
79-
arr : 1-dimensional ndarray
80-
"""
81-
cdef:
82-
object loc
83-
84-
loc = self.get_loc(key)
85-
if isinstance(loc, slice) or util.is_array(loc):
86-
return arr[loc]
87-
else:
88-
return get_value_at(arr, loc, tz=tz)
89-
9060
cpdef get_loc(self, object val):
9161
cdef:
9262
Py_ssize_t loc

pandas/_libs/util.pxd

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from pandas._libs.tslibs.util cimport *
22

3-
from cython cimport Py_ssize_t
4-
53
cimport numpy as cnp
64
from numpy cimport ndarray
75

@@ -51,49 +49,3 @@ cdef inline void set_array_not_contiguous(ndarray ao) nogil:
5149
PyArray_CLEARFLAGS(ao,
5250
(NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS))
5351

54-
55-
cdef inline Py_ssize_t validate_indexer(ndarray arr, object loc) except -1:
56-
"""
57-
Cast the given indexer `loc` to an integer. If it is negative, i.e. a
58-
python-style indexing-from-the-end indexer, translate it to a
59-
from-the-front indexer. Raise if this is not possible.
60-
61-
Parameters
62-
----------
63-
arr : ndarray
64-
loc : object
65-
66-
Returns
67-
-------
68-
idx : Py_ssize_t
69-
70-
Raises
71-
------
72-
IndexError
73-
"""
74-
cdef:
75-
Py_ssize_t idx, size
76-
int casted
77-
78-
if is_float_object(loc):
79-
casted = int(loc)
80-
if casted == loc:
81-
loc = casted
82-
83-
idx = <Py_ssize_t>loc
84-
size = cnp.PyArray_SIZE(arr)
85-
86-
if idx < 0 and size > 0:
87-
idx += size
88-
if idx >= size or size == 0 or idx < 0:
89-
raise IndexError('index out of bounds')
90-
91-
return idx
92-
93-
94-
cdef inline object get_value_at(ndarray arr, object loc):
95-
cdef:
96-
Py_ssize_t i
97-
98-
i = validate_indexer(arr, loc)
99-
return arr[i]

pandas/_testing.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from shutil import rmtree
99
import string
1010
import tempfile
11-
from typing import Any, List, Optional, Union, cast
11+
from typing import Any, Callable, List, Optional, Type, Union, cast
1212
import warnings
1313
import zipfile
1414

@@ -2757,3 +2757,24 @@ def convert_rows_list_to_csv_str(rows_list: List[str]):
27572757
sep = os.linesep
27582758
expected = sep.join(rows_list) + sep
27592759
return expected
2760+
2761+
2762+
def external_error_raised(
2763+
expected_exception: Type[Exception],
2764+
) -> Callable[[Type[Exception], None], None]:
2765+
"""
2766+
Helper function to mark pytest.raises that have an external error message.
2767+
2768+
Parameters
2769+
----------
2770+
expected_exception : Exception
2771+
Expected error to raise.
2772+
2773+
Returns
2774+
-------
2775+
Callable
2776+
Regular `pytest.raises` function with `match` equal to `None`.
2777+
"""
2778+
import pytest
2779+
2780+
return pytest.raises(expected_exception, match=None)

pandas/core/arrays/sparse/array.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import numpy as np
1111

12-
from pandas._libs import index as libindex, lib
12+
from pandas._libs import lib
1313
import pandas._libs.sparse as splib
1414
from pandas._libs.sparse import BlockIndex, IntIndex, SparseIndex
1515
from pandas._libs.tslibs import NaT
@@ -794,7 +794,9 @@ def _get_val_at(self, loc):
794794
if sp_loc == -1:
795795
return self.fill_value
796796
else:
797-
return libindex.get_value_at(self.sp_values, sp_loc)
797+
val = self.sp_values[sp_loc]
798+
val = com.maybe_box_datetimelike(val, self.sp_values.dtype)
799+
return val
798800

799801
def take(self, indices, allow_fill=False, fill_value=None):
800802
if is_scalar(indices):

pandas/core/common.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,12 @@ def consensus_name_attr(objs):
7272
return name
7373

7474

75-
def maybe_box_datetimelike(value):
75+
def maybe_box_datetimelike(value, dtype=None):
7676
# turn a datetime like into a Timestamp/timedelta as needed
77+
if dtype == object:
78+
# If we dont have datetime64/timedelta64 dtype, we dont want to
79+
# box datetimelike scalars
80+
return value
7781

7882
if isinstance(value, (np.datetime64, datetime)):
7983
value = tslibs.Timestamp(value)

pandas/core/generic.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3498,7 +3498,9 @@ def _iget_item_cache(self, item):
34983498
def _box_item_values(self, key, values):
34993499
raise AbstractMethodError(self)
35003500

3501-
def _slice(self: FrameOrSeries, slobj: slice, axis=0, kind=None) -> FrameOrSeries:
3501+
def _slice(
3502+
self: FrameOrSeries, slobj: slice, axis=0, kind: str = "getitem"
3503+
) -> FrameOrSeries:
35023504
"""
35033505
Construct a slice of this container.
35043506

pandas/core/indexes/base.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3100,20 +3100,16 @@ def _filter_indexer_tolerance(
31003100
# --------------------------------------------------------------------
31013101
# Indexer Conversion Methods
31023102

3103-
def _convert_scalar_indexer(self, key, kind=None):
3103+
def _convert_scalar_indexer(self, key, kind: str_t):
31043104
"""
31053105
Convert a scalar indexer.
31063106
31073107
Parameters
31083108
----------
31093109
key : label of the slice bound
3110-
kind : {'loc', 'getitem', 'iloc'} or None
3110+
kind : {'loc', 'getitem'}
31113111
"""
3112-
assert kind in ["loc", "getitem", "iloc", None]
3113-
3114-
if kind == "iloc":
3115-
self._validate_indexer("positional", key, "iloc")
3116-
return key
3112+
assert kind in ["loc", "getitem"]
31173113

31183114
if len(self) and not isinstance(self, ABCMultiIndex):
31193115

@@ -4590,9 +4586,9 @@ def get_value(self, series: "Series", key):
45904586
# If that fails, raise a KeyError if an integer
45914587
# index, otherwise, see if key is an integer, and
45924588
# try that
4593-
loc = self._engine.get_loc(key)
4589+
loc = self.get_loc(key)
45944590
except KeyError:
4595-
if len(self) > 0 and (self.holds_integer() or self.is_boolean()):
4591+
if not self._should_fallback_to_positional():
45964592
raise
45974593
elif is_integer(key):
45984594
# If the Index cannot hold integer, then this is unambiguously
@@ -4603,6 +4599,14 @@ def get_value(self, series: "Series", key):
46034599

46044600
return self._get_values_for_loc(series, loc)
46054601

4602+
def _should_fallback_to_positional(self) -> bool:
4603+
"""
4604+
If an integer key is not found, should we fall back to positional indexing?
4605+
"""
4606+
if len(self) > 0 and (self.holds_integer() or self.is_boolean()):
4607+
return False
4608+
return True
4609+
46064610
def _get_values_for_loc(self, series: "Series", loc):
46074611
"""
46084612
Do a positional lookup on the given Series, returning either a scalar

pandas/core/indexes/category.py

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -439,44 +439,10 @@ def _to_safe_for_reshape(self):
439439
""" convert to object if we are a categorical """
440440
return self.astype("object")
441441

442-
def get_loc(self, key, method=None):
443-
"""
444-
Get integer location, slice or boolean mask for requested label.
445-
446-
Parameters
447-
----------
448-
key : label
449-
method : {None}
450-
* default: exact matches only.
451-
452-
Returns
453-
-------
454-
loc : int if unique index, slice if monotonic index, else mask
455-
456-
Raises
457-
------
458-
KeyError : if the key is not in the index
459-
460-
Examples
461-
--------
462-
>>> unique_index = pd.CategoricalIndex(list('abc'))
463-
>>> unique_index.get_loc('b')
464-
1
465-
466-
>>> monotonic_index = pd.CategoricalIndex(list('abbc'))
467-
>>> monotonic_index.get_loc('b')
468-
slice(1, 3, None)
469-
470-
>>> non_monotonic_index = pd.CategoricalIndex(list('abcb'))
471-
>>> non_monotonic_index.get_loc('b')
472-
array([False, True, False, True], dtype=bool)
473-
"""
442+
def _maybe_cast_indexer(self, key):
474443
code = self.categories.get_loc(key)
475444
code = self.codes.dtype.type(code)
476-
try:
477-
return self._engine.get_loc(code)
478-
except KeyError:
479-
raise KeyError(key)
445+
return code
480446

481447
def get_value(self, series: "Series", key: Any):
482448
"""
@@ -658,10 +624,11 @@ def get_indexer_non_unique(self, target):
658624
return ensure_platform_int(indexer), missing
659625

660626
@Appender(Index._convert_scalar_indexer.__doc__)
661-
def _convert_scalar_indexer(self, key, kind=None):
627+
def _convert_scalar_indexer(self, key, kind: str):
628+
assert kind in ["loc", "getitem"]
662629
if kind == "loc":
663630
try:
664-
return self.categories._convert_scalar_indexer(key, kind=kind)
631+
return self.categories._convert_scalar_indexer(key, kind="loc")
665632
except TypeError:
666633
self._invalid_indexer("label", key)
667634
return super()._convert_scalar_indexer(key, kind=kind)

pandas/core/indexes/datetimelike.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,18 +385,18 @@ def _format_attrs(self):
385385
# --------------------------------------------------------------------
386386
# Indexing Methods
387387

388-
def _convert_scalar_indexer(self, key, kind=None):
388+
def _convert_scalar_indexer(self, key, kind: str):
389389
"""
390390
We don't allow integer or float indexing on datetime-like when using
391391
loc.
392392
393393
Parameters
394394
----------
395395
key : label of the slice bound
396-
kind : {'loc', 'getitem', 'iloc'} or None
396+
kind : {'loc', 'getitem'}
397397
"""
398398

399-
assert kind in ["loc", "getitem", "iloc", None]
399+
assert kind in ["loc", "getitem"]
400400

401401
if not is_scalar(key):
402402
raise TypeError(key)

0 commit comments

Comments
 (0)