Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,5 @@ In the case of a false positive, use the disable command to remove the pylint er
| no-typing-import-in-type-check | Do not import typing under TYPE_CHECKING. | pylint:disable=no-typing-import-in-type-check | No Link. |
| do-not-log-raised-errors | Do not log errors at `error` or `warning` level when error is raised in an exception block. | pylint:disable=do-not-log-raised-errors | No Link. |
| do-not-use-legacy-typing | Do not use legacy (<Python 3.8) type hinting comments | pylint:disable=do-not-use-legacy-typing | No Link.
| do-not-import-asyncio | Do not import asyncio directly. | pylint:disable=do-not-import-asyncio | No Link. |
| do-not-import-asyncio | Do not import asyncio directly. | pylint:disable=do-not-import-asyncio | No Link. |
| invalid-use-of-overload | Do not mix async and synchronous overloads | pylint:disable=invalid-use-of-overload | No Link. |
Original file line number Diff line number Diff line change
Expand Up @@ -2865,6 +2865,65 @@ def visit_import(self, node):


# [Pylint] custom linter check for invalid use of @overload #3229


class InvalidUseOfOverload(BaseChecker):
"""Rule to check that use of the @overload decorator matches the async/sync nature of the underlying function"""

name = "invalid-use-of-overload"
priority = -1
msgs = {
"C4765": (
"Do not mix async and synchronous overloads",
"invalid-use-of-overload",
"Functions and their overloads must be either all async or all synchronous.",
),
}

def visit_classdef(self, node):
"""Check that use of the @overload decorator matches the async/sync nature of the underlying function"""

# Obtain a list of all functions and function names
functions = []
node.body
for item in node.body:
if hasattr(item, 'name'):
functions.append(item)

# Dictionary of lists of all functions by name
overloadedfunctions = {}
for item in functions:
if item.name in overloadedfunctions:
overloadedfunctions[item.name].append(item)
else:
overloadedfunctions[item.name] = [item]


# Loop through the overloaded functions and check they are the same type
for funct in overloadedfunctions.values():
if len(funct) > 1: # only need to check if there is more than 1 function with the same name
function_is_async = None

for item in funct:
if function_is_async is None:
function_is_async = self.is_function_async(item)

else:
if function_is_async != self.is_function_async(item):
self.add_message(
msgid=f"invalid-use-of-overload",
node=item,
confidence=None,
)


def is_function_async(self, node):
try:
str(node.__class__).index("Async")
return True
except:
return False

# [Pylint] Custom Linter check for Exception Logging #3227
# [Pylint] Address Commented out Pylint Custom Plugin Checkers #3228
# [Pylint] Add a check for connection_verify hardcoded settings #35355
Expand Down Expand Up @@ -2907,8 +2966,7 @@ def register(linter):
linter.register_checker(NoImportTypingFromTypeCheck(linter))
linter.register_checker(DoNotUseLegacyTyping(linter))
linter.register_checker(DoNotLogErrorsEndUpRaising(linter))

# [Pylint] custom linter check for invalid use of @overload #3229
linter.register_checker(InvalidUseOfOverload(linter))
# [Pylint] Custom Linter check for Exception Logging #3227
# [Pylint] Address Commented out Pylint Custom Plugin Checkers #3228
# [Pylint] Add a check for connection_verify hardcoded settings #35355
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Test file for InvalidUseOfOverload checker

from typing import overload, Union

class testingOverload:
@overload
async def double(a: str):
...

@overload
async def double(a: int):
...

async def double(a: Union[str, int]) -> int:
if isinstance(a, str):
return len(a)*2
return a * 2


@overload
def single(a: str):
...

@overload
def single(a: int):
...

def single(a: Union[str, int]) -> int:
if isinstance(a, str):
return len(a)
return a
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Test file for InvalidUseOfOverload checker - testing what mypy doesn't pick up

from typing import overload, Union

class testingOverload:
@overload
def double(a: str):
...

@overload
def double(a: int):
...

async def double(a: Union[str, int]):
if isinstance(a, str):
return len(a)*2
return a * 2


@overload
async def doubleAgain(a: str) -> int:
...

@overload
def doubleAgain(a: int) -> int:
...

async def doubleAgain(a: Union[str, int]) -> int:
if isinstance(a, str):
return len(a)*2
return a * 2
Original file line number Diff line number Diff line change
Expand Up @@ -3597,7 +3597,53 @@ def test_extra_nested_branches_exception_logged(self, setup):
):
self.checker.visit_try(try_node)

# [Pylint] custom linter check for invalid use of @overload #3229
class TestInvalidUseOfOverload(pylint.testutils.CheckerTestCase):
"""Test that use of the @overload decorator matches the async/sync nature of the underlying function"""

CHECKER_CLASS = checker.InvalidUseOfOverload

def test_valid_use_overload(self):
file = open(
os.path.join(
TEST_FOLDER, "test_files", "invalid_use_of_overload_acceptable.py"
)
)
node = astroid.parse(file.read())
file.close()
with self.assertNoMessages():
self.checker.visit_classdef(node.body[1])


def test_invalid_use_overload(self):
file = open(
os.path.join(
TEST_FOLDER, "test_files", "invalid_use_of_overload_violation.py"
)
)
node = astroid.extract_node(file.read())
file.close()

with self.assertAddsMessages(
pylint.testutils.MessageTest(
msg_id="invalid-use-of-overload",
line=14,
node=node.body[2],
col_offset=4,
end_line=14,
end_col_offset=20,
),
pylint.testutils.MessageTest(
msg_id="invalid-use-of-overload",
line=25,
node=node.body[4],
col_offset=4,
end_line=25,
end_col_offset=19,
),
):
self.checker.visit_classdef(node)


# [Pylint] Custom Linter check for Exception Logging #3227
# [Pylint] Address Commented out Pylint Custom Plugin Checkers #3228
# [Pylint] Add a check for connection_verify hardcoded settings #35355
Expand Down