Skip to content

Add a nodes.Arg to hold argument names, annotations, defaults for nodes.Arguments #215

@pylint-bot

Description

@pylint-bot

Originally reported by: BitBucket: ceridwenv, GitHub: @ceridwen


The constructors for Arguments nodes now look like:

    def __init__(self, vararg=None, kwarg=None, parent=None):
        self.vararg = vararg
        self.kwarg = kwarg
        self.parent = parent
        self.args = []
        self.defaults = []
        self.kwonlyargs = []
        self.kw_defaults = []
        self.annotations = []
        self.kwonly_annotations = []

    def postinit(self, args, defaults, kwonlyargs, kw_defaults,
                 annotations, kwonly_annotations, varargannotation=None,
                 kwargannotation=None):
        self.args = args
        self.defaults = defaults
        self.kwonlyargs = kwonlyargs
        self.kw_defaults = kw_defaults
        self.annotations = annotations
        self.varargannotation = varargannotation
        self.kwargannotation = kwargannotation
        self.kwonly_annotations = kwonly_annotations

Every property for every argument is held in a different field. I want to move to a different arrangement that's similar to how inspect's Signature objects handle arguments: https://docs.python.org/3/library/inspect.html#introspecting-callables-with-the-signature-object. Arguments will have four fields, args, vararg, kwarg, and (on Python 3) kwonlyargs, each of which will hold a sequence of Arg (I'm not sure this is the best name) nodes which will have a name field, a default field, and (on Python 3) an annotation field. This arrangement makes it easier to look up the value of an argument's annotation or default by name, by first finding the appropriate Arg.node and then looking up the annotation or default. Some disadvantages to this layout are that on Python 2 the Args node for varargs and kwargs is entirely superfluous, since they can't have default values and there are no annotations on Python 2, and that there will need to be a special constant object representing cases where there's no annotation or default.

Some possible alternative layouts imitate inspect.Signature more closely or imitate the standard library ast module. inspect.Signature has only one field for function parameters and has parameter objects with a kind field that distinguishes between positional-or-keyword arguments, keyword-only arguments, varargs, and kwargs. In my experience, this ends up leading to a lot of filtering boilerplate because when processing arguments, the argument's kind almost always matters. The standard library ast.Arguments has a layout of args, defaults (default values for positional-or-keyword arguments), vararg, kwonlyargs, kw_defaults, and kwargs. On Python 3, the elements of the appropriate sequences are an ast.Arg node with name and annotation fields, while on Python 2 they're strings. This arrangement has two disadvantages: writing Python 2/3-compatible code requires constant dispatching on six.PY2/PY3 because the elements of the sequences are different objects with different fields depending on the version, and looking the default value corresponding to a given name requires code like reversed(list(zip(reversed(args), reversed(defaults))), something similar with zip_longest, or the equivalent using indexing to line up the correct name with the correct default.


Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions