From 390e5d93cd5945e675f50929081d6e69ab126e74 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Fri, 18 Jul 2025 16:17:50 +0200 Subject: [PATCH 01/11] feat(index): append --- pandas-stubs/core/indexes/base.pyi | 7 ++++- pyproject.toml | 2 +- tests/test_indexes.py | 43 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 4f9ebd44..83151d3e 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -401,7 +401,12 @@ class Index(IndexOpsMixin[S1]): ) -> Self: ... @overload def __getitem__(self, idx: int | tuple[np_ndarray_anyint, ...]) -> S1: ... - def append(self, other): ... + @overload + def append(self, other: Index[Never]) -> Index: ... + @overload + def append(self, other: Index[S1] | Sequence[Index[S1]]) -> Index[S1]: ... + @overload + def append(self, other: Index | Sequence) -> Index: ... def putmask(self, mask, value): ... def equals(self, other) -> bool: ... @final diff --git a/pyproject.toml b/pyproject.toml index 71400163..d916bfa9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ mypy = "1.17.0" pandas = "2.3.0" pyarrow = ">=10.0.1" pytest = ">=7.1.2" -pyright = ">=1.1.400" +pyright = ">=1.1.403" ty = "^0.0.1a8" pyrefly = "^0.21.0" poethepoet = ">=0.16.5" diff --git a/tests/test_indexes.py b/tests/test_indexes.py index b3f566cd..d10717a3 100644 --- a/tests/test_indexes.py +++ b/tests/test_indexes.py @@ -1028,6 +1028,49 @@ def test_getitem() -> None: check(assert_type(i0[[0, 2]], "pd.Index[str]"), pd.Index, str) +def test_append_any() -> None: + """Test pd.Index.append that gives pd.Index[Any]""" + first = pd.Index([1]) + second = pd.Index(["a"]) + third = pd.Index([1, "a"]) + check(assert_type(first.append(second), pd.Index), pd.Index) + check(assert_type(first.append([second]), pd.Index), pd.Index) + + check(assert_type(first.append(third), pd.Index), pd.Index) + check(assert_type(first.append([third]), pd.Index), pd.Index) + check(assert_type(first.append([second, third]), pd.Index), pd.Index) + + check(assert_type(third.append([]), "pd.Index[str | int]"), pd.Index) # type: ignore[assert-type] + check(assert_type(third.append([first]), pd.Index), pd.Index) + + +def test_append_int() -> None: + """Test pd.Index[int].append""" + first = pd.Index([1]) + second = pd.Index([2]) + check(assert_type(first.append([]), "pd.Index[int]"), pd.Index, np.int64) + check(assert_type(first.append(second), "pd.Index[int]"), pd.Index, np.int64) + check(assert_type(first.append([second]), "pd.Index[int]"), pd.Index, np.int64) + + +def test_append_str() -> None: + """Test pd.Index[str].append""" + first = pd.Index(["str"]) + second = pd.Index(["rts"]) + check(assert_type(first.append([]), "pd.Index[str]"), pd.Index, str) + check(assert_type(first.append(second), "pd.Index[str]"), pd.Index, str) + check(assert_type(first.append([second]), "pd.Index[str]"), pd.Index, str) + + +def test_append_list_str() -> None: + """Test pd.Index[list[str]].append""" + first = pd.Index([["str", "rts"]]) + second = pd.Index([["srt", "trs"]]) + check(assert_type(first.append([]), "pd.Index[list[str]]"), pd.Index, list) + check(assert_type(first.append(second), "pd.Index[list[str]]"), pd.Index, list) + check(assert_type(first.append([second]), "pd.Index[list[str]]"), pd.Index, list) + + def test_range_index_range() -> None: """Test that pd.RangeIndex can be initialized from range.""" iri = pd.RangeIndex(range(5)) From 3a3405797429eb262949b6b9d3c7e6d6a0d301bd Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Fri, 18 Jul 2025 17:17:34 +0200 Subject: [PATCH 02/11] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1282#discussion_r2216245105 --- pandas-stubs/core/indexes/base.pyi | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 83151d3e..e9ccdb12 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -402,8 +402,6 @@ class Index(IndexOpsMixin[S1]): @overload def __getitem__(self, idx: int | tuple[np_ndarray_anyint, ...]) -> S1: ... @overload - def append(self, other: Index[Never]) -> Index: ... - @overload def append(self, other: Index[S1] | Sequence[Index[S1]]) -> Index[S1]: ... @overload def append(self, other: Index | Sequence) -> Index: ... From 45e0ad30fd18379d6b97f74d8e2a68ca37c3fa3a Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Fri, 18 Jul 2025 17:37:04 +0200 Subject: [PATCH 03/11] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1282/files#r2216273709 --- pandas-stubs/core/indexes/base.pyi | 5 ++++- tests/test_indexes.py | 35 +++++++++++++++++++++++------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index e9ccdb12..abb327b9 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -43,6 +43,7 @@ from typing_extensions import ( from pandas._libs.interval import _OrderableT from pandas._typing import ( S1, + S2, AnyAll, AxesData, DropKeep, @@ -402,7 +403,9 @@ class Index(IndexOpsMixin[S1]): @overload def __getitem__(self, idx: int | tuple[np_ndarray_anyint, ...]) -> S1: ... @overload - def append(self, other: Index[S1] | Sequence[Index[S1]]) -> Index[S1]: ... + def append(self, other: Index[S1] | Sequence[Index[S1]]) -> Self: ... + @overload + def append(self, other: Index[S2] | Sequence[Index[S2]]) -> Index[S1 | S2]: ... @overload def append(self, other: Index | Sequence) -> Index: ... def putmask(self, mask, value): ... diff --git a/tests/test_indexes.py b/tests/test_indexes.py index d10717a3..fd852647 100644 --- a/tests/test_indexes.py +++ b/tests/test_indexes.py @@ -3,7 +3,9 @@ import datetime as dt from typing import ( TYPE_CHECKING, + Any, Union, + cast, ) import numpy as np @@ -1028,20 +1030,37 @@ def test_getitem() -> None: check(assert_type(i0[[0, 2]], "pd.Index[str]"), pd.Index, str) -def test_append_any() -> None: +def test_append_mix() -> None: """Test pd.Index.append that gives pd.Index[Any]""" first = pd.Index([1]) second = pd.Index(["a"]) third = pd.Index([1, "a"]) - check(assert_type(first.append(second), pd.Index), pd.Index) - check(assert_type(first.append([second]), pd.Index), pd.Index) + check(assert_type(first.append(second), "pd.Index[int | str]"), pd.Index) + check(assert_type(first.append([second]), "pd.Index[int | str]"), pd.Index) - check(assert_type(first.append(third), pd.Index), pd.Index) - check(assert_type(first.append([third]), pd.Index), pd.Index) - check(assert_type(first.append([second, third]), pd.Index), pd.Index) + check(assert_type(first.append(third), "pd.Index[int | str]"), pd.Index) # type: ignore[assert-type] + check(assert_type(first.append([third]), "pd.Index[int | str]"), pd.Index) # type: ignore[assert-type] + check( + assert_type( # type: ignore[assert-type] + first.append([second, third]), # pyright: ignore[reportAssertTypeFailure] + "pd.Index[int | str]", + ), + pd.Index, + ) - check(assert_type(third.append([]), "pd.Index[str | int]"), pd.Index) # type: ignore[assert-type] - check(assert_type(third.append([first]), pd.Index), pd.Index) + check(assert_type(third.append([]), "pd.Index[int | str]"), pd.Index) # type: ignore[assert-type] + check( + assert_type(third.append(cast("list[Index[Any]]", [])), "pd.Index[int | str]"), # type: ignore[assert-type] + pd.Index, + ) + check(assert_type(third.append([first]), "pd.Index[int | str]"), pd.Index) # type: ignore[assert-type] + check( + assert_type( # type: ignore[assert-type] + third.append([first, second]), # pyright: ignore[reportAssertTypeFailure] + "pd.Index[int | str]", + ), + pd.Index, + ) def test_append_int() -> None: From 6c8ba76ac82bdc27b2c012a45d660a0f0488b6da Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Fri, 18 Jul 2025 17:49:19 +0200 Subject: [PATCH 04/11] fix(pyrefly): ignore --- pandas-stubs/core/indexes/multi.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas-stubs/core/indexes/multi.pyi b/pandas-stubs/core/indexes/multi.pyi index d313852d..5278d081 100644 --- a/pandas-stubs/core/indexes/multi.pyi +++ b/pandas-stubs/core/indexes/multi.pyi @@ -135,7 +135,7 @@ class MultiIndex(Index): def take( self, indices, axis: int = ..., allow_fill: bool = ..., fill_value=..., **kwargs ): ... - def append(self, other): ... + def append(self, other): ... # pyrefly: ignore def argsort(self, *args, **kwargs): ... def repeat(self, repeats, axis=...): ... @final From 3844062b0df37d810c10744b226d2aa9641c4286 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sat, 19 Jul 2025 20:05:25 +0200 Subject: [PATCH 05/11] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1282#discussion_r2217319354 --- pandas-stubs/core/indexes/base.pyi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index abb327b9..0480ac05 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -15,6 +15,7 @@ from typing import ( ClassVar, Literal, TypeAlias, + TypeVar, final, overload, ) @@ -65,6 +66,8 @@ from pandas._typing import ( type_t, ) +_T_INDEX = TypeVar("_T_INDEX", bound=Index) # ty: ignore[unresolved-reference] + class InvalidIndexError(Exception): ... class Index(IndexOpsMixin[S1]): @@ -407,6 +410,8 @@ class Index(IndexOpsMixin[S1]): @overload def append(self, other: Index[S2] | Sequence[Index[S2]]) -> Index[S1 | S2]: ... @overload + def append(self, other: Sequence[_T_INDEX]) -> Self | _T_INDEX: ... + @overload def append(self, other: Index | Sequence) -> Index: ... def putmask(self, mask, value): ... def equals(self, other) -> bool: ... From ac0857ba032422c8342c616b6479ae2054416d3a Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 29 Jul 2025 12:46:51 +0200 Subject: [PATCH 06/11] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1282#discussion_r2229540968 --- tests/test_indexes.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/test_indexes.py b/tests/test_indexes.py index fd852647..1d788a70 100644 --- a/tests/test_indexes.py +++ b/tests/test_indexes.py @@ -1081,15 +1081,6 @@ def test_append_str() -> None: check(assert_type(first.append([second]), "pd.Index[str]"), pd.Index, str) -def test_append_list_str() -> None: - """Test pd.Index[list[str]].append""" - first = pd.Index([["str", "rts"]]) - second = pd.Index([["srt", "trs"]]) - check(assert_type(first.append([]), "pd.Index[list[str]]"), pd.Index, list) - check(assert_type(first.append(second), "pd.Index[list[str]]"), pd.Index, list) - check(assert_type(first.append([second]), "pd.Index[list[str]]"), pd.Index, list) - - def test_range_index_range() -> None: """Test that pd.RangeIndex can be initialized from range.""" iri = pd.RangeIndex(range(5)) From 67e6bde96ea6894aa32b827610347f76c2728989 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 29 Jul 2025 12:59:27 +0200 Subject: [PATCH 07/11] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1282#discussion_r2229516180 --- pandas-stubs/core/indexes/base.pyi | 9 ++------- tests/test_indexes.py | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 0480ac05..b1531aaf 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -15,7 +15,6 @@ from typing import ( ClassVar, Literal, TypeAlias, - TypeVar, final, overload, ) @@ -66,8 +65,6 @@ from pandas._typing import ( type_t, ) -_T_INDEX = TypeVar("_T_INDEX", bound=Index) # ty: ignore[unresolved-reference] - class InvalidIndexError(Exception): ... class Index(IndexOpsMixin[S1]): @@ -408,11 +405,9 @@ class Index(IndexOpsMixin[S1]): @overload def append(self, other: Index[S1] | Sequence[Index[S1]]) -> Self: ... @overload - def append(self, other: Index[S2] | Sequence[Index[S2]]) -> Index[S1 | S2]: ... - @overload - def append(self, other: Sequence[_T_INDEX]) -> Self | _T_INDEX: ... + def append(self, other: Index[S2]) -> Index[S1 | S2]: ... @overload - def append(self, other: Index | Sequence) -> Index: ... + def append(self, other: Sequence) -> Index: ... def putmask(self, mask, value): ... def equals(self, other) -> bool: ... @final diff --git a/tests/test_indexes.py b/tests/test_indexes.py index 1d788a70..222edebf 100644 --- a/tests/test_indexes.py +++ b/tests/test_indexes.py @@ -1036,31 +1036,31 @@ def test_append_mix() -> None: second = pd.Index(["a"]) third = pd.Index([1, "a"]) check(assert_type(first.append(second), "pd.Index[int | str]"), pd.Index) - check(assert_type(first.append([second]), "pd.Index[int | str]"), pd.Index) + check(assert_type(first.append([second]), pd.Index), pd.Index) - check(assert_type(first.append(third), "pd.Index[int | str]"), pd.Index) # type: ignore[assert-type] - check(assert_type(first.append([third]), "pd.Index[int | str]"), pd.Index) # type: ignore[assert-type] check( assert_type( # type: ignore[assert-type] - first.append([second, third]), # pyright: ignore[reportAssertTypeFailure] - "pd.Index[int | str]", + first.append(third), "pd.Index[int | str]" ), pd.Index, ) + check(assert_type(first.append([third]), pd.Index), pd.Index) + check(assert_type(first.append([second, third]), pd.Index), pd.Index) - check(assert_type(third.append([]), "pd.Index[int | str]"), pd.Index) # type: ignore[assert-type] check( - assert_type(third.append(cast("list[Index[Any]]", [])), "pd.Index[int | str]"), # type: ignore[assert-type] + assert_type( # type: ignore[assert-type] + third.append([]), "pd.Index[int | str]" + ), pd.Index, ) - check(assert_type(third.append([first]), "pd.Index[int | str]"), pd.Index) # type: ignore[assert-type] check( assert_type( # type: ignore[assert-type] - third.append([first, second]), # pyright: ignore[reportAssertTypeFailure] - "pd.Index[int | str]", + third.append(cast("list[Index[Any]]", [])), "pd.Index[int | str]" ), pd.Index, ) + check(assert_type(third.append([first]), pd.Index), pd.Index) + check(assert_type(third.append([first, second]), pd.Index), pd.Index) def test_append_int() -> None: From fa3c401b0624bcb0c05afc1fc43ef0fea381e6c1 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 29 Jul 2025 13:11:38 +0200 Subject: [PATCH 08/11] fix: Sequence[Index] instead of Sequence --- pandas-stubs/core/indexes/base.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index b1531aaf..ceb7641e 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -407,7 +407,7 @@ class Index(IndexOpsMixin[S1]): @overload def append(self, other: Index[S2]) -> Index[S1 | S2]: ... @overload - def append(self, other: Sequence) -> Index: ... + def append(self, other: Sequence[Index]) -> Index: ... def putmask(self, mask, value): ... def equals(self, other) -> bool: ... @final From d7a538d85b2a6cb93fc6e18b8afb4b3b289fe03f Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 29 Jul 2025 17:25:18 +0200 Subject: [PATCH 09/11] fix(comment): avoid union types https://github.com/pandas-dev/pandas-stubs/pull/1282#discussion_r2240001838 --- pandas-stubs/core/indexes/base.pyi | 5 +---- tests/test_indexes.py | 11 +++-------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index ceb7641e..9dbee927 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -43,7 +43,6 @@ from typing_extensions import ( from pandas._libs.interval import _OrderableT from pandas._typing import ( S1, - S2, AnyAll, AxesData, DropKeep, @@ -405,9 +404,7 @@ class Index(IndexOpsMixin[S1]): @overload def append(self, other: Index[S1] | Sequence[Index[S1]]) -> Self: ... @overload - def append(self, other: Index[S2]) -> Index[S1 | S2]: ... - @overload - def append(self, other: Sequence[Index]) -> Index: ... + def append(self, other: Index | Sequence[Index]) -> Index: ... def putmask(self, mask, value): ... def equals(self, other) -> bool: ... @final diff --git a/tests/test_indexes.py b/tests/test_indexes.py index 222edebf..f922f180 100644 --- a/tests/test_indexes.py +++ b/tests/test_indexes.py @@ -1031,19 +1031,14 @@ def test_getitem() -> None: def test_append_mix() -> None: - """Test pd.Index.append that gives pd.Index[Any]""" + """Test pd.Index.append with mixed types""" first = pd.Index([1]) second = pd.Index(["a"]) third = pd.Index([1, "a"]) - check(assert_type(first.append(second), "pd.Index[int | str]"), pd.Index) + check(assert_type(first.append(second), pd.Index), pd.Index) check(assert_type(first.append([second]), pd.Index), pd.Index) - check( - assert_type( # type: ignore[assert-type] - first.append(third), "pd.Index[int | str]" - ), - pd.Index, - ) + check(assert_type(first.append(third), pd.Index), pd.Index) check(assert_type(first.append([third]), pd.Index), pd.Index) check(assert_type(first.append([second, third]), pd.Index), pd.Index) From fe5f1a9036102a136f82557c7b3e3ace937803a7 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 30 Jul 2025 09:58:43 +0200 Subject: [PATCH 10/11] chore: https://github.com/pandas-dev/pandas-stubs/pull/1282#discussion_r2240528370 --- tests/test_indexes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_indexes.py b/tests/test_indexes.py index f922f180..6811477e 100644 --- a/tests/test_indexes.py +++ b/tests/test_indexes.py @@ -1042,6 +1042,8 @@ def test_append_mix() -> None: check(assert_type(first.append([third]), pd.Index), pd.Index) check(assert_type(first.append([second, third]), pd.Index), pd.Index) + # mypy thinks the following two are of the type `Index[Any]`, whereas + # pyright recognises them as `Index[int | str]` check( assert_type( # type: ignore[assert-type] third.append([]), "pd.Index[int | str]" From 1c75df60c1a4c901204dbef1edc389032b73fd8c Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 30 Jul 2025 17:40:50 +0200 Subject: [PATCH 11/11] fix: constraint instead of bound to get rid of Any https://github.com/python/mypy/issues/19525#issuecomment-3136400619 --- pandas-stubs/_typing.pyi | 20 ++++++++++++++++++++ pandas-stubs/core/indexes/base.pyi | 5 ++++- tests/test_indexes.py | 16 ++-------------- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index 7b2b0081..f14c393f 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -847,6 +847,26 @@ S1 = TypeVar("S1", bound=SeriesDType, default=Any) S2 = TypeVar("S2", bound=SeriesDType) S3 = TypeVar("S3", bound=SeriesDType) +# Constraint, instead of bound +C2 = TypeVar( + "C2", + str, + bytes, + datetime.date, + datetime.time, + bool, + int, + float, + complex, + Dtype, + datetime.datetime, # includes pd.Timestamp + datetime.timedelta, # includes pd.Timedelta + Period, + Interval, + CategoricalDtype, + BaseOffset, +) + IndexingInt: TypeAlias = ( int | np.int_ | np.integer | np.unsignedinteger | np.signedinteger | np.int8 ) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 9dbee927..cea53a64 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -42,6 +42,7 @@ from typing_extensions import ( from pandas._libs.interval import _OrderableT from pandas._typing import ( + C2, S1, AnyAll, AxesData, @@ -402,7 +403,9 @@ class Index(IndexOpsMixin[S1]): @overload def __getitem__(self, idx: int | tuple[np_ndarray_anyint, ...]) -> S1: ... @overload - def append(self, other: Index[S1] | Sequence[Index[S1]]) -> Self: ... + def append( + self: Index[C2], other: Index[C2] | Sequence[Index[C2]] + ) -> Index[C2]: ... @overload def append(self, other: Index | Sequence[Index]) -> Index: ... def putmask(self, mask, value): ... diff --git a/tests/test_indexes.py b/tests/test_indexes.py index 6811477e..57042c29 100644 --- a/tests/test_indexes.py +++ b/tests/test_indexes.py @@ -1042,20 +1042,8 @@ def test_append_mix() -> None: check(assert_type(first.append([third]), pd.Index), pd.Index) check(assert_type(first.append([second, third]), pd.Index), pd.Index) - # mypy thinks the following two are of the type `Index[Any]`, whereas - # pyright recognises them as `Index[int | str]` - check( - assert_type( # type: ignore[assert-type] - third.append([]), "pd.Index[int | str]" - ), - pd.Index, - ) - check( - assert_type( # type: ignore[assert-type] - third.append(cast("list[Index[Any]]", [])), "pd.Index[int | str]" - ), - pd.Index, - ) + check(assert_type(third.append([]), pd.Index), pd.Index) + check(assert_type(third.append(cast("list[Index[Any]]", [])), pd.Index), pd.Index) check(assert_type(third.append([first]), pd.Index), pd.Index) check(assert_type(third.append([first, second]), pd.Index), pd.Index)