diff options
Diffstat (limited to 'astroid/tree/node_classes.py')
-rw-r--r-- | astroid/tree/node_classes.py | 157 |
1 files changed, 78 insertions, 79 deletions
diff --git a/astroid/tree/node_classes.py b/astroid/tree/node_classes.py index 722e2b75..7189b068 100644 --- a/astroid/tree/node_classes.py +++ b/astroid/tree/node_classes.py @@ -98,18 +98,36 @@ class AssignedStmtsMixin(object): # Name classes -@util.register_implementation(treeabc.AssignName) -class AssignName(base.LookupMixIn, base.ParentAssignTypeMixin, - AssignedStmtsMixin, base.NodeNG): - """class representing an AssignName node""" + +class BaseAssignName(base.LookupMixIn, base.ParentAssignTypeMixin, + AssignedStmtsMixin, base.NodeNG): _other_fields = ('name',) def __init__(self, name=None, lineno=None, col_offset=None, parent=None): self.name = name - super(AssignName, self).__init__(lineno, col_offset, parent) + super(BaseAssignName, self).__init__(lineno, col_offset, parent) infer_lhs = inference.infer_name +@util.register_implementation(treeabc.AssignName) +class AssignName(BaseAssignName): + """class representing an AssignName node""" + + +@util.register_implementation(treeabc.Parameter) +class Parameter(BaseAssignName): + + _astroid_fields = ('default', 'annotation') + _other_fields = ('name', ) + + def __init__(self, name=None, lineno=None, col_offset=None, parent=None): + super(Parameter, self).__init__(name=name, lineno=lineno, + col_offset=col_offset, parent=parent) + + def postinit(self, default, annotation): + self.default = default + self.annotation = annotation + @util.register_implementation(treeabc.DelName) class DelName(base.LookupMixIn, base.ParentAssignTypeMixin, base.NodeNG): @@ -129,54 +147,25 @@ class Name(base.LookupMixIn, base.NodeNG): def __init__(self, name=None, lineno=None, col_offset=None, parent=None): self.name = name super(Name, self).__init__(lineno, col_offset, parent) - + @util.register_implementation(treeabc.Arguments) class Arguments(base.AssignTypeMixin, AssignedStmtsMixin, base.NodeNG): """class representing an Arguments node""" - if six.PY3: - # Python 3.4+ uses a different approach regarding annotations, - # each argument is a new class, _ast.arg, which exposes an - # 'annotation' attribute. In astroid though, arguments are exposed - # as is in the Arguments node and the only way to expose annotations - # is by using something similar with Python 3.3: - # - we expose 'varargannotation' and 'kwargannotation' of annotations - # of varargs and kwargs. - # - we expose 'annotation', a list with annotations for - # for each normal argument. If an argument doesn't have an - # annotation, its value will be None. - - _astroid_fields = ('args', 'defaults', 'kwonlyargs', - 'kw_defaults', 'annotations', 'kwonly_annotations', - 'varargannotation', 'kwargannotation') - varargannotation = None - kwargannotation = None - else: - _astroid_fields = ('args', 'defaults', 'kwonlyargs', 'kw_defaults') - _other_fields = ('vararg', 'kwarg') - def __init__(self, vararg=None, kwarg=None, parent=None): + _astroid_fields = ('args', 'vararg', 'kwarg', 'keyword_only', 'positional_only') + + def __init__(self, parent=None): + # We don't want lineno and col_offset from the parent's __init__. + super(Arguments, self).__init__(parent=parent) + + def postinit(self, args, vararg, kwarg, keyword_only, positional_only): + self.args = args 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 + self.keyword_only = keyword_only + self.positional_only = positional_only + self.positional_and_keyword = self.args + self.positional_only def _infer_name(self, frame, name): if self.parent is frame: @@ -194,19 +183,16 @@ class Arguments(base.AssignTypeMixin, AssignedStmtsMixin, base.NodeNG): def format_args(self): """return arguments formatted as string""" result = [] - if self.args: - result.append( - _format_args(self.args, self.defaults, - getattr(self, 'annotations', None)) - ) + if self.positional_and_keyword: + result.append(_format_args(self.positional_and_keyword)) if self.vararg: - result.append('*%s' % self.vararg) - if self.kwonlyargs: + result.append('*%s' % _format_args((self.vararg, ))) + if self.keyword_only: if not self.vararg: result.append('*') - result.append(_format_args(self.kwonlyargs, self.kw_defaults)) + result.append(_format_args(self.keyword_only)) if self.kwarg: - result.append('**%s' % self.kwarg) + result.append('**%s' % _format_args((self.kwarg, ))) return ', '.join(result) def default_value(self, argname): @@ -214,28 +200,28 @@ class Arguments(base.AssignTypeMixin, AssignedStmtsMixin, base.NodeNG): :raise `NoDefault`: if there is no default value defined """ - i = _find_arg(argname, self.args)[0] - if i is not None: - 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] + for place in (self.positional_and_keyword, self.keyword_only): + i = _find_arg(argname, place)[0] + if i is not None: + value = place[i] + if not value.default: + continue + return value.default + raise exceptions.NoDefault(func=self.parent, name=argname) def is_argument(self, name): """return True if the name is defined in arguments""" - if name == self.vararg: + if self.vararg and name == self.vararg.name: return True - if name == self.kwarg: + if self.kwarg and name == self.kwarg.name: return True return self.find_argname(name, True)[1] is not None def find_argname(self, argname, rec=False): """return index and Name node with given name""" - if self.args: # self.args may be None in some cases (builtin function) - return _find_arg(argname, self.args, rec) + if self.positional_and_keyword: # self.args may be None in some cases (builtin function) + return _find_arg(argname, self.positional_and_keyword, rec) return None, None def get_children(self): @@ -257,27 +243,24 @@ def _find_arg(argname, args, rec=False): return None, None -def _format_args(args, defaults=None, annotations=None): +def _format_args(args): values = [] - if args is None: + if not args: return '' - if annotations is None: - annotations = [] - if defaults is not None: - default_offset = len(args) - len(defaults) - packed = six.moves.zip_longest(args, annotations) - for i, (arg, annotation) in enumerate(packed): + for i, arg in enumerate(args): if isinstance(arg, Tuple): values.append('(%s)' % _format_args(arg.elts)) else: argname = arg.name - if annotation is not None: + annotation = arg.annotation + if annotation: argname += ':' + annotation.as_string() values.append(argname) + + default = arg.default + if default: + values[-1] += '=' + default.as_string() - if defaults is not None and i >= default_offset: - if defaults[i-default_offset] is not None: - values[-1] += '=' + defaults[i-default_offset].as_string() return ', '.join(values) @@ -1322,6 +1305,22 @@ class DictUnpack(base.NodeNG): """Represents the unpacking of dicts into dicts using PEP 448.""" +@object.__new__ +@util.register_implementation(treeabc.Empty) +class Empty(base.NodeNG): + """Empty nodes represents the lack of something + + For instance, they can be used to represent missing annotations + or defaults for arguments or anything where None is a valid + value. + """ + + def __bool__(self): + return False + + __nonzero__ = __bool__ + + # Register additional inference dispatched functions. We do # this here, since we need to pass this module as an argument # to these functions, in order to avoid circular dependencies |