Disallow calling type on Protocol
Fixes #16919, fixes #16890
~It's possible we should not issue the diagnostic and only return object, but that may confuse users. Let's see the primer.~
Should also probably disallow type[P] as well.
Diff from mypy_primer, showing the effect of this PR on open source code:
websockets (https://github.com/aaugustin/websockets)
+ src/websockets/legacy/protocol.py:683: error: Calling type() on a protocol class is unsound [misc]
+ src/websockets/legacy/protocol.py:683: error: "object" has no attribute "__aiter__" (not async iterable) [attr-defined]
+ src/websockets/legacy/protocol.py:690: error: Calling type() on a protocol class is unsound [misc]
+ src/websockets/legacy/protocol.py:690: error: "object" has no attribute "__anext__"; maybe "__ne__"? [attr-defined]
operator (https://github.com/canonical/operator)
+ ops/pebble.py:2230: error: "object" has no attribute "__name__"; maybe "__ne__" or "__new__"? [attr-defined]
+ ops/pebble.py:2230: error: Calling type() on a protocol class is unsound [misc]
+ ops/pebble.py:3019: error: "object" has no attribute "__name__"; maybe "__ne__" or "__new__"? [attr-defined]
+ ops/pebble.py:3019: error: Calling type() on a protocol class is unsound [misc]
+ ops/framework.py:1245: error: Calling type() on a protocol class is unsound [misc]
+ ops/framework.py:1247: error: "object" has no attribute "__name__"; maybe "__ne__" or "__new__"? [attr-defined]
+ ops/framework.py:1249: error: "object" has no attribute "__name__"; maybe "__ne__" or "__new__"? [attr-defined]
pandas (https://github.com/pandas-dev/pandas)
+ pandas/io/common.py:476: error: Calling type() on a protocol class is unsound [misc]
+ pandas/io/html.py:918: error: "object" has no attribute "__name__"; maybe "__ne__" or "__new__"? [attr-defined]
+ pandas/io/html.py:918: error: Calling type() on a protocol class is unsound [misc]
+ pandas/core/reshape/concat.py:744: error: "object" has no attribute "__name__"; maybe "__ne__" or "__new__"? [attr-defined]
+ pandas/core/reshape/concat.py:744: error: Calling type() on a protocol class is unsound [misc]
dd-trace-py (https://github.com/DataDog/dd-trace-py)
+ ddtrace/internal/module.py:331: error: Calling type() on a protocol class is unsound [misc]
streamlit (https://github.com/streamlit/streamlit)
+ lib/streamlit/runtime/context.py: note: In function "_get_request":
+ lib/streamlit/runtime/context.py:46:12: error: Calling type() on a protocol class is unsound [misc]
+ lib/streamlit/runtime/context.py:46:45: error: "object" has no attribute "__qualname__" [attr-defined]
spark (https://github.com/apache/spark)
+ python/pyspark/ml/linalg/__init__.py:389: error: Calling type() on a protocol class is unsound [misc]
+ python/pyspark/mllib/linalg/__init__.py:442: error: Calling type() on a protocol class is unsound [misc]
scrapy (https://github.com/scrapy/scrapy)
+ scrapy/utils/python.py:311: error: Unused "type: ignore" comment [unused-ignore]
+ scrapy/utils/python.py:311: error: Calling type() on a protocol class is unsound [misc]
+ scrapy/utils/python.py:311: note: Error code "misc" not covered by "type: ignore" comment
+ scrapy/utils/python.py:311: error: "object" not callable [operator]
+ scrapy/utils/python.py:311: note: Error code "operator" not covered by "type: ignore" comment
+ scrapy/extensions/feedexport.py:538: error: Calling type() on a protocol class is unsound [misc]
+ scrapy/extensions/feedexport.py:538: error: "object" has no attribute "__name__"; maybe "__ne__" or "__new__"? [attr-defined]
+ scrapy/extensions/feedexport.py:541: error: Calling type() on a protocol class is unsound [misc]
+ scrapy/extensions/feedexport.py:541: error: "object" has no attribute "__name__"; maybe "__ne__" or "__new__"? [attr-defined]
hydra-zen (https://github.com/mit-ll-responsible-ai/hydra-zen)
- src/hydra_zen/structured_configs/_implementations.py:1137: error: No overload variant of "builds" of "BuildsFn" matches argument types "type[DataclassInstance]", "dict[str, int | float | Path | DataClass_ | type[DataClass_] | ListConfig | DictConfig | Enum | Sequence[HydraSupportedType] | Mapping[Any, HydraSupportedType] | None]", "bool | None", "Literal['none', 'partial', 'all', 'object'] | None", "DataclassOptions" [call-overload]
+ src/hydra_zen/structured_configs/_implementations.py:1117: error: Calling type() on a protocol class is unsound [misc]
+ src/hydra_zen/structured_configs/_implementations.py:1117: error: Argument 1 to "signature" has incompatible type "object"; expected "Callable[..., Any]" [arg-type]
+ src/hydra_zen/structured_configs/_implementations.py:1123: error: "object" has no attribute "__name__"; maybe "__ne__" or "__new__"? [attr-defined]
+ src/hydra_zen/structured_configs/_implementations.py:1123: error: Calling type() on a protocol class is unsound [misc]
+ src/hydra_zen/structured_configs/_implementations.py:1137: error: No overload variant of "builds" of "BuildsFn" matches argument types "object", "dict[str, int | float | Path | DataClass_ | type[DataClass_] | ListConfig | DictConfig | Enum | Sequence[HydraSupportedType] | Mapping[Any, HydraSupportedType] | None]", "bool | None", "Literal['none', 'partial', 'all', 'object'] | None", "DataclassOptions" [call-overload]
+ src/hydra_zen/structured_configs/_implementations.py:1138: error: Calling type() on a protocol class is unsound [misc]
pylox (https://github.com/sco1/pylox)
+ pylox/interpreter.py:65: error: Calling type() on a protocol class is unsound [misc]
jax (https://github.com/google/jax)
+ jax/_src/api.py:958: error: Calling type() on a protocol class is unsound [misc]
kornia (https://github.com/kornia/kornia)
+ kornia/geometry/camera/pinhole.py:401: error: Calling type() on a protocol class is unsound [misc]
xarray-dataclasses (https://github.com/astropenguin/xarray-dataclasses)
+ xarray_dataclasses/datamodel.py:214: error: Calling type() on a protocol class is unsound [misc]
+ xarray_dataclasses/datamodel.py:214: error: Incompatible types in assignment (expression has type "object", variable has type "type[DataClass[PInit]] | DataClass[PInit]") [assignment]
+ xarray_dataclasses/datamodel.py:216: error: Argument 1 to "get_type_hints" has incompatible type "type[DataClass[PInit]] | DataClass[PInit]"; expected "Callable[..., Any]" [arg-type]
antidote (https://github.com/Finistere/antidote)
+ src/antidote/core/wiring.py:187: error: Calling type() on a protocol class is unsound [misc]
+ src/antidote/core/_catalog.py:477: error: Calling type() on a protocol class is unsound [misc]
+ src/antidote/core/_scope.py:39: error: Calling type() on a protocol class is unsound [misc]
+ src/antidote/core/_inject.py:104: error: Calling type() on a protocol class is unsound [misc]
+ src/antidote/core/_inject.py:230: error: Calling type() on a protocol class is unsound [misc]
+ src/antidote/lib/interface_ext/predicate.py:319: error: Calling type() on a protocol class is unsound [misc]
+ src/antidote/lib/lazy_ext/_lazy.py:136: error: Calling type() on a protocol class is unsound [misc]
+ src/antidote/lib/interface_ext/_internal.py:170: error: Calling type() on a protocol class is unsound [misc]
+ src/antidote/lib/interface_ext/_internal.py:171: error: Argument 1 to "setdefault" of "MutableMapping" has incompatible type "object"; expected "type[PredicateConstraint[Any]]" [arg-type]
+ src/antidote/lib/interface_ext/_internal.py:172: error: Argument 1 to "issubclass" has incompatible type "object"; expected "type" [arg-type]
+ src/antidote/lib/interface_ext/_internal.py:173: error: Unused "type: ignore" comment [unused-ignore]
+ src/antidote/lib/injectable_ext/__init__.py:171: error: Calling type() on a protocol class is unsound [misc]
+ src/antidote/lib/interface_ext/_interface.py:98: error: Calling type() on a protocol class is unsound [misc]
+ src/antidote/lib/interface_ext/_interface.py:161: error: Calling type() on a protocol class is unsound [misc]
+ src/antidote/lib/interface_ext/_interface.py:344: error: Calling type() on a protocol class is unsound [misc]
Diff from mypy_primer, showing the effect of this PR on open source code:
websockets (https://github.com/aaugustin/websockets)
+ src/websockets/legacy/protocol.py:683: error: Item "type" of "type | Module | Any" has no attribute "__aiter__" (not async iterable) [union-attr]
+ src/websockets/legacy/protocol.py:690: error: Item "type" of "type | Module | Any" has no attribute "__anext__" [union-attr]
scrapy (https://github.com/scrapy/scrapy)
+ scrapy/utils/python.py:311: error: Unused "type: ignore" comment [unused-ignore]
+ scrapy/utils/python.py:311: error: Module not callable [operator]
+ scrapy/utils/python.py:311: note: Error code "operator" not covered by "type: ignore" comment
hydra-zen (https://github.com/mit-ll-responsible-ai/hydra-zen)
+ src/hydra_zen/structured_configs/_implementations.py:1117: error: Argument 1 to "signature" has incompatible type "type | Module | Any"; expected "Callable[..., Any]" [arg-type]
- src/hydra_zen/structured_configs/_implementations.py:1137: error: No overload variant of "builds" of "BuildsFn" matches argument types "type[DataclassInstance]", "dict[str, int | float | Path | DataClass_ | type[DataClass_] | ListConfig | DictConfig | Enum | Sequence[HydraSupportedType] | Mapping[Any, HydraSupportedType] | None]", "bool | None", "Literal['none', 'partial', 'all', 'object'] | None", "DataclassOptions" [call-overload]
+ src/hydra_zen/structured_configs/_implementations.py:1137: error: No overload variant of "builds" of "BuildsFn" matches argument types "type | Module | Any", "dict[str, int | float | Path | DataClass_ | type[DataClass_] | ListConfig | DictConfig | Enum | Sequence[HydraSupportedType] | Mapping[Any, HydraSupportedType] | None]", "bool | None", "Literal['none', 'partial', 'all', 'object'] | None", "DataclassOptions" [call-overload]
xarray-dataclasses (https://github.com/astropenguin/xarray-dataclasses)
+ xarray_dataclasses/datamodel.py:214: error: Incompatible types in assignment (expression has type "type | Module | Any", variable has type "type[DataClass[PInit]] | DataClass[PInit]") [assignment]
+ xarray_dataclasses/datamodel.py:216: error: Argument 1 to "get_type_hints" has incompatible type "type[DataClass[PInit]] | DataClass[PInit]"; expected "Callable[..., Any]" [arg-type]
antidote (https://github.com/Finistere/antidote)
+ src/antidote/lib/interface_ext/_internal.py:171: error: Argument 1 to "setdefault" of "MutableMapping" has incompatible type "type | Module | Any"; expected "type[PredicateConstraint[Any]]" [arg-type]
+ src/antidote/lib/interface_ext/_internal.py:172: error: Argument 1 to "issubclass" has incompatible type "type | Module | Any"; expected "type" [arg-type]
+ src/antidote/lib/interface_ext/_internal.py:173: error: Unused "type: ignore" comment [unused-ignore]
The websockets error is an interesting one:
elif isinstance(message, AsyncIterable):
... type(message).__aiter__ ...
This is kind of reasonable, since modules can't really implement __aiter__.
Maybe we could infer that protocols with certain dunder methods can only be implemented by regular class instances, and fall back to the to the old type(x) behavior? This would imply that a module object, for example, can never be assignable to AsyncIterable.
Diff from mypy_primer, showing the effect of this PR on open source code:
pydantic (https://github.com/pydantic/pydantic)
+ pydantic/dataclasses.py:266: error: "type" has no attribute "__pydantic_validator__" [attr-defined]
scrapy (https://github.com/scrapy/scrapy)
+ scrapy/utils/python.py:268: error: Unused "type: ignore" comment [unused-ignore]
hydra-zen (https://github.com/mit-ll-responsible-ai/hydra-zen)
- src/hydra_zen/structured_configs/_implementations.py:1155: error: No overload variant of "builds" of "BuildsFn" matches argument types "type[DataclassInstance]", "dict[str, int | float | Path | DataClass_ | type[DataClass_] | ListConfig | DictConfig | Enum | Sequence[HydraSupportedType] | Mapping[Any, HydraSupportedType] | None]", "bool | None", "Literal['none', 'partial', 'all', 'object'] | None", "DataclassOptions" [call-overload]
+ src/hydra_zen/structured_configs/_implementations.py:1155: error: No overload variant of "builds" of "BuildsFn" matches argument types "type", "dict[str, int | float | Path | DataClass_ | type[DataClass_] | ListConfig | DictConfig | Enum | Sequence[HydraSupportedType] | Mapping[Any, HydraSupportedType] | None]", "bool | None", "Literal['none', 'partial', 'all', 'object'] | None", "DataclassOptions" [call-overload]
websockets (https://github.com/aaugustin/websockets)
+ src/websockets/legacy/protocol.py:682: error: "type" has no attribute "__aiter__" (not async iterable) [attr-defined]
+ src/websockets/legacy/protocol.py:689: error: "type" has no attribute "__anext__" [attr-defined]