Skip to content

GH1269 Add @Final decorator to match pandas code where possible #1277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pandas-stubs/core/arrays/sparse/array.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from enum import Enum
from typing import (
Any,
final,
overload,
)

Expand All @@ -16,6 +17,7 @@ from pandas._typing import (
SequenceIndexer,
)

@final
class ellipsis(Enum):
Ellipsis = "..."

Expand Down
38 changes: 37 additions & 1 deletion pandas-stubs/core/frame.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ from typing import (
Generic,
Literal,
NoReturn,
final,
overload,
)

Expand Down Expand Up @@ -705,6 +706,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
def transpose(self, *args: Any, copy: _bool = ...) -> Self: ...
@property
def T(self) -> Self: ...
@final
def __getattr__(self, name: str) -> Series: ...
def isetitem(
self, loc: int | Sequence[int], value: Scalar | ArrayLike | list[Any]
Expand Down Expand Up @@ -795,6 +797,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
allow_duplicates: _bool = ...,
) -> None: ...
def assign(self, **kwargs: IntoColumn) -> Self: ...
@final
def align(
self,
other: NDFrameT,
Expand Down Expand Up @@ -1700,6 +1703,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
@property
def values(self) -> np.ndarray: ...
# methods
@final
def abs(self) -> Self: ...
def add(
self,
Expand All @@ -1708,7 +1712,9 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
level: Level | None = ...,
fill_value: float | None = ...,
) -> Self: ...
@final
def add_prefix(self, prefix: _str, axis: Axis | None = None) -> Self: ...
@final
def add_suffix(self, suffix: _str, axis: Axis | None = None) -> Self: ...
@overload
def all(
Expand Down Expand Up @@ -1744,7 +1750,9 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
skipna: _bool = ...,
**kwargs: Any,
) -> Series[_bool]: ...
@final
def asof(self, where, subset: _str | list[_str] | None = ...) -> Self: ...
@final
def asfreq(
self,
freq,
Expand All @@ -1753,18 +1761,21 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
normalize: _bool = ...,
fill_value: Scalar | None = ...,
) -> Self: ...
@final
def astype(
self,
dtype: AstypeArg | Mapping[Any, Dtype] | Series,
copy: _bool = ...,
errors: IgnoreRaise = ...,
) -> Self: ...
@final
def at_time(
self,
time: _str | dt.time,
asof: _bool = ...,
axis: Axis | None = ...,
) -> Self: ...
@final
def between_time(
self,
start_time: _str | dt.time,
Expand Down Expand Up @@ -1859,6 +1870,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
inplace: Literal[True],
**kwargs: Any,
) -> None: ...
@final
def copy(self, deep: _bool = ...) -> Self: ...
def cummax(
self, axis: Axis | None = ..., skipna: _bool = ..., *args: Any, **kwargs: Any
Expand All @@ -1872,6 +1884,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
def cumsum(
self, axis: Axis | None = ..., skipna: _bool = ..., *args: Any, **kwargs: Any
) -> Self: ...
@final
def describe(
self,
percentiles: list[float] | None = ...,
Expand All @@ -1892,9 +1905,12 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
level: Level | None = ...,
fill_value: float | None = ...,
) -> Self: ...
@final
def droplevel(self, level: Level | list[Level], axis: Axis = ...) -> Self: ...
def eq(self, other, axis: Axis = ..., level: Level | None = ...) -> Self: ...
@final
def equals(self, other: Series | DataFrame) -> _bool: ...
@final
def ewm(
self,
com: float | None = ...,
Expand All @@ -1906,6 +1922,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
ignore_na: _bool = ...,
axis: Axis = ...,
) -> ExponentialMovingWindow[Self]: ...
@final
def expanding(
self,
min_periods: int = ...,
Expand Down Expand Up @@ -1937,7 +1954,9 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
regex: _str | None = ...,
axis: Axis | None = ...,
) -> Self: ...
@final
def first(self, offset) -> Self: ...
@final
def first_valid_index(self) -> Scalar: ...
def floordiv(
self,
Expand All @@ -1958,7 +1977,9 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
@overload
def get(self, key: list[Hashable], default: _T) -> Self | _T: ...
def gt(self, other, axis: Axis = ..., level: Level | None = ...) -> Self: ...
@final
def head(self, n: int = ...) -> Self: ...
@final
def infer_objects(self) -> Self: ...
# def info
@overload
Expand Down Expand Up @@ -2000,7 +2021,9 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
numeric_only: _bool = ...,
**kwargs: Any,
) -> Series: ...
@final
def last(self, offset) -> Self: ...
@final
def last_valid_index(self) -> Scalar: ...
def le(self, other, axis: Axis = ..., level: Level | None = ...) -> Self: ...
def lt(self, other, axis: Axis = ..., level: Level | None = ...) -> Self: ...
Expand Down Expand Up @@ -2088,6 +2111,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
fill_value: float | None = ...,
) -> Self: ...
def ne(self, other, axis: Axis = ..., level: Level | None = ...) -> Self: ...
@final
def pct_change(
self,
periods: int = ...,
Expand Down Expand Up @@ -2130,6 +2154,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
level: Level | None = ...,
fill_value: float | None = ...,
) -> Self: ...
@final
def rank(
self,
axis: Axis = ...,
Expand All @@ -2146,6 +2171,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
level: Level | None = ...,
fill_value: float | None = ...,
) -> Self: ...
@final
def reindex_like(
self,
other: DataFrame,
Expand Down Expand Up @@ -2264,7 +2290,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
level: Level | None = ...,
fill_value: float | None = ...,
) -> Self: ...
# sample is missing a weights arg
@final
def sample(
self,
n: int | None = ...,
Expand Down Expand Up @@ -2294,6 +2320,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
numeric_only: _bool = ...,
**kwargs: Any,
) -> Series: ...
@final
def squeeze(self, axis: Axis | None = ...) -> DataFrame | Series | Scalar: ...
def std(
self,
Expand Down Expand Up @@ -2327,7 +2354,9 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
min_count: int = ...,
**kwargs: Any,
) -> Series: ...
@final
def swapaxes(self, axis1: Axis, axis2: Axis, copy: _bool = ...) -> Self: ...
@final
def tail(self, n: int = ...) -> Self: ...
@overload
def to_json(
Expand Down Expand Up @@ -2441,6 +2470,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
max_colwidth: int | None = ...,
encoding: _str | None = ...,
) -> _str: ...
@final
def to_xarray(self) -> xr.Dataset: ...
def truediv(
self,
Expand All @@ -2449,20 +2479,23 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
level: Level | None = ...,
fill_value: float | None = ...,
) -> Self: ...
@final
def truncate(
self,
before: dt.date | _str | int | None = ...,
after: dt.date | _str | int | None = ...,
axis: Axis | None = ...,
copy: _bool = ...,
) -> Self: ...
@final
def tz_convert(
self,
tz: TimeZones,
axis: Axis = ...,
level: Level | None = ...,
copy: _bool = ...,
) -> Self: ...
@final
def tz_localize(
self,
tz: TimeZones,
Expand Down Expand Up @@ -2514,7 +2547,9 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
level: Level | None = ...,
) -> Self: ...
# Move from generic because Series is Generic and it returns Series[bool] there
@final
def __invert__(self) -> Self: ...
@final
def xs(
self,
key: Hashable,
Expand All @@ -2531,6 +2566,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack):
) -> Self: ...
def __truediv__(self, other: float | DataFrame | Series | Sequence) -> Self: ...
def __rtruediv__(self, other: float | DataFrame | Series | Sequence) -> Self: ...
@final
def __bool__(self) -> NoReturn: ...

class _PandasNamedTuple(tuple[Any, ...]):
Expand Down
17 changes: 17 additions & 0 deletions pandas-stubs/core/generic.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ from pandas.io.sql import SQLTable
class NDFrame(indexing.IndexingMixin):
__hash__: ClassVar[None] # type: ignore[assignment] # pyright: ignore[reportIncompatibleMethodOverride]

@final
def set_flags(
self,
*,
Expand All @@ -84,18 +85,24 @@ class NDFrame(indexing.IndexingMixin):
@property
def size(self) -> int: ...
def equals(self, other: Series) -> _bool: ...
@final
def __neg__(self) -> Self: ...
@final
def __pos__(self) -> Self: ...
@final
def __nonzero__(self) -> None: ...
@final
def bool(self) -> _bool: ...
def __abs__(self) -> Self: ...
@final
def __round__(self, decimals: int = ...) -> Self: ...
@final
def __contains__(self, key) -> _bool: ...
@property
def empty(self) -> _bool: ...
__array_priority__: int = ...
def __array__(self, dtype=...) -> np.ndarray: ...
@final
def to_excel(
self,
excel_writer,
Expand All @@ -113,6 +120,7 @@ class NDFrame(indexing.IndexingMixin):
inf_rep: _str = ...,
freeze_panes: tuple[int, int] | None = ...,
) -> None: ...
@final
def to_hdf(
self,
path_or_buf: FilePath | HDFStore,
Expand Down Expand Up @@ -149,6 +157,7 @@ class NDFrame(indexing.IndexingMixin):
storage_options: StorageOptions = ...,
**kwargs: Any,
) -> _str: ...
@final
def to_sql(
self,
name: _str,
Expand All @@ -168,13 +177,15 @@ class NDFrame(indexing.IndexingMixin):
| None
) = ...,
) -> int | None: ...
@final
def to_pickle(
self,
path: FilePath | WriteBuffer[bytes],
compression: CompressionOptions = ...,
protocol: int = ...,
storage_options: StorageOptions = ...,
) -> None: ...
@final
def to_clipboard(
self,
excel: _bool = ...,
Expand Down Expand Up @@ -300,6 +311,7 @@ class NDFrame(indexing.IndexingMixin):
errors: OpenFileErrors = ...,
storage_options: StorageOptions = ...,
) -> _str: ...
@final
def __delitem__(self, idx: Hashable) -> None: ...
@overload
def drop(
Expand Down Expand Up @@ -387,10 +399,15 @@ class NDFrame(indexing.IndexingMixin):
*args: Any,
**kwargs: Any,
) -> T: ...
@final
def __finalize__(self, other, method=..., **kwargs) -> Self: ...
@final
def __setattr__(self, name: _str, value) -> None: ...
@final
def __copy__(self, deep: _bool = ...) -> Self: ...
@final
def __deepcopy__(self, memo=...) -> Self: ...
@final
def convert_dtypes(
self,
infer_objects: _bool = ...,
Expand Down
Loading
Loading