Skip to content

TYP: misc annotations #56667

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 1 commit into from
Dec 29, 2023
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
5 changes: 4 additions & 1 deletion pandas/_testing/_warnings.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from contextlib import (
AbstractContextManager,
contextmanager,
nullcontext,
)
Expand Down Expand Up @@ -112,7 +113,9 @@ class for all warnings. To raise multiple types of exceptions,
)


def maybe_produces_warning(warning: type[Warning], condition: bool, **kwargs):
def maybe_produces_warning(
warning: type[Warning], condition: bool, **kwargs
) -> AbstractContextManager:
"""
Return a context manager that possibly checks a warning based on the condition
"""
Expand Down
33 changes: 30 additions & 3 deletions pandas/compat/_optional.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

import importlib
import sys
from typing import TYPE_CHECKING
from typing import (
TYPE_CHECKING,
Literal,
overload,
)
import warnings

from pandas.util._exceptions import find_stack_level
Expand Down Expand Up @@ -82,12 +86,35 @@ def get_version(module: types.ModuleType) -> str:
return version


@overload
def import_optional_dependency(
name: str,
extra: str = ...,
min_version: str | None = ...,
*,
errors: Literal["raise"] = ...,
) -> types.ModuleType:
...


@overload
def import_optional_dependency(
name: str,
extra: str = ...,
min_version: str | None = ...,
*,
errors: Literal["warn", "ignore"],
) -> types.ModuleType | None:
...


def import_optional_dependency(
name: str,
extra: str = "",
errors: str = "raise",
min_version: str | None = None,
):
*,
errors: Literal["raise", "warn", "ignore"] = "raise",
) -> types.ModuleType | None:
"""
Import an optional dependency.

Expand Down
20 changes: 13 additions & 7 deletions pandas/core/arrays/_arrow_string_mixins.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from __future__ import annotations

from typing import Literal
from typing import (
TYPE_CHECKING,
Literal,
)

import numpy as np

Expand All @@ -10,6 +13,9 @@
import pyarrow as pa
import pyarrow.compute as pc

if TYPE_CHECKING:
from pandas._typing import Self


class ArrowStringArrayMixin:
_pa_array = None
Expand All @@ -22,7 +28,7 @@ def _str_pad(
width: int,
side: Literal["left", "right", "both"] = "left",
fillchar: str = " ",
):
) -> Self:
if side == "left":
pa_pad = pc.utf8_lpad
elif side == "right":
Expand All @@ -35,7 +41,7 @@ def _str_pad(
)
return type(self)(pa_pad(self._pa_array, width=width, padding=fillchar))

def _str_get(self, i: int):
def _str_get(self, i: int) -> Self:
lengths = pc.utf8_length(self._pa_array)
if i >= 0:
out_of_bounds = pc.greater_equal(i, lengths)
Expand All @@ -59,7 +65,7 @@ def _str_get(self, i: int):

def _str_slice_replace(
self, start: int | None = None, stop: int | None = None, repl: str | None = None
):
) -> Self:
if repl is None:
repl = ""
if start is None:
Expand All @@ -68,13 +74,13 @@ def _str_slice_replace(
stop = np.iinfo(np.int64).max
return type(self)(pc.utf8_replace_slice(self._pa_array, start, stop, repl))

def _str_capitalize(self):
def _str_capitalize(self) -> Self:
return type(self)(pc.utf8_capitalize(self._pa_array))

def _str_title(self):
def _str_title(self) -> Self:
return type(self)(pc.utf8_title(self._pa_array))

def _str_swapcase(self):
def _str_swapcase(self) -> Self:
return type(self)(pc.utf8_swapcase(self._pa_array))

def _str_removesuffix(self, suffix: str):
Expand Down
37 changes: 20 additions & 17 deletions pandas/core/dtypes/inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
is_iterator = lib.is_iterator


def is_number(obj) -> TypeGuard[Number | np.number]:
def is_number(obj: object) -> TypeGuard[Number | np.number]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious, is there any difference between object and Any?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think typeshed recommends to use object, when literally any object is accepted (typically for __eq__ and similar methods) and to use Any when it is too difficult to write a type annotation/when the code is too dynamic.

"""
Check if the object is a number.

Expand Down Expand Up @@ -77,7 +77,7 @@ def is_number(obj) -> TypeGuard[Number | np.number]:
return isinstance(obj, (Number, np.number))


def iterable_not_string(obj) -> bool:
def iterable_not_string(obj: object) -> bool:
"""
Check if the object is an iterable but not a string.

Expand All @@ -102,7 +102,7 @@ def iterable_not_string(obj) -> bool:
return isinstance(obj, abc.Iterable) and not isinstance(obj, str)


def is_file_like(obj) -> bool:
def is_file_like(obj: object) -> bool:
"""
Check if the object is a file-like object.

Expand Down Expand Up @@ -138,7 +138,7 @@ def is_file_like(obj) -> bool:
return bool(hasattr(obj, "__iter__"))


def is_re(obj) -> TypeGuard[Pattern]:
def is_re(obj: object) -> TypeGuard[Pattern]:
"""
Check if the object is a regex pattern instance.

Expand All @@ -163,7 +163,7 @@ def is_re(obj) -> TypeGuard[Pattern]:
return isinstance(obj, Pattern)


def is_re_compilable(obj) -> bool:
def is_re_compilable(obj: object) -> bool:
"""
Check if the object can be compiled into a regex pattern instance.

Expand All @@ -185,14 +185,14 @@ def is_re_compilable(obj) -> bool:
False
"""
try:
re.compile(obj)
re.compile(obj) # type: ignore[call-overload]
except TypeError:
return False
else:
return True


def is_array_like(obj) -> bool:
def is_array_like(obj: object) -> bool:
"""
Check if the object is array-like.

Expand Down Expand Up @@ -224,7 +224,7 @@ def is_array_like(obj) -> bool:
return is_list_like(obj) and hasattr(obj, "dtype")


def is_nested_list_like(obj) -> bool:
def is_nested_list_like(obj: object) -> bool:
"""
Check if the object is list-like, and that all of its elements
are also list-like.
Expand Down Expand Up @@ -265,12 +265,13 @@ def is_nested_list_like(obj) -> bool:
return (
is_list_like(obj)
and hasattr(obj, "__len__")
and len(obj) > 0
and all(is_list_like(item) for item in obj)
# need PEP 724 to handle these typing errors
and len(obj) > 0 # pyright: ignore[reportGeneralTypeIssues]
and all(is_list_like(item) for item in obj) # type: ignore[attr-defined]
)


def is_dict_like(obj) -> bool:
def is_dict_like(obj: object) -> bool:
"""
Check if the object is dict-like.

Expand Down Expand Up @@ -303,7 +304,7 @@ def is_dict_like(obj) -> bool:
)


def is_named_tuple(obj) -> bool:
def is_named_tuple(obj: object) -> bool:
"""
Check if the object is a named tuple.

Expand Down Expand Up @@ -331,7 +332,7 @@ def is_named_tuple(obj) -> bool:
return isinstance(obj, abc.Sequence) and hasattr(obj, "_fields")


def is_hashable(obj) -> TypeGuard[Hashable]:
def is_hashable(obj: object) -> TypeGuard[Hashable]:
"""
Return True if hash(obj) will succeed, False otherwise.

Expand Down Expand Up @@ -370,7 +371,7 @@ def is_hashable(obj) -> TypeGuard[Hashable]:
return True


def is_sequence(obj) -> bool:
def is_sequence(obj: object) -> bool:
"""
Check if the object is a sequence of objects.
String types are not included as sequences here.
Expand All @@ -394,14 +395,16 @@ def is_sequence(obj) -> bool:
False
"""
try:
iter(obj) # Can iterate over it.
len(obj) # Has a length associated with it.
# Can iterate over it.
iter(obj) # type: ignore[call-overload]
# Has a length associated with it.
len(obj) # type: ignore[arg-type]
return not isinstance(obj, (str, bytes))
except (TypeError, AttributeError):
return False


def is_dataclass(item) -> bool:
def is_dataclass(item: object) -> bool:
"""
Checks if the object is a data-class instance

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def __setitem__(self, key: str, value) -> None:
def __repr__(self) -> str:
return f"<Flags(allows_duplicate_labels={self.allows_duplicate_labels})>"

def __eq__(self, other) -> bool:
def __eq__(self, other: object) -> bool:
if isinstance(other, type(self)):
return self.allows_duplicate_labels == other.allows_duplicate_labels
return False
10 changes: 7 additions & 3 deletions pandas/core/ops/invalid.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
from __future__ import annotations

import operator
from typing import TYPE_CHECKING
from typing import (
TYPE_CHECKING,
Callable,
NoReturn,
)

import numpy as np

Expand Down Expand Up @@ -41,7 +45,7 @@ def invalid_comparison(left, right, op) -> npt.NDArray[np.bool_]:
return res_values


def make_invalid_op(name: str):
def make_invalid_op(name: str) -> Callable[..., NoReturn]:
"""
Return a binary method that always raises a TypeError.

Expand All @@ -54,7 +58,7 @@ def make_invalid_op(name: str):
invalid_op : function
"""

def invalid_op(self, other=None):
def invalid_op(self, other=None) -> NoReturn:
typ = type(self).__name__
raise TypeError(f"cannot perform {name} with this index type: {typ}")

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/ops/missing.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from pandas.core import roperator


def _fill_zeros(result: np.ndarray, x, y):
def _fill_zeros(result: np.ndarray, x, y) -> np.ndarray:
"""
If this is a reversed op, then flip x,y

Expand Down
6 changes: 2 additions & 4 deletions pandas/io/orc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from __future__ import annotations

import io
from types import ModuleType
from typing import (
TYPE_CHECKING,
Any,
Expand Down Expand Up @@ -218,7 +217,7 @@ def to_orc(

if engine != "pyarrow":
raise ValueError("engine must be 'pyarrow'")
engine = import_optional_dependency(engine, min_version="10.0.1")
pyarrow = import_optional_dependency(engine, min_version="10.0.1")
pa = import_optional_dependency("pyarrow")
orc = import_optional_dependency("pyarrow.orc")

Expand All @@ -227,10 +226,9 @@ def to_orc(
path = io.BytesIO()
assert path is not None # For mypy
with get_handle(path, "wb", is_text=False) as handles:
assert isinstance(engine, ModuleType) # For mypy
try:
orc.write_table(
engine.Table.from_pandas(df, preserve_index=index),
pyarrow.Table.from_pandas(df, preserve_index=index),
handles.handle,
**engine_kwargs,
)
Expand Down
2 changes: 1 addition & 1 deletion pandas/util/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ def __getattr__(key: str):
raise AttributeError(f"module 'pandas.util' has no attribute '{key}'")


def capitalize_first_letter(s):
def capitalize_first_letter(s: str) -> str:
return s[:1].upper() + s[1:]
2 changes: 1 addition & 1 deletion pandas/util/_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ def wrapper(*args, **kwargs):
return decorate


def doc(*docstrings: None | str | Callable, **params) -> Callable[[F], F]:
def doc(*docstrings: None | str | Callable, **params: object) -> Callable[[F], F]:
"""
A decorator to take docstring templates, concatenate them and perform string
substitution on them.
Expand Down
2 changes: 0 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,6 @@ module = [
"pandas._testing.*", # TODO
"pandas.arrays", # TODO
"pandas.compat.numpy.function", # TODO
"pandas.compat._optional", # TODO
"pandas.compat.compressors", # TODO
"pandas.compat.pickle_compat", # TODO
"pandas.core._numba.executor", # TODO
Expand All @@ -602,7 +601,6 @@ module = [
"pandas.core.dtypes.concat", # TODO
"pandas.core.dtypes.dtypes", # TODO
"pandas.core.dtypes.generic", # TODO
"pandas.core.dtypes.inference", # TODO
"pandas.core.dtypes.missing", # TODO
"pandas.core.groupby.categorical", # TODO
"pandas.core.groupby.generic", # TODO
Expand Down