Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 9519 super init with non self arg #10190

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
55 changes: 51 additions & 4 deletions pylint/checkers/typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -1464,22 +1464,69 @@
# those errors are handled by different warnings.
return

# Build the set of keyword arguments, checking for duplicate keywords,
# and count the positional arguments.
call_site = astroid.arguments.CallSite.from_call(node)

### Debug cruft used during dev, will remove when done.

Check notice on line 1471 in pylint/checkers/typecheck.py

View workflow job for this annotation

GitHub Actions / pylint

C0401

Wrong spelling of a word 'dev' in a comment:
### def _dp(s, val=None):
### return
### ## if "Attribute.__init__" not in str(node):
### ## return
### ## if val is None:
### ## print(f" {s}", flush=True)
### ## else:
### ## print(f" {s}: {val}", flush=True)
### _dp("-" * 25)
### _dp("visit call, node", node)
### _dp("Data dump for __init__ call")
### _dp("call_site", call_site)
### _dp("call_site args", call_site.arguments)
### _dp("call site positional args:", call_site.positional_arguments)
### _dp("call site keyword args:", call_site.keyword_arguments)
### _dp("call site invalid args", call_site.has_invalid_arguments())
### _dp("call site inv keywords", call_site.has_invalid_keywords())
### _dp("node args", node.args)
### _dp("node frame", node.frame())
### _dp("isinst", isinstance(node.frame(), nodes.ClassDef))
### _dp("funcdef", isinstance(called, nodes.FunctionDef))
### _dp("called", called)
### _dp("bound method init in called", "BoundMethod __init__ of builtins.object" in str(called))
### _dp("called.args", called.args)
### _dp("frame body", node.frame().body)
### _dp("called in frame body", called in node.frame().body)
### _dp("dec names", called.decoratornames())

Check notice on line 1498 in pylint/checkers/typecheck.py

View workflow job for this annotation

GitHub Actions / pylint

C0401

Wrong spelling of a word 'decoratornames' in a comment:

def _call_site_has_args(cs: arguments.CallSite) -> bool:
"""True if any args passed."""
has_args = (
False
or len(cs.positional_arguments) > 0
or len(cs.keyword_arguments.items()) > 0
# or cs.starargs is not None
# or cs.kwargs is not None
)
return has_args

if called.args.args is None:
if called.name == "isinstance":
# Verify whether second argument of isinstance is a valid type
self._check_isinstance_args(node, callable_name)
# Built-in functions have no argument information.
# Check built-in __init__ ... a user-defined __init__ function
# is handled elsewhere.
if "BoundMethod __init__ of builtins.object" in str(called):
if _call_site_has_args(call_site):
self.add_message(
"too-many-function-args", node=node, args=("__init__",)
)
return

if len(called.argnames()) != len(set(called.argnames())):
# Duplicate parameter name (see duplicate-argument). We can't really
# make sense of the function call in this case, so just return.
return

# Build the set of keyword arguments, checking for duplicate keywords,
# and count the positional arguments.
call_site = astroid.arguments.CallSite.from_call(node)

# Warn about duplicated keyword arguments, such as `f=24, **{'f': 24}`
for keyword in call_site.duplicated_keywords:
self.add_message("repeated-keyword", node=node, args=(keyword,))
Expand Down
15 changes: 15 additions & 0 deletions tests/regrtest_data/super_init_with_non_self_argument.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
https://github.com/pylint-dev/pylint/issues/9519
"""

# pylint: disable=missing-class-docstring,missing-function-docstring,too-few-public-methods
class Window:
def print_text(self, txt):
print(f'{__class__} {txt}')


class Win(Window):
def __init__(self, txt):
super().__init__(txt)

Win('hello')
14 changes: 14 additions & 0 deletions tests/test_self.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,20 @@ def test_wrong_import_position_when_others_disabled(self) -> None:
actual_output = actual_output[actual_output.find("\n") :]
assert self._clean_paths(expected_output.strip()) == actual_output.strip()

def test_super_init_with_non_self_argument(self) -> None:
module1 = join(HERE, "regrtest_data", "super_init_with_non_self_argument.py")
args = [module1, "-rn", "-sn"]
out = StringIO()
self._run_pylint(args, out=out)
actual_output = self._clean_paths(out.getvalue().strip())
expected = textwrap.dedent(
f"""
************* Module super_init_with_non_self_argument
{module1}:13:8: E1121: Too many positional arguments for __init__ call (too-many-function-args)
"""
)
assert self._clean_paths(expected.strip()) == actual_output.strip()

def test_progress_reporting(self) -> None:
module1 = join(HERE, "regrtest_data", "import_something.py")
module2 = join(HERE, "regrtest_data", "wrong_import_position.py")
Expand Down
Loading