Skip to content

Commit 72bf4ef

Browse files
authored
Merge pull request #34 from pandas-dev/master
Sync Fork from Upstream Repo
2 parents d74e655 + 106ed85 commit 72bf4ef

File tree

14 files changed

+87
-78
lines changed

14 files changed

+87
-78
lines changed

doc/redirects.csv

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ developer,development/developer
4646
extending,development/extending
4747
internals,development/internals
4848

49-
# api
49+
# api moved function
50+
reference/api/pandas.io.json.json_normalize,pandas.json_normalize
51+
52+
# api rename
5053
api,reference/index
5154
generated/pandas.api.extensions.ExtensionArray.argsort,../reference/api/pandas.api.extensions.ExtensionArray.argsort
5255
generated/pandas.api.extensions.ExtensionArray.astype,../reference/api/pandas.api.extensions.ExtensionArray.astype

doc/source/whatsnew/v1.0.1.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Fixed regressions
1717

1818
- Fixed regression in :class:`DataFrame` setting values with a slice (e.g. ``df[-4:] = 1``) indexing by label instead of position (:issue:`31469`)
1919
- Fixed regression when indexing a ``Series`` or ``DataFrame`` indexed by ``DatetimeIndex`` with a slice containg a :class:`datetime.date` (:issue:`31501`)
20+
- Fixed regression in ``DataFrame.__setitem__`` raising an ``AttributeError`` with a :class:`MultiIndex` and a non-monotonic indexer (:issue:`31449`)
2021
- Fixed regression in :class:`Series` multiplication when multiplying a numeric :class:`Series` with >10000 elements with a timedelta-like scalar (:issue:`31457`)
2122
- Fixed regression in :meth:`GroupBy.apply` if called with a function which returned a non-pandas non-scalar object (e.g. a list or numpy array) (:issue:`31441`)
2223
- Fixed regression in :meth:`to_datetime` when parsing non-nanosecond resolution datetimes (:issue:`31491`)

doc/source/whatsnew/v1.1.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ Datetimelike
109109
- :meth:`DatetimeArray.searchsorted`, :meth:`TimedeltaArray.searchsorted`, :meth:`PeriodArray.searchsorted` not recognizing non-pandas scalars and incorrectly raising ``ValueError`` instead of ``TypeError`` (:issue:`30950`)
110110
- Bug in :class:`Timestamp` where constructing :class:`Timestamp` with dateutil timezone less than 128 nanoseconds before daylight saving time switch from winter to summer would result in nonexistent time (:issue:`31043`)
111111
- Bug in :meth:`DataFrame.reindex` and :meth:`Series.reindex` when reindexing with a tz-aware index (:issue:`26683`)
112+
- Bug in :meth:`Period.to_timestamp`, :meth:`Period.start_time` with microsecond frequency returning a timestamp one nanosecond earlier than the correct time (:issue:`31475`)
112113

113114
Timedelta
114115
^^^^^^^^^

pandas/_libs/tslibs/period.pyx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ PyDateTime_IMPORT
2222
from pandas._libs.tslibs.np_datetime cimport (
2323
npy_datetimestruct, dtstruct_to_dt64, dt64_to_dtstruct,
2424
pandas_datetime_to_datetimestruct, check_dts_bounds,
25-
NPY_DATETIMEUNIT, NPY_FR_D)
25+
NPY_DATETIMEUNIT, NPY_FR_D, NPY_FR_us)
2626

2727
cdef extern from "src/datetime/np_datetime.h":
2828
int64_t npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT fr,
@@ -1169,7 +1169,12 @@ cdef int64_t period_ordinal_to_dt64(int64_t ordinal, int freq) except? -1:
11691169
if ordinal == NPY_NAT:
11701170
return NPY_NAT
11711171

1172-
get_date_info(ordinal, freq, &dts)
1172+
if freq == 11000:
1173+
# Microsecond, avoid get_date_info to prevent floating point errors
1174+
pandas_datetime_to_datetimestruct(ordinal, NPY_FR_us, &dts)
1175+
else:
1176+
get_date_info(ordinal, freq, &dts)
1177+
11731178
check_dts_bounds(&dts)
11741179
return dtstruct_to_dt64(&dts)
11751180

pandas/core/indexing.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -893,7 +893,8 @@ def _setitem_with_indexer(self, indexer, value):
893893

894894
# we can directly set the series here
895895
# as we select a slice indexer on the mi
896-
idx = index._convert_slice_indexer(idx)
896+
if isinstance(idx, slice):
897+
idx = index._convert_slice_indexer(idx)
897898
obj._consolidate_inplace()
898899
obj = obj.copy()
899900
obj._data = obj._data.setitem(indexer=tuple([idx]), value=value)

pandas/core/reshape/concat.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,8 @@ def __init__(
352352
for obj in objs:
353353
if not isinstance(obj, (Series, DataFrame)):
354354
msg = (
355-
"cannot concatenate object of type '{typ}'; "
356-
"only Series and DataFrame objs are valid".format(typ=type(obj))
355+
f"cannot concatenate object of type '{type(obj)}'; "
356+
"only Series and DataFrame objs are valid"
357357
)
358358
raise TypeError(msg)
359359

@@ -403,8 +403,7 @@ def __init__(
403403
self._is_series = isinstance(sample, ABCSeries)
404404
if not 0 <= axis <= sample.ndim:
405405
raise AssertionError(
406-
"axis must be between 0 and {ndim}, input was "
407-
"{axis}".format(ndim=sample.ndim, axis=axis)
406+
f"axis must be between 0 and {sample.ndim}, input was {axis}"
408407
)
409408

410409
# if we have mixed ndims, then convert to highest ndim
@@ -622,11 +621,7 @@ def _make_concat_multiindex(indexes, keys, levels=None, names=None) -> MultiInde
622621
try:
623622
i = level.get_loc(key)
624623
except KeyError:
625-
raise ValueError(
626-
"Key {key!s} not in level {level!s}".format(
627-
key=key, level=level
628-
)
629-
)
624+
raise ValueError(f"Key {key} not in level {level}")
630625

631626
to_concat.append(np.repeat(i, len(index)))
632627
codes_list.append(np.concatenate(to_concat))
@@ -677,11 +672,7 @@ def _make_concat_multiindex(indexes, keys, levels=None, names=None) -> MultiInde
677672

678673
mask = mapped == -1
679674
if mask.any():
680-
raise ValueError(
681-
"Values not found in passed level: {hlevel!s}".format(
682-
hlevel=hlevel[mask]
683-
)
684-
)
675+
raise ValueError(f"Values not found in passed level: {hlevel[mask]!s}")
685676

686677
new_codes.append(np.repeat(mapped, n))
687678

pandas/core/reshape/melt.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,7 @@ def melt(
8888
if len(frame.columns.names) == len(set(frame.columns.names)):
8989
var_name = frame.columns.names
9090
else:
91-
var_name = [
92-
"variable_{i}".format(i=i) for i in range(len(frame.columns.names))
93-
]
91+
var_name = [f"variable_{i}" for i in range(len(frame.columns.names))]
9492
else:
9593
var_name = [
9694
frame.columns.name if frame.columns.name is not None else "variable"
@@ -417,9 +415,7 @@ def wide_to_long(
417415
"""
418416

419417
def get_var_names(df, stub: str, sep: str, suffix: str) -> List[str]:
420-
regex = r"^{stub}{sep}{suffix}$".format(
421-
stub=re.escape(stub), sep=re.escape(sep), suffix=suffix
422-
)
418+
regex = fr"^{re.escape(stub)}{re.escape(sep)}{suffix}$"
423419
pattern = re.compile(regex)
424420
return [col for col in df.columns if pattern.match(col)]
425421

pandas/core/reshape/merge.py

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -611,8 +611,9 @@ def __init__(
611611
if _left.columns.nlevels != _right.columns.nlevels:
612612
msg = (
613613
"merging between different levels can give an unintended "
614-
"result ({left} levels on the left, {right} on the right)"
615-
).format(left=_left.columns.nlevels, right=_right.columns.nlevels)
614+
f"result ({left.columns.nlevels} levels on the left,"
615+
f"{right.columns.nlevels} on the right)"
616+
)
616617
warnings.warn(msg, UserWarning)
617618

618619
self._validate_specification()
@@ -679,7 +680,7 @@ def _indicator_pre_merge(
679680
if i in columns:
680681
raise ValueError(
681682
"Cannot use `indicator=True` option when "
682-
"data contains a column named {name}".format(name=i)
683+
f"data contains a column named {i}"
683684
)
684685
if self.indicator_name in columns:
685686
raise ValueError(
@@ -831,7 +832,7 @@ def _maybe_add_join_keys(self, result, left_indexer, right_indexer):
831832
else:
832833
result.index = Index(key_col, name=name)
833834
else:
834-
result.insert(i, name or "key_{i}".format(i=i), key_col)
835+
result.insert(i, name or f"key_{i}", key_col)
835836

836837
def _get_join_indexers(self):
837838
""" return the join indexers """
@@ -1185,13 +1186,10 @@ def _validate_specification(self):
11851186
if len(common_cols) == 0:
11861187
raise MergeError(
11871188
"No common columns to perform merge on. "
1188-
"Merge options: left_on={lon}, right_on={ron}, "
1189-
"left_index={lidx}, right_index={ridx}".format(
1190-
lon=self.left_on,
1191-
ron=self.right_on,
1192-
lidx=self.left_index,
1193-
ridx=self.right_index,
1194-
)
1189+
f"Merge options: left_on={self.left_on}, "
1190+
f"right_on={self.right_on}, "
1191+
f"left_index={self.left_index}, "
1192+
f"right_index={self.right_index}"
11951193
)
11961194
if not common_cols.is_unique:
11971195
raise MergeError(f"Data columns not unique: {repr(common_cols)}")
@@ -1486,12 +1484,12 @@ def get_result(self):
14861484

14871485

14881486
def _asof_function(direction: str):
1489-
name = "asof_join_{dir}".format(dir=direction)
1487+
name = f"asof_join_{direction}"
14901488
return getattr(libjoin, name, None)
14911489

14921490

14931491
def _asof_by_function(direction: str):
1494-
name = "asof_join_{dir}_on_X_by_Y".format(dir=direction)
1492+
name = f"asof_join_{direction}_on_X_by_Y"
14951493
return getattr(libjoin, name, None)
14961494

14971495

@@ -1601,9 +1599,7 @@ def _validate_specification(self):
16011599

16021600
# check 'direction' is valid
16031601
if self.direction not in ["backward", "forward", "nearest"]:
1604-
raise MergeError(
1605-
"direction invalid: {direction}".format(direction=self.direction)
1606-
)
1602+
raise MergeError(f"direction invalid: {self.direction}")
16071603

16081604
@property
16091605
def _asof_key(self):
@@ -1628,17 +1624,13 @@ def _get_merge_keys(self):
16281624
# later with a ValueError, so we don't *need* to check
16291625
# for them here.
16301626
msg = (
1631-
"incompatible merge keys [{i}] {lkdtype} and "
1632-
"{rkdtype}, both sides category, but not equal ones".format(
1633-
i=i, lkdtype=repr(lk.dtype), rkdtype=repr(rk.dtype)
1634-
)
1627+
f"incompatible merge keys [{i}] {repr(lk.dtype)} and "
1628+
f"{repr(rk.dtype)}, both sides category, but not equal ones"
16351629
)
16361630
else:
16371631
msg = (
1638-
"incompatible merge keys [{i}] {lkdtype} and "
1639-
"{rkdtype}, must be the same type".format(
1640-
i=i, lkdtype=repr(lk.dtype), rkdtype=repr(rk.dtype)
1641-
)
1632+
f"incompatible merge keys [{i}] {repr(lk.dtype)} and "
1633+
f"{repr(rk.dtype)}, must be the same type"
16421634
)
16431635
raise MergeError(msg)
16441636

@@ -1651,10 +1643,8 @@ def _get_merge_keys(self):
16511643
lt = left_join_keys[-1]
16521644

16531645
msg = (
1654-
"incompatible tolerance {tolerance}, must be compat "
1655-
"with type {lkdtype}".format(
1656-
tolerance=type(self.tolerance), lkdtype=repr(lt.dtype)
1657-
)
1646+
f"incompatible tolerance {self.tolerance}, must be compat "
1647+
f"with type {repr(lk.dtype)}"
16581648
)
16591649

16601650
if needs_i8_conversion(lt):
@@ -1680,8 +1670,11 @@ def _get_merge_keys(self):
16801670

16811671
# validate allow_exact_matches
16821672
if not is_bool(self.allow_exact_matches):
1683-
msg = "allow_exact_matches must be boolean, passed {passed}"
1684-
raise MergeError(msg.format(passed=self.allow_exact_matches))
1673+
msg = (
1674+
"allow_exact_matches must be boolean, "
1675+
f"passed {self.allow_exact_matches}"
1676+
)
1677+
raise MergeError(msg)
16851678

16861679
return left_join_keys, right_join_keys, join_names
16871680

pandas/core/reshape/pivot.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ def _add_margins(
200200
if not isinstance(margins_name, str):
201201
raise ValueError("margins_name argument must be a string")
202202

203-
msg = 'Conflicting name "{name}" in margins'.format(name=margins_name)
203+
msg = f'Conflicting name "{margins_name}" in margins'
204204
for level in table.index.names:
205205
if margins_name in table.index.get_level_values(level):
206206
raise ValueError(msg)
@@ -650,9 +650,7 @@ def _normalize(table, normalize, margins: bool, margins_name="All"):
650650
if (margins_name not in table.iloc[-1, :].name) | (
651651
margins_name != table.iloc[:, -1].name
652652
):
653-
raise ValueError(
654-
"{mname} not in pivoted DataFrame".format(mname=margins_name)
655-
)
653+
raise ValueError(f"{margins_name} not in pivoted DataFrame")
656654
column_margin = table.iloc[:-1, -1]
657655
index_margin = table.iloc[-1, :-1]
658656

@@ -702,7 +700,7 @@ def _get_names(arrs, names, prefix: str = "row"):
702700
if isinstance(arr, ABCSeries) and arr.name is not None:
703701
names.append(arr.name)
704702
else:
705-
names.append("{prefix}_{i}".format(prefix=prefix, i=i))
703+
names.append(f"{prefix}_{i}")
706704
else:
707705
if len(names) != len(arrs):
708706
raise AssertionError("arrays and names must have the same length")

pandas/core/reshape/reshape.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -873,15 +873,13 @@ def get_dummies(
873873

874874
# validate prefixes and separator to avoid silently dropping cols
875875
def check_len(item, name):
876-
len_msg = (
877-
"Length of '{name}' ({len_item}) did not match the "
878-
"length of the columns being encoded ({len_enc})."
879-
)
880876

881877
if is_list_like(item):
882878
if not len(item) == data_to_encode.shape[1]:
883-
len_msg = len_msg.format(
884-
name=name, len_item=len(item), len_enc=data_to_encode.shape[1]
879+
len_msg = (
880+
f"Length of '{name}' ({len(item)}) did not match the "
881+
"length of the columns being encoded "
882+
f"({data_to_encode.shape[1]})."
885883
)
886884
raise ValueError(len_msg)
887885

@@ -990,8 +988,7 @@ def get_empty_frame(data) -> DataFrame:
990988

991989
# PY2 embedded unicode, gh-22084
992990
def _make_col_name(prefix, prefix_sep, level) -> str:
993-
fstr = "{prefix}{prefix_sep}{level}"
994-
return fstr.format(prefix=prefix, prefix_sep=prefix_sep, level=level)
991+
return f"{prefix}{prefix_sep}{level}"
995992

996993
dummy_cols = [_make_col_name(prefix, prefix_sep, level) for level in levels]
997994

pandas/tests/indexing/multiindex/test_setitem.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,16 @@ def test_astype_assignment_with_dups(self):
414414
df["A"] = df["A"].astype(np.float64)
415415
tm.assert_index_equal(df.index, index)
416416

417+
def test_setitem_nonmonotonic(self):
418+
# https://github.com/pandas-dev/pandas/issues/31449
419+
index = pd.MultiIndex.from_tuples(
420+
[("a", "c"), ("b", "x"), ("a", "d")], names=["l1", "l2"]
421+
)
422+
df = pd.DataFrame(data=[0, 1, 2], index=index, columns=["e"])
423+
df.loc["a", "e"] = np.arange(99, 101, dtype="int64")
424+
expected = pd.DataFrame({"e": [99, 1, 100]}, index=index)
425+
tm.assert_frame_equal(df, expected)
426+
417427

418428
def test_frame_setitem_view_direct(multiindex_dataframe_random_data):
419429
# this works because we are modifying the underlying array

pandas/tests/io/test_pickle.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@ def compare_element(result, expected, typ, version=None):
6060
assert result == expected
6161
assert result.freq == expected.freq
6262
else:
63-
comparator = getattr(
64-
tm, "assert_{typ}_equal".format(typ=typ), tm.assert_almost_equal
65-
)
63+
comparator = getattr(tm, f"assert_{typ}_equal", tm.assert_almost_equal)
6664
comparator(result, expected)
6765

6866

@@ -77,7 +75,7 @@ def compare(data, vf, version):
7775

7876
# use a specific comparator
7977
# if available
80-
comparator = "compare_{typ}_{dt}".format(typ=typ, dt=dt)
78+
comparator = f"compare_{typ}_{dt}"
8179

8280
comparator = m.get(comparator, m["compare_element"])
8381
comparator(result, expected, typ, version)
@@ -234,7 +232,7 @@ def test_legacy_sparse_warning(datapath):
234232

235233
@pytest.fixture
236234
def get_random_path():
237-
return "__{}__.pickle".format(tm.rands(10))
235+
return f"__{tm.rands(10)}__.pickle"
238236

239237

240238
class TestCompression:
@@ -262,7 +260,7 @@ def compress_file(self, src_path, dest_path, compression):
262260
elif compression == "xz":
263261
f = _get_lzma_file(lzma)(dest_path, "w")
264262
else:
265-
msg = "Unrecognized compression type: {}".format(compression)
263+
msg = f"Unrecognized compression type: {compression}"
266264
raise ValueError(msg)
267265

268266
if compression != "zip":

pandas/tests/reshape/merge/test_merge.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,10 +371,8 @@ def test_no_overlap_more_informative_error(self):
371371

372372
msg = (
373373
"No common columns to perform merge on. "
374-
"Merge options: left_on={lon}, right_on={ron}, "
375-
"left_index={lidx}, right_index={ridx}".format(
376-
lon=None, ron=None, lidx=False, ridx=False
377-
)
374+
f"Merge options: left_on={None}, right_on={None}, "
375+
f"left_index={False}, right_index={False}"
378376
)
379377

380378
with pytest.raises(MergeError, match=msg):

0 commit comments

Comments
 (0)