Skip to content

Commit de7d819

Browse files
committed
Provide more info on *args and **kwargs
If available, these nodes (accessed through arguments()) now contain lineno and col offset information.
1 parent 9503e9a commit de7d819

File tree

3 files changed

+53
-20
lines changed

3 files changed

+53
-20
lines changed

astroid/nodes/node_classes.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,9 @@ def _infer(
605605
DEPRECATED_ARGUMENT_DEFAULT = "DEPRECATED_ARGUMENT_DEFAULT"
606606

607607

608-
class Arguments(_base_nodes.AssignTypeNode):
608+
class Arguments(
609+
_base_nodes.AssignTypeNode
610+
): # pylint: disable=too-many-instance-attributes
609611
"""Class representing an :class:`ast.arguments` node.
610612
611613
An :class:`Arguments` node represents that arguments in a
@@ -704,7 +706,20 @@ class Arguments(_base_nodes.AssignTypeNode):
704706
kwargannotation: NodeNG | None
705707
"""The type annotation for the variable length keyword arguments."""
706708

707-
def __init__(self, vararg: str | None, kwarg: str | None, parent: NodeNG) -> None:
709+
vararg_node: NodeNG | None
710+
"""The node for variable length arguments"""
711+
712+
kwarg_node: NodeNG | None
713+
"""The node for keyword arguments"""
714+
715+
def __init__(
716+
self,
717+
vararg: str | None,
718+
kwarg: str | None,
719+
parent: NodeNG,
720+
vararg_node: NodeNG | None = None,
721+
kwarg_node: NodeNG | None = None,
722+
) -> None:
708723
"""Almost all attributes can be None for living objects where introspection failed."""
709724
super().__init__(
710725
parent=parent,
@@ -720,6 +735,9 @@ def __init__(self, vararg: str | None, kwarg: str | None, parent: NodeNG) -> Non
720735
self.kwarg = kwarg
721736
"""The name of the variable length keyword arguments."""
722737

738+
self.vararg_node = vararg_node
739+
self.kwarg_node = kwarg_node
740+
723741
# pylint: disable=too-many-arguments
724742
def postinit(
725743
self,
@@ -788,22 +806,11 @@ def arguments(self):
788806
* Keyword only arguments (e.g **kwargs)
789807
"""
790808
retval = list(itertools.chain((self.posonlyargs or ()), (self.args or ())))
791-
if self.vararg:
792-
retval.append(
793-
AssignName(
794-
self.vararg,
795-
-1,
796-
-1,
797-
self,
798-
end_lineno=-1,
799-
end_col_offset=-1,
800-
)
801-
)
809+
if self.vararg_node:
810+
retval.append(self.vararg_node)
802811
retval += self.kwonlyargs or ()
803-
if self.kwarg:
804-
retval.append(
805-
AssignName(self.kwarg, -1, -1, self, end_lineno=-1, end_col_offset=-1)
806-
)
812+
if self.kwarg_node:
813+
retval.append(self.kwarg_node)
807814

808815
return retval
809816

@@ -935,7 +942,9 @@ def default_value(self, argname):
935942
:raises NoDefault: If there is no default value defined for the
936943
given argument.
937944
"""
938-
args = [arg for arg in self.arguments if arg.lineno >= 0]
945+
args = [
946+
arg for arg in self.arguments if arg.name not in [self.vararg, self.kwarg]
947+
]
939948

940949
index = _find_arg(argname, self.kwonlyargs)[0]
941950
if index is not None and self.kw_defaults[index] is not None:
@@ -984,7 +993,7 @@ def find_argname(self, argname, rec=DEPRECATED_ARGUMENT_DEFAULT):
984993
)
985994
if self.arguments:
986995
index, argument = _find_arg(argname, self.arguments)
987-
if argument and argument.lineno >= 0:
996+
if argument and argument.name not in [self.vararg, self.kwarg]:
988997
return index, argument
989998
return None, None
990999

astroid/protocols.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ def _arguments_infer_argname(
356356
yield util.Uninferable
357357
return
358358

359-
args = [arg for arg in self.arguments if arg.lineno >= 0]
359+
args = [arg for arg in self.arguments if arg.name not in [self.vararg, self.kwarg]]
360360
functype = self.parent.type
361361
# first argument of instance/class method
362362
if (

astroid/rebuilder.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from astroid.const import IS_PYPY, PY38, PY39_PLUS, PY312_PLUS, Context
2222
from astroid.manager import AstroidManager
2323
from astroid.nodes import NodeNG
24+
from astroid.nodes.node_classes import AssignName
2425
from astroid.nodes.utils import Position
2526
from astroid.typing import InferenceResult
2627

@@ -561,10 +562,33 @@ def visit_arguments(self, node: ast.arguments, parent: NodeNG) -> nodes.Argument
561562
"""Visit an Arguments node by returning a fresh instance of it."""
562563
vararg: str | None = None
563564
kwarg: str | None = None
565+
vararg_node = node.vararg
566+
kwarg_node = node.kwarg
567+
564568
newnode = nodes.Arguments(
565569
node.vararg.arg if node.vararg else None,
566570
node.kwarg.arg if node.kwarg else None,
567571
parent,
572+
AssignName(
573+
vararg_node.arg,
574+
vararg_node.lineno,
575+
vararg_node.col_offset,
576+
parent,
577+
end_lineno=vararg_node.end_lineno,
578+
end_col_offset=vararg_node.end_col_offset,
579+
)
580+
if vararg_node
581+
else None,
582+
AssignName(
583+
kwarg_node.arg,
584+
kwarg_node.lineno,
585+
kwarg_node.col_offset,
586+
parent,
587+
end_lineno=kwarg_node.end_lineno,
588+
end_col_offset=kwarg_node.end_col_offset,
589+
)
590+
if kwarg_node
591+
else None,
568592
)
569593
args = [self.visit(child, newnode) for child in node.args]
570594
defaults = [self.visit(child, newnode) for child in node.defaults]

0 commit comments

Comments
 (0)