Uh oh!
There was an error while loading. Please reload this page.
Allow arbitrary types in dict.pop (3 overloads) - #15297
Conversation
dict.pop (3 overloads)
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
randolf-scholz
commented
Jan 16, 2026
Although the primer looks nicer as in #15296, I think this is mostly due to false negatives (see #15296 (comment) and #15296 (comment)) |
randolf-scholz
commented
Jan 19, 2026
Reopened due to suggestion of splitting #15296 into 2 steps: (1) convert key to object, (2) investigate the removal of middle overload. |
This comment has been minimized.
This comment has been minimized.
srittau
commented
Jan 19, 2026
Why are you sometimes using The primer output is not very convincing. Lots of churn, and only one weird case – which could arguably point to a real problem or at least weird typing – and one case that could be solved by using I remain unconvinced that this change is actually beneficial to our users, although I won't argue if other maintainers feel differently. |
randolf-scholz
commented
Jan 19, 2026
I am using Let me do a test of only removing the second overload without changing the annotation. I have a suspicion that these two things may be entangled, so disentangling them into 2 separate PRs may not be appropriate after all. |
I don't have a strong opinion on
This change would be very beneficial to ty users. ty attempts to do type narrowing in a stricter, more principled way than other type checkers, but this causes false positives when encountering methods that are annotated like this in typeshed, so I would be in favour of landing something along these lines. For example, mypy's behaviour here is as follows: deff(x: object):
ifisinstance(x, dict):
reveal_type(x) # revealed: dict[Any, Any]x.pop("foo") # no errorwhereas ty's behaviour is: deff(x: object):
ifisinstance(x, dict):
reveal_type(x) # revealed: Top[dict[Unknown, Unknown]]x.pop("foo") # Argument to bound method `pop` is incorrect: Expected `Never`, found `Literal["foo"]`
Our reasoning for using |
Cf. python/typing#2154 for a potential future "best of both worlds" solution. If this would be beneficial for ty, this has my blessing (for now). |
Actually, I think we should use |
That was my rationale for using This is the default implementation: https://github.com/python/cpython/blob/3c9c3d33cbdef257526871cbc12e93635026f5d6/Lib/_collections_abc.py#L929-L941 defpop(self, key, default=__marker):
'''D.pop(k[,d]) -> v, remove specified key and return the corresponding value. If key is not found, d is returned if given, otherwise KeyError is raised. '''try:
value=self[key]
exceptKeyError:
ifdefaultisself.__marker:
raisereturndefaultelse:
delself[key]
returnvalueIt will catch But I am easily convinced that there are |
67daa7d to
a56bd36Compare
This comment has been minimized.
This comment has been minimized.
So, I ran a test using I still think Personally I could live with either
I want to avoid the situation that later on we discover that e.g. the PR for |
AlexWaygood
commented
Feb 9, 2026
To me, the fact that these But making the methods on a subclass ( |
I can split it if you want, and as I said, both variants (
For reference, here's again the primer when we make and here if me make |
Diff from mypy_primer, showing the effect of this PR on open source code: mongo-python-driver (https://github.com/mongodb/mongo-python-driver)
+ bson/son.py:126: error: Signature of "pop" incompatible with supertype "builtins.dict" [override]+ bson/son.py:126: note: Superclass:+ bson/son.py:126: note: @overload+ bson/son.py:126: note: def pop(self, object, /) -> _Value+ bson/son.py:126: note: @overload+ bson/son.py:126: note: def pop(self, object, _Value, /) -> _Value+ bson/son.py:126: note: @overload+ bson/son.py:126: note: def [_T] pop(self, object, _T, /) -> _Value | _T+ bson/son.py:126: note: Subclass:+ bson/son.py:126: note: def [_T] pop(self, key: _Key, *args: _Value | _T) -> _Value | _T
pylox (https://github.com/sco1/pylox)
+ pylox/containers/array.py:83: note: def pop(self, object, /) -> Any- pylox/containers/array.py:83: note: def pop(self, Any, /) -> Any+ pylox/containers/array.py:83: note: def pop(self, object, Any, /) -> Any- pylox/containers/array.py:83: note: def pop(self, Any, Any, /) -> Any- pylox/containers/array.py:83: note: def [_T] pop(self, Any, _T, /) -> Any | _T+ pylox/containers/array.py:83: note: def [_T] pop(self, object, _T, /) -> Any | _T
rotki (https://github.com/rotki/rotki)
+ rotkehlchen/chain/aggregator.py:732: error: Unused "type: ignore" comment [unused-ignore]
django-stubs (https://github.com/typeddjango/django-stubs)
+ django-stubs/contrib/sessions/backends/base.pyi:31: error: Signature of "pop" incompatible with supertype "builtins.dict" [override]+ django-stubs/contrib/sessions/backends/base.pyi:31: note: Superclass:+ django-stubs/contrib/sessions/backends/base.pyi:31: note: @overload+ django-stubs/contrib/sessions/backends/base.pyi:31: note: def pop(self, object, /) -> Any+ django-stubs/contrib/sessions/backends/base.pyi:31: note: @overload+ django-stubs/contrib/sessions/backends/base.pyi:31: note: def pop(self, object, Any, /) -> Any+ django-stubs/contrib/sessions/backends/base.pyi:31: note: @overload+ django-stubs/contrib/sessions/backends/base.pyi:31: note: def [_T] pop(self, object, _T, /) -> Any | _T+ django-stubs/contrib/sessions/backends/base.pyi:31: note: Subclass:+ django-stubs/contrib/sessions/backends/base.pyi:31: note: @overload+ django-stubs/contrib/sessions/backends/base.pyi:31: note: def pop(self, key: str) -> Any+ django-stubs/contrib/sessions/backends/base.pyi:31: note: @overload+ django-stubs/contrib/sessions/backends/base.pyi:31: note: def pop(self, key: str, default: Any) -> Any+ django-stubs/http/request.pyi:202: error: Signature of "pop" incompatible with supertype "builtins.dict" [override]+ django-stubs/http/request.pyi:202: note: Superclass:+ django-stubs/http/request.pyi:202: note: @overload+ django-stubs/http/request.pyi:202: note: def pop(self, object, /) -> str+ django-stubs/http/request.pyi:202: note: @overload+ django-stubs/http/request.pyi:202: note: def pop(self, object, str, /) -> str+ django-stubs/http/request.pyi:202: note: @overload+ django-stubs/http/request.pyi:202: note: def [_T] pop(self, object, _T, /) -> str | _T+ django-stubs/http/request.pyi:202: note: Subclass:+ django-stubs/http/request.pyi:202: note: @overload+ django-stubs/http/request.pyi:202: note: def pop(self, str | bytes, /) -> Never+ django-stubs/http/request.pyi:202: note: @overload+ django-stubs/http/request.pyi:202: note: def [_Z] pop(self, str | bytes, str | _Z = ..., /) -> Never
scrapy (https://github.com/scrapy/scrapy)
+ scrapy/utils/datatypes.py:98: error: Signature of "pop" incompatible with supertype "builtins.dict" [override]+ scrapy/utils/datatypes.py:98: note: Superclass:+ scrapy/utils/datatypes.py:98: note: @overload+ scrapy/utils/datatypes.py:98: note: def pop(self, object, /) -> Any+ scrapy/utils/datatypes.py:98: note: @overload+ scrapy/utils/datatypes.py:98: note: def pop(self, object, Any, /) -> Any+ scrapy/utils/datatypes.py:98: note: @overload+ scrapy/utils/datatypes.py:98: note: def [_T] pop(self, object, _T, /) -> Any | _T+ scrapy/utils/datatypes.py:98: note: Subclass:+ scrapy/utils/datatypes.py:98: note: def [AnyStr: (str, bytes)] pop(self, key: AnyStr, *args: Any) -> Any
pylint (https://github.com/pycqa/pylint)
+ pylint/config/arguments_provider.py:54: error: Incompatible types in "yield" (actual type "tuple[None, list[tuple[str, dict[str, str | bool | int | Pattern[str] | Iterable[str | int | Pattern[str]] | type[_CallbackAction] | Callable[[Any], Any] | Callable[[Any, Any, Any, Any], Any] | None], Any]]]", expected type "tuple[str, list[tuple[str, dict[str, str | bool | int | Pattern[str] | Iterable[str | int | Pattern[str]] | type[_CallbackAction] | Callable[[Any], Any] | Callable[[Any, Any, Any, Any], Any] | None], Any]]] | tuple[None, dict[str, list[tuple[str, dict[str, str | bool | int | Pattern[str] | Iterable[str | int | Pattern[str]] | type[_CallbackAction] | Callable[[Any], Any] | Callable[[Any, Any, Any, Any], Any] | None], Any]]]]") [misc]+ pylint/config/arguments_provider.py:54: note: Error code "misc" not covered by "type: ignore" comment+ pylint/config/arguments_provider.py:54: error: Unused "type: ignore" comment [unused-ignore]
discord.py (https://github.com/Rapptz/discord.py)
- ...typeshed_to_test/stdlib/typing.pyi:1055: note: "update" of "TypedDict" defined here+ ...typeshed_to_test/stdlib/typing.pyi:1057: note: "update" of "TypedDict" defined here+ discord/ui/view.py:936: error: Unused "type: ignore" comment [unused-ignore]
steam.py (https://github.com/Gobot1234/steam.py)
- steam/ext/commands/utils.py:52: note: def pop(self, str, /) -> _VT+ steam/ext/commands/utils.py:52: note: def pop(self, object, /) -> _VT- steam/ext/commands/utils.py:52: note: def pop(self, str, _VT, /) -> _VT+ steam/ext/commands/utils.py:52: note: def pop(self, object, _VT, /) -> _VT- steam/ext/commands/utils.py:52: note: def [_T] pop(self, str, _T, /) -> _VT | _T+ steam/ext/commands/utils.py:52: note: def [_T] pop(self, object, _T, /) -> _VT | _T- steam/ext/commands/utils.py:52: note: def pop(self, str, /) -> _VT+ steam/ext/commands/utils.py:52: note: def pop(self, Any, /) -> _VT- steam/ext/commands/utils.py:52: note: def pop(self, str, _VT, /) -> _VT+ steam/ext/commands/utils.py:52: note: def pop(self, Any, _VT, /) -> _VT- steam/ext/commands/utils.py:52: note: def [_T] pop(self, str, _T, /) -> _VT | _T+ steam/ext/commands/utils.py:52: note: def [_T] pop(self, Any, _T, /) -> _VT | _T
werkzeug (https://github.com/pallets/werkzeug)
+ src/werkzeug/datastructures/mixins.py:265: error: Signature of "pop" incompatible with supertype "builtins.dict" [override]+ src/werkzeug/datastructures/mixins.py:265: note: Superclass:+ src/werkzeug/datastructures/mixins.py:265: note: @overload+ src/werkzeug/datastructures/mixins.py:265: note: def pop(self, object, /) -> V+ src/werkzeug/datastructures/mixins.py:265: note: @overload+ src/werkzeug/datastructures/mixins.py:265: note: def pop(self, object, V, /) -> V+ src/werkzeug/datastructures/mixins.py:265: note: @overload+ src/werkzeug/datastructures/mixins.py:265: note: def [_T] pop(self, object, _T, /) -> V | _T+ src/werkzeug/datastructures/mixins.py:265: note: Subclass:+ src/werkzeug/datastructures/mixins.py:265: note: @overload+ src/werkzeug/datastructures/mixins.py:265: note: def pop(self, key: K) -> V+ src/werkzeug/datastructures/mixins.py:265: note: @overload+ src/werkzeug/datastructures/mixins.py:265: note: def pop(self, key: K, default: V) -> V+ src/werkzeug/datastructures/mixins.py:265: note: @overload+ src/werkzeug/datastructures/mixins.py:265: note: def [T] pop(self, key: K, default: T) -> T+ src/werkzeug/datastructures/structures.py:469: error: Signature of "pop" incompatible with supertype "builtins.dict" [override]+ src/werkzeug/datastructures/structures.py:469: note: Superclass:+ src/werkzeug/datastructures/structures.py:469: note: @overload+ src/werkzeug/datastructures/structures.py:469: note: def pop(self, object, /) -> V+ src/werkzeug/datastructures/structures.py:469: note: @overload+ src/werkzeug/datastructures/structures.py:469: note: def pop(self, object, V, /) -> V+ src/werkzeug/datastructures/structures.py:469: note: @overload+ src/werkzeug/datastructures/structures.py:469: note: def [_T] pop(self, object, _T, /) -> V | _T+ src/werkzeug/datastructures/structures.py:469: note: Subclass:+ src/werkzeug/datastructures/structures.py:469: note: @overload+ src/werkzeug/datastructures/structures.py:469: note: def pop(self, key: K) -> V+ src/werkzeug/datastructures/structures.py:469: note: @overload+ src/werkzeug/datastructures/structures.py:469: note: def pop(self, key: K, default: V) -> V+ src/werkzeug/datastructures/structures.py:469: note: @overload+ src/werkzeug/datastructures/structures.py:469: note: def [T] pop(self, key: K, default: T) -> V | T
operator (https://github.com/canonical/operator)
- ops/_private/harness.py:2649: error: No overload variant of "pop" of "dict" matches argument types "str", "None" [call-overload]- ops/_private/harness.py:2649: note: Possible overload variants:- ops/_private/harness.py:2649: note: def pop(self, int, /) -> dict[str, Any]- ops/_private/harness.py:2649: note: def pop(self, int, dict[str, Any], /) -> dict[str, Any]- ops/_private/harness.py:2649: note: def [_T] pop(self, int, _T, /) -> dict[str, Any] | _T |
I've followed Alex's advice and made a pull request for only changing
|
Fixes#15271
new overloads: