Skip to content

Commit f377242

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 4efb411 commit f377242

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
@@ -604,7 +604,9 @@ def _infer(
604604
DEPRECATED_ARGUMENT_DEFAULT = "DEPRECATED_ARGUMENT_DEFAULT"
605605

606606

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

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

737+
self.vararg_node = vararg_node
738+
self.kwarg_node = kwarg_node
739+
722740
# pylint: disable=too-many-arguments
723741
def postinit(
724742
self,
@@ -787,22 +805,11 @@ def arguments(self):
787805
* Keyword only arguments (e.g **kwargs)
788806
"""
789807
retval = list(itertools.chain((self.posonlyargs or ()), (self.args or ())))
790-
if self.vararg:
791-
retval.append(
792-
AssignName(
793-
self.vararg,
794-
-1,
795-
-1,
796-
self,
797-
end_lineno=-1,
798-
end_col_offset=-1,
799-
)
800-
)
808+
if self.vararg_node:
809+
retval.append(self.vararg_node)
801810
retval += self.kwonlyargs or ()
802-
if self.kwarg:
803-
retval.append(
804-
AssignName(self.kwarg, -1, -1, self, end_lineno=-1, end_col_offset=-1)
805-
)
811+
if self.kwarg_node:
812+
retval.append(self.kwarg_node)
806813

807814
return retval
808815

@@ -934,7 +941,9 @@ def default_value(self, argname):
934941
:raises NoDefault: If there is no default value defined for the
935942
given argument.
936943
"""
937-
args = [arg for arg in self.arguments if arg.lineno >= 0]
944+
args = [
945+
arg for arg in self.arguments if arg.name not in [self.vararg, self.kwarg]
946+
]
938947

939948
index = _find_arg(argname, self.kwonlyargs)[0]
940949
if index is not None and self.kw_defaults[index] is not None:
@@ -983,7 +992,7 @@ def find_argname(self, argname, rec=DEPRECATED_ARGUMENT_DEFAULT):
983992
)
984993
if self.arguments:
985994
index, argument = _find_arg(argname, self.arguments)
986-
if argument and argument.lineno >= 0:
995+
if argument and argument.name not in [self.vararg, self.kwarg]:
987996
return index, argument
988997
return None, None
989998

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

@@ -564,10 +565,33 @@ def visit_arguments(self, node: ast.arguments, parent: NodeNG) -> nodes.Argument
564565
"""Visit an Arguments node by returning a fresh instance of it."""
565566
vararg: str | None = None
566567
kwarg: str | None = None
568+
vararg_node = node.vararg
569+
kwarg_node = node.kwarg
570+
567571
newnode = nodes.Arguments(
568572
node.vararg.arg if node.vararg else None,
569573
node.kwarg.arg if node.kwarg else None,
570574
parent,
575+
AssignName(
576+
vararg_node.arg,
577+
vararg_node.lineno,
578+
vararg_node.col_offset,
579+
parent,
580+
end_lineno=vararg_node.end_lineno,
581+
end_col_offset=vararg_node.end_col_offset,
582+
)
583+
if vararg_node
584+
else None,
585+
AssignName(
586+
kwarg_node.arg,
587+
kwarg_node.lineno,
588+
kwarg_node.col_offset,
589+
parent,
590+
end_lineno=kwarg_node.end_lineno,
591+
end_col_offset=kwarg_node.end_col_offset,
592+
)
593+
if kwarg_node
594+
else None,
571595
)
572596
args = [self.visit(child, newnode) for child in node.args]
573597
defaults = [self.visit(child, newnode) for child in node.defaults]

0 commit comments

Comments
 (0)