mypy icon indicating copy to clipboard operation
mypy copied to clipboard

Disallow calling type on Protocol

Open hauntsaninja opened this issue 1 year ago • 4 comments

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.

hauntsaninja avatar Nov 03 '24 07:11 hauntsaninja

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]

github-actions[bot] avatar Nov 03 '24 09:11 github-actions[bot]

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]

github-actions[bot] avatar Nov 03 '24 09:11 github-actions[bot]

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.

JukkaL avatar Nov 04 '24 13:11 JukkaL

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]

github-actions[bot] avatar Nov 30 '25 08:11 github-actions[bot]