diff options
author | Julien Cristau <julien.cristau@logilab.fr> | 2013-07-18 22:57:13 +0200 |
---|---|---|
committer | Julien Cristau <julien.cristau@logilab.fr> | 2013-07-18 22:57:13 +0200 |
commit | ba2393d46474b72bb04b50dce629a9fa2bd6c7c5 (patch) | |
tree | 499d0d7df051006e30b85fff4cc9eae87e0a0294 | |
parent | 5b0746a34b39a9c8d0fb00a1277fd844666a247d (diff) | |
download | astroid-git-ba2393d46474b72bb04b50dce629a9fa2bd6c7c5.tar.gz |
Add support for py3k's keyword only arguments
PEP 3102
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | node_classes.py | 20 | ||||
-rw-r--r-- | rebuilder.py | 10 | ||||
-rw-r--r-- | scoped_nodes.py | 2 |
4 files changed, 31 insertions, 3 deletions
@@ -15,6 +15,8 @@ Change log for the astroid package (used to be astng) * Added the test_utils module for building ASTs and extracting deeply nested nodes for easier testing. + * Add support for py3k's keyword only arguments (PEP 3102) + * rename the project as astroid 2013-04-16 -- 0.24.3 diff --git a/node_classes.py b/node_classes.py index 8c6ad8aa..97bd9079 100644 --- a/node_classes.py +++ b/node_classes.py @@ -253,9 +253,11 @@ class Name(LookupMixIn, NodeNG): class Arguments(NodeNG, AssignTypeMixin): """class representing an Arguments node""" - _astroid_fields = ('args', 'defaults') + _astroid_fields = ('args', 'defaults', 'kwonlyargs', 'kw_defaults') args = None defaults = None + kwonlyargs = None + kw_defaults = None def __init__(self, vararg=None, kwarg=None): self.vararg = vararg @@ -275,6 +277,10 @@ class Arguments(NodeNG, AssignTypeMixin): result.append('*%s' % self.vararg) if self.kwarg: result.append('**%s' % self.kwarg) + if self.kwonlyargs: + if not self.vararg: + result.append('*') + result.append(_format_args(self.kwonlyargs, self.kw_defaults)) return ', '.join(result) def default_value(self, argname): @@ -287,6 +293,9 @@ class Arguments(NodeNG, AssignTypeMixin): idx = i - (len(self.args) - len(self.defaults)) if idx >= 0: return self.defaults[idx] + i = _find_arg(argname, self.kwonlyargs)[0] + if i is not None and self.kw_defaults[i] is not None: + return self.kw_defaults[i] raise NoDefault() def is_argument(self, name): @@ -303,6 +312,12 @@ class Arguments(NodeNG, AssignTypeMixin): return _find_arg(argname, self.args, rec) return None, None + def get_children(self): + """override get_children to skip over None elements in kw_defaults""" + for child in super(Arguments, self).get_children(): + if child is not None: + yield child + def _find_arg(argname, args, rec=False): for i, arg in enumerate(args): @@ -328,7 +343,8 @@ def _format_args(args, defaults=None): else: values.append(arg.name) if defaults is not None and i >= default_offset: - values[-1] += '=' + defaults[i-default_offset].as_string() + if defaults[i-default_offset] is not None: + values[-1] += '=' + defaults[i-default_offset].as_string() return ', '.join(values) diff --git a/rebuilder.py b/rebuilder.py index e06adeaf..cf92da09 100644 --- a/rebuilder.py +++ b/rebuilder.py @@ -185,6 +185,8 @@ class TreeRebuilder(object): newnode.args = [self.visit(child, newnode) for child in node.args] self.asscontext = None newnode.defaults = [self.visit(child, newnode) for child in node.defaults] + newnode.kwonlyargs = [] + newnode.kw_defaults = [] newnode.vararg = node.vararg newnode.kwarg = node.kwarg # save argument names in locals: @@ -836,6 +838,14 @@ class TreeRebuilder3k(TreeRebuilder): # XXX or we should instead introduce a Arg node in astroid ? return self.visit_assname(node, parent, node.arg) + def visit_arguments(self, node, parent): + newnode = super(TreeRebuilder3k, self).visit_arguments(node, parent) + self.asscontext = "Ass" + newnode.kwonlyargs = [self.visit(child, newnode) for child in node.kwonlyargs] + self.asscontext = None + newnode.kw_defaults = [self.visit(child, newnode) if child else None for child in node.kw_defaults] + return newnode + def visit_excepthandler(self, node, parent): """visit an ExceptHandler node by returning a fresh instance of it""" newnode = new.ExceptHandler() diff --git a/scoped_nodes.py b/scoped_nodes.py index dabaf0c7..3886b7e1 100644 --- a/scoped_nodes.py +++ b/scoped_nodes.py @@ -506,7 +506,7 @@ class Lambda(LocalsDictNodeNG, FilterStmtsMixin): return self.body.infer(context) def scope_lookup(self, node, name, offset=0): - if node in self.args.defaults: + if node in self.args.defaults or node in self.args.kw_defaults: frame = self.parent.frame() # line offset to avoid that def func(f=func) resolve the default # value to the defined function |