Skip to content
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: 1 addition & 1 deletion requirements-tests.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Type checkers that we test our stubs against. These should always
# be pinned to a specific version to make failure reproducible.
mypy==2.3.1
mypy==2.4.0
pyrefly==1.3.2
pyright==1.1.414
ty==0.0.84
Expand Down
9 changes: 9 additions & 0 deletions stdlib/@tests/stubtest_allowlists/common.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ builtins.super.__self__
builtins.super.__self_class__
builtins.super.__thisclass__

# The following reverse operators are present in the C implementation
# (probably incidental), but missing from the Python implementation.
Comment on lines +46 to +47

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would still personally lean towards just following the C implementation here, since it's the only one that will be relevant to the vast majority of type-checker users. And I think that's what we've done elsewhere in a few other places. But don't feel strongly; this is fine for now. And as you say, these aren't particularly useful, so it probably just doesn't really matter for users.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I prefer to support only what's supported by both versions.

datetime.date.__rsub__
datetime.datetime.__rsub__
datetime.timedelta.__rdivmod__
datetime.timedelta.__rfloordiv__
datetime.timedelta.__rmod__
datetime.timedelta.__rtruediv__

# Undocumented implementation details
email.contentmanager.get_and_fixup_unknown_message_content
email.contentmanager.get_message_content
Expand Down
3 changes: 0 additions & 3 deletions stdlib/@tests/stubtest_allowlists/py315.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@

dataclasses.MISSING
dataclasses._MISSING_TYPE
dataclasses.field

# =============================================================
# Allowlist entries that cannot or should not be fixed; >= 3.15
# =============================================================

# runtime default is a list object used as a sentinel
base64.b64decode
urllib.parse.urlunparse
urllib.parse.urlunsplit

# Internal implementation details of the sampling profiler.
profiling.sampling.binary_collector
Expand Down
60 changes: 56 additions & 4 deletions stdlib/builtins.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ from typing import ( # noqa: Y022 # ruff: ignore[deprecated-import]

# we can't import `Literal` from typing or mypy crashes: see #11247
# ruff: ignore[deprecated-import]
from typing_extensions import Literal, LiteralString, Self, TypeIs, TypeVarTuple, deprecated, disjoint_base # noqa: Y023
from typing_extensions import Buffer, Literal, LiteralString, Self, TypeIs, TypeVarTuple, deprecated, disjoint_base # noqa: Y023

if sys.version_info >= (3, 14):
from _typeshed import AnnotateFunc
Expand Down Expand Up @@ -711,7 +711,9 @@ class str(Sequence[str]):
@overload
def __mod__(self: LiteralString, value: LiteralString | tuple[LiteralString, ...], /) -> LiteralString: ...
@overload
def __mod__(self, value: Any, /) -> str: ...
def __mod__(self, value: object, /) -> str: ...

def __rmod__(self, value: str, /) -> str: ...

@overload
def __mul__(self: LiteralString, value: SupportsIndex, /) -> LiteralString: ...
Expand Down Expand Up @@ -826,7 +828,8 @@ class bytes(Sequence[int]):
def __add__(self, value: ReadableBuffer, /) -> bytes: ...
def __mul__(self, value: SupportsIndex, /) -> bytes: ...
def __rmul__(self, value: SupportsIndex, /) -> bytes: ...
def __mod__(self, value: Any, /) -> bytes: ...
def __mod__(self, value: Buffer | SupportsBytes | tuple[Buffer | SupportsBytes, ...], /) -> bytes: ...
def __rmod__(self, value: bytes, /) -> bytes: ...
# Incompatible with Sequence.__contains__
def __contains__(self, key: SupportsIndex | ReadableBuffer, /) -> bool: ... # type: ignore[override]
def __eq__(self, value: object, /) -> bool: ...
Expand Down Expand Up @@ -957,7 +960,8 @@ class bytearray(MutableSequence[int]):
def __mul__(self, value: SupportsIndex, /) -> bytearray: ...
def __rmul__(self, value: SupportsIndex, /) -> bytearray: ...
def __imul__(self, value: SupportsIndex, /) -> Self: ...
def __mod__(self, value: Any, /) -> bytes: ...
def __mod__(self, value: Buffer | SupportsBytes | tuple[Buffer | SupportsBytes, ...], /) -> bytearray: ...
def __rmod__(self, value: bytearray, /) -> bytearray: ...
# Incompatible with Sequence.__contains__
def __contains__(self, key: SupportsIndex | ReadableBuffer, /) -> bool: ... # type: ignore[override]
def __eq__(self, value: object, /) -> bool: ...
Expand Down Expand Up @@ -1457,12 +1461,36 @@ class set(MutableSet[_T]):
def __iter__(self) -> Iterator[_T]: ...
def __and__(self, value: AbstractSet[object], /) -> set[_T]: ...
def __iand__(self, value: AbstractSet[object], /) -> Self: ...

@overload
def __rand__(self, value: set[_S], /) -> set[_S]: ...
@overload
def __rand__(self, value: frozenset[_S], /) -> frozenset[_S]: ...
Comment on lines +1465 to +1468

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

not an issue to be fixed in this PR, but we might want to revisit the annotations for set.__and__. They look incorrect -- it doesn't seem like set.__and__ really takes any abstract set for its second argument. It seems like it might also only take sets and frozensets, similar to set.__rand__:

>>> from collections.abc import Set
>>> class Foo(Set):
...     __contains__ = __iter__ = __len__ = lambda *args: ...
...
>>> {1, 2}.__and__(Foo())
NotImplemented

Possibly the same also goes for other set dunders?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'll actually fix this here, since I've also fixed a few other dunder annotations.

Similar to the other builtins, set checks explicitly for set or frozenset (or derived classes) using PyAnySet_Check:

https://github.com/python/cpython/blob/2eb2af805c156ca52b316bb4ced5e0ab3971d0ae/Objects/setobject.c#L1876-L1889

static PyObject *
set_and(PyObject *self, PyObject *other)
{
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
        Py_RETURN_NOTIMPLEMENTED;
    /* ... */
}


def __or__(self, value: AbstractSet[_S], /) -> set[_T | _S]: ...
def __ior__(self, value: AbstractSet[_T], /) -> Self: ... # type: ignore[override,misc]

@overload
def __ror__(self, value: set[_S], /) -> set[_T | _S]: ...
@overload
def __ror__(self, value: frozenset[_S], /) -> frozenset[_T | _S]: ...

def __sub__(self, value: AbstractSet[object], /) -> set[_T]: ...
def __isub__(self, value: AbstractSet[object], /) -> Self: ...

@overload
def __rsub__(self, value: set[_S], /) -> set[_S]: ...
@overload
def __rsub__(self, value: frozenset[_S], /) -> frozenset[_S]: ...

def __xor__(self, value: AbstractSet[_S], /) -> set[_T | _S]: ...
def __ixor__(self, value: AbstractSet[_T], /) -> Self: ... # type: ignore[override,misc]

@overload
def __rxor__(self, value: set[_S], /) -> set[_T | _S]: ...
@overload
def __rxor__(self, value: frozenset[_S], /) -> frozenset[_T | _S]: ...

def __le__(self, value: AbstractSet[object], /) -> bool: ...
def __lt__(self, value: AbstractSet[object], /) -> bool: ...
def __ge__(self, value: AbstractSet[object], /) -> bool: ...
Expand Down Expand Up @@ -1490,9 +1518,33 @@ class frozenset(AbstractSet[_T_co]):
def __contains__(self, o: object, /) -> bool: ...
def __iter__(self) -> Iterator[_T_co]: ...
def __and__(self, value: AbstractSet[object], /) -> frozenset[_T_co]: ...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think the nonreflected frozenset dunders have the same issue:

>>> from collections.abc import Set
>>> class Foo(Set):
...     __contains__ = __iter__ = __len__ = lambda *args: ...
...
>>> frozenset({1, 2}).__and__(Foo())
NotImplemented

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch, they would have.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

That said, I'm going to revert the last two commits for now and commit. This seems to open a whole new can of worms.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sounds good


@overload
def __rand__(self, value: set[_S], /) -> set[_S]: ...
@overload
def __rand__(self, value: frozenset[_S], /) -> frozenset[_S]: ...
Comment thread
AlexWaygood marked this conversation as resolved.

def __or__(self, value: AbstractSet[_S], /) -> frozenset[_T_co | _S]: ...

@overload
def __ror__(self, value: set[_S], /) -> set[_T_co | _S]: ...
@overload
def __ror__(self, value: frozenset[_S], /) -> frozenset[_T_co | _S]: ...

def __sub__(self, value: AbstractSet[object], /) -> frozenset[_T_co]: ...

@overload
def __rsub__(self, value: set[_S], /) -> set[_S]: ...
@overload
def __rsub__(self, value: frozenset[_S], /) -> frozenset[_S]: ...

def __xor__(self, value: AbstractSet[_S], /) -> frozenset[_T_co | _S]: ...

@overload
def __rxor__(self, value: set[_S], /) -> set[_T_co | _S]: ...
@overload
def __rxor__(self, value: frozenset[_S], /) -> frozenset[_T_co | _S]: ...

def __le__(self, value: AbstractSet[object], /) -> bool: ...
def __lt__(self, value: AbstractSet[object], /) -> bool: ...
def __ge__(self, value: AbstractSet[object], /) -> bool: ...
Expand Down
4 changes: 4 additions & 0 deletions stdlib/types.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,10 @@ if sys.version_info >= (3, 15):
def __len__(self) -> int: ...
def __contains__(self, key: object, /) -> bool: ...
def __reversed__(self) -> Iterator[str]: ...
def __or__(self, other: dict[str, Any] | FrameLocalsProxyType, /) -> dict[str, Any]: ...
# Will raise a NameError if invoked via |=
def __ior__(self, other: dict[str, Any] | FrameLocalsProxyType, /) -> dict[str, Any]: ... # noqa: Y034
def __ror__(self, other: dict[str, Any] | FrameLocalsProxyType, /) -> dict[str, Any]: ...
def copy(self) -> dict[str, Any]: ...
def pop(self, key: str, default: Any = ..., /) -> Any: ...
def setdefault(self, key: str, default: Any = ..., /) -> Any: ...
Expand Down
4 changes: 2 additions & 2 deletions stubs/tensorflow/tensorflow/io/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ class RaggedFeature(NamedTuple):

dtype: DTypeLike
value_key: str | None = None
partitions: tuple[ # type: ignore[name-defined]
RowSplits | RowLengths | RowStarts | RowLimits | ValueRowIds | UniformRowLength, ...
partitions: tuple[
RowSplits | RowLengths | RowStarts | RowLimits | ValueRowIds | UniformRowLength, ... # type: ignore[name-defined]
] = ()
row_splits_dtype: DTypeLike = ...
validate: bool = False
Expand Down
Loading