Skip to content

Commit b2df890

Browse files
TYP: MergeHow + JoinHow (#49664)
1 parent 0ca49fc commit b2df890

File tree

4 files changed

+50
-28
lines changed

4 files changed

+50
-28
lines changed

pandas/_typing.py

+6
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,12 @@ def closed(self) -> bool:
343343
# dropna
344344
AnyAll = Literal["any", "all"]
345345

346+
# merge
347+
MergeHow = Literal["left", "right", "inner", "outer", "cross"]
348+
349+
# join
350+
JoinHow = Literal["left", "right", "inner", "outer"]
351+
346352
MatplotlibColor = Union[str, Sequence[float]]
347353
TimeGrouperOrigin = Union[
348354
"Timestamp", Literal["epoch", "start", "start_day", "end", "end_day"]

pandas/core/frame.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
IndexKeyFunc,
7272
IndexLabel,
7373
Level,
74+
MergeHow,
7475
NaPosition,
7576
PythonFuncType,
7677
QuantileInterpolation,
@@ -9588,7 +9589,7 @@ def join(
95889589
self,
95899590
other: DataFrame | Series | list[DataFrame | Series],
95909591
on: IndexLabel | None = None,
9591-
how: str = "left",
9592+
how: MergeHow = "left",
95929593
lsuffix: str = "",
95939594
rsuffix: str = "",
95949595
sort: bool = False,
@@ -9761,7 +9762,7 @@ def _join_compat(
97619762
self,
97629763
other: DataFrame | Series | Iterable[DataFrame | Series],
97639764
on: IndexLabel | None = None,
9764-
how: str = "left",
9765+
how: MergeHow = "left",
97659766
lsuffix: str = "",
97669767
rsuffix: str = "",
97679768
sort: bool = False,
@@ -9847,7 +9848,7 @@ def _join_compat(
98479848
def merge(
98489849
self,
98499850
right: DataFrame | Series,
9850-
how: str = "inner",
9851+
how: MergeHow = "inner",
98519852
on: IndexLabel | None = None,
98529853
left_on: IndexLabel | None = None,
98539854
right_on: IndexLabel | None = None,

pandas/core/indexes/base.py

+17-13
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
F,
5454
IgnoreRaise,
5555
IndexLabel,
56+
JoinHow,
5657
Level,
5758
Shape,
5859
npt,
@@ -216,7 +217,7 @@ def join(
216217
self,
217218
other: Index,
218219
*,
219-
how: str_t = "left",
220+
how: JoinHow = "left",
220221
level=None,
221222
return_indexers: bool = False,
222223
sort: bool = False,
@@ -4243,7 +4244,7 @@ def join(
42434244
self,
42444245
other: Index,
42454246
*,
4246-
how: str_t = ...,
4247+
how: JoinHow = ...,
42474248
level: Level = ...,
42484249
return_indexers: Literal[True],
42494250
sort: bool = ...,
@@ -4255,7 +4256,7 @@ def join(
42554256
self,
42564257
other: Index,
42574258
*,
4258-
how: str_t = ...,
4259+
how: JoinHow = ...,
42594260
level: Level = ...,
42604261
return_indexers: Literal[False] = ...,
42614262
sort: bool = ...,
@@ -4267,7 +4268,7 @@ def join(
42674268
self,
42684269
other: Index,
42694270
*,
4270-
how: str_t = ...,
4271+
how: JoinHow = ...,
42714272
level: Level = ...,
42724273
return_indexers: bool = ...,
42734274
sort: bool = ...,
@@ -4280,7 +4281,7 @@ def join(
42804281
self,
42814282
other: Index,
42824283
*,
4283-
how: str_t = "left",
4284+
how: JoinHow = "left",
42844285
level: Level = None,
42854286
return_indexers: bool = False,
42864287
sort: bool = False,
@@ -4355,7 +4356,8 @@ def join(
43554356
return join_index, None, rindexer
43564357

43574358
if self._join_precedence < other._join_precedence:
4358-
how = {"right": "left", "left": "right"}.get(how, how)
4359+
flip: dict[JoinHow, JoinHow] = {"right": "left", "left": "right"}
4360+
how = flip.get(how, how)
43594361
join_index, lidx, ridx = other.join(
43604362
self, how=how, level=level, return_indexers=True
43614363
)
@@ -4401,7 +4403,7 @@ def join(
44014403

44024404
@final
44034405
def _join_via_get_indexer(
4404-
self, other: Index, how: str_t, sort: bool
4406+
self, other: Index, how: JoinHow, sort: bool
44054407
) -> tuple[Index, npt.NDArray[np.intp] | None, npt.NDArray[np.intp] | None]:
44064408
# Fallback if we do not have any fastpaths available based on
44074409
# uniqueness/monotonicity
@@ -4435,7 +4437,7 @@ def _join_via_get_indexer(
44354437
return join_index, lindexer, rindexer
44364438

44374439
@final
4438-
def _join_multi(self, other: Index, how: str_t):
4440+
def _join_multi(self, other: Index, how: JoinHow):
44394441
from pandas.core.indexes.multi import MultiIndex
44404442
from pandas.core.reshape.merge import restore_dropped_levels_multijoin
44414443

@@ -4507,7 +4509,8 @@ def _join_multi(self, other: Index, how: str_t):
45074509
self, other = other, self
45084510
flip_order = True
45094511
# flip if join method is right or left
4510-
how = {"right": "left", "left": "right"}.get(how, how)
4512+
flip: dict[JoinHow, JoinHow] = {"right": "left", "left": "right"}
4513+
how = flip.get(how, how)
45114514

45124515
level = other.names.index(jl)
45134516
result = self._join_level(other, level, how=how)
@@ -4518,7 +4521,7 @@ def _join_multi(self, other: Index, how: str_t):
45184521

45194522
@final
45204523
def _join_non_unique(
4521-
self, other: Index, how: str_t = "left"
4524+
self, other: Index, how: JoinHow = "left"
45224525
) -> tuple[Index, npt.NDArray[np.intp], npt.NDArray[np.intp]]:
45234526
from pandas.core.reshape.merge import get_join_indexers
45244527

@@ -4537,7 +4540,7 @@ def _join_non_unique(
45374540

45384541
@final
45394542
def _join_level(
4540-
self, other: Index, level, how: str_t = "left", keep_order: bool = True
4543+
self, other: Index, level, how: JoinHow = "left", keep_order: bool = True
45414544
) -> tuple[MultiIndex, npt.NDArray[np.intp] | None, npt.NDArray[np.intp] | None]:
45424545
"""
45434546
The join method *only* affects the level of the resulting
@@ -4588,7 +4591,8 @@ def _get_leaf_sorter(labels: list[np.ndarray]) -> npt.NDArray[np.intp]:
45884591
flip_order = not isinstance(self, MultiIndex)
45894592
if flip_order:
45904593
left, right = right, left
4591-
how = {"right": "left", "left": "right"}.get(how, how)
4594+
flip: dict[JoinHow, JoinHow] = {"right": "left", "left": "right"}
4595+
how = flip.get(how, how)
45924596

45934597
assert isinstance(left, MultiIndex)
45944598

@@ -4685,7 +4689,7 @@ def _get_leaf_sorter(labels: list[np.ndarray]) -> npt.NDArray[np.intp]:
46854689

46864690
@final
46874691
def _join_monotonic(
4688-
self, other: Index, how: str_t = "left"
4692+
self, other: Index, how: JoinHow = "left"
46894693
) -> tuple[Index, npt.NDArray[np.intp] | None, npt.NDArray[np.intp] | None]:
46904694
# We only get here with matching dtypes and both monotonic increasing
46914695
assert other.dtype == self.dtype

pandas/core/reshape/merge.py

+23-12
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
AxisInt,
3131
DtypeObj,
3232
IndexLabel,
33+
JoinHow,
34+
Literal,
35+
MergeHow,
3336
Shape,
3437
Suffixes,
3538
npt,
@@ -120,7 +123,7 @@
120123
def merge(
121124
left: DataFrame | Series,
122125
right: DataFrame | Series,
123-
how: str = "inner",
126+
how: MergeHow = "inner",
124127
on: IndexLabel | None = None,
125128
left_on: IndexLabel | None = None,
126129
right_on: IndexLabel | None = None,
@@ -219,7 +222,7 @@ def merge_ordered(
219222
right_by=None,
220223
fill_method: str | None = None,
221224
suffixes: Suffixes = ("_x", "_y"),
222-
how: str = "outer",
225+
how: JoinHow = "outer",
223226
) -> DataFrame:
224227
"""
225228
Perform a merge for ordered data with optional filling/interpolation.
@@ -633,7 +636,7 @@ class _MergeOperation:
633636
"""
634637

635638
_merge_type = "merge"
636-
how: str
639+
how: MergeHow | Literal["asof"]
637640
on: IndexLabel | None
638641
# left_on/right_on may be None when passed, but in validate_specification
639642
# get replaced with non-None.
@@ -656,7 +659,7 @@ def __init__(
656659
self,
657660
left: DataFrame | Series,
658661
right: DataFrame | Series,
659-
how: str = "inner",
662+
how: MergeHow | Literal["asof"] = "inner",
660663
on: IndexLabel | None = None,
661664
left_on: IndexLabel | None = None,
662665
right_on: IndexLabel | None = None,
@@ -1031,7 +1034,8 @@ def _get_join_indexers(self) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]
10311034
def _get_join_info(
10321035
self,
10331036
) -> tuple[Index, npt.NDArray[np.intp] | None, npt.NDArray[np.intp] | None]:
1034-
1037+
# make mypy happy
1038+
assert self.how != "cross"
10351039
left_ax = self.left.axes[self.axis]
10361040
right_ax = self.right.axes[self.axis]
10371041

@@ -1093,7 +1097,7 @@ def _create_join_index(
10931097
index: Index,
10941098
other_index: Index,
10951099
indexer: npt.NDArray[np.intp],
1096-
how: str = "left",
1100+
how: JoinHow = "left",
10971101
) -> Index:
10981102
"""
10991103
Create a join index by rearranging one index to match another
@@ -1427,7 +1431,7 @@ def _maybe_coerce_merge_keys(self) -> None:
14271431

14281432
def _create_cross_configuration(
14291433
self, left: DataFrame, right: DataFrame
1430-
) -> tuple[DataFrame, DataFrame, str, str]:
1434+
) -> tuple[DataFrame, DataFrame, JoinHow, str]:
14311435
"""
14321436
Creates the configuration to dispatch the cross operation to inner join,
14331437
e.g. adding a join column and resetting parameters. Join column is added
@@ -1445,7 +1449,7 @@ def _create_cross_configuration(
14451449
to join over.
14461450
"""
14471451
cross_col = f"_cross_{uuid.uuid4()}"
1448-
how = "inner"
1452+
how: JoinHow = "inner"
14491453
return (
14501454
left.assign(**{cross_col: 1}),
14511455
right.assign(**{cross_col: 1}),
@@ -1605,7 +1609,11 @@ def _validate(self, validate: str) -> None:
16051609

16061610

16071611
def get_join_indexers(
1608-
left_keys, right_keys, sort: bool = False, how: str = "inner", **kwargs
1612+
left_keys,
1613+
right_keys,
1614+
sort: bool = False,
1615+
how: MergeHow | Literal["asof"] = "inner",
1616+
**kwargs,
16091617
) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]:
16101618
"""
16111619
@@ -1778,7 +1786,7 @@ def __init__(
17781786
axis: AxisInt = 1,
17791787
suffixes: Suffixes = ("_x", "_y"),
17801788
fill_method: str | None = None,
1781-
how: str = "outer",
1789+
how: JoinHow | Literal["asof"] = "outer",
17821790
) -> None:
17831791

17841792
self.fill_method = fill_method
@@ -1868,7 +1876,7 @@ def __init__(
18681876
suffixes: Suffixes = ("_x", "_y"),
18691877
copy: bool = True,
18701878
fill_method: str | None = None,
1871-
how: str = "asof",
1879+
how: Literal["asof"] = "asof",
18721880
tolerance=None,
18731881
allow_exact_matches: bool = True,
18741882
direction: str = "backward",
@@ -2277,7 +2285,10 @@ def _left_join_on_index(
22772285

22782286

22792287
def _factorize_keys(
2280-
lk: ArrayLike, rk: ArrayLike, sort: bool = True, how: str = "inner"
2288+
lk: ArrayLike,
2289+
rk: ArrayLike,
2290+
sort: bool = True,
2291+
how: MergeHow | Literal["asof"] = "inner",
22812292
) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp], int]:
22822293
"""
22832294
Encode left and right keys as enumerated types.

0 commit comments

Comments
 (0)