Add lock checks to pylint type-hint plugin (#73521)

* Add ability to check kwargs type annotation

* Add checks for lock

* Add tests

* Fix components

* Fix spelling

* Revert "Fix components"

This reverts commit 121ff6dc51.

* Adjust comment

* Add comments to TypeHintMatch
This commit is contained in:
epenet 2022-06-21 18:53:31 +02:00 committed by GitHub
parent 3823edda32
commit 9fd48da132
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 6 deletions

View File

@ -21,7 +21,10 @@ class TypeHintMatch:
function_name: str
return_type: list[str] | str | None | object
# arg_types is for positional arguments
arg_types: dict[int, str] | None = None
# kwarg_types is for the special case `**kwargs`
kwargs_type: str | None = None
check_return_type_inheritance: bool = False
@ -442,9 +445,9 @@ _CLASS_MATCH: dict[str, list[ClassTypeHintMatch]] = {
),
],
}
# Properties are normally checked by mypy, and will only be checked
# by pylint when --ignore-missing-annotations is False
_PROPERTY_MATCH: dict[str, list[ClassTypeHintMatch]] = {
# Overriding properties and functions are normally checked by mypy, and will only
# be checked by pylint when --ignore-missing-annotations is False
_INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = {
"lock": [
ClassTypeHintMatch(
base_class="LockEntity",
@ -473,6 +476,36 @@ _PROPERTY_MATCH: dict[str, list[ClassTypeHintMatch]] = {
function_name="is_jammed",
return_type=["bool", None],
),
TypeHintMatch(
function_name="lock",
kwargs_type="Any",
return_type=None,
),
TypeHintMatch(
function_name="async_lock",
kwargs_type="Any",
return_type=None,
),
TypeHintMatch(
function_name="unlock",
kwargs_type="Any",
return_type=None,
),
TypeHintMatch(
function_name="async_unlock",
kwargs_type="Any",
return_type=None,
),
TypeHintMatch(
function_name="open",
kwargs_type="Any",
return_type=None,
),
TypeHintMatch(
function_name="async_open",
kwargs_type="Any",
return_type=None,
),
],
),
],
@ -613,7 +646,7 @@ class HassTypeHintChecker(BaseChecker): # type: ignore[misc]
priority = -1
msgs = {
"W7431": (
"Argument %d should be of type %s",
"Argument %s should be of type %s",
"hass-argument-type",
"Used when method argument type is incorrect",
),
@ -659,7 +692,7 @@ class HassTypeHintChecker(BaseChecker): # type: ignore[misc]
self._class_matchers.extend(class_matches)
if not self.linter.config.ignore_missing_annotations and (
property_matches := _PROPERTY_MATCH.get(module_platform)
property_matches := _INHERITANCE_MATCH.get(module_platform)
):
self._class_matchers.extend(property_matches)
@ -709,6 +742,16 @@ class HassTypeHintChecker(BaseChecker): # type: ignore[misc]
args=(key + 1, expected_type),
)
# Check that kwargs is correctly annotated.
if match.kwargs_type and not _is_valid_type(
match.kwargs_type, node.args.kwargannotation
):
self.add_message(
"hass-argument-type",
node=node,
args=(node.args.kwarg, match.kwargs_type),
)
# Check the return type.
if not _is_valid_return_type(match, node.returns):
self.add_message(

View File

@ -478,7 +478,7 @@ def test_invalid_entity_properties(
# Set bypass option
type_hint_checker.config.ignore_missing_annotations = False
class_node, prop_node = astroid.extract_node(
class_node, prop_node, func_node = astroid.extract_node(
"""
class LockEntity():
pass
@ -491,6 +491,12 @@ def test_invalid_entity_properties(
self
):
pass
async def async_lock( #@
self,
**kwargs
) -> bool:
pass
""",
"homeassistant.components.pylint_test.lock",
)
@ -507,6 +513,24 @@ def test_invalid_entity_properties(
end_line=9,
end_col_offset=18,
),
pylint.testutils.MessageTest(
msg_id="hass-argument-type",
node=func_node,
args=("kwargs", "Any"),
line=14,
col_offset=4,
end_line=14,
end_col_offset=24,
),
pylint.testutils.MessageTest(
msg_id="hass-return-type",
node=func_node,
args="None",
line=14,
col_offset=4,
end_line=14,
end_col_offset=24,
),
):
type_hint_checker.visit_classdef(class_node)
@ -528,6 +552,12 @@ def test_ignore_invalid_entity_properties(
self
):
pass
async def async_lock(
self,
**kwargs
) -> bool:
pass
""",
"homeassistant.components.pylint_test.lock",
)